UNPKG

@progress/kendo-e2e

Version:

Kendo UI end-to-end test utilities.

385 lines 14.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EC = void 0; const selenium_webdriver_1 = require("selenium-webdriver"); const VIEWPORT_SCRIPT = function (element) { const box = element.getBoundingClientRect(); const cx = box.left + box.width / 2; const cy = box.top + box.height / 2; let target = document.elementFromPoint(cx, cy); while (target) { if (target === element) { return true; } target = target.parentElement; } return false; }; /** * Expected Conditions (EC) - factory methods for creating wait conditions. * * Provides a collection of commonly used wait conditions for element states. * These conditions are designed to work with {@link WebApp.wait} and {@link WebApp.waitSafely}. * * **All conditions automatically handle:** * - Elements that don't exist yet * - Stale element references * - Timing issues * * @example * ```typescript * // Wait for element to be visible * await app.wait(EC.isVisible('#modal')); * * // Wait for element to have specific text * await app.wait(EC.hasText(element, 'Success')); * * // Wait for element to have focus * await app.wait(EC.hasFocus(inputElement)); * * // Check condition without throwing error * const isVisible = await app.waitSafely(EC.isVisible('.optional-banner')); * if (isVisible) { * await app.click('.banner-close'); * } * ``` */ class EC { /** * Creates a condition that waits for an element to have specific text. * * Compares the element's visible text content (via getText()) with the expected text. * Match must be exact. * * @param element - WebElement to check text of * @param text - Exact text to wait for * @returns Condition function for use with wait() * * @example * ```typescript * const message = await app.find('#message'); * await app.wait(EC.hasText(message, 'Operation completed')); * * // Or check without waiting * const hasCorrectText = await app.hasText('#status', 'Active'); * ``` */ static hasText(element, text) { return () => element.getText().then(result => { return result === text; }); } /** * Creates a condition that waits for an input element to have a specific value. * * Checks the 'value' attribute of form inputs. Perfect for validating input fields * after auto-fill, dynamic updates, or user interaction. * * @param element - Input WebElement to check * @param value - Expected value * @returns Condition function for use with wait() * * @example * ```typescript * const input = await app.find('#username'); * await app.type(input, 'testuser'); * await app.wait(EC.hasValue(input, 'testuser')); * * // Wait for auto-filled value * await app.wait(EC.hasValue(await app.find('#email'), 'user@example.com')); * ``` */ static hasValue(element, value) { return () => element.getAttribute("value").then(result => { return result === value; }); } /** * Creates a condition that waits for an element to have keyboard focus. * * Checks if the element is the currently active (focused) element in the document. * Useful for testing keyboard navigation and focus management. * * @param element - WebElement to check for focus * @returns Condition function for use with wait() * * @example * ```typescript * const input = await app.find('#search'); * await app.click(input); * await app.wait(EC.hasFocus(input)); * * // Verify focus moved after Tab key * await app.sendKey(Key.TAB); * const nextInput = await app.find('#next-field'); * await app.wait(EC.hasFocus(nextInput)); * ``` */ static hasFocus(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { const focused = yield driver.switchTo().activeElement(); return (yield element.getId()) === (yield focused.getId()); }); } /** * Creates a condition that waits for an element to lose keyboard focus. * * Opposite of {@link hasFocus}. Useful for testing blur events and focus movement. * * @param element - WebElement to check for lack of focus * @returns Condition function for use with wait() * * @example * ```typescript * const input = await app.find('#field'); * await app.focus(input); * await app.sendKey(Key.TAB); // Move focus away * await app.wait(EC.hasNoFocus(input)); * ``` */ static hasNoFocus(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { const focused = yield driver.switchTo().activeElement(); return (yield element.getId()) !== (yield focused.getId()); }); } /** * Creates a condition that waits for an element to have at least one child matching a locator. * * Checks if the parent element contains any child elements matching the selector. * Useful for waiting for dynamic content to load within a container. * * @param element - Parent WebElement to search within * @param locator - Child element selector (By locator or CSS selector string) * @returns Condition function for use with wait() * * @example * ```typescript * const list = await app.find('ul#results'); * await app.wait(EC.hasChild(list, 'li')); * * // Wait for specific child * const table = await app.find('#data-table'); * await app.wait(EC.hasChild(table, '.loaded-row')); * ``` */ static hasChild(element, locator) { return () => __awaiter(this, void 0, void 0, function* () { return (locator instanceof selenium_webdriver_1.By) ? element.findElements(locator).then(result => { return result.length > 0; }) : element.findElements(selenium_webdriver_1.By.css(locator)).then(result => { return result.length > 0; }); }); } /** * Creates a condition that waits for an element to have a specific attribute value. * * Can check for exact match or partial match (contains). Useful for validating * data attributes, ARIA attributes, disabled state, etc. * * @param element - WebElement to check * @param attribute - Attribute name (e.g., 'disabled', 'data-id', 'aria-label') * @param value - Expected value * @param exactMatch - If true, value must match exactly; if false, attribute must contain value (default: true) * @returns Condition function for use with wait() * * @example * ```typescript * const button = await app.find('#submit'); * * // Wait for button to become disabled * await app.wait(EC.hasAttribute(button, 'disabled', 'true')); * * // Wait for data attribute (partial match) * await app.wait(EC.hasAttribute(button, 'data-state', 'loading', false)); * * // Check ARIA label * await app.wait(EC.hasAttribute(button, 'aria-label', 'Submit form')); * ``` */ static hasAttribute(element, attribute, value, exactMatch = true) { return () => element.getAttribute(attribute).then(result => { if (exactMatch) { return result === value; } else { return result.includes(value); } }); } /** * Creates a condition that waits for an element to have a specific CSS class. * * Convenience method that checks the 'class' attribute. Can do exact or partial match. * Perfect for waiting for state changes reflected in CSS classes. * * @param element - WebElement to check * @param value - Class name to wait for * @param exactMatch - If true, class attribute must match exactly; if false, must contain the class (default: false) * @returns Condition function for use with wait() * * @example * ```typescript * const button = await app.find('#submit'); * * // Wait for class to be added (partial match) * await app.wait(EC.hasClass(button, 'active')); * * // Wait for exact class attribute * await app.wait(EC.hasClass(button, 'btn btn-primary', true)); * * // Wait for loading class * await app.wait(EC.hasClass(await app.find('.spinner'), 'loading')); * ``` */ static hasClass(element, value, exactMatch = false) { return this.hasAttribute(element, "class", value, exactMatch); } /** * Creates a condition that waits for an element to be visible. * * Element must be present in DOM and have display style that makes it visible. * Accepts WebElement, By locator, or CSS selector string. * * @param element - Element to check visibility of (WebElement, By locator, or CSS selector) * @returns Condition function for use with wait() * * @example * ```typescript * // Wait for modal to appear * await app.wait(EC.isVisible('#modal')); * * // Wait for element after click * await app.click('#show-details'); * await app.wait(EC.isVisible('.details-panel')); * * // With By locator * await app.wait(EC.isVisible(By.css('[data-test="banner"]'))); * ``` */ static isVisible(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { try { if (!(element instanceof selenium_webdriver_1.WebElement)) { element = (element instanceof selenium_webdriver_1.By) ? yield driver.findElement(element) : yield driver.findElement(selenium_webdriver_1.By.css(element)); } return yield element.isDisplayed(); } catch (_a) { return false; } }); } /** * Creates a condition that waits for an element to become hidden or not present. * * Element is considered not visible if it's either not in DOM or has display:none or similar. * Opposite of {@link isVisible}. * * @param element - Element to check (WebElement, By locator, or CSS selector) * @returns Condition function for use with wait() * * @example * ```typescript * // Wait for loading spinner to disappear * await app.wait(EC.notVisible('.spinner')); * * // Wait for modal to close * await app.click('.modal .close'); * await app.wait(EC.notVisible('.modal')); * ``` */ static notVisible(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { try { if (!(element instanceof selenium_webdriver_1.WebElement)) { element = (element instanceof selenium_webdriver_1.By) ? yield driver.findElement(element) : yield driver.findElement(selenium_webdriver_1.By.css(element)); } return !(yield element.isDisplayed()); } catch (_a) { return true; } }); } /** * Creates a condition that waits for an element to be in the visible viewport. * * Checks if the center point of the element is actually visible in the viewport and not * covered by other elements. Stricter than {@link isVisible} - element must be scrolled into view. * * @param element - Element to check (WebElement, By locator, or CSS selector) * @returns Condition function for use with wait() * * @example * ```typescript * // Wait for element to scroll into view * await app.wait(EC.isInViewport('.footer-content')); * * // Verify element is actually visible to user * await app.scrollIntoView('#target'); * await app.wait(EC.isInViewport('#target')); * ``` */ static isInViewport(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { try { if (!(element instanceof selenium_webdriver_1.WebElement)) { element = (element instanceof selenium_webdriver_1.By) ? yield driver.findElement(element) : yield driver.findElement(selenium_webdriver_1.By.css(element)); } const result = yield driver.executeScript(VIEWPORT_SCRIPT, element); return (result + '') === 'true'; } catch (_a) { return false; } }); } /** * Creates a condition that waits for an element to be outside the visible viewport. * * Checks if the element is scrolled out of view or covered. Opposite of {@link isInViewport}. * * @param element - Element to check (WebElement, By locator, or CSS selector) * @returns Condition function for use with wait() * * @example * ```typescript * // Wait for element to scroll out of view * await app.scrollIntoView('#bottom-element'); * await app.wait(EC.notInViewport('#top-element')); * ``` */ static notInViewport(element) { return (driver) => __awaiter(this, void 0, void 0, function* () { try { if (!(element instanceof selenium_webdriver_1.WebElement)) { element = (element instanceof selenium_webdriver_1.By) ? yield driver.findElement(element) : yield driver.findElement(selenium_webdriver_1.By.css(element)); } const result = yield driver.executeScript(VIEWPORT_SCRIPT, element); return (result + '') === 'false'; } catch (_a) { return true; } }); } } exports.EC = EC; //# sourceMappingURL=conditions.js.map