feat(expect): toHaveText/toContainText work with text in shadow dom (#16433)

This commit is contained in:
Dmitry Gozman 2022-08-11 14:10:12 -07:00 committed by GitHub
parent fce45210c1
commit 3dc1920ce8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 3 deletions

View File

@ -21,7 +21,7 @@ import { VueEngine } from './vueSelectorEngine';
import { RoleEngine } from './roleSelectorEngine';
import type { NestedSelectorBody, ParsedSelector, ParsedSelectorPart } from '../isomorphic/selectorParser';
import { allEngineNames, parseSelector, stringifySelector } from '../isomorphic/selectorParser';
import { type TextMatcher, elementMatchesText, createRegexTextMatcher, createStrictTextMatcher, createLaxTextMatcher } from './selectorUtils';
import { type TextMatcher, elementMatchesText, createRegexTextMatcher, createStrictTextMatcher, createLaxTextMatcher, elementText } from './selectorUtils';
import { SelectorEvaluatorImpl } from './selectorEvaluator';
import { isElementVisible, parentElementOrShadowHost } from './domUtils';
import type { CSSComplexSelectorList } from '../isomorphic/cssParser';
@ -1091,7 +1091,7 @@ export class InjectedScript {
} else if (expression === 'to.have.id') {
received = element.id;
} else if (expression === 'to.have.text') {
received = options.useInnerText ? (element as HTMLElement).innerText : element.textContent || '';
received = options.useInnerText ? (element as HTMLElement).innerText : elementText(new Map(), element).full;
} else if (expression === 'to.have.title') {
received = document.title;
} else if (expression === 'to.have.url') {
@ -1124,7 +1124,7 @@ export class InjectedScript {
// List of values.
let received: string[] | undefined;
if (expression === 'to.have.text.array' || expression === 'to.contain.text.array')
received = elements.map(e => options.useInnerText ? (e as HTMLElement).innerText : e.textContent || '');
received = elements.map(e => options.useInnerText ? (e as HTMLElement).innerText : elementText(new Map(), e).full);
else if (expression === 'to.have.class.array')
received = elements.map(e => e.classList.toString());

View File

@ -107,6 +107,27 @@ test.describe('toHaveText with text', () => {
const locator = page.locator('#node');
await expect(locator).toHaveText('Text content', { useInnerText: true });
});
test('in shadow dom', async ({ page }) => {
await page.setContent(`
<div></div>
<script>
const div = document.querySelector('div');
const span = document.createElement('span');
span.textContent = 'some text';
div.attachShadow({ mode: 'open' }).appendChild(span);
</script>
`);
await expect(page.locator('span')).toHaveText('some text');
await expect(page.locator('span')).toContainText('text');
await expect(page.locator('div')).toHaveText('some text');
await expect(page.locator('div')).toContainText('text');
await expect(page.locator('span')).toHaveText('some text', { useInnerText: true });
await expect(page.locator('span')).toContainText('text', { useInnerText: true });
// Playwright intentionally does not perform innerText piercing on shadow dom.
await expect(page.locator('div')).not.toHaveText('some text', { useInnerText: true });
await expect(page.locator('div')).not.toContainText('text', { useInnerText: true });
});
});
test.describe('not.toHaveText', () => {