Skip to content

Commit

Permalink
Added some method for better selector strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
harshit-bs committed Jan 23, 2023
1 parent cefae71 commit 068a1ba
Show file tree
Hide file tree
Showing 8 changed files with 335 additions and 6 deletions.
53 changes: 50 additions & 3 deletions lib/api/element-commands/findElement.js
Expand Up @@ -25,20 +25,67 @@ module.exports = class FindElement extends FindElements {
async elementFound(response) {
if (response && response.value) {
const elementId = this.transport.getElementId(response.value);

response.value = Object.assign(response.value, {
const _this = this;

Object.assign(response.value, {
get getId() {
return function() {
return elementId;
};
}
},

findChildElement(...args) {
return _this.createElementChain(this, false, ...args);
},

findChildElements(...args) {
const promiseOnElements = _this.createElementChain(this, true, ...args);

const getElementByIndex = (index) => {
const promiseOnGetElementByIndex = (async () => {
const elements = await promiseOnElements;
return elements[index];
})();

promiseOnGetElementByIndex.findChildElements = this.findChildElements;
promiseOnGetElementByIndex.findChildElement = this.findChildElement;

return promiseOnGetElementByIndex;
}

promiseOnElements.getElementByIndex = getElementByIndex;
return promiseOnElements;
},
});
}

return response;
}

createElementChain(element, multiElements, ...args) {
let promise = Promise.resolve(element);

promise = promise.then(async parent => {
const parentId = () => parent.WebdriverElementId ? parent.WebdriverElementId : parent.getId();

if (multiElements) {
return await this.api.findElements(...args, parentId);
}

return await this.api.findElement(...args, parentId);
});

promise.findChildElement = element.findChildElement;
promise.findChildElements = element.findChildElements;

return promise;
}

findElementAction() {
if (this.parentId) {
return this.findElement({id: this.parentId, cacheElementId: false, transportAction: 'locateSingleElementByElementId'});
}

return this.findElement();
}
};
44 changes: 44 additions & 0 deletions lib/api/element-commands/findElementByLabel.js
@@ -0,0 +1,44 @@
/**
* Returns input element related to label . The element will be returned as web element JSON object (with some convenience method).
*
*
* @example
* module.exports = {
* 'demo Test': function(browser) {
* const resultElement = await browser.findElementByLabel('username');
*
* console.log('element Id:', resultElement.getId());
* },
*
* @syntax browser.findElementByLabel(label_text, callback)
* @syntax browser.findElementByLabel(label_text)
* @param {string} label_text The label_text used to locate the input element. Can be a string
* @param {object} {exact: true} Used to exact match of label_text
* @param {function} callback Callback function which is called with the result value.
* @method findElementByLabel
* @since 2.0.0
* @api protocol.elements
*/

const LocateStrategy = require('../../element/strategy.js');
const FindElement = require('./findElement.js');

class FindElementByLabel extends FindElement {
get selector() {
if (this.args[1] && this.args[1].exact === true) {
return `//${this.__selector}[text()='${this.args[0]}']//following::input[1]`;
}

return `//${this.__selector}[contains(text(), '${this.args[0]}')]//following::input[1]`;
}

setStrategy() {
this.__strategy = LocateStrategy.XPATH;

return this;
}

setStrategyFromArgs() {}
}

module.exports = FindElementByLabel;
43 changes: 43 additions & 0 deletions lib/api/element-commands/findElementByPlaceholderText.js
@@ -0,0 +1,43 @@
const LocateStrategy = require('../../element/strategy.js');
const FindElement = require('./findElement.js');
/**
* Returns an element's first child. The child element will be returned as web element JSON object (with an added .getId() convenience method).
*
*
* @example
* module.exports = {
* 'demo Test': function(browser) {
* const resultElement = await browser.getFirstElementChild('.features-container');
*
* console.log('last child element Id:', resultElement.getId());
* },
*
* @syntax browser.getFirstElementChild(selector, callback)
* @syntax browser.getFirstElementChild(selector)
* @param {string} [using] The locator strategy to use. See [W3C Webdriver - locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
* @param {string|object} selector The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
* @param {function} callback Callback function which is called with the result value.
* @method findElementByLabel
* @since 2.0.0
* @moreinfo developer.mozilla.org/en-US/docs/Web/API/Element/firstElementChild
* @api protocol.elements
*/
class FindElementByPlaceholderText extends FindElement {
get selector() {
if (this.args[1] && this.args[1].exact === true) {
return `//input[@placeholder='${this.args[0]}']`;
}

return `//input[contains(@placeholder, '${this.args[0]}')]`;
}

setStrategy() {
this.__strategy = LocateStrategy.XPATH;

return this;
}

setStrategyFromArgs() {}
}

module.exports = FindElementByPlaceholderText;
43 changes: 43 additions & 0 deletions lib/api/element-commands/findElementByText.js
@@ -0,0 +1,43 @@
const LocateStrategy = require('../../element/strategy.js');
const FindElement = require('./findElement.js');
/**
* Returns an element's first child. The child element will be returned as web element JSON object (with an added .getId() convenience method).
*
*
* @example
* module.exports = {
* 'demo Test': function(browser) {
* const resultElement = await browser.getFirstElementChild('.features-container');
*
* console.log('last child element Id:', resultElement.getId());
* },
*
* @syntax browser.getFirstElementChild(selector, callback)
* @syntax browser.getFirstElementChild(selector)
* @param {string} [using] The locator strategy to use. See [W3C Webdriver - locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
* @param {string|object} selector The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
* @param {function} callback Callback function which is called with the result value.
* @method getFirstElementChild
* @since 2.0.0
* @moreinfo developer.mozilla.org/en-US/docs/Web/API/Element/firstElementChild
* @api protocol.elements
*/
class FindElementByText extends FindElement {
get selector() {
if (this.args[1] && this.args[1].exact === true) {
return `//${this.__selector}[text()='${this.args[0]}']`;
}

return `//${this.__selector}[contains(text(), '${this.args[0]}')]`;
}

setStrategy() {
this.__strategy = LocateStrategy.XPATH;

return this;
}

setStrategyFromArgs() {}
}

module.exports = FindElementByText;
61 changes: 61 additions & 0 deletions lib/api/element-commands/findElements.js
@@ -1,3 +1,4 @@
const { WebElement } = require('selenium-webdriver');
const BaseElementCommand = require('./_baseElementCommand.js');

/**
Expand Down Expand Up @@ -36,12 +37,72 @@ module.exports = class Elements extends BaseElementCommand {
}
});
});

const driver = this.transport.driver;

Object.assign(response.value, {
getElementByIndex(index) {
return response.value[index];
},

filterVisibleElements() {
const promises = response.value.map(async element => {
const webElement = new WebElement(driver, element.getId());

if (await webElement.isDisplayed()) {
return element;
}
})

const visibleElements = (async() => (await Promise.all(promises)).filter((element) => {
return element;
}))();

return visibleElements;
},

filterByText(text) {
const promises = response.value.map(async element => {
const webElement = new WebElement(driver, element.getId());

if ((await webElement.getAttribute("textContent")).includes(text)) {
return element;
}
})

const elementsHasText = (async() => (await Promise.all(promises)).filter((element) => {
return element;
}))();

return elementsHasText;
},

filterByCSS(className) {
const promises = response.value.map(async element => {
const webElement = new WebElement(driver, element.getId());

if ((await webElement.getAttribute("class")).includes(className)) {
return element;
}
})

const elementsHasText = (async() => (await Promise.all(promises)).filter((element) => {
return element;
}))();

return elementsHasText;
},
})
}

return response;
}

findElementAction() {
if (this.parentId) {
return this.findElement({id: this.parentId, cacheElementId: false, transportAction: 'locateMultipleElementsByElementId', returnSingleElement: false});
}

return this.findElement({returnSingleElement: false});
}

Expand Down
66 changes: 66 additions & 0 deletions lib/api/protocol/findElementMultipleORCriteria.js
@@ -0,0 +1,66 @@
/**
* Search for an elements on the page, starting from the document root. The located element will be returned as web element JSON object (with an added .getId() convenience method).
* First argument is the element selector, either specified as a string or as an object (with 'selector' and 'locateStrategy' properties).
*
* @example
* module.exports = {
* 'demo Test': function(browser) {
* const resultElement = await browser.findElement('.features-container li:first-child');
*
* console.log('Element Id:', resultElement.getId());
* },
*
*
* @link /#find-element
* @syntax browser.findElement(selector, callback)
* @syntax await browser.findElement(selector);
* @param {string} selector The search target.
* @param {function} [callback] Callback function to be invoked with the result when the command finishes.
* @since 1.7.0
* @api protocol.elements
*/
const Utils = require('../../utils/index.js');
const ProtocolAction = require('./_base-action.js');


module.exports = class FindElementMultipleORCriteria extends ProtocolAction {
async command(...args) {
let cssSelectors , xpathSelector, callback = function() {};

args.forEach((selector) => {
if (Utils.isString(selector)) {
if (Utils.isValidXpath(selector)){
xpathSelector = xpathSelector ? xpathSelector + " | " + selector : selector;
} else {
cssSelectors = cssSelectors ? cssSelectors + ", " + selector : selector;
}
}
});

if (Utils.isFunction(args.at(-1))) {
callback = args.at(-1);
}

let result = [];

if (cssSelectors) {
const cssRes = await this.api.findElements(cssSelectors, callback);

if (!cssRes.error) {
result = result.concat(cssRes);
result = Object.assign(cssRes, result);
}
}

if (xpathSelector) {
const xpathRes = await this.api.findElements('xpath', xpathSelector, callback)

if (!xpathRes.error) {
result = result.concat(xpathRes);
result = Object.assign(xpathRes, result);
}
}

return result;
}
};

0 comments on commit 068a1ba

Please sign in to comment.