diff --git a/lib/locator.js b/lib/locator.js index f10a94399..eef8277f7 100644 --- a/lib/locator.js +++ b/lib/locator.js @@ -299,6 +299,49 @@ class Locator { return new Locator({ xpath }); } + /** + * Adds condition: attribute value starts with text + * (analog of XPATH: [starts-with(@attr,'startValue')] or CSS [attr^='startValue'] + * Example: I.click(locate('a').withAttrStartsWith('href', 'https://'))); + * Works with any attribute: class, href etc. + * @param {string} attrName + * @param {string} startsWith + * @returns {Locator} + */ + withAttrStartsWith(attrName, startsWith) { + const xpath = sprintf('%s[%s]', this.toXPath(), `starts-with(@${attrName}, "${startsWith}")`); + return new Locator({ xpath }); + } + + /** + * Adds condition: attribute value ends with text + * (analog of XPATH: [ends-with(@attr,'endValue')] or CSS [attr$='endValue'] + * Example: I.click(locate('a').withAttrEndsWith('href', '.com'))); + * Works with any attribute: class, href etc. + * @param {string} attrName + * @param {string} endsWith + * @returns {Locator} + */ + withAttrEndsWith(attrName, endsWith) { + const xpath = sprintf('%s[%s]', this.toXPath(), `substring(@${attrName}, string-length(@${attrName}) - string-length("${endsWith}") + 1) = "${endsWith}"`, + ); + return new Locator({ xpath }); + } + + /** + * Adds condition: attribute value contains text + * (analog of XPATH: [contains(@attr,'partOfAttribute')] or CSS [attr*='partOfAttribute'] + * Example: I.click(locate('a').withAttrContains('href', 'google'))); + * Works with any attribute: class, href etc. + * @param {string} attrName + * @param {string} partOfAttrValue + * @returns {Locator} + */ + withAttrContains(attrName, partOfAttrValue) { + const xpath = sprintf('%s[%s]', this.toXPath(), `contains(@${attrName}, "${partOfAttrValue}")`); + return new Locator({ xpath }); + } + /** * @param {String} text * @returns {Locator} diff --git a/test/unit/locator_test.js b/test/unit/locator_test.js index 41680548f..0993c416e 100644 --- a/test/unit/locator_test.js +++ b/test/unit/locator_test.js @@ -455,4 +455,22 @@ describe('Locator', () => { const nodes = xpath.select(l.toXPath(), doc) expect(nodes).to.have.length(0, l.toXPath()) }) + + it('should find element with attribute value starts with text', () => { + const l = Locator.build('a').withAttrStartsWith('class', 'ps-menu-button') + const nodes = xpath.select(l.toXPath(), doc) + expect(nodes).to.have.length(10, l.toXPath()) + }) + + it('should find element with attribute value ends with text', () => { + const l = Locator.build('a').withAttrEndsWith('class', 'ps-menu-button') + const nodes = xpath.select(l.toXPath(), doc) + expect(nodes).to.have.length(9, l.toXPath()) + }) + + it('should find element with attribute value contains text', () => { + const l = Locator.build('a').withAttrEndsWith('class', 'active') + const nodes = xpath.select(l.toXPath(), doc) + expect(nodes).to.have.length(1, l.toXPath()) + }) })