fix(actions): ignore indeterminate for isChecked api (#20834)

Fixes #20190.
This commit is contained in:
Dmitry Gozman 2023-02-10 18:56:45 -08:00 committed by GitHub
parent 77b598110f
commit 6b69d23f44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 6 deletions

View File

@ -29,7 +29,7 @@ import type { CSSComplexSelectorList } from '../isomorphic/cssParser';
import { generateSelector } from './selectorGenerator';
import type * as channels from '@protocol/channels';
import { Highlight } from './highlight';
import { getAriaCheckedStrict, getAriaDisabled, getAriaLabelledByElements, getAriaRole, getElementAccessibleName } from './roleUtils';
import { getChecked, getAriaDisabled, getAriaLabelledByElements, getAriaRole, getElementAccessibleName } from './roleUtils';
import { kLayoutSelectorNames, type LayoutSelectorName, layoutSelectorScore } from './layoutSelectorUtils';
import { asLocator } from '../isomorphic/locatorGenerators';
import type { Language } from '../isomorphic/locatorGenerators';
@ -614,7 +614,7 @@ export class InjectedScript {
if (state === 'checked' || state === 'unchecked') {
const need = state === 'checked';
const checked = getAriaCheckedStrict(element);
const checked = getChecked(element, false);
if (checked === 'error')
throw this.createStacklessError('Not a checkbox or radio button');
return need === checked;

View File

@ -662,13 +662,13 @@ export function getAriaSelected(element: Element): boolean {
export const kAriaCheckedRoles = ['checkbox', 'menuitemcheckbox', 'option', 'radio', 'switch', 'menuitemradio', 'treeitem'];
export function getAriaChecked(element: Element): boolean | 'mixed' {
const result = getAriaCheckedStrict(element);
const result = getChecked(element, true);
return result === 'error' ? false : result;
}
export function getAriaCheckedStrict(element: Element): boolean | 'mixed' | 'error' {
export function getChecked(element: Element, allowMixed: boolean): boolean | 'mixed' | 'error' {
// https://www.w3.org/TR/wai-aria-1.2/#aria-checked
// https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
if (element.tagName === 'INPUT' && (element as HTMLInputElement).indeterminate)
if (allowMixed && element.tagName === 'INPUT' && (element as HTMLInputElement).indeterminate)
return 'mixed';
if (element.tagName === 'INPUT' && ['checkbox', 'radio'].includes((element as HTMLInputElement).type))
return (element as HTMLInputElement).checked;
@ -676,7 +676,7 @@ export function getAriaCheckedStrict(element: Element): boolean | 'mixed' | 'err
const checked = element.getAttribute('aria-checked');
if (checked === 'true')
return true;
if (checked === 'mixed')
if (allowMixed && checked === 'mixed')
return 'mixed';
return false;
}

View File

@ -144,6 +144,21 @@ it('isChecked should work', async ({ page }) => {
expect(error.message).toContain('Not a checkbox or radio button');
});
it('isChecked should work for indeterminate input', async ({ page }) => {
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/20190' });
await page.setContent(`<input type="checkbox" checked>`);
await page.locator('input').evaluate((e: HTMLInputElement) => e.indeterminate = true);
expect(await page.locator('input').isChecked()).toBe(true);
await expect(page.locator('input')).toBeChecked();
await page.locator('input').uncheck();
expect(await page.locator('input').isChecked()).toBe(false);
await expect(page.locator('input')).not.toBeChecked();
});
it('allTextContents should work', async ({ page }) => {
await page.setContent(`<div>A</div><div>B</div><div>C</div>`);
expect(await page.locator('div').allTextContents()).toEqual(['A', 'B', 'C']);