Protractor: Find element by text (content)

Created on 25 Jan 2014  路  8Comments  路  Source: angular/protractor

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

question

Most helpful comment

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

All 8 comments

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

datatables

@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:

  • Phone_assign_43534
  • image

    Was this page helpful?
    0 / 5 - 0 ratings