fix(isVisible): do not retarget visibility checks (#16002)

We used to go to the enclosing button (inherited from click logic), which is unexpected.
This commit is contained in:
Dmitry Gozman 2022-07-27 14:02:35 -07:00 committed by GitHub
parent 93b255ce90
commit 607910f6aa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 2 deletions

View file

@ -437,10 +437,12 @@ export class InjectedScript {
return { left: parseInt(style.borderLeftWidth || '', 10), top: parseInt(style.borderTopWidth || '', 10) };
}
retarget(node: Node, behavior: 'follow-label' | 'no-follow-label'): Element | null {
retarget(node: Node, behavior: 'none' | 'follow-label' | 'no-follow-label'): Element | null {
let element = node.nodeType === Node.ELEMENT_NODE ? node as Element : node.parentElement;
if (!element)
return null;
if (behavior === 'none')
return element;
if (!element.matches('input, textarea, select'))
element = element.closest('button, [role=button], [role=checkbox], [role=radio]') || element;
if (behavior === 'follow-label') {
@ -517,7 +519,7 @@ export class InjectedScript {
}
elementState(node: Node, state: ElementStateWithoutStable): boolean | 'error:notconnected' {
const element = this.retarget(node, ['stable', 'visible', 'hidden'].includes(state) ? 'no-follow-label' : 'follow-label');
const element = this.retarget(node, ['stable', 'visible', 'hidden'].includes(state) ? 'none' : 'follow-label');
if (!element || !element.isConnected) {
if (state === 'hidden')
return true;

View file

@ -228,3 +228,29 @@ it('should return page', async ({ page, server }) => {
const inFrame = page.frames()[1].locator('div');
expect(inFrame.page()).toBe(page);
});
it('isVisible inside a button', async ({ page }) => {
await page.setContent(`<button><span></span>a button</button>`);
const span = page.locator('span');
expect(await span.isVisible()).toBe(false);
expect(await span.isHidden()).toBe(true);
expect(await page.isVisible('span')).toBe(false);
expect(await page.isHidden('span')).toBe(true);
await expect(span).not.toBeVisible();
await expect(span).toBeHidden();
await span.waitFor({ state: 'hidden' });
await page.locator('button').waitFor({ state: 'visible' });
});
it('isVisible inside a role=button', async ({ page }) => {
await page.setContent(`<div role=button><span></span>a button</div>`);
const span = page.locator('span');
expect(await span.isVisible()).toBe(false);
expect(await span.isHidden()).toBe(true);
expect(await page.isVisible('span')).toBe(false);
expect(await page.isHidden('span')).toBe(true);
await expect(span).not.toBeVisible();
await expect(span).toBeHidden();
await span.waitFor({ state: 'hidden' });
await page.locator('[role=button]').waitFor({ state: 'visible' });
});