@progress/kendo-e2e
Version:
Kendo UI end-to-end test utilities.
385 lines • 14.8 kB
JavaScript
;
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