diff --git a/lib/helper/Playwright.js b/lib/helper/Playwright.js index f358a189c..fb2037272 100644 --- a/lib/helper/Playwright.js +++ b/lib/helper/Playwright.js @@ -4428,7 +4428,8 @@ async function proceedSee(assertType, text, context, strict = false) { description = `element ${locator.toString()}` const els = await this._locate(locator) assertElementExists(els, locator.toString()) - allText = await Promise.all(els.map(el => el.innerText())) + allText = (await Promise.all(els.map(el => el.evaluateAll(nodes => nodes.map(node => node.innerText ?? node.textContent))))).flat() + assertElementExists(allText, locator.toString()) } if (store?.currentStep?.opts?.ignoreCase === true) { diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index e7fdec3f5..45c522edf 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -730,6 +730,86 @@ describe('Playwright', function () { }) }) + describe('#see with context when a matched element is removed', () => { + let locatorProto + let originalAll + + beforeEach(async () => { + await I.amOnPage('/form/field') + await I.executeScript(() => { + for (const text of ['old toast', 'new toast']) { + const el = document.createElement('div') + el.className = 'toast' + el.textContent = text + document.body.append(el) + } + }) + + locatorProto = Object.getPrototypeOf(page.locator('body')) + originalAll = locatorProto.all + locatorProto.all = async function () { + locatorProto.all = originalAll + const els = await originalAll.call(this) + await page.evaluate(() => document.querySelector('.toast')?.remove()) + return els + } + page.setDefaultTimeout(10000) + }) + + afterEach(() => { + locatorProto.all = originalAll + page.setDefaultTimeout(I.options.timeout) + }) + + it('should see text in a remaining element without waiting for timeout', async () => { + const start = Date.now() + await I.see('new toast', '.toast') + expect(Date.now() - start).to.be.below(1000) + }) + + it('should not see text of the removed element without waiting for timeout', async () => { + const start = Date.now() + await I.dontSee('old toast', '.toast') + expect(Date.now() - start).to.be.below(1000) + }) + + it('should fail text equality check when every matched element is removed', async () => { + await I.executeScript(() => document.querySelectorAll('.toast')[1].remove()) + const start = Date.now() + let error + try { + await I.seeTextEquals('old toast', '.toast') + } catch (err) { + error = err + } + expect(error?.message).to.include('was not found') + expect(Date.now() - start).to.be.below(1000) + }) + }) + + describe('#see with context matching a non-HTML element', () => { + beforeEach(async () => { + await I.amOnPage('/form/field') + await I.executeScript(() => { + document.body.insertAdjacentHTML('beforeend', 'chart label') + }) + }) + + it('should see text of an SVG element', async () => { + await I.see('chart label', '.chart-label') + }) + + it('should fail to not see text of an SVG element', async () => { + let error + try { + await I.dontSee('chart label', '.chart-label') + } catch (err) { + error = err + } + expect(error).to.be.instanceOf(AssertionFailedError) + }) + }) + describe('check fields: #seeInField, #seeCheckboxIsChecked, ...', () => { it('should throw error if field is not empty', () => I.amOnPage('/form/empty')