UNPKG

cypress-plus

Version:

A bunch of useful Cypress commands with full TypeScript support.

929 lines (808 loc) 47.1 kB
function logCommand({ options, originalOptions }) { if (options.log) { options.logger({ name: options.description, message: options.customLogMessage, consoleProps: () => originalOptions, }) } } function logCommandCheck({ result, options, originalOptions }) { if (!options.log || !options.verbose) return const message = [result] if (options.customLogCheckMessage) { message.unshift(options.customLogCheckMessage) } options.logger({ name: options.description, message, consoleProps: () => originalOptions, }) } function polling(subject: any, checkFunction: any, originalOptions = {}) { if (!(checkFunction instanceof Function)) { throw new Error("'checkFunction' parameter should be a function. Found: " + checkFunction) } const defaultOptions = { interval: 200, timeout: 5000, retries: 25, errorMessage: <any>"Timed out retrying.", description: "polling", log: true, customLogMessage: undefined, logger: Cypress.log, verbose: false, customLogCheckMessage: undefined, postFailureAction: <any>undefined, mode: "timeout", ignoreFailureException: false, } const options = { ...defaultOptions, ...originalOptions } options.customLogMessage = <any>[options.customLogMessage, originalOptions].filter(Boolean) let retries = 0 if (options.mode == "timeout") { retries = Math.floor(options.timeout / options.interval) options.errorMessage = "Timed out retrying." } else { retries = options.retries options.errorMessage = "Retried too many times." } let currentWaitTime: number | undefined let waitTime: number | number[] = 0 if (Array.isArray(options.interval)) { waitTime = options.interval.reverse(); } else { waitTime = options.interval; } if (Array.isArray(options.interval)) { if (options.interval.length > 1) { currentWaitTime = (<number[]>waitTime).pop(); } else { currentWaitTime = waitTime[0]; } } else { currentWaitTime = <number>waitTime; } logCommand({ options, originalOptions }); const check = (result: any) => { logCommandCheck({ result, options, originalOptions }) if (Array.isArray(options.interval)) { if (options.interval.length > 1) { currentWaitTime = (<number[]>waitTime).pop(); } else { currentWaitTime = waitTime[0]; } } else { currentWaitTime = <number>waitTime; } if (result) { return result; } if (retries < 1) { const msg = options.errorMessage instanceof Function ? options.errorMessage(result, options) : options.errorMessage if (options.postFailureAction && options.postFailureAction instanceof Function) { const fnResult = options.postFailureAction(); if (fnResult === true || fnResult === false) { return fnResult; } } if (!options.ignoreFailureException && !options.postFailureAction) throw new Error(msg); return; } if (currentWaitTime) { cy.wait(currentWaitTime, { log: false }).then(() => { retries-- return resolveValue(); }) } } const resolveValue = () => { const result = checkFunction(subject) const isAPromise = Boolean(result && result.then) if (isAPromise) { return result.then(check) } else { return check(result) } } return resolveValue() } Cypress.Commands.add("polling", { prevSubject: "optional" }, polling); Cypress.Commands.add("clickOnDataCy", (selector: string, options?: any) => { return cy.get(`[data-cy="${selector}"]`, options).click(options); }); Cypress.Commands.add("clickOnDataCyAdv", (selector: string, moreSelectors: string, options?: any) => { return cy.getByDataCyAdv(selector, moreSelectors, options).click(options); }); Cypress.Commands.add("waitForUrlAndVisibleDataCy", (url: string, selector: string, timeout?: number) => { if (url && selector) { cy.visit(url as string, { timeout: timeout || 5000 }); return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }).should("be.visible"); } }); Cypress.Commands.add("waitForUrlAndVisible", (url: string, selector: string, timeout?: number) => { if (url && selector) { cy.visit(url as string, { timeout: timeout || 5000 }); return cy.get(selector, { timeout: timeout || 5000 }).should("be.visible"); } }); Cypress.Commands.add("rightClickOnDataCy", (selector: string, options?: any) => { return cy.get(`[data-cy="${selector}"]`, options).rightclick(options); }); Cypress.Commands.add("getByDataCy", (selector: string, options?: any) => { return cy.get(`[data-cy="${selector}"]`, options); }); Cypress.Commands.add("getByDataCyStartsWith", (selector: string, options?: any) => { return cy.get(`[data-cy^="${selector}"]`, options); }); Cypress.Commands.add("getByDataCyEndsWith", (selector: string, options?: any) => { return cy.get(`[data-cy$="${selector}"]`, options); }); Cypress.Commands.add("getByDataCyContains", (selector: string, options?: any) => { return cy.get(`[data-cy*="${selector}"]`, options); }); Cypress.Commands.add("getByData", (dataName: string, selector: string, options?: any) => { return cy.get(`[data-${dataName}="${selector}"]`, options); }); Cypress.Commands.add("getByDataStartsWith", (dataName: string, selector: string, options?: any) => { return cy.get(`[data-${dataName}^="${selector}"]`, options); }); Cypress.Commands.add("getByDataEndsWith", (dataName: string, selector: string, options?: any) => { return cy.get(`[data-${dataName}$="${selector}"]`, options); }); Cypress.Commands.add("getByDataContains", (dataName: string, selector: string, options?: any) => { return cy.get(`[data-${dataName}*="${selector}"]`, options); }); Cypress.Commands.add("getByDataAdv", (dataName: string, selector: string, moreSelectors: string, options?: any) => { moreSelectors = moreSelectors ?? ""; return cy.get(`[data-${dataName}="${selector}"] ${moreSelectors}`.trim(), options); }); Cypress.Commands.add("getByDataCyAdv", (selector: string, moreSelectors: string, options?: any) => { moreSelectors = moreSelectors ?? ""; return cy.get(`[data-cy="${selector}"] ${moreSelectors}`.trim(), options); }); Cypress.Commands.add("await", <T>(promise: Promise<T>, throwException?: boolean, wait?: number) => { return cy.then(() => { return cy.wrap(null, { log: false }).then(() => { if (wait && wait > 0) { cy.wait(wait); } if (throwException) { return new Cypress.Promise((resolve, reject) => { return promise.then(resolve, reject); }); } else { return new Cypress.Promise((resolve, reject) => { return promise.catch(resolve).then(resolve, reject); }); } }); }); }); Cypress.Commands.add("awaitFor", (promise: Promise<unknown>, throwException?: boolean, wait?: number) => { return cy.then(() => { return cy.wrap(null, { log: false }).then(() => { if (wait && wait > 0) { cy.wait(wait); } if (throwException) { return new Cypress.Promise((resolve, reject) => { return promise.then(resolve, reject); }); } else { return new Cypress.Promise((resolve, reject) => { return promise.catch(resolve).then(resolve, reject); }); } }); }); }); Cypress.Commands.add("justWrap", (action: (...args: any[]) => any, wait?: number, options?: any) => { if (!options) { options = { log: false }; }; return cy.wrap(null, options).then(() => { if (wait && wait > 0) { cy.wait(wait); } return action(); }); }); Cypress.Commands.add("waitForUrlToChange", (currentUrl: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.polling(() => { return cy.url().then(url => { return url != currentUrl; }) }, { mode: "timeout", timeout: timeout, interval: 100 }).then(() => { return cy.url().should("not.eq", currentUrl); }); }); Cypress.Commands.add("assertElementsCount", (selector: string, count: number, lengthComparison: "equal" | "above" | "below" | "atMost" | "atLeast", options?: any) => { if (count <= 0) count = 0; switch (lengthComparison) { case "equal": return cy.get(selector, options).should("have.length", count); case "above": return cy.get(selector, options).should("have.length.above", count); case "below": return cy.get(selector, options).should("have.length.below", count); case "atLeast": return cy.get(selector, options).should("have.length.at.least", count); case "atMost": return cy.get(selector, options).should("have.length.at.most", count); } }); Cypress.Commands.add("getCount", (selector: string, options?: any) => { return cy.get(selector, options).then($elements => { const countOfElements = $elements.length; return cy.wrap(countOfElements, { log: false }); }); }); Cypress.Commands.add("getByAriaLabel", (ariaLabel: string, options?: any) => { return cy.get(`[aria-label="${ariaLabel}"]`, options); }); Cypress.Commands.add("getByTitle", (title: string, options?: any) => { return cy.get(`[title="${title}"]`, options); }); Cypress.Commands.add("getByAlt", (alt: string, options?: any) => { return cy.get(`[alt="${alt}"]`, options); }); Cypress.Commands.add("getByPlaceholder", (placeholder: string, options?: any) => { return cy.get(`[placeholder="${placeholder}"]`, options); }); Cypress.Commands.add("getByValue", (value: string, options?: any) => { return cy.get(`[value="${value}"]`, options); }); Cypress.Commands.add("waitAndClick", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(selector, { timeout: timeout }).click(); }); Cypress.Commands.add("getByText", (text: string, timeout?: number) => { return cy.contains(text, { matchCase: false, includeShadowDom: true, timeout: timeout || 5000 }); }); Cypress.Commands.add("getByExactText", (text: string, timeout?: number) => { return cy.contains(text, { matchCase: true, includeShadowDom: true, timeout: timeout || 5000 }); }); Cypress.Commands.add("justType", (selector: string, text: string, pressEnter = false, options?: any) => { if (pressEnter) return cy.get(selector, options).type("{selectall}" + text + "{enter}") return cy.get(selector, options).type("{selectall}" + text); }); Cypress.Commands.add("waitForType", (selector: string, text: string, timeout?: number, pressEnter = false, options?: any) => { if (!timeout || timeout <= 0) timeout = 5000; cy.wait(timeout); if (pressEnter) return cy.get(selector, options).type("{selectall}" + text + "{enter}") return cy.get(selector, options).type("{selectall}" + text); }); Cypress.Commands.add("waitForTypeByDataCy", (selector: string, text: string, timeout?: number, pressEnter = false, options?: any) => { if (!timeout || timeout <= 0) timeout = 5000; cy.wait(timeout); if (pressEnter) return cy.get(`[data-cy="${selector}"]`, options).type("{selectall}" + text + "{enter}") return cy.get(`[data-cy="${selector}"]`, options).type("{selectall}" + text); }); Cypress.Commands.add("clearAndType", (selector: string, text: string, pressEnter = false, options?: any) => { if (pressEnter) return cy.get(selector, options).clear().type("{selectall}" + text + "{enter}") return cy.get(selector, options).clear().type("{selectall}" + text); }); Cypress.Commands.add("clearAndTypeByDataCy", (selector: string, text: string, pressEnter = false, options?: any) => { if (pressEnter) return cy.get(`[data-cy="${selector}"]`, options).clear().type("{selectall}" + text + "{enter}") return cy.get(`[data-cy="${selector}"]`, options).clear().type("{selectall}" + text); }); Cypress.Commands.add("typeByDataCy", (selector: string, text: string, pressEnter = false, options?: any) => { if (pressEnter) return cy.get(`[data-cy="${selector}"]`, options).type("{selectall}" + text + "{enter}") return cy.get(`[data-cy="${selector}"]`, options).type("{selectall}" + text); }); Cypress.Commands.add("waitForClearAndType", (selector: string, text: string, timeout?: number, pressEnter = false, options?: any) => { if (!timeout || timeout <= 0) timeout = 5000; cy.wait(timeout); if (pressEnter) return cy.get(selector, options).clear().type("{selectall}" + text + "{enter}") return cy.get(selector, options).clear().type("{selectall}" + text); }); Cypress.Commands.add("waitForClearAndTypeByDataCy", (selector: string, text: string, timeout?: number, pressEnter = false, options?: any) => { if (!timeout || timeout <= 0) timeout = 5000; cy.wait(timeout); if (pressEnter) return cy.get(`[data-cy="${selector}"]`, options).clear().type("{selectall}" + text + "{enter}") return cy.get(`[data-cy="${selector}"]`, options).clear().type("{selectall}" + text); }); Cypress.Commands.add("selectFromDropdown", (selector: string, value: string, options?: any) => { return cy.get(selector, options).select(value); }); Cypress.Commands.add("hover", (selector: string, options?: any) => { return cy.get(selector, options).trigger("mouseover"); }); Cypress.Commands.add("waitForElement", (selector: string, timeout?: number) => { return cy.get(selector, { timeout: timeout || 5000 }); }); Cypress.Commands.add("waitForElementDataCy", (selector: string, timeout?: number) => { return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }); }); Cypress.Commands.add("waitForElementDataCyAdv", (selector: string, moreSelectors: string, timeout?: number) => { moreSelectors = moreSelectors ?? ""; return cy.get(`[data-cy="${selector}"] ${moreSelectors}`.trim(), { timeout: timeout || 5000 }); }); Cypress.Commands.add("getInputValue", (selector: string, options?: any) => { return cy.get(selector, options).then(($input) => { return cy.wrap($input.val(), { log: false }); }); }); Cypress.Commands.add("getParent", (selector: string, options?: any) => { return cy.get(selector, options).parent(); }); Cypress.Commands.add("getSibling", (selector: string, nth: number, options?: any) => { return cy.get(selector, options).siblings(":nth-child(" + nth + ")"); }); Cypress.Commands.add("getNthChild", (selector: string, nth: number, options?: any) => { return cy.get(selector, options).children().eq(nth); }); Cypress.Commands.add("checkCheckbox", (selector: string, options?: any) => { return cy.get(selector, options).check(); }); Cypress.Commands.add("uncheckCheckbox", (selector: string, options?: any) => { return cy.get(selector, options).uncheck(); }); Cypress.Commands.add("getByClass", (className: string, options?: any) => { return cy.get(`.${className}`, options); }); Cypress.Commands.add("getByClassStartsWith", (className: string, options?: any) => { return cy.get(`[class^="${className}"]`, options); }); Cypress.Commands.add("getByClassEndsWith", (className: string, options?: any) => { return cy.get(`[class$="${className}"]`, options); }); Cypress.Commands.add("getByClassContains", (className: string, options?: any) => { return cy.get(`[class*="${className}"]`, options); }); Cypress.Commands.add("clickButton", (buttonText: string, options?: any) => { return cy.get(`button:contains("${buttonText}")`, options).click(); }); Cypress.Commands.add("clickLink", (linkText: string, options?: any) => { return cy.get(`link:contains("${linkText}")`, options).click(); }); Cypress.Commands.add("getByRole", (role: string, options?: any) => { return cy.get(`[role=${role}]`, options); }); Cypress.Commands.add("getByName", (name: string, options?: any) => { return cy.get(`[name=${name}]`, options); }); Cypress.Commands.add("getByHref", (href: string, options?: any) => { return cy.get(`a[href='${href}']`, options); }); Cypress.Commands.add("getFirst", (selector: string, options?: any) => { return cy.get(selector, options).first(); }); Cypress.Commands.add("getLast", (selector: string, options?: any) => { return cy.get(selector, options).last(); }); Cypress.Commands.add("getFirstNth", (selector: string, nth: number, options?: any) => { return cy.get(selector, options).first().nextAll().eq(nth); }); Cypress.Commands.add("getLastNth", (selector: string, nth: number, options?: any) => { return cy.get(selector, options).last().prevAll().eq(nth); }); Cypress.Commands.add("getByAriaDescribedBy", (ariaDescribedBy: string, options?: any) => { return cy.get(`[aria-describedby='${ariaDescribedBy}']`, options); }); Cypress.Commands.add("getByAriaControls", (ariaControls: string, options?: any) => { return cy.get(`[aria-controls='${ariaControls}']`, options); }); Cypress.Commands.add("getByAriaCurrent", (ariaCurrent: string, options?: any) => { return cy.get(`[aria-current='${ariaCurrent}']`, options); }); Cypress.Commands.add("waitForInvisible", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(selector, { timeout: timeout || 5000 }).should("not.be.visible"); }); Cypress.Commands.add("waitForVisible", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(selector, { timeout: timeout || 5000 }).should("be.visible"); }); Cypress.Commands.add("waitForInvisibleDataCy", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }).should("not.be.visible"); }); Cypress.Commands.add("waitForVisibleDataCy", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }).should("be.visible"); }); Cypress.Commands.add("waitForExist", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(selector, { timeout: timeout || 5000 }).should("exist"); }); Cypress.Commands.add("waitForNotExist", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(selector, { timeout: timeout || 5000 }).should("not.exist"); }); Cypress.Commands.add("waitForExistDataCy", (selector: string, timeout?: number) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }).should("exist"); }); Cypress.Commands.add("waitForNotExistDataCy", (selector: string, timeout) => { if (!timeout || timeout <= 0) timeout = 5000; return cy.get(`[data-cy="${selector}"]`, { timeout: timeout || 5000 }).should("not.exist"); }); Cypress.Commands.add("goBack", () => { return cy.go("back"); }); Cypress.Commands.add("goForward", () => { return cy.go("forward"); }); Cypress.Commands.add("clearStoragesAndCookies", () => { return cy.window().then((win) => { win.sessionStorage.clear(); cy.clearCookies(); cy.clearLocalStorage(); }); }); Cypress.Commands.add("getByAttribute", (attrName: string, attrValue: string, options?: any) => { return cy.get(`[${attrName}="${attrValue}"]`, options); }); Cypress.Commands.add("getByAttributeStartsWith", (attrName: string, attrValue: string, options?: any) => { return cy.get(`[${attrName}^="${attrValue}"]`, options); }); Cypress.Commands.add("getByAttributeEndsWith", (attrName: string, attrValue: string, options?: any) => { return cy.get(`[${attrName}$="${attrValue}"]`, options); }); Cypress.Commands.add("getByAttributeContains", (attrName: string, attrValue: string, options?: any) => { return cy.get(`[${attrName}*="${attrValue}"]`, options); }); Cypress.Commands.add("getAttribute", (selector: string, attribute: string, options?: any) => { return cy.get(selector, options).then($el => { return cy.wrap($el.attr(attribute), { log: false }); }); }); Cypress.Commands.add("getAttributeDataCy", (selector: string, attribute: string, options?: any) => { return cy.get(`[data-cy="${selector}"]`, options).then($el => { return cy.wrap($el.attr(attribute), { log: false }); }); }); Cypress.Commands.add("getAttributeDataCyAdv", (selector: string, attribute: string, moreSelectors: string, options?: any) => { moreSelectors = moreSelectors ?? ""; return cy.get(`[data-cy="${selector}"] ${moreSelectors}`.trim(), options).then($el => { return cy.wrap($el.attr(attribute), { log: false }); }); }); Cypress.Commands.add("getParentIf", (selector: string, condition: (parent: any) => boolean, options?: any) => { return cy.get(selector, options).parents().each($el => { if (condition($el)) return cy.wrap($el, { log: false }); }); }); Cypress.Commands.add("getParentsIf", (selector: string, condition: (parent: any) => boolean, options?: any) => { const result: JQuery<HTMLElement>[] = []; cy.get(selector, options).parents().each($el => { if (condition($el)) result.push($el); }); return cy.wrap(result, { log: false }); }); Cypress.Commands.add("getChildIf", (selector: string, condition: (child: any) => boolean, options?: any) => { return cy.get(selector, options).children().each($el => { if (condition($el)) return cy.wrap($el, { log: false }); }); }); Cypress.Commands.add("getChildrenIf", (selector: string, condition: (child: any) => boolean, options?: any) => { const result: JQuery<HTMLElement>[] = []; cy.get(selector, options).children().each($el => { if (condition($el)) result.push($el); }); return cy.wrap(result, { log: false }); }); Cypress.Commands.add("iterateChildren", (selector: string, callback: (child: any) => void, options?: any) => { return cy.get(selector, options).find("*").each(($el) => { callback($el); }); }); Cypress.Commands.add("iterateChildrenIf", (selector: string, condition: (child: any) => boolean, callback: (child: any) => void, options?: any) => { return cy.get(selector, options).find("*").each(($el) => { if (condition($el)) callback($el); }); }); Cypress.Commands.add("scrollToElement", (selector: string, position?: Cypress.PositionType, options?: Partial<Cypress.ScrollToOptions>) => { position = position || "center"; options = options || { ensureScrollable: false }; return cy.get(selector).scrollTo(position, options); }); Cypress.Commands.add("scrollToElementByDataCy", (selector: string, position?: Cypress.PositionType, options?: Partial<Cypress.ScrollToOptions>) => { position = position || "center"; options = options || { ensureScrollable: false }; return cy.get(`[data-cy="${selector}"]`).scrollTo(position, options); }); Cypress.Commands.add("isEmpty", (selector: string, options?: any) => { return cy.get(selector, options).should('be.empty'); }); Cypress.Commands.add("isNotEmpty", (selector: string, options?: any) => { return cy.get(selector, options).should('not.be.empty'); }); Cypress.Commands.add("hasValue", (selector: string, value: string, options?: any) => { return cy.get(selector, options).should('have.value', value); }); Cypress.Commands.add("doesNotHaveValue", (selector: string, value: string, options?: any) => { return cy.get(selector, options).should('have.value', value); }); Cypress.Commands.add("hasClass", (selector: string, value: string, options?: any) => { return cy.get(selector, options).should('have.class', value); }); Cypress.Commands.add("doesNotHaveClass", (selector: string, value: string, options?: any) => { return cy.get(selector, options).should('not.have.class', value) }); Cypress.Commands.add("isVisible", (selector: string, options?: any) => { return cy.get(selector, options).should('be.visible'); }); Cypress.Commands.add("isNotVisible", (selector: string, options?: any) => { return cy.get(selector, options).should('not.be.visible'); }); Cypress.Commands.add("checkURL", (url: string) => { return cy.url().should('include', url); }); Cypress.Commands.add("invokeText", (selector: string, options?: any) => { return cy.get(selector, options).invoke('text').then(value => { return cy.wrap(value); }); }); Cypress.Commands.add("invokeTextByDataCy", (selector: string, options?: any) => { return cy.get(`[data-cy="${selector}"]`, options).invoke('text').then(value => { return cy.wrap(value); }); }); Cypress.Commands.add("hasAttribute", (selector: string, attribute: string, value: string, options?: any) => { return cy.get(selector, options).should('have.attr', attribute, value) }); Cypress.Commands.add("doesNotHaveAttribute", (selector: string, attribute: string, value: string, options?: any) => { return cy.get(selector, options).should('not.have.attr', attribute, value) }); export abstract class Ability<T> { public abstract can(): T; } export class UseCypress extends Ability<Cypress.cy & CyEventEmitter> { public can(): Cypress.cy & CyEventEmitter { return cy; } } export abstract class Interaction { public abstract attemptAs(actor: Actor): Cypress.Chainable<unknown>; } export abstract class Task { constructor(private readonly interactions: Interaction[]) { } public getInteractions(): Interaction[] { return this.interactions; } public attemptInteractionsAs(actor: Actor): void { for (const interaction of this.getInteractions()) { interaction.attemptAs(actor); } } public attemptInteractionAs(actor: Actor, interactionClass: new (...args: never[]) => Interaction ): Cypress.Chainable<unknown> { const matchingInteractions = this.interactions?.filter( (a) => a instanceof interactionClass ) as Interaction[]; if (matchingInteractions.length === 0) { throw new Error( `Interaction with name of '${interactionClass.name}' not found.` ); } return matchingInteractions[0].attemptAs(actor); } public abstract performAs(actor: Actor): Cypress.Chainable<unknown>; } export abstract class Question { public abstract askAs(actor: Actor): Cypress.Chainable<unknown>; } export class Actor { constructor(private readonly abilities?: Ability<unknown>[]) { } public useAbility<T>( abilityClass: new (...args: never[]) => Ability<T> ): T { const matchingAbilities = this.abilities?.filter( (a) => a instanceof abilityClass ) as Ability<T>[]; if (matchingAbilities.length === 0) { throw new Error( `Actor does not have ability with name of '${abilityClass.name}'.` ); } return matchingAbilities[0].can(); } public performs( taskOrInteraction: Task | Task[] | Interaction | Interaction[] ): Cypress.Chainable<unknown> | undefined { if (taskOrInteraction instanceof Task) { return taskOrInteraction.performAs(this); } if (taskOrInteraction instanceof Interaction) { return taskOrInteraction.attemptAs(this); } if ( Array.isArray(taskOrInteraction) && taskOrInteraction.length > 0 && taskOrInteraction[0] instanceof Task ) { for (const interaction of taskOrInteraction) { (interaction as Task).performAs(this); } return; } if ( Array.isArray(taskOrInteraction) && taskOrInteraction.length > 0 && taskOrInteraction[0] instanceof Interaction ) { for (const interaction of taskOrInteraction) { (interaction as Interaction).attemptAs(this); } return; } } public asserts<T>( question: Question, assert: (answer: T) => void ): void { question.askAs(this).then((answer: unknown) => { assert(answer as T); }); } public asksAbout<T>(question: Question): Cypress.Chainable<T> { return question.askAs(this) as Cypress.Chainable<T>; } } export type PollingLog = Pick<Cypress.LogConfig, "name" | "message" | "consoleProps">; export type PollingErrorMsgCallback<Subject = any> = (result: Subject, options: PollingOptions<Subject>) => string; export interface PollingOptions<Subject = any> { retries?: number; timeout?: number; interval: number | number[]; errorMessage?: string | PollingErrorMsgCallback<Subject>; description?: string; customLogMessage?: string; verbose?: boolean; customLogCheckMessage?: string; logger?: (logOptions: PollingLog) => any; log?: boolean; mode: "timeout" | "retry", ignoreFailureException?: boolean, postFailureAction?: () => boolean | void, } // TypeScript declaration declare global { namespace Cypress { // eslint-disable-next-line @typescript-eslint/no-unused-vars interface Chainable<Subject = any> { getByDataCyContains<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataCyStartsWith<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataCyEndsWith<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataCy<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow & Cypress.ActionableOptions>): Chainable<JQuery<E>>; getByDataCyAdv<E extends Node = HTMLElement>(selector: string, moreSelectors: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; waitForUrlAndVisible(url: string, selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForUrlAndVisibleDataCy(url: string, selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; clickOnDataCy(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; clickOnDataCyAdv(selector: string, moreSelectors: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; rightClickOnDataCy(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getByDataContains<E extends Node = HTMLElement>(dataName: string, selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataStartsWith<E extends Node = HTMLElement>(dataName: string, selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataEndsWith<E extends Node = HTMLElement>(dataName: string, selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByData<E extends Node = HTMLElement>(dataName: string, selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByDataAdv<E extends Node = HTMLElement>(dataName: string, selector: string, moreSelectors: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; await<T>(promise: Promise<T>, throwException?: boolean, wait?: number): Chainable<T>; awaitFor(promise: Promise<unknown>, throwException?: boolean, wait?: number): Chainable<unknown>; justWrap(action: (...args: any[]) => any, wait?: number, options?: Partial<Loggable & Timeoutable>): Chainable<any>; waitForUrlToChange(currentUrl: string, timeout?: number): Chainable<string>; getByAriaDescribedBy<E extends Node = HTMLElement>(ariaLabel: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAriaControls<E extends Node = HTMLElement>(ariaLabel: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAriaCurrent<E extends Node = HTMLElement>(ariaLabel: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAriaLabel<E extends Node = HTMLElement>(ariaLabel: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByTitle<E extends Node = HTMLElement>(title: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAlt<E extends Node = HTMLElement>(alt: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByPlaceholder<E extends Node = HTMLElement>(placeholder: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByValue<E extends Node = HTMLElement>(value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByClass<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByClassContains<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByClassStartsWith<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByClassEndsWith<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAttribute<E extends Node = HTMLElement>(attrName: string, attrValue: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAttributeContains<E extends Node = HTMLElement>(attrName: string, attrValue: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAttributeStartsWith<E extends Node = HTMLElement>(attrName: string, attrValue: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByAttributeEndsWith<E extends Node = HTMLElement>(attrName: string, attrValue: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByRole<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getByName<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; waitAndClick(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; getByText(selector: string, timeout?: number): Chainable<any>; getByExactText(selector: string, timeout?: number): Chainable<any>; justType(selector: string, text: string, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; clearAndType(selector: string, text: string, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; waitForClearAndType(selector: string, text: string, timeout?: number, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; clearAndTypeByDataCy(selector: string, text: string, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; typeByDataCy(selector: string, text: string, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; waitForTypeByDataCy(selector: string, text: string, timeout?: number, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; waitForType(selector: string, text: string, timeout?: number, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; waitForClearAndTypeByDataCy(selector: string, text: string, timeout?: number, pressEnter?: boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getCount(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<number>; clearStoragesAndCookies(): Chainable<Cypress.AUTWindow>; goBack(): Chainable<Cypress.AUTWindow>; goForward(): Chainable<Cypress.AUTWindow>; navigateTo(route: string): Chainable<Cypress.AUTWindow>; assertElementsCount(selector: string, count: number, lengthComparison: "equal" | "above" | "below" | "atMost" | "atLeast", options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getInputValue(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string | number | string[] | undefined>; getParent<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getSibling<E extends Node = HTMLElement>(selector: string, nth: number, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getNthChild<E extends Node = HTMLElement>(selector: string, nth: number, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getFirst(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getLast<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getFirstNth<E extends Node = HTMLElement>(selector: string, nth: number, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; getLastNth<E extends Node = HTMLElement>(selector: string, nth: number, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; checkCheckbox(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; uncheckCheckbox(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; clickButton(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; clickLink(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getByHref<E extends Node = HTMLElement>(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<E>>; waitForNotExistDataCy(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForNotExist(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForExistDataCy(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForExist(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForInvisibleDataCy(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForInvisible(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForVisibleDataCy(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForVisible(selector: string, timeout?: number): Chainable<JQuery<HTMLElement>>; waitForElement<E extends Node = HTMLElement>(selector: string, timeout?: number): Chainable<JQuery<E>>; waitForElementDataCy<E extends Node = HTMLElement>(selector: string, timeout?: number): Chainable<JQuery<E>>; waitForElementDataCyAdv<E extends Node = HTMLElement>(selector: string, moreSelectors: string, timeout?: number): Chainable<JQuery<E>>; selectFromDropdown(selector: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; hover(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getAttribute(selector: string, attribute: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string | undefined>; getAttributeDataCy(selector: string, attribute: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string | undefined>; getAttributeDataCyAdv(selector: string, attribute: string, moreSelectors: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string | undefined>; getParentIf(selector: string, condition: (parent: JQuery<HTMLElement>) => boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getChildIf(selector: string, condition: (child: JQuery<HTMLElement>) => boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; getParentsIf(selector: string, condition: (parent: JQuery<HTMLElement>) => boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>[]>; getChildrenIf(selector: string, condition: (child: JQuery<HTMLElement>) => boolean, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>[]>; iterateChildren(selector: string, callback: (child: JQuery<HTMLElement>) => void, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; iterateChildrenIf(selector: string, condition: (child: JQuery<HTMLElement>) => boolean, callback: (child: JQuery<HTMLElement>) => void, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; scrollToElement(selector: string, position?: Cypress.PositionType, options?: Partial<Cypress.ScrollToOptions>): Chainable<JQuery<HTMLElement>>; scrollToElementByDataCy(selector: string, position?: Cypress.PositionType, options?: Partial<Cypress.ScrollToOptions>): Chainable<JQuery<HTMLElement>>; isEmpty(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; isNotEmpty(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; hasValue(selector: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; doesNotHaveValue(selector: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; hasClass(selector: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; doesNotHaveClass(selector: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; isVisible(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; isNotVisible(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; checkURL(url: string): Chainable<string>; invokeText(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string>; invokeTextByDataCy(selector: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<string>; hasAttribute(selector: string, attribute: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; doesNotHaveAttribute(selector: string, attribute: string, value: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<JQuery<HTMLElement>>; polling<ReturnType = any>( checkFunction: (subject: Subject | undefined) => ReturnType | Chainable<ReturnType> | Promise<ReturnType>, options?: PollingOptions<Subject>, ): Chainable<Subject>; } } }