UNPKG

playwright-elements

Version:
590 lines (589 loc) 20.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebElement = void 0; exports.$ = $; exports.$getByAltText = $getByAltText; exports.$getByLabel = $getByLabel; exports.$getByPlaceholder = $getByPlaceholder; exports.$getByRole = $getByRole; exports.$getByTestId = $getByTestId; exports.$getByText = $getByText; exports.$getByTitle = $getByTitle; exports.initDesktopOrMobile = initDesktopOrMobile; const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); const index_1 = require("./index"); const test_1 = require("@playwright/test"); function extractSelector(pointer) { return pointer instanceof WebElement ? pointer.selector : pointer; } const _expect = test_1.expect; class WebElement { _isFrame = false; _isInFrame = false; _frameSelector = 'iframe'; _parents = []; _selector; _by; _byOptions; _hasLocator; _hasNotLocator; _hasText; _hasNotText; _nth; _and = []; _or = []; constructor(selector, by, options) { this._selector = selector; this._by = by; this._byOptions = options; } // page and frame pointers selectLocatorMethod(element) { if (!element) return undefined; if (typeof element === 'string') return index_1.BrowserInstance.currentPage.locator(element); return element.locator; } buildLocator(locatorsChain, element) { const locatorsChainWithIframeType = element._isInFrame ? locatorsChain.frameLocator(element._frameSelector) : locatorsChain; switch (element._by) { case By.getByAltText: locatorsChain = locatorsChainWithIframeType[By.getByAltText](element.narrowSelector, element._byOptions); break; case By.getByLabel: locatorsChain = locatorsChainWithIframeType[By.getByLabel](element.narrowSelector, element._byOptions); break; case By.getByPlaceholder: locatorsChain = locatorsChainWithIframeType[By.getByPlaceholder](element.narrowSelector, element._byOptions); break; case By.getByRole: locatorsChain = locatorsChainWithIframeType[By.getByRole](element.narrowSelector, element._byOptions); break; case By.getByTestId: locatorsChain = locatorsChainWithIframeType[By.getByTestId](element.narrowSelector); break; case By.getByText: locatorsChain = locatorsChainWithIframeType[By.getByText](element.narrowSelector, element._byOptions); break; case By.getByTitle: locatorsChain = locatorsChainWithIframeType[By.getByTitle](element.narrowSelector, element._byOptions); break; default: locatorsChain = locatorsChainWithIframeType.locator(element.narrowSelector, { hasText: element._hasText, hasNotText: element._hasNotText, has: this.selectLocatorMethod(element._hasLocator), hasNot: this.selectLocatorMethod(element._hasNotLocator) }); break; } for (const andElement of element._and) { locatorsChain = locatorsChain.and(andElement instanceof WebElement ? andElement.locator : locatorsChainWithIframeType.locator(andElement)); } for (const andElement of element._or) { locatorsChain = locatorsChain.or(andElement instanceof WebElement ? andElement.locator : locatorsChainWithIframeType.locator(andElement)); } if (element._nth != undefined) locatorsChain = locatorsChain.nth(element._nth); return locatorsChain; } buildParentLocatorsChain() { let locatorsChain = index_1.BrowserInstance.currentPage; if (this.parentElements.length > 0) { let isInFrame = false; let frameSelector; for (const element of this.parentElements) { if (element._isFrame) { isInFrame = true; frameSelector = element.narrowSelector; continue; } if (isInFrame) { element._isInFrame = true; if (frameSelector) element._frameSelector = frameSelector; isInFrame = false; frameSelector = undefined; } locatorsChain = this.buildLocator(locatorsChain, element); } if (isInFrame) { this._isInFrame = true; if (frameSelector) this._frameSelector = frameSelector; } } return locatorsChain; } get locator() { return this.buildLocator(this.buildParentLocatorsChain(), this); } get _() { return this.locator; } static useExpect(expect) { expect; } expect(message) { return _expect(this.locator, message); } softExpect(message) { return _expect.soft(this.locator, message); } // augmentation recursiveParentSelectorInjection(element) { const entries = Object.entries(element) .filter(([key, value]) => { if (key == '_hasLocator' || key == '_hasNotLocator') return false; return value instanceof WebElement; }); const values = entries.map(entry => entry[1]); if (values.length) { values.forEach((value) => { value.addParentSelector(this); const parents = this.parentElements; for (const parent of parents) { value.addParentSelector(parent); } this.recursiveParentSelectorInjection(value); }); } } subElements(augment) { const elements = augment; Object.entries(elements).forEach(([key, value]) => { const clone = (0, lodash_clonedeep_1.default)(value); clone.addParentSelector(this); const parents = this.parentElements; for (const parent of parents) { clone.addParentSelector(parent); } this.recursiveParentSelectorInjection(clone); this[key] = clone; }); return this; } withMethods(augment) { const methods = augment; Object.keys(methods).forEach(key => { if (key in this) throw new Error(`Can not add method with name '${key}' because such method already exists.`); this[key] = methods[key]; }); return this; } with(augment) { const elements = Object.fromEntries(Object.entries(augment) .filter(e => e[1] instanceof WebElement)); const functions = Object.fromEntries(Object.entries(augment) .filter(e => e[1] instanceof Function)); if (Object.keys(elements).length !== 0) this.subElements(elements); if (Object.keys(functions).length !== 0) this.withMethods(functions); return this; } // getters setters get narrowSelector() { return this._selector; } buildNarrowSelectorWithInternalLocator(target = this) { return target._hasLocator ? `${target.narrowSelector} >> internal:has="${typeof target._hasLocator === 'string' ? target._hasLocator : target._hasLocator.narrowSelector}"` : target.narrowSelector; } get selector() { if (this.parentElements.length) return `${this.parentsSelector} >> ${this.buildNarrowSelectorWithInternalLocator()}`; else return this.buildNarrowSelectorWithInternalLocator(); } get parentsSelector() { return this.parentElements.map(element => this.buildNarrowSelectorWithInternalLocator(element)).join(' >> '); } parent() { return this._parents.at(-1); } get parentElements() { return this._parents; } addParentSelector(parent) { this._parents.unshift(parent); } // chainable web element creation clone(options) { return Object.defineProperties((0, lodash_clonedeep_1.default)(this), { _selector: { value: options?.selector ?? this._selector, writable: false, configurable: false }, _hasLocator: { value: options?.hasLocator ?? this._hasLocator, writable: true, configurable: false }, _hasNotLocator: { value: options?.hasNotLocator ?? this._hasNotLocator, writable: true, configurable: false }, _hasText: { value: options?.hasText ?? this._hasText, writable: true, configurable: false }, _hasNotText: { value: options?.hasNotText ?? this._hasNotLocator, writable: true, configurable: false }, _nth: { value: options?.nth ?? this._nth, writable: true, configurable: false } }); } and(element) { const clone = this.clone(); clone._and.push(element); return clone; } or(element) { const clone = this.clone(); clone._or.push(element); return clone; } has(element) { if (this._by) throw Error(`has option can not be used with ${this._by}, it can be used only with $ or new WebElement('#id') syntax.`); return this.clone({ selector: this.narrowSelector, hasLocator: element, hasNotLocator: this._hasNotLocator, hasText: this._hasText, hasNotText: this._hasNotText, nth: this._nth }); } hasNot(element) { if (this._by) throw Error(`hasNot option can not be used with ${this._by}, it can be used only with $ or new WebElement('#id') syntax.`); return this.clone({ selector: this.narrowSelector, hasLocator: this._hasLocator, hasNotLocator: element, hasText: this._hasText, hasNotText: this._hasNotText, nth: this._nth }); } hasText(text) { if (this._by) throw Error(`has option can not be used with ${this._by}, it can be used only with $ or new WebElement('#id') syntax.`); return this.clone({ selector: this.narrowSelector, hasLocator: this._hasLocator, hasNotLocator: this._hasNotLocator, hasText: text, hasNotText: this._hasNotText, nth: this._nth }); } hasNotText(text) { if (this._by) throw Error(`hasNot option can not be used with ${this._by}, it can be used only with $ or new WebElement('#id') syntax.`); return this.clone({ selector: this.narrowSelector, hasLocator: this._hasLocator, hasNotLocator: this._hasNotLocator, hasText: this._hasText, hasNotText: text, nth: this._nth }); } addParentsToWebElement(element) { element.addParentSelector(this); for (const parent of (0, lodash_clonedeep_1.default)(this.parentElements).reverse()) { element.addParentSelector(parent); } return element; } contentFrame() { this._isFrame = true; return this; } owner() { this._isFrame = false; return this; } addHandler(handler, options) { const callBack = async () => { await handler(this); }; return index_1.BrowserInstance.currentPage.addLocatorHandler(this.locator, callBack, options); } removeHandler() { return index_1.BrowserInstance.currentPage.removeLocatorHandler(this.locator); } $(selector) { return this.addParentsToWebElement(new WebElement(selector)); } $getByAltText(altText, options) { return this.addParentsToWebElement(new WebElement(altText, By.getByAltText, options)); } $getByLabel(label, options) { return this.addParentsToWebElement(new WebElement(label, By.getByLabel, options)); } $getByPlaceholder(placeholder, options) { return this.addParentsToWebElement(new WebElement(placeholder, By.getByPlaceholder, options)); } $getByRole(role, options) { return this.addParentsToWebElement(new WebElement(role, By.getByRole, options)); } $getByTestId(testId) { return this.addParentsToWebElement(new WebElement(testId, By.getByTestId)); } $getByText(text, options) { return this.addParentsToWebElement(new WebElement(text, By.getByText, options)); } $getByTitle(title, options) { return this.addParentsToWebElement(new WebElement(title, By.getByTitle, options)); } nth(index) { return this.clone({ selector: this.narrowSelector, hasLocator: this._hasLocator, hasNotLocator: this._hasNotLocator, hasText: this._hasText, hasNotText: this._hasNotText, nth: index }); } first() { return this.nth(0); } last() { return this.nth(-1); } // arrays of elements async getAll() { const elements = []; const amount = await this.count(); for (let i = 0; i < amount; i++) { elements.push(this.nth(i)); } return elements; } async asyncForEach(action) { const list = await this.getAll(); const promises = []; for (const ele of list) { promises.push(action(ele)); } await Promise.all(promises); } async syncForEach(action) { const list = await this.getAll(); for (const ele of list) { await action(ele); } } async map(item) { const list = await this.getAll(); const futureItems = []; for (const ele of list) { futureItems.push(Promise.resolve(item(ele))); } return Promise.all(futureItems); } filter(options) { return this.clone({ selector: this.narrowSelector, hasLocator: options.has ? extractSelector(options.has) : undefined, hasNotLocator: options.hasNot ? extractSelector(options.hasNot) : undefined, hasText: options.hasText, hasNotText: options.hasNotText, }); } async filterElements(predicate) { const list = await this.getAll(); const matchedElements = []; for (const ele of list) { if (await predicate(ele)) matchedElements.push(ele); } return matchedElements; } // Locator methods async allInnerTexts() { return this.locator.allInnerTexts(); } async allTextContents() { return this.locator.allTextContents(); } async ariaSnapshot(options) { return this.locator.ariaSnapshot(options); } async blur(options) { await this.locator.blur(options); } async boundingBox(options) { return this.locator.boundingBox(options); } async check(options) { await this.locator.check(options); } async clear(options) { await this.locator.clear(options); } async click(options) { await this.locator.click(options); } async count() { return this.locator.count(); } async dblclick(options) { await this.locator.dblclick(options); } async dispatchEvent(type, eventInit, options) { await this.locator.dispatchEvent(type, eventInit, options); } async dragTo(target, options) { await this.locator.dragTo(target instanceof WebElement ? target.locator : target, options); } async fill(value, options) { await this.locator.fill(value, options); } async focus(options) { await this.locator.focus(options); } async getAttribute(name, options) { return this.locator.getAttribute(name, options); } async highlight() { await this.locator.highlight(); } async hover(options) { await this.locator.hover(options); } async innerHTML(options) { return this.locator.innerHTML(options); } async innerText(options) { return this.locator.innerText(options); } async inputValue(options) { return this.locator.inputValue(options); } async isChecked(options) { return this.locator.isChecked(options); } async isDisabled(options) { return this.locator.isDisabled(options); } async isEditable(options) { return this.locator.isEditable(options); } async isEnabled(options) { return this.locator.isEnabled(options); } async isHidden() { return this.locator.isHidden(); } async isVisible(options) { return this.locator.isVisible(options); } async press(key, options) { await this.locator.press(key, options); } async screenshot(options) { return this.locator.screenshot(options); } async scrollIntoViewIfNeeded(options) { await this.locator.scrollIntoViewIfNeeded(options); } async selectOption(values, options) { return this.locator.selectOption(values, options); } async selectText(options) { await this.locator.selectText(options); } async setChecked(checked, options) { await this.locator.setChecked(checked, options); } async setInputFiles(files, options) { await this.locator.setInputFiles(files, options); } async tap(options) { await this.locator.tap(options); } async textContent(options) { return this.locator.textContent(options); } async type(text, options) { await this.locator.type(text, options); } async pressSequentially(text, options) { await this.locator.pressSequentially(text, options); } async uncheck(options) { await this.locator.uncheck(options); } async waitFor(options) { await this.locator.waitFor(options); } // additional methods async getText(options) { const text = await this.locator.textContent(options); if (text) return text; throw new Error(`Text content method returned null for selector: "${this.selector}"`); } } exports.WebElement = WebElement; var By; (function (By) { By["getByAltText"] = "getByAltText"; By["getByLabel"] = "getByLabel"; By["getByPlaceholder"] = "getByPlaceholder"; By["getByRole"] = "getByRole"; By["getByTestId"] = "getByTestId"; By["getByText"] = "getByText"; By["getByTitle"] = "getByTitle"; })(By || (By = {})); function $(selector) { return new WebElement(selector); } function $getByAltText(altText, options) { return new WebElement(altText, By.getByAltText, options); } function $getByLabel(label, options) { return new WebElement(label, By.getByLabel, options); } function $getByPlaceholder(placeholder, options) { return new WebElement(placeholder, By.getByPlaceholder, options); } function $getByRole(role, options) { return new WebElement(role, By.getByRole, options); } function $getByTestId(testId) { return new WebElement(testId, By.getByTestId); } function $getByText(text, options) { return new WebElement(text, By.getByText, options); } function $getByTitle(title, options) { return new WebElement(title, By.getByTitle, options); } function initDesktopOrMobile(desktop, mobile) { return index_1.BrowserInstance.isContextMobile ? mobile : desktop; }