feat(toBeChecked): allow mixed expectation
This commit is contained in:
parent
809225503c
commit
40fa42476a
|
|
@ -1431,6 +1431,16 @@ checked = page.get_by_role("checkbox").is_checked()
|
||||||
var isChecked = await page.GetByRole(AriaRole.Checkbox).IsCheckedAsync();
|
var isChecked = await page.GetByRole(AriaRole.Checkbox).IsCheckedAsync();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### option: Locator.isChecked.checked
|
||||||
|
* since: v1.50
|
||||||
|
* langs: js, python
|
||||||
|
- `checked` <[boolean]|"mixed">
|
||||||
|
|
||||||
|
### option: Locator.isChecked.checked
|
||||||
|
* since: v1.50
|
||||||
|
* langs: java, csharp
|
||||||
|
- `checked` <[boolean]>
|
||||||
|
|
||||||
### option: Locator.isChecked.timeout = %%-input-timeout-%%
|
### option: Locator.isChecked.timeout = %%-input-timeout-%%
|
||||||
* since: v1.14
|
* since: v1.14
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -539,6 +539,12 @@ await Expect(locator).ToBeCheckedAsync();
|
||||||
|
|
||||||
### option: LocatorAssertions.toBeChecked.checked
|
### option: LocatorAssertions.toBeChecked.checked
|
||||||
* since: v1.18
|
* since: v1.18
|
||||||
|
* langs: js, python
|
||||||
|
- `checked` <[boolean]|"mixed">
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toBeChecked.checked
|
||||||
|
* since: v1.18
|
||||||
|
* langs: java, csharp
|
||||||
- `checked` <[boolean]>
|
- `checked` <[boolean]>
|
||||||
|
|
||||||
### option: LocatorAssertions.toBeChecked.timeout = %%-js-assertions-timeout-%%
|
### option: LocatorAssertions.toBeChecked.timeout = %%-js-assertions-timeout-%%
|
||||||
|
|
|
||||||
|
|
@ -256,8 +256,9 @@ export class Locator implements api.Locator {
|
||||||
return await this._frame.inputValue(this._selector, { strict: true, ...options });
|
return await this._frame.inputValue(this._selector, { strict: true, ...options });
|
||||||
}
|
}
|
||||||
|
|
||||||
async isChecked(options?: TimeoutOptions): Promise<boolean> {
|
async isChecked(options?: { checked?: boolean | 'mixed' } & TimeoutOptions): Promise<boolean> {
|
||||||
return await this._frame.isChecked(this._selector, { strict: true, ...options });
|
const checked = options?.checked === true ? 'checked' : options?.checked === false ? 'unchecked' : options?.checked === 'mixed' ? 'mixed' : undefined;
|
||||||
|
return await this._frame.isChecked(this._selector, { strict: true, ...options, checked });
|
||||||
}
|
}
|
||||||
|
|
||||||
async isDisabled(options?: TimeoutOptions): Promise<boolean> {
|
async isDisabled(options?: TimeoutOptions): Promise<boolean> {
|
||||||
|
|
|
||||||
|
|
@ -1591,6 +1591,7 @@ scheme.FrameInputValueResult = tObject({
|
||||||
});
|
});
|
||||||
scheme.FrameIsCheckedParams = tObject({
|
scheme.FrameIsCheckedParams = tObject({
|
||||||
selector: tString,
|
selector: tString,
|
||||||
|
checked: tOptional(tEnum(['checked', 'unchecked', 'mixed'])),
|
||||||
strict: tOptional(tBoolean),
|
strict: tOptional(tBoolean),
|
||||||
timeout: tOptional(tNumber),
|
timeout: tOptional(tNumber),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -777,7 +777,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||||
|
|
||||||
async _setChecked(progress: Progress, state: boolean, options: { position?: types.Point } & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
async _setChecked(progress: Progress, state: boolean, options: { position?: types.Point } & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {
|
||||||
const isChecked = async () => {
|
const isChecked = async () => {
|
||||||
const result = await this.evaluateInUtility(([injected, node]) => injected.elementState(node, 'checked'), {});
|
const result = await this.evaluateInUtility(([injected, node]) => injected.elementState(node, 'lax-checked'), {});
|
||||||
if (result === 'error:notconnected' || result.received === 'error:notconnected')
|
if (result === 'error:notconnected' || result.received === 'error:notconnected')
|
||||||
throwElementIsNotAttached();
|
throwElementIsNotAttached();
|
||||||
return result.matches;
|
return result.matches;
|
||||||
|
|
|
||||||
|
|
@ -1336,19 +1336,19 @@ export class Frame extends SdkObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
async isDisabled(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
async isDisabled(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
||||||
return this._elementState(metadata, selector, 'disabled', options, scope);
|
return await this._elementState(metadata, selector, 'disabled', options, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isEnabled(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
async isEnabled(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
||||||
return this._elementState(metadata, selector, 'enabled', options, scope);
|
return await this._elementState(metadata, selector, 'enabled', options, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isEditable(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
async isEditable(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
||||||
return this._elementState(metadata, selector, 'editable', options, scope);
|
return await this._elementState(metadata, selector, 'editable', options, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isChecked(metadata: CallMetadata, selector: string, options: types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
async isChecked(metadata: CallMetadata, selector: string, options: { checked?: 'checked' | 'unchecked' | 'mixed' } & types.QueryOnSelectorOptions = {}, scope?: dom.ElementHandle): Promise<boolean> {
|
||||||
return this._elementState(metadata, selector, 'checked', options, scope);
|
return await this._elementState(metadata, selector, options?.checked || 'lax-checked', options, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
async hover(metadata: CallMetadata, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
async hover(metadata: CallMetadata, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions = {}) {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import type { CSSComplexSelectorList } from '../../utils/isomorphic/cssParser';
|
||||||
import { generateSelector, type GenerateSelectorOptions } from './selectorGenerator';
|
import { generateSelector, type GenerateSelectorOptions } from './selectorGenerator';
|
||||||
import type * as channels from '@protocol/channels';
|
import type * as channels from '@protocol/channels';
|
||||||
import { Highlight } from './highlight';
|
import { Highlight } from './highlight';
|
||||||
import { getChecked, getAriaDisabled, getAriaRole, getElementAccessibleName, getElementAccessibleDescription, getReadonly, getElementAccessibleErrorMessage } from './roleUtils';
|
import { getAriaDisabled, getAriaRole, getElementAccessibleName, getElementAccessibleDescription, getReadonly, getElementAccessibleErrorMessage, getCheckedAllowMixed, getCheckedWithoutMixed } from './roleUtils';
|
||||||
import { kLayoutSelectorNames, type LayoutSelectorName, layoutSelectorScore } from './layoutSelectorUtils';
|
import { kLayoutSelectorNames, type LayoutSelectorName, layoutSelectorScore } from './layoutSelectorUtils';
|
||||||
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
import { asLocator } from '../../utils/isomorphic/locatorGenerators';
|
||||||
import type { Language } from '../../utils/isomorphic/locatorGenerators';
|
import type { Language } from '../../utils/isomorphic/locatorGenerators';
|
||||||
|
|
@ -41,7 +41,7 @@ import { parseYamlTemplate } from '@isomorphic/ariaSnapshot';
|
||||||
|
|
||||||
export type FrameExpectParams = Omit<channels.FrameExpectParams, 'expectedValue'> & { expectedValue?: any };
|
export type FrameExpectParams = Omit<channels.FrameExpectParams, 'expectedValue'> & { expectedValue?: any };
|
||||||
|
|
||||||
export type ElementState = 'visible' | 'hidden' | 'enabled' | 'disabled' | 'editable' | 'checked' | 'unchecked' | 'mixed' | 'stable';
|
export type ElementState = 'visible' | 'hidden' | 'enabled' | 'disabled' | 'editable' | 'checked' | 'unchecked' | 'mixed' | 'lax-checked' | 'stable';
|
||||||
export type ElementStateWithoutStable = Exclude<ElementState, 'stable'>;
|
export type ElementStateWithoutStable = Exclude<ElementState, 'stable'>;
|
||||||
export type ElementStateQueryResult = { matches: boolean, received?: string | 'error:notconnected' };
|
export type ElementStateQueryResult = { matches: boolean, received?: string | 'error:notconnected' };
|
||||||
|
|
||||||
|
|
@ -646,7 +646,7 @@ export class InjectedScript {
|
||||||
|
|
||||||
if (state === 'checked' || state === 'unchecked' || state === 'mixed') {
|
if (state === 'checked' || state === 'unchecked' || state === 'mixed') {
|
||||||
const need = state === 'checked' ? true : state === 'unchecked' ? false : 'mixed';
|
const need = state === 'checked' ? true : state === 'unchecked' ? false : 'mixed';
|
||||||
const checked = getChecked(element, false);
|
const checked = getCheckedAllowMixed(element);
|
||||||
if (checked === 'error')
|
if (checked === 'error')
|
||||||
throw this.createStacklessError('Not a checkbox or radio button');
|
throw this.createStacklessError('Not a checkbox or radio button');
|
||||||
return {
|
return {
|
||||||
|
|
@ -654,6 +654,17 @@ export class InjectedScript {
|
||||||
received: checked === true ? 'checked' : checked === false ? 'unchecked' : 'mixed',
|
received: checked === true ? 'checked' : checked === false ? 'unchecked' : 'mixed',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state === 'lax-checked') {
|
||||||
|
const checked = getCheckedWithoutMixed(element);
|
||||||
|
if (checked === 'error')
|
||||||
|
throw this.createStacklessError('Not a checkbox or radio button');
|
||||||
|
return {
|
||||||
|
matches: checked,
|
||||||
|
received: checked ? 'checked' : 'unchecked',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
throw this.createStacklessError(`Unexpected element state "${state}"`);
|
throw this.createStacklessError(`Unexpected element state "${state}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1241,9 +1252,7 @@ export class InjectedScript {
|
||||||
received: hasAttribute ? 'attribute present' : 'attribute not present',
|
received: hasAttribute ? 'attribute present' : 'attribute not present',
|
||||||
};
|
};
|
||||||
} else if (expression === 'to.be.checked') {
|
} else if (expression === 'to.be.checked') {
|
||||||
result = this.elementState(element, 'checked');
|
result = this.elementState(element, options.expectedValue);
|
||||||
} else if (expression === 'to.be.unchecked') {
|
|
||||||
result = this.elementState(element, 'unchecked');
|
|
||||||
} else if (expression === 'to.be.disabled') {
|
} else if (expression === 'to.be.disabled') {
|
||||||
result = this.elementState(element, 'disabled');
|
result = this.elementState(element, 'disabled');
|
||||||
} else if (expression === 'to.be.editable') {
|
} else if (expression === 'to.be.editable') {
|
||||||
|
|
|
||||||
|
|
@ -894,7 +894,17 @@ export function getAriaChecked(element: Element): boolean | 'mixed' {
|
||||||
const result = getChecked(element, true);
|
const result = getChecked(element, true);
|
||||||
return result === 'error' ? false : result;
|
return result === 'error' ? false : result;
|
||||||
}
|
}
|
||||||
export function getChecked(element: Element, allowMixed: boolean): boolean | 'mixed' | 'error' {
|
|
||||||
|
export function getCheckedAllowMixed(element: Element): boolean | 'mixed' | 'error' {
|
||||||
|
return getChecked(element, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCheckedWithoutMixed(element: Element): boolean | 'error' {
|
||||||
|
const result = getChecked(element, false);
|
||||||
|
return result as boolean | 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChecked(element: Element, allowMixed: boolean): boolean | 'mixed' | 'error' {
|
||||||
const tagName = elementSafeTagName(element);
|
const tagName = elementSafeTagName(element);
|
||||||
// https://www.w3.org/TR/wai-aria-1.2/#aria-checked
|
// 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
|
// https://www.w3.org/TR/html-aam-1.0/#html-attribute-state-and-property-mappings
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ export async function performAction(callMetadata: CallMetadata, pageAliases: Map
|
||||||
await mainFrame.expect(callMetadata, selector, {
|
await mainFrame.expect(callMetadata, selector, {
|
||||||
selector,
|
selector,
|
||||||
expression: 'to.be.checked',
|
expression: 'to.be.checked',
|
||||||
|
expectedValue: 'checked',
|
||||||
isNot: !action.checked,
|
isNot: !action.checked,
|
||||||
timeout: kActionTimeout,
|
timeout: kActionTimeout,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
2
packages/playwright-core/types/types.d.ts
vendored
2
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -13643,6 +13643,8 @@ export interface Locator {
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
isChecked(options?: {
|
isChecked(options?: {
|
||||||
|
checked?: boolean|"mixed";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum time in milliseconds. Defaults to `0` - no timeout. The default value can be changed via `actionTimeout`
|
* Maximum time in milliseconds. Defaults to `0` - no timeout. The default value can be changed via `actionTimeout`
|
||||||
* option in the config, or by using the
|
* option in the config, or by using the
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,13 @@ export function toBeAttached(
|
||||||
export function toBeChecked(
|
export function toBeChecked(
|
||||||
this: ExpectMatcherState,
|
this: ExpectMatcherState,
|
||||||
locator: LocatorEx,
|
locator: LocatorEx,
|
||||||
options?: { checked?: boolean, timeout?: number },
|
options?: { checked?: boolean | 'mixed', timeout?: number },
|
||||||
) {
|
) {
|
||||||
const checked = !options || options.checked === undefined || options.checked;
|
const expected = options?.checked === true ? 'checked' : options?.checked === false ? 'unchecked' : options?.checked === 'mixed' ? 'mixed' : 'checked';
|
||||||
const expected = checked ? 'checked' : 'unchecked';
|
const expectedValue = options?.checked === true ? 'checked' : options?.checked === false ? 'unchecked' : options?.checked === 'mixed' ? 'mixed' : 'lax-checked';
|
||||||
const arg = checked ? '' : '{ checked: false }';
|
const arg = options?.checked === undefined ? '' : `{ checked: ${JSON.stringify(options.checked)} }`;
|
||||||
return toBeTruthy.call(this, 'toBeChecked', locator, 'Locator', expected, arg, async (isNot, timeout) => {
|
return toBeTruthy.call(this, 'toBeChecked', locator, 'Locator', expected, arg, async (isNot, timeout) => {
|
||||||
return await locator._expect(checked ? 'to.be.checked' : 'to.be.unchecked', { isNot, timeout });
|
return await locator._expect('to.be.checked', { isNot, timeout, expectedValue });
|
||||||
}, options);
|
}, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
packages/playwright/types/test.d.ts
vendored
2
packages/playwright/types/test.d.ts
vendored
|
|
@ -7813,7 +7813,7 @@ interface LocatorAssertions {
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
toBeChecked(options?: {
|
toBeChecked(options?: {
|
||||||
checked?: boolean;
|
checked?: boolean|"mixed";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`.
|
* Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`.
|
||||||
|
|
|
||||||
2
packages/protocol/src/channels.d.ts
vendored
2
packages/protocol/src/channels.d.ts
vendored
|
|
@ -2879,10 +2879,12 @@ export type FrameInputValueResult = {
|
||||||
};
|
};
|
||||||
export type FrameIsCheckedParams = {
|
export type FrameIsCheckedParams = {
|
||||||
selector: string,
|
selector: string,
|
||||||
|
checked?: 'checked' | 'unchecked' | 'mixed',
|
||||||
strict?: boolean,
|
strict?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
};
|
};
|
||||||
export type FrameIsCheckedOptions = {
|
export type FrameIsCheckedOptions = {
|
||||||
|
checked?: 'checked' | 'unchecked' | 'mixed',
|
||||||
strict?: boolean,
|
strict?: boolean,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2128,6 +2128,12 @@ Frame:
|
||||||
isChecked:
|
isChecked:
|
||||||
parameters:
|
parameters:
|
||||||
selector: string
|
selector: string
|
||||||
|
checked:
|
||||||
|
type: enum?
|
||||||
|
literals:
|
||||||
|
- checked
|
||||||
|
- unchecked
|
||||||
|
- mixed
|
||||||
strict: boolean?
|
strict: boolean?
|
||||||
timeout: number?
|
timeout: number?
|
||||||
returns:
|
returns:
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,13 @@ test.describe('toBeChecked', () => {
|
||||||
await expect(locator).not.toBeChecked({ checked: false });
|
await expect(locator).not.toBeChecked({ checked: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('with checked:mixed', async ({ page }) => {
|
||||||
|
await page.setContent('<input type=checkbox aria-checked=mixed></input>');
|
||||||
|
await page.locator('input').evaluate((e: HTMLInputElement) => e.indeterminate = true);
|
||||||
|
const locator = page.locator('input');
|
||||||
|
await expect(locator).toBeChecked({ checked: 'mixed' });
|
||||||
|
});
|
||||||
|
|
||||||
test('fail', async ({ page }) => {
|
test('fail', async ({ page }) => {
|
||||||
await page.setContent('<input type=checkbox></input>');
|
await page.setContent('<input type=checkbox></input>');
|
||||||
const locator = page.locator('input');
|
const locator = page.locator('input');
|
||||||
|
|
@ -69,6 +76,13 @@ test.describe('toBeChecked', () => {
|
||||||
expect(error.message).toContain(`expect.toBeChecked with timeout 1000ms`);
|
expect(error.message).toContain(`expect.toBeChecked with timeout 1000ms`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('fail with checked:mixed', async ({ page }) => {
|
||||||
|
await page.setContent('<input type=checkbox></input>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
const error = await expect(locator).toBeChecked({ checked: 'mixed', timeout: 1000 }).catch(e => e);
|
||||||
|
expect(error.message).toContain(`expect.toBeChecked with timeout 1000ms`);
|
||||||
|
});
|
||||||
|
|
||||||
test('fail missing', async ({ page }) => {
|
test('fail missing', async ({ page }) => {
|
||||||
await page.setContent('<div>no inputs here</div>');
|
await page.setContent('<div>no inputs here</div>');
|
||||||
const locator2 = page.locator('input2');
|
const locator2 = page.locator('input2');
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,7 @@ Call log`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toBeChecked({ checked: false }) should have expected: false', async ({ page }) => {
|
test('toBeChecked({ checked }) should have expected', async ({ page }) => {
|
||||||
await page.setContent(`
|
await page.setContent(`
|
||||||
<input id=checked type=checkbox checked></input>
|
<input id=checked type=checkbox checked></input>
|
||||||
<input id=unchecked type=checkbox></input>
|
<input id=unchecked type=checkbox></input>
|
||||||
|
|
@ -251,6 +251,28 @@ Call log`);
|
||||||
Locator: locator('#unchecked')
|
Locator: locator('#unchecked')
|
||||||
Expected: not unchecked
|
Expected: not unchecked
|
||||||
Received: unchecked
|
Received: unchecked
|
||||||
|
Call log`);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const e = await expect(page.locator('#unchecked')).toBeChecked({ checked: 'mixed', timeout: 1 }).catch(e => e);
|
||||||
|
e.matcherResult.message = stripAnsi(e.matcherResult.message);
|
||||||
|
expect.soft(e.matcherResult).toEqual({
|
||||||
|
actual: 'unchecked',
|
||||||
|
expected: 'mixed',
|
||||||
|
message: expect.stringContaining(`Timed out 1ms waiting for expect(locator).toBeChecked({ checked: "mixed" })`),
|
||||||
|
name: 'toBeChecked',
|
||||||
|
pass: false,
|
||||||
|
log: expect.any(Array),
|
||||||
|
timeout: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect.soft(stripAnsi(e.toString())).toContain(`Error: Timed out 1ms waiting for expect(locator).toBeChecked({ checked: "mixed" })
|
||||||
|
|
||||||
|
Locator: locator('#unchecked')
|
||||||
|
Expected: mixed
|
||||||
|
Received: unchecked
|
||||||
Call log`);
|
Call log`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,32 @@ it('isChecked should work for indeterminate input', async ({ page }) => {
|
||||||
await expect(page.locator('input')).not.toBeChecked();
|
await expect(page.locator('input')).not.toBeChecked();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('isChecked with explicit checked 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({ checked: true })).toBe(false);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: false })).toBe(false);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: 'mixed' })).toBe(true);
|
||||||
|
await expect(page.locator('input')).toBeChecked({ checked: 'mixed' });
|
||||||
|
|
||||||
|
await page.locator('input').uncheck();
|
||||||
|
|
||||||
|
expect(await page.locator('input').isChecked({ checked: true })).toBe(false);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: false })).toBe(true);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: 'mixed' })).toBe(false);
|
||||||
|
await expect(page.locator('input')).toBeChecked({ checked: false });
|
||||||
|
|
||||||
|
await page.locator('input').check();
|
||||||
|
|
||||||
|
expect(await page.locator('input').isChecked({ checked: true })).toBe(true);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: false })).toBe(false);
|
||||||
|
expect(await page.locator('input').isChecked({ checked: 'mixed' })).toBe(false);
|
||||||
|
await expect(page.locator('input')).toBeChecked({ checked: true });
|
||||||
|
});
|
||||||
|
|
||||||
it('allTextContents should work', async ({ page }) => {
|
it('allTextContents should work', async ({ page }) => {
|
||||||
await page.setContent(`<div>A</div><div>B</div><div>C</div>`);
|
await page.setContent(`<div>A</div><div>B</div><div>C</div>`);
|
||||||
expect(await page.locator('div').allTextContents()).toEqual(['A', 'B', 'C']);
|
expect(await page.locator('div').allTextContents()).toEqual(['A', 'B', 'C']);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue