diff --git a/docs/src/api/class-locatorassertions.md b/docs/src/api/class-locatorassertions.md index 111c57a973..04ce5ad9fb 100644 --- a/docs/src/api/class-locatorassertions.md +++ b/docs/src/api/class-locatorassertions.md @@ -909,16 +909,11 @@ Whether to use `element.innerText` instead of `element.textContent` when retriev * langs: - alias-java: hasAttribute -Ensures the [Locator] points to an element with given attribute. If the method -is used without `'value'` argument, then the method will assert attribute existance. +Ensures the [Locator] points to an element with given attribute. ```js const locator = page.locator('input'); -// Assert attribute with given value. await expect(locator).toHaveAttribute('type', 'text'); -// Assert attribute existance. -await expect(locator).toHaveAttribute('disabled'); -await expect(locator).not.toHaveAttribute('open'); ``` ```java @@ -952,9 +947,9 @@ Attribute name. ### param: LocatorAssertions.toHaveAttribute.value * since: v1.18 -- `value` ?<[string]|[RegExp]> +- `value` <[string]|[RegExp]> -Optional expected attribute value. If missing, method will assert attribute presence. +Expected attribute value. ### option: LocatorAssertions.toHaveAttribute.timeout = %%-js-assertions-timeout-%% * since: v1.18 diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index df9f119887..fe757d123e 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -1038,9 +1038,7 @@ export class InjectedScript { { // Element state / boolean values. let elementState: boolean | 'error:notconnected' | 'error:notcheckbox' | undefined; - if (expression === 'to.have.attribute') { - elementState = element.hasAttribute(options.expressionArg); - } else if (expression === 'to.be.checked') { + if (expression === 'to.be.checked') { elementState = progress.injectedScript.elementState(element, 'checked'); } else if (expression === 'to.be.unchecked') { elementState = progress.injectedScript.elementState(element, 'unchecked'); @@ -1100,7 +1098,7 @@ export class InjectedScript { { // Single text value. let received: string | undefined; - if (expression === 'to.have.attribute.value') { + if (expression === 'to.have.attribute') { received = element.getAttribute(options.expressionArg) || ''; } else if (expression === 'to.have.class') { received = element.classList.toString(); diff --git a/packages/playwright-test/src/matchers/matchers.ts b/packages/playwright-test/src/matchers/matchers.ts index 33e8b8a8c1..bccb016aff 100644 --- a/packages/playwright-test/src/matchers/matchers.ts +++ b/packages/playwright-test/src/matchers/matchers.ts @@ -141,17 +141,12 @@ export function toHaveAttribute( this: ReturnType, locator: LocatorEx, name: string, - expected: string | RegExp | undefined, + expected: string | RegExp, options?: { timeout?: number }, ) { - if (expected === undefined) { - return toBeTruthy.call(this, 'toHaveAttribute', locator, 'Locator', async (isNot, timeout, customStackTrace) => { - return await locator._expect(customStackTrace, 'to.have.attribute', { expressionArg: name, isNot, timeout }); - }, options); - } return toMatchText.call(this, 'toHaveAttribute', locator, 'Locator', async (isNot, timeout, customStackTrace) => { const expectedText = toExpectedTextValues([expected]); - return await locator._expect(customStackTrace, 'to.have.attribute.value', { expressionArg: name, expectedText, isNot, timeout }); + return await locator._expect(customStackTrace, 'to.have.attribute', { expressionArg: name, expectedText, isNot, timeout }); }, expected, options); } diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index b2e00fda88..0f31ea22cd 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -3437,23 +3437,18 @@ interface LocatorAssertions { }): Promise; /** - * Ensures the [Locator] points to an element with given attribute. If the method is used without `'value'` argument, then - * the method will assert attribute existance. + * Ensures the [Locator] points to an element with given attribute. * * ```js * const locator = page.locator('input'); - * // Assert attribute with given value. * await expect(locator).toHaveAttribute('type', 'text'); - * // Assert attribute existance. - * await expect(locator).toHaveAttribute('disabled'); - * await expect(locator).not.toHaveAttribute('open'); * ``` * * @param name Attribute name. - * @param value Optional expected attribute value. If missing, method will assert attribute presence. + * @param value Expected attribute value. * @param options */ - toHaveAttribute(name: string, value?: string|RegExp, options?: { + toHaveAttribute(name: string, value: string|RegExp, options?: { /** * Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`. */ diff --git a/tests/page/expect-misc.spec.ts b/tests/page/expect-misc.spec.ts index c3d09aac88..3b48c0d49e 100644 --- a/tests/page/expect-misc.spec.ts +++ b/tests/page/expect-misc.spec.ts @@ -228,11 +228,8 @@ test.describe('toHaveURL', () => { test.describe('toHaveAttribute', () => { test('pass', async ({ page }) => { - await page.setContent('
Text content
'); + await page.setContent('
Text content
'); const locator = page.locator('#node'); - await expect(locator).toHaveAttribute('id'); - await expect(locator).toHaveAttribute('checked'); - await expect(locator).not.toHaveAttribute('open'); await expect(locator).toHaveAttribute('id', 'node'); }); });