Search code examples
testingfilterautomated-testse2e-testingtestcafe

TestCafe functional selectors


I'm trying to figure out how to make the selectors that I need, but I'm a bit stumped. My DOM looks like this:

<div class="project index_list__item_container">
  <div class="index_item__header">
    <h3 class="index_item__title">
      <a class="index_item__title_link" href="/foo_bar_link">
        foo bar title
      </a>
    </h3>
    <div class="index_list__item_detail index_list__item_detail--light">
      <span data-test="progress-p">
        In Progress / Started about 1 month ago
      </span>
    </div>
  </div>
  <div class="index_item__stats_and_actions">
    <a class="index_item__stat_indicator" href="/foo_bar_link">
      <span class="stat_indicator__stat_total">23</span>
      <span class="index_item__stat_description">views</span>
    </a>
    <a class="index_item__stat_indicator" href="/foo_bar_link">
      <span class="stat_indicator__stat_total">25</span>
      <span class="index_item__stat_description">plays</span>
    </a>
  </div>
</div>

There are many of these "item containers" on the page all in a list. In words, what I'm trying to do is "find the specific item that has "foo bar title" in it, and then verify that the item detail has the text "In Progress"."

I tried using .filter (and previously .find) like this:

test('Verify states', async (t) => {
  const draftItemDetail = await 
    indexPage.indexItemContainer.withText('foo bar title')
      .filter(indexPage.indexItemDetail);

  await t
    .expect(draftItemDetail.textContent).contains('In Progress');
});

// Page Object
import { Selector } from 'testcafe';

export default class IndexPage {
  constructor() {
    this.indexItemContainer = Selector('.index_list__item_container');
    this.indexItemDetail = Selector('.index_list__item_detail');
  }
}

The error that I'm getting is:

 1) filter code is expected to be specified as a function, but string was passed.

I keep seeing examples of people using selectors in find and filter, so I'm clearly doing something else wrong. Any help would be much appreciated, I have a lot of similar patterns that I need to code up for this page, and I'd rather not have to use a long specific descendant chain. Thanks!


Solution

  • The filter function accepts a predicate or a cssSelector. However, you pass a Selector (indexPage.indexItemDetail).

    For instance, the following find function properly finds the desired element and the test is passed:  

    test('Verify states', async (t) => {
      const draftItemDetail = await indexPage.indexItemContainer
        .withText('foo bar title')
        .find(".index_list__item_detail")
    
      await t.expect(draftItemDetail.textContent).contains('In Progress');
    });
    

    Alternatively, you might want to pass the second Selector as a dependency to a child/parent predicate:

    test('Verify states', async (t) => {
      const indexItemDetail = indexPage.indexItemDetail;
      const draftItemDetail = await indexPage.indexItemContainer
        .withText('foo bar title')
        .child((node, idx, originNode) => {
            const itemDetail = indexItemDetail();
            if (node.contains(itemDetail))
                return true;
        }, { indexItemDetail });
    
      await t.expect(draftItemDetail.textContent).contains('In Progress');
    });