testing-library/playwright-testing-library

findByText returns [object Promise], hence erroring out with the error 'toContainText can be only used with Locator object'

InduKrish opened this issue ยท 4 comments

getByText - the below script with getByText() works fine
async checkActiveStatusdom(text) {

    const header = await this.screen.findByTestId('erow-GroupCode-0');
    console.log(" header" + header)
    const base = this.within(header).getByText("NEW HIRE")
    console.log("base value" + base);
    const check = this.within(header).getByText("check")
    console.log(" value " + check)
    await expect(base).toContainText(text);

}

however findByText - returns Error: toContainText can be only used with Locator object

async checkActiveStatusdom(text) {

   const header = await this.screen.findByTestId('erow-GroupCode-0');
   console.log(" header" + header)
   const base = this.within(header).findByText("LINEHOLDER")
   console.log("base value" + base);
   const check = this.within(header).findByText("check")
   console.log(" value " + check)
   await expect(base).toContainText(text);

console log:
headerLocator@query-by-test-id=["erow-GroupCode-0"]
base value[object Promise]
value [object Promise]

why getByText auto waits, but findByText returns no value, and returns Error: toContainText can be only used with Locator object.

From the previous ticket , #507

I was told that findby auto waits and getby does not auto wait, in this scenario it works differently.
Screen Shot 2022-09-19 at 4 52 10 PM

The find* queries currently return Promise<Locator> as they use Locator.waitFor() internally to wait for deferred elements, so you're missing some awaits in your example.

This will work:

const header = await this.screen.findByTestId('erow-GroupCode-0');
console.log(" header" + header)

const base = await this.within(header).findByText("LINEHOLDER")
console.log("base value" + base);

const check = await this.within(header).findByText("check")
console.log(" value " + check)

await expect(base).toContainText(text);

Depending on when different elements are rendered in your application, you probably don't need asynchronous findByText for all of your queries. For example, if data-testid="erow-GroupCode-0 is really the element you're waiting for, and its contents appear synchronously within it, then you can just do this:

// Here we wait for the element to show up in the page
const header = await this.screen.findByTestId('erow-GroupCode-0');
console.log(" header" + header)

// Since we've waited for `header`, we can use synchronous queries with `within()`
const base = this.within(header).getByText("LINEHOLDER")
console.log("base value" + base);
const check = this.within(header).getByText("check")
console.log(" value " + check)

await expect(base).toContainText(text);

I will add some documentation explaining this.

Thank you for the detailed explanation!, I appreciate it

The find* queries currently return Promise<Locator> as they use Locator.waitFor() internally to wait for deferred elements, so you're missing some awaits in your example.

This will work:

const header = await this.screen.findByTestId('erow-GroupCode-0');
console.log(" header" + header)

const base = await this.within(header).findByText("LINEHOLDER")
console.log("base value" + base);

const check = await this.within(header).findByText("check")
console.log(" value " + check)

await expect(base).toContainText(text);

I tried to test this, and i see the following error

Screen Shot 2022-09-20 at 10 14 50 AM

however with by getByText, the test passed, and attached is the screenshot.

Screen Shot 2022-09-20 at 10 15 18 AM

๐ŸŽ‰ This issue has been resolved in version 4.4.1 ๐ŸŽ‰

The release is available on:

Your semantic-release bot ๐Ÿ“ฆ๐Ÿš€