diff --git a/docs/helpers/Playwright.md b/docs/helpers/Playwright.md index b85b3ebe8..17511c27b 100644 --- a/docs/helpers/Playwright.md +++ b/docs/helpers/Playwright.md @@ -299,7 +299,7 @@ const elements = await this.helpers['Playwright']._locate({name: 'password'}); ### _locateCheckable -Find a checkbox by providing human readable text: +Find a checkbox by providing human-readable text: NOTE: Assumes the checkable element exists ```js @@ -313,7 +313,7 @@ this.helpers['Playwright']._locateCheckable('I agree with terms and conditions') ### _locateClickable -Find a clickable element by providing human readable text: +Find a clickable element by providing human-readable text: ```js this.helpers['Playwright']._locateClickable('Next page').then // ... @@ -323,9 +323,22 @@ this.helpers['Playwright']._locateClickable('Next page').then // ... - `locator` +### _locateElement + +Get the first element by different locator types, including strict locator +Should be used in custom helpers: + +```js +const element = await this.helpers['Playwright']._locateElement({name: 'password'}); +``` + +#### Parameters + +- `locator` + ### _locateFields -Find field elements by providing human readable text: +Find field elements by providing human-readable text: ```js this.helpers['Playwright']._locateFields('Your email').then // ... diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index a6ea7b199..573dd2c30 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -825,9 +825,9 @@ class Playwright extends Helper { return; } - const els = await this._locate(locator); - assertElementExists(els, locator); - this.context = els[0]; + const el = await this._locateElement(locator); + assertElementExists(el, locator); + this.context = el; this.contextLocator = locator; this.withinLocator = new Locator(locator); @@ -930,11 +930,11 @@ class Playwright extends Helper { * */ async moveCursorTo(locator, offsetX = 0, offsetY = 0) { - const els = await this._locate(locator); - assertElementExists(els, locator); + const el = await this._locateElement(locator); + assertElementExists(el, locator); // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates - const { x, y } = await clickablePoint(els[0]); + const { x, y } = await clickablePoint(el); await this.page.mouse.move(x + offsetX, y + offsetY); return this._waitForAction(); } @@ -944,9 +944,8 @@ class Playwright extends Helper { * */ async focus(locator, options = {}) { - const els = await this._locate(locator); - assertElementExists(els, locator, 'Element to focus'); - const el = els[0]; + const el = await this._locateElement(locator); + assertElementExists(el, locator, 'Element to focus'); await el.focus(options); return this._waitForAction(); @@ -957,12 +956,10 @@ class Playwright extends Helper { * */ async blur(locator, options = {}) { - const els = await this._locate(locator); - assertElementExists(els, locator, 'Element to blur'); - // TODO: locator change required after #3677 implementation - const elXpath = await getXPathForElement(els[0]); + const el = await this._locateElement(locator); + assertElementExists(el, locator, 'Element to blur'); - await this.page.locator(elXpath).blur(options); + await el.blur(options); return this._waitForAction(); } @@ -1062,10 +1059,10 @@ class Playwright extends Helper { } if (locator) { - const els = await this._locate(locator); - assertElementExists(els, locator, 'Element'); - await els[0].scrollIntoViewIfNeeded(); - const elementCoordinates = await clickablePoint(els[0]); + const el = await this._locateElement(locator); + assertElementExists(el, locator, 'Element'); + await el.scrollIntoViewIfNeeded(); + const elementCoordinates = await clickablePoint(el); await this.executeScript((offsetX, offsetY) => window.scrollBy(offsetX, offsetY), { offsetX: elementCoordinates.x + offsetX, offsetY: elementCoordinates.y + offsetY }); } else { await this.executeScript(({ offsetX, offsetY }) => window.scrollTo(offsetX, offsetY), { offsetX, offsetY }); @@ -1133,7 +1130,20 @@ class Playwright extends Helper { } /** - * Find a checkbox by providing human readable text: + * Get the first element by different locator types, including strict locator + * Should be used in custom helpers: + * + * ```js + * const element = await this.helpers['Playwright']._locateElement({name: 'password'}); + * ``` + */ + async _locateElement(locator) { + const context = await this.context || await this._getContext(); + return findElement(context, locator); + } + + /** + * Find a checkbox by providing human-readable text: * NOTE: Assumes the checkable element exists * * ```js @@ -1148,7 +1158,7 @@ class Playwright extends Helper { } /** - * Find a clickable element by providing human readable text: + * Find a clickable element by providing human-readable text: * * ```js * this.helpers['Playwright']._locateClickable('Next page').then // ... @@ -1160,7 +1170,7 @@ class Playwright extends Helper { } /** - * Find field elements by providing human readable text: + * Find field elements by providing human-readable text: * * ```js * this.helpers['Playwright']._locateFields('Your email').then // ... @@ -1536,13 +1546,8 @@ class Playwright extends Helper { const els = await findFields.call(this, field); assertElementExists(els, field, 'Field'); const el = els[0]; - const tag = await el.getProperty('tagName').then(el => el.jsonValue()); - const editable = await el.getProperty('contenteditable').then(el => el.jsonValue()); - if (tag === 'INPUT' || tag === 'TEXTAREA') { - await this._evaluateHandeInContext(el => el.value = '', el); - } else if (editable) { - await this._evaluateHandeInContext(el => el.innerHTML = '', el); - } + + await el.clear(); highlightActiveElement.call(this, el, this.page); @@ -1569,21 +1574,16 @@ class Playwright extends Helper { * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-locator#locator-clear) for available options object as 2nd argument. */ async clearField(locator, options = {}) { - let result; - const isNewClearMethodPresent = false; // not works, disabled for now. Prev: typeof this.page.locator().clear === 'function'; + const els = await findFields.call(this, locator); + assertElementExists(els, locator, 'Field to clear'); - if (isNewClearMethodPresent) { - const els = await findFields.call(this, locator); - assertElementExists(els, locator, 'Field to clear'); - // TODO: locator change required after #3677 implementation - const elXpath = await getXPathForElement(els[0]); + const el = els[0]; - await this.page.locator(elXpath).clear(options); - result = await this._waitForAction(); - } else { - result = await this.fillField(locator, ''); - } - return result; + highlightActiveElement.call(this, el, this.page); + + await el.clear(); + + return this._waitForAction(); } /** @@ -1637,29 +1637,11 @@ class Playwright extends Helper { const els = await findFields.call(this, select); assertElementExists(els, select, 'Selectable field'); const el = els[0]; - if (await el.getProperty('tagName').then(t => t.jsonValue()) !== 'SELECT') { - throw new Error('Element is not ,