Skip to content

Add "label=" locator strategy #533

Closed

Description

@boakley

I would like to have another locator strategy added, tentatively named "label". This would look for a label element with the given text, then return the element pointed to by the "for" attribute of that label element.

Rationale:

Django (and other frameworks?) create forms that look like this:

<label for="id_some_form_field">I accept the terms</label>
<input id='id_some_form_field' type='checkbox'>

I would like to interact with the form field by specifying the label rather than having to use some other locator. For example, to validate that this checkbox is checked I want to do something like this:

click element    label=I accept the terms
checkbox should be selected    label=I accept the terms

I think this would make it easier for people who didn't write the code be able to write tests, because they wouldn't have to know the underlying element IDs; instead, they can simply enter in what they see on the screen.

Further, I recommend we support the stripping of leading and trailing spaces and dots to allow for a simple type of pattern matching. Say, for example, you have a form field that has the label "I have read the terms of service and agree to be bound by them". It would be cumbersome to type all of that into a test case, so it would be nice to support something like this:

checkbox should be selected    label=I have read the terms of service...

I am willing to write the implementation. This issue is for generating discussion, and to see if this would be a generally useful locator strategy.

Activity

  1. just-be-dev commented on Nov 13, 2015

    @just-be-dev
    Contributor

    Maybe it isn't documented well enough, but you can add a custom location strategy. Here's the acceptance test for it: https://github.com/robotframework/Selenium2Library/blob/master/test/acceptance/locators/custom.robot

  2. boakley commented on Nov 13, 2015

    @boakley
    ContributorAuthor

    Yes, I know you can add a custom location strategy. I'm doing this now. I
    think it is a generally useful location strategy which is why I'm
    suggesting it be included in the core set of location strategies.

    On Fri, Nov 13, 2015 at 3:59 PM, Zephraph notifications@github.com wrote:

    Maybe it isn't documented well enough, but you can add a custom location
    strategy. Here's the acceptance test for it:
    https://github.com/robotframework/Selenium2Library/blob/master/test/acceptance/locators/custom.robot

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156571112
    .

  3. aaltat commented on Nov 14, 2015

    @aaltat
    Contributor

    Although @boakley idea is good one and perhaps we should do it, I feel that doing this with xpath is more flexible and better. Also because many web development frameworks do produce very different kind of DOM trees, for same kind of looking elements, nailing this one down could be really difficult.

    In @boakley case perhaps I would do it like this: xpath=//label[[starts-with(.,'${text}')]/input and I would create general keyword which would click/select/or what ever it should be doing, so that it can be used anywhere the general activity is created.

  4. emanlove commented on Nov 14, 2015

    @emanlove
    Member

    To me the hard part, which I think would need to be discussed and debated, is exactly how one specifies either full text or partial text. Does/Can one use regular expression? Can one use eclipses (...)? How else would someone want to specify the search text? This is important as once implemented it will be hard to change.

    @boakley Do you see a need beyond what @aaltat suggests using xpath? Is this more of a problem of education where we need to better help users use locators?

  5. boakley commented on Nov 14, 2015

    @boakley
    ContributorAuthor

    The input element isn't necessarily immediately following the label, so
    your xpath can't work in a general sense. Plus, the whole point is to ask
    the label for the input element it belongs to.

    On Sat, Nov 14, 2015 at 7:11 AM, Tatu Aalto notifications@github.com
    wrote:

    Although @boakley https://github.com/boakley idea is good one and
    perhaps we should do it, I feel that doing this with xpath is more flexible
    and better. Also because many web development frameworks do produce very
    different kind of DOM trees, for same kind of looking elements, nailing
    this one down could be really difficult.

    In @boakley https://github.com/boakley case perhaps I would do it like
    this: xpath=//label[[starts-with(.,'${text}')]/input and I would create
    general keyword which would click/select/or what ever it should be doing,
    so that it can be used anywhere the general activity is created.

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156694580
    .

  6. boakley commented on Nov 14, 2015

    @boakley
    ContributorAuthor

    To me the hard part, which I think would need to be discussed and debated,
    is exactly how one specifies either full text or partial text. Does/Can one
    use regular expression?

    What I do now is strip of leading and trailing spaces and dots, and then
    search for a label that contains the text. It works quite well.

    On Sat, Nov 14, 2015 at 7:49 AM, Bryan Oakley bryan.oakley@gmail.com
    wrote:

    The input element isn't necessarily immediately following the label, so
    your xpath can't work in a general sense. Plus, the whole point is to ask
    the label for the input element it belongs to.

    On Sat, Nov 14, 2015 at 7:11 AM, Tatu Aalto notifications@github.com
    wrote:

    Although @boakley https://github.com/boakley idea is good one and
    perhaps we should do it, I feel that doing this with xpath is more flexible
    and better. Also because many web development frameworks do produce very
    different kind of DOM trees, for same kind of looking elements, nailing
    this one down could be really difficult.

    In @boakley https://github.com/boakley case perhaps I would do it like
    this: xpath=//label[[starts-with(.,'${text}')]/input and I would create
    general keyword which would click/select/or what ever it should be doing,
    so that it can be used anywhere the general activity is created.

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156694580
    .

  7. emanlove commented on Nov 14, 2015

    @emanlove
    Member

    Agreed and I like the simply solution. But the question arises what other needs/requirements could one have? And if such needs arise would they be backward compatible? How could we accommodate them to perform the same action, find the element with the associated label, with a more complex need?

  8. aaltat commented on Nov 14, 2015

    @aaltat
    Contributor

    Ugh

    Could you share the code? I don't quite understand, how finding the label
    helps one to click the check box. Unless the label is listening the click
    event and is able to check the check box (which of course is good
    implementation but don't work with all cases).

    Also xpath has contains and normalise-space, which could be also useful.

    -Tatu
    Send from my mobile
    On 14 Nov 2015 3:51 p.m., "Bryan Oakley" notifications@github.com wrote:

    To me the hard part, which I think would need to be discussed and
    debated,
    is exactly how one specifies either full text or partial text. Does/Can
    one
    use regular expression?

    What I do now is strip of leading and trailing spaces and dots, and then
    search for a label that contains the text. It works quite well.

    On Sat, Nov 14, 2015 at 7:49 AM, Bryan Oakley bryan.oakley@gmail.com
    wrote:

    The input element isn't necessarily immediately following the label, so
    your xpath can't work in a general sense. Plus, the whole point is to ask
    the label for the input element it belongs to.

    On Sat, Nov 14, 2015 at 7:11 AM, Tatu Aalto notifications@github.com
    wrote:

    Although @boakley https://github.com/boakley idea is good one and
    perhaps we should do it, I feel that doing this with xpath is more
    flexible
    and better. Also because many web development frameworks do produce very
    different kind of DOM trees, for same kind of looking elements, nailing
    this one down could be really difficult.

    In @boakley https://github.com/boakley case perhaps I would do it
    like
    this: xpath=//label[[starts-with(.,'${text}')]/input and I would create
    general keyword which would click/select/or what ever it should be
    doing,
    so that it can be used anywhere the general activity is created.

    —
    Reply to this email directly or view it on GitHub
    <
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156694580

    .

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156697872
    .

  9. boakley commented on Nov 14, 2015

    @boakley
    ContributorAuthor

    Could you share the code? I don't quite understand, how finding the label
    helps one to click the check box. Unless the label is listening the click
    event and is able to check the check box (which of course is good
    implementation but don't work with all cases).

    You don't click on the label. You use xpath to get the "for" attribute of
    the label. This will return an element id of a form element. You then click
    on that id. So, assuming you have something like "Username", a locator of "label=Username" is
    identical to the locator "id=id_username".

    The benefit is that with "label=" you don't have to know the id of the form
    element. All you need is to look at the web page and use the label.
    Assuming the label doesn't change, the underlying id can change without
    having to modify the test. This happens a lot with systems that
    auto-generate ids.

    On Sat, Nov 14, 2015 at 10:03 AM, Tatu Aalto notifications@github.com
    wrote:

    Ugh

    Could you share the code? I don't quite understand, how finding the label
    helps one to click the check box. Unless the label is listening the click
    event and is able to check the check box (which of course is good
    implementation but don't work with all cases).

    Also xpath has contains and normalise-space, which could be also useful.

    -Tatu
    Send from my mobile
    On 14 Nov 2015 3:51 p.m., "Bryan Oakley" notifications@github.com wrote:

    To me the hard part, which I think would need to be discussed and
    debated,
    is exactly how one specifies either full text or partial text. Does/Can
    one
    use regular expression?

    What I do now is strip of leading and trailing spaces and dots, and then
    search for a label that contains the text. It works quite well.

    On Sat, Nov 14, 2015 at 7:49 AM, Bryan Oakley bryan.oakley@gmail.com
    wrote:

    The input element isn't necessarily immediately following the label, so
    your xpath can't work in a general sense. Plus, the whole point is to
    ask
    the label for the input element it belongs to.

    On Sat, Nov 14, 2015 at 7:11 AM, Tatu Aalto notifications@github.com
    wrote:

    Although @boakley https://github.com/boakley idea is good one and
    perhaps we should do it, I feel that doing this with xpath is more
    flexible
    and better. Also because many web development frameworks do produce
    very
    different kind of DOM trees, for same kind of looking elements,
    nailing
    this one down could be really difficult.

    In @boakley https://github.com/boakley case perhaps I would do it
    like
    this: xpath=//label[[starts-with(.,'${text}')]/input and I would
    create
    general keyword which would click/select/or what ever it should be
    doing,
    so that it can be used anywhere the general activity is created.

    —
    Reply to this email directly or view it on GitHub
    <

    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156694580

    .

    —
    Reply to this email directly or view it on GitHub
    <
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156697872

    .

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156714104
    .

  10. aaltat commented on Nov 14, 2015

    @aaltat
    Contributor

    Ah, I think I understand what you do in our keyword and if the Django framework does it like that, I understand your reasoning behind keyword logic. In practice you want to find label element, get the id of the label and then find input, or some other element based based on the id of the label element. All the other web app frameworks, which I have say that can be counted with one hand fingers, do not do it like the Djongo does it. If you want to hide the complexity of selecting elements, I am not sure is Selenium2Library a correct level for it. I am not sure will it be possible to make general keyword that would fit to the need described in the above. But I am not against to create a label strategy for selecting elements, but I think the label strategy should only match to the <label for='id_username'>Username</label> element and nothing more.

    But I can understand your need and basically, I am facing similar situation in my work place. I need to raise the abstraction level so that the keywords are easier to use for people that do not actively work with seleniun(2library) and/or understand the xpath that well. Also there is lot of shared resources, example for table keywords and also other stuff. It has come quite nightmare to handle all the inheritance in the Robot Framework data and therefore we have decided to move to a page object model and it is done in Python. This allows us to provide better and clearer interface, handle inheritance better and get the all the benefits of using real programming language.

    We use and will use Selenium2Library in the future but we are going to the same direction, which the Page Object Library did try to do. We have just started of doing this and but it looks really good and for now, I only regret that we did not start it sooner.

  11. emanlove commented on Nov 15, 2015

    @emanlove
    Member

    You use xpath to get the "for" attribute of the label. This will return an element id of a form element.

    Don't forget that the "for" attribute is not necessary. One can also wrap the input element with the associated label (as per spec: HTML4, HTML5). So the implementation of this keyword should handle this allowance by the specification.

  12. boakley commented on Nov 15, 2015

    @boakley
    ContributorAuthor

    We use and will use Selenium2Library in the future but we are going to the
    same direction, which the Page Object Library
    https://github.com/ncbi/robotframework-pageobjects did try to do. We
    have just started of doing this and but it looks really good and for now, I
    only regret that we did not start it sooner.

    I completely agree. I first used page objects seriously at my previous job,
    and it helped make our tests more stable. At my current job I wrote my own
    page object implementation and we're having absolutely fantastic success.
    This really is the better approach -- embed all of the page knowledge in
    python code so that the test can focus on test logic. We still leverage
    Selenium2Library within in the page object implementation, however.

    That's how this feature request came to be. I had implemented my own
    locator strategy for labels to deal with all of the checkboxes that our
    site uses. I thought this could be more generally useful if it was part of
    Selenium2Library rather than a feature of our custom page objects.

    On Sat, Nov 14, 2015 at 1:07 PM, Tatu Aalto notifications@github.com
    wrote:

    Ah, I think I understand what you do in our keyword and if the Django
    framework does it like that, I understand your reasoning behind keyword
    logic. In practice you want to find label element, get the id of the label
    and then find input, or some other element based based on the id of the
    label element. All the other web app frameworks, which I have say that can
    be counted with one hand fingers, do not do it like the Djongo does it. If
    you want to hide the complexity of selecting elements, I am not sure is
    Selenium2Library a correct level for it. I am not sure will it be possible
    to make general keyword that would fit to the need described in the above.
    But I am not against to create a label strategy for selecting elements, but
    I think the label strategy should only match to the Username element and nothing more.

    But I can understand your need and basically, I am facing similar
    situation in my work place, I need to raise the abstraction level so that
    the keywords are easier to use for people that do not actively work with
    seleniun(2library) and/or understand the xpath that well. Also there is lot
    of shared resources, example for table keywords and also other stuff. It
    has come quite nightmare to handle all the inheritance in the Robot
    Framework data and therefore we have decided to move to a page object model
    and it is done in Python. This allows us to provide better and clearer
    interface, handle inheritance better and get the all the benefits of using
    real programming language.

    We use and will use Selenium2Library in the future but we are going to the
    same direction, which the Page Object Library
    https://github.com/ncbi/robotframework-pageobjects did try to do. We
    have just started of doing this and but it looks really good and for now, I
    only regret that we did not start it sooner.

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-156734488
    .

  13. aaltat commented on Nov 23, 2015

    @aaltat
    Contributor

    @boakley What you want to do with this issue? And what do others think?

  14. ombre42 commented on Nov 23, 2015

    @ombre42
    Contributor

    A more generic approach would be using nested locators. Like label=xpath=//label[., starts-with('Blah')]. This way the label could be located however desired. The label strategy could have key attributes like id or text so that label=Blah would search by id or text "Blah" since a second locator prefix was not used. This is just brainstorming. With nested locator prefixes, the prefix with label makes more sense e.g. "with label=id=label_123"

  15. divfor commented on Nov 25, 2015

    @divfor
    Contributor

    here is an example to use 'Add Location Strategy' for this:

    *** Settings ***
    Library           Selenium2Library
    Resource          define.txt
    
    *** Test Cases ***
    test Add Strategy
        [Setup]    Add Location Strategy    page_main    Map Baidu Main Page
        Open Browser    https://www.baidu.com    gc
        Click Element    page_main=label_text_hao123
        Sleep    1
        [Teardown]    Close Browser
    
    *** Keywords ***
    Map Baidu Main Page
        [Arguments]    ${browser}    ${criteria}    ${tag}    ${constraints}
        ${e}    Get Webelement    &{dict_main_page}[${criteria}]
        [Return]    ${e}

    define.txt:

    *** Variables ***
    &{dict_main_page}    label_text_hao123=css=#u1 > a:nth-child(3)    label_text_nuomi=css=#u1 > a:nth-child(1)
  16. boakley commented on Nov 25, 2015

    @boakley
    ContributorAuthor

    A more generic approach would be using nested locators. Like
    label=xpath=//label[., starts-with('Blah')]

    No, not really. That solves a completely different problem. This proposal
    specifically is to address the case where you have a label element with a
    "for" attribute that points to the form element that the label is for. The
    label and the input element could each be anywhere in the DOM.

    On Mon, Nov 23, 2015 at 10:53 AM, Kevin Ormbrek notifications@github.com
    wrote:

    A more generic approach would be using nested locators. Like
    label=xpath=//label[., starts-with('Blah')]. This way the label could be
    located however desired. The label strategy could have key attributes like
    id or text so that label=Blah would search by id or text "Blah" since a
    second locator prefix was not used. This is just brainstorming. With nested
    locator prefixes, the prefix with label makes more sense e.g. "with
    label=id=label_123"

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-158994250
    .

  17. boakley commented on Nov 25, 2015

    @boakley
    ContributorAuthor

    Sorry I didn't respond earlier.

    I don't know what I want to do. I'm a bit surprised at how confusing this
    request has been to the few people who have responded. I don't want to add
    something that will confuse people.

    I've been sitting back, hoping more people would join the discussion. I
    guess if there's very little interest I'll probably withdraw the request.
    Perhaps there aren't very many people using robot with django...?

    On Mon, Nov 23, 2015 at 10:01 AM, Tatu Aalto notifications@github.com
    wrote:

    @boakley https://github.com/boakley What you want to do with this
    issue? And what do others think?

    —
    Reply to this email directly or view it on GitHub
    https://github.com/robotframework/Selenium2Library/issues/533#issuecomment-158979468
    .

  18. aaltat commented on Nov 25, 2015

    @aaltat
    Contributor

    Not many people actively follow issue tracker, perhaps it would be good idea to advertise the problem in the user group and in the slack channel?

  19. ombre42 commented on Nov 25, 2015

    @ombre42
    Contributor

    @boakley I think I understand the problem. My suggestion of nested locators was to address @emanlove's concern about partial text, full text, regular expression, etc. If you have the full power of a locator than you can handle locating the label element in any way you want (except for regex). The final element located would always be the element the label is for, regardless of location in DOM. Your use case of matching full label text is pretty narrow, and I'm just thinking of the long run.

  20. pekkaklarck commented on Nov 25, 2015

    @pekkaklarck
    Member

    FWIW, I think that

    • locating elements by label is a good idea
    • both labels with for and labels wrapping the element should be supported
    • locating labels by the their text by default is a good idea (label=My label)
    • supporting other locators would be handy too (label=id=example)
  21. aaltat commented on May 23, 2016

    @aaltat
    Contributor

    There has not been activity for this issue for long time and we are planning to close the old issues if they are not anymore valid ones. If you feel that this is still valid issue, could you send an update. If update is not received in a month, we will assume that this is not anymore an issues and we will close this issue.

  22. andreabisello commented on Nov 16, 2016

    @andreabisello

    @aaltat in my web application i often use as "button" but i have any locator to find a label.
    now i'm using, as a workaround, this finder

    Click Element xpath=//*[contains(text(),'ABC')]

    but i think a

    Click Element label=ABC

    that will click element with label - span containing ABC will be usefull.

  23. andreabisello commented on Oct 2, 2017

    @andreabisello

    @aaltat with @HelioGuilherme66 and another user in the slack channel , the need of a "Click Element Where Text Is" raised again. Due a solution can be the use of a xpath, maybe we can add this example in the documentation of Click Element with xpath locator?

  24. pekkaklarck commented on Oct 2, 2017

    @pekkaklarck
    Member

    Searching "by label" is not same as searching "by text". When searching by label you'd find first a label element and based on it then the actual element. Then searching by text, you find the element directly based on its text content.

    I'd be fine adding built-in support for both labels and text, but they both require someone to need them badly enough to provide a PR. Adding a new example to documentation is a good idea too. Please submit a new issue and/or PR!

  25. jruuttun commented on Jan 4, 2019

    @jruuttun

    Hi All, I too came here looking for this very feature. I wish there was a label-based input selector out of the box, and I don't think this is by any means a Django-specific issue. I want to use it specifically with for="some-id" but agree that the wrapped variation would be useful as well.

  26. aaltat commented on Jan 4, 2019

    @aaltat
    Contributor

    It is true that it would be useful, but @pekkaklarck comment from the above still holds water very well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions