3

I'm trying to chain together a Selector, a withText, a find, and another withText in order to find a particular link.

Here's the HTML I'm trying to search through, and I want to select the "Edit" button that's in the div with the text "Reviewers":

<div class="content">
    <div class="ui edit-segment--header">Documents
        <button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
    </div>
    <div class="ui segment segment__compact-top">
        <div role="list" class="ui bulleted list">
            <div role="listitem" class="item"><span>Budget</span></div>
            <div role="listitem" class="item"><span>Draw cover sheet</span></div>
            <!-- (a few more...) -->
        </div>
    </div>
</div>
<div class="content">
    <div class="ui edit-segment--header">Rules
        <button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
    </div>
    <div class="ui segment segment__compact-top">
        <h4 class="ui header">Automatic</h4><span>No rules selected</span>
        <h4 class="ui header">Manual</h4><span>No rules selected</span></div>
</div>
<div class="content">
    <div class="ui edit-segment--header">Reviewers
        <button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
    </div>
    <div class="ui segment segment__compact-top">
        <div role="list" class="ui list">None</div>
    </div>
</div>

I'm trying to click this using:

await t.click(Selector("div").withText("Reviewers").find("button").withText("Edit"));

TestCafe ends up finding the "Edit" button that's in the div with the text "Documents" inside and clicking it.

I would expect that Selector("div").withText("Reviewers") would find the specific div with the text Reviewers inside it, and then the .find("button").withText("Edit") would find the only child button (which happens to have the text Edit) inside that. Am I misunderstanding how it should work? Thanks

Alex Skorkin
  • 4,264
  • 3
  • 25
  • 47
strylee
  • 31
  • 4

1 Answers1

4

Your "Edit button" selector (Selector('div').withText('Reviewers').find('button').withText('Edit')) is correct.

I would expect that Selector("div").withText("Reviewers") would find the specific div with the text Reviewers inside it

The main point of your example is that the "Reviewers" (Selector('div').withText('Reviewers')) selector matches two div elements.

To illustrate it I made the following test in the context of your example page:

test.js

import { Selector } from 'testcafe';

fixture `fixture`
    .page `http://localhost:8080`;

test('test', async t => {
    const divReviewers = Selector('div').withText('Reviewers').addCustomDOMProperties({
        outerHTML: el => el.outerHTML
    });

    await t
        .expect(divReviewers.count).eql(2);

    console.log('[1] divReviewers.nth(0).outerHTML:\n', await divReviewers.nth(0).outerHTML);
    console.log('[2] divReviewers.nth(1).outerHTML:\n', await divReviewers.nth(1).outerHTML);
});

Result

[1] divReviewers.nth(0).outerHTML:
 <div class="content">
    <div class="ui edit-segment--header">Reviewers
        <button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
    </div>
    <div class="ui segment segment__compact-top">
        <div role="list" class="ui list">None</div>
    </div>
</div>
[2] divReviewers.nth(1).outerHTML:
 <div class="ui edit-segment--header">Reviewers
        <button type="button" data-testid="edit-segment" class="material link right floated relaxed-top">Edit</button>
    </div>
 √ test


 1 passed (1s)
Vladimir A.
  • 2,202
  • 2
  • 10
  • 28
  • Thanks V! That's very helpful, I didn't realize that the selector also grabbed all the ancestors. So the actual code on our site also includes many more ancestors, and based on the debugging method you've given me here I can see that it grabs those as well as the "sibling" that it's mistakenly clicking on. Do you know of any way to find what I'm looking for while excluding the ancestors? To just narrow in on that specific div with the text Reviewers, and only look at its children for the link I want? Thanks – strylee Jul 04 '19 at 20:33
  • I'd like to clarify my comment - My sample HTML given above is the simplified stuff - on the actual site the selector `Selector('div').withText('Reviewers')` grabs everything starting with a great-great-great^n grandparent div, and all the corresponding children and great-grandchildren of that root, so ultimately it's almost the same as grabbing the entire DOM, with how much comes back. Both in nth(0) and nth(1). So it's kind of not that useful to even do that if I still have to `.find("button").withText("Edit")` and then call .nth(4) on that... I may as well not use the first selector. Thanks – strylee Jul 04 '19 at 21:46
  • 1
    The search logic for `Selector('div').withText('Reviewers')` is very easy: find all div elements with innerText='Reviewers'. If the Selector finds a lot of extra elements then you need to specify a more strict selector. For example for your case the target selector can be changed to `Selector('div.ui').withText('Reviewers')`. Changed selectors return only one element. – mlosev Jul 05 '19 at 08:56
  • 1
    thanks @mlosev! that's exactly what I needed. (Sorry StackOverflow for breaking the rules and saying thanks, but I did want to show my gratitude) – strylee Jul 05 '19 at 19:17