From 7f054ef8c6d6c3dcbbf0ce4c766f704c140c49a0 Mon Sep 17 00:00:00 2001 From: aairiian <33619896+aairiian@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:46:47 +0100 Subject: [PATCH] feat(aria): extend toHaveAccessibleName() to accept an array of expected accessible names (#33277) --- docs/src/api/class-locatorassertions.md | 2 +- .../src/server/injected/injectedScript.ts | 2 + packages/playwright/src/matchers/matchers.ts | 19 +++++++--- packages/playwright/types/test.d.ts | 2 +- tests/page/expect-misc.spec.ts | 37 +++++++++++++++++++ 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/docs/src/api/class-locatorassertions.md b/docs/src/api/class-locatorassertions.md index c252b1348b..3102ef085e 100644 --- a/docs/src/api/class-locatorassertions.md +++ b/docs/src/api/class-locatorassertions.md @@ -1236,7 +1236,7 @@ await Expect(locator).ToHaveAccessibleNameAsync("Save to disk"); ### param: LocatorAssertions.toHaveAccessibleName.name * since: v1.44 -- `name` <[string]|[RegExp]> +- `name` <[string]|[RegExp]|[Array]<[string]|[RegExp]>> Expected accessible name. diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index 7c235b700f..aa0eb1004f 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -1354,6 +1354,8 @@ export class InjectedScript { 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()); + else if (expression === 'to.have.accessible.name.array') + received = elements.map(e => getElementAccessibleName(e, false)); if (received && options.expectedText) { // "To match an array" is "to contain an array" + "equal length" diff --git a/packages/playwright/src/matchers/matchers.ts b/packages/playwright/src/matchers/matchers.ts index dd159a7f5e..8a8089e91e 100644 --- a/packages/playwright/src/matchers/matchers.ts +++ b/packages/playwright/src/matchers/matchers.ts @@ -189,13 +189,20 @@ export function toHaveAccessibleDescription( export function toHaveAccessibleName( this: ExpectMatcherState, locator: LocatorEx, - expected: string | RegExp, - options?: { timeout?: number, ignoreCase?: boolean }, + expected: string | RegExp | (string | RegExp)[], + options: { timeout?: number, ignoreCase?: boolean, normalizeWhiteSpace?: boolean } = {} ) { - return toMatchText.call(this, 'toHaveAccessibleName', locator, 'Locator', async (isNot, timeout) => { - const expectedText = serializeExpectedTextValues([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true }); - return await locator._expect('to.have.accessible.name', { expectedText, isNot, timeout }); - }, expected, options); + if (Array.isArray(expected)) { + return toEqual.call(this, 'toHaveAccessibleName', locator, 'Locator', async (isNot, timeout) => { + const expectedText = serializeExpectedTextValues(expected, { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true }); + return await locator._expect('to.have.accessible.name.array', { expectedText, isNot, timeout }); + }, expected, options); + } else { + return toMatchText.call(this, 'toHaveAccessibleName', locator, 'Locator', async (isNot, timeout) => { + const expectedText = serializeExpectedTextValues([expected], { ignoreCase: options?.ignoreCase, normalizeWhiteSpace: true }); + return await locator._expect('to.have.accessible.name', { expectedText, isNot, timeout }); + }, expected, options); + } } export function toHaveAttribute( diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index b3d66a7f6d..715762cffe 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -7899,7 +7899,7 @@ interface LocatorAssertions { * @param name Expected accessible name. * @param options */ - toHaveAccessibleName(name: string|RegExp, options?: { + toHaveAccessibleName(name: string|RegExp|ReadonlyArray, options?: { /** * Whether to perform case-insensitive match. * [`ignoreCase`](https://playwright.dev/docs/api/class-locatorassertions#locator-assertions-to-have-accessible-name-option-ignore-case) diff --git a/tests/page/expect-misc.spec.ts b/tests/page/expect-misc.spec.ts index f99ac12376..0ab5707a62 100644 --- a/tests/page/expect-misc.spec.ts +++ b/tests/page/expect-misc.spec.ts @@ -436,6 +436,43 @@ test('toHaveAccessibleName', async ({ page }) => { await expect(page.locator('button')).toHaveAccessibleName('foo bar baz'); }); +test('toHaveAccessibleName should accept array of names for multiple elements', async ({ page }) => { + await page.setContent(` + + + + + + + + + + + + + + + + +
Cell A1Cell B1Cell C1
Cell A2Cell B2Cell C2
Cell A3Cell B3Cell C3
+ `); + await expect(page.getByRole('row')).toHaveAccessibleName([ + 'Cell A1 Cell B1 Cell C1', + 'Cell A2 Cell B2 Cell C2', + 'Cell A3 Cell B3 Cell C3', + ]); + await expect(page.getByRole('row')).toHaveAccessibleName(['cell a1 cell b1 cell C1', + 'cell A2 Cell b2 Cell c2', + 'Cell a3 Cell b3 cell C3',], { ignoreCase: true }); + + await expect(page.getByRole('row')).not.toHaveAccessibleName([ + 'Cel A4 Cell B4 Cell C4', + 'Cell A5 Cell B5 Cell C5', + 'Cell A6 Cell B6 Cell C6', + ]); +}); + + test('toHaveAccessibleDescription', async ({ page }) => { await page.setContent(`