Is there a built-in locator to find an element by its html content?
This is for example the xpath expression to locate any element containing the string _"You have successfully signed up!"_
by.xpath("//*[contains(text(),'You have successfully signed up!')]");
I wonder if there is a nicer DSL for this, e.g.
by.text('You have successfully signed up!');
Or see an example of how to write this with Protractor.By.addLocator
There's one for links by text, but not other elements: by.linkText or by.partialLinkText. That's a webdriver build-in.
Unfortunately, there's no webdriver build in for finding elements by text. I think the rationale is that that makes it easy to write tests which fail immediately on internationalization and are otherwise frail.
With Protractor.by.addLocator (very naive implementation - find leaf nodes, check their innerHTML. You'd probably want to do something better so that it would also find text in non-leaf nodes.):
var findByText = function() {
var using = arguments[0] || document;
var text = arguments[1];
var matches = [];
function addMatchingLeaves(element) {
if (element.children.length === 0 && element.textContent.match(text)) {
matches.push(element);
}
for (var i = 0; i < element.children.length; ++i) {
addMatchingLeaves(element.children[i]);
}
}
addMatchingLeaves(using);
return matches;
};
by.addLocator('text', findByText);
Thanks @juliemr that worked really well on Chrome and Firefox!!
Didn't work on IE9 nor IE10, i'm currently using protractor master branch as of friday, could be related to that?
// resetPwd.spec.js
expect(element(by.text('Reset password')).isDisplayed()).toBe(true);
// Stack Trace for Internet Explorer (works well on Chrome/FF)
UnknownError: JavaScript error (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 47 milliseconds
Build info: version: '2.39.0', revision: 'ff23eac', time: '2013-12-16 16:11:15'
System info: host: 'mingo-acer', ip: '192.168.0.109', os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.7.0_51'
Session ID: c16ffd5f-3592-4720-b3b2-5c09dcdc043b
Driver info: org.openqa.selenium.ie.InternetExplorerDriver
Capabilities [{platform=WINDOWS, javascriptEnabled=true, elementScrollBehavior=0, ignoreZoomSetting=false, enablePersistentHover=true, ie.ensureCleanSession=false, browserName=internet explorer, enableElementCacheCleanup=true, unexpectedAlertBehaviour=dismiss, version=9, ie.usePerProcessProxy=false, cssSelectorsEnabled=true, ignoreProtectedModeSettings=false, requireWindowFocus=false, handlesAlerts=true, initialBrowserUrl=http://localhost:45834/, ie.forceCreateProcessApi=false, nativeEvents=true, browserAttachTimeout=0, ie.browserCommandLineSwitches=, takesScreenshot=true}]
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
==== async task ====
WebDriver.executeScript()
at Object.findElementsOverride (~/oss/protractor/lib/locators.js:37:23)
at Protractor.findElementsOverrideHelper_ (~/oss/protractor/lib/protractor.js:755:15)
at Protractor.findElement (~/oss/protractor/lib/protractor.js:559:18)
at Object.elementFinder.(anonymous function) [as isDisplayed] (~/oss/protractor/lib/protractor.js:88:24)
at null.<anonymous> (~/.../resetPwd.spec.js:28:59)
at ~/oss/protractor/jasminewd/index.js:54:12
at wrapper [as _onTimeout] (timers.js:252:14)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
==== async task ====
at null.<anonymous> (~/oss/protractor/jasminewd/index.js:53:12)
at null.<anonymous> (~/oss/protractor/node_modules/minijasminenode/lib/async-callback.js:45:37)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
No, that's because IE doesn't support element.children. Sorry, I didn't intend that to be production level code, just to show you how you would write a find by text function (thus the 'very naive' disclaimer). (https://developer.mozilla.org/en-US/docs/Web/API/ParentNode.children)
Oh of course!
Thanks for the help :)
How is it possible to find an element inside datatables without using css-classes, ng-model, ng-repeat and ng-bind. My idea was to search for an element by text to find a certain row I need to select.
Thank you for your help @juliemr

@elgalu Could you reopen the discussion?
I implemented this in Pioneer as follows
let _selector = Driver.By.xpath('.//*[normalize-space(text())=normalize-space("' + opts.text + '")]')
return el.findElement(_selector)
full method:
https://github.com/mojotech/pioneer/blob/master/src/widgets/Widget.coffee#L184-L197
I was mislead by this issue... currently correct answer seems to be:
var dog = element(by.cssContainingText('.pet', 'Dog'));
https://angular.github.io/protractor/#/api?view=ProtractorBy.prototype.cssContainingText
Hi guys, somebody knows how declare locators for this case:

Most helpful comment
I was mislead by this issue... currently correct answer seems to be:
https://angular.github.io/protractor/#/api?view=ProtractorBy.prototype.cssContainingText