chore: revert toHaveAttribute type sig and overloads (#17406)

Relates #16517.

Revert "docs(python): add missing NotToHaveAttribute overloads (#17371)"

This reverts commit 2e1ea29614.

Revert "docs(release-notes): add 1.26 release notes for language ports
(#17345)"

This reverts commit 4b8a85e69d.

Revert "test: unflake "should support boolean attribute with options"
(#17024)"

This reverts commit 1dc05bd4c6.

Revert "fix: support toHaveAttribute(name, options) (#16941)"

This reverts commit f30ac1d678.

Revert "feat: expect(locator).toHaveAttribute to assert attribute
presence (#16767)"

This reverts commit 622c73cc1e.
This commit is contained in:
Ross Wollman 2022-09-16 14:17:35 -04:00 committed by GitHub
parent a6d9aa8708
commit 8d639ae50e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 23 additions and 254 deletions

View file

@ -213,46 +213,29 @@ Whether to use `element.innerText` instead of `element.textContent` when retriev
### option: LocatorAssertions.NotToContainText.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.18
## async method: LocatorAssertions.NotToHaveAttribute#1
* since: v1.18
## async method: LocatorAssertions.NotToHaveAttribute
* since: v1.20
* langs: python
The opposite of [`method: LocatorAssertions.toHaveAttribute#1`].
The opposite of [`method: LocatorAssertions.toHaveAttribute`].
### param: LocatorAssertions.NotToHaveAttribute#1.name
### param: LocatorAssertions.NotToHaveAttribute.name
* since: v1.18
- `name` <[string]>
Attribute name.
### param: LocatorAssertions.NotToHaveAttribute#1.value
### param: LocatorAssertions.NotToHaveAttribute.value
* since: v1.18
- `value` <[string]|[RegExp]>
Expected attribute value.
### option: LocatorAssertions.NotToHaveAttribute#1.timeout = %%-js-assertions-timeout-%%
### option: LocatorAssertions.NotToHaveAttribute.timeout = %%-js-assertions-timeout-%%
* since: v1.18
### option: LocatorAssertions.NotToHaveAttribute#1.timeout = %%-csharp-java-python-assertions-timeout-%%
### option: LocatorAssertions.NotToHaveAttribute.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.18
## async method: LocatorAssertions.NotToHaveAttribute#2
* since: v1.26
* langs: python
The opposite of [`method: LocatorAssertions.toHaveAttribute#2`].
### param: LocatorAssertions.NotToHaveAttribute#2.name
* since: v1.26
- `name` <[string]>
Attribute name.
### option: LocatorAssertions.NotToHaveAttribute#2.timeout = %%-js-assertions-timeout-%%
* since: v1.26
### option: LocatorAssertions.NotToHaveAttribute#2.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.26
## async method: LocatorAssertions.NotToHaveClass
* since: v1.20
* langs: python
@ -921,16 +904,15 @@ Whether to use `element.innerText` instead of `element.textContent` when retriev
* since: v1.18
## async method: LocatorAssertions.toHaveAttribute#1
* since: v1.18
## async method: LocatorAssertions.toHaveAttribute
* since: v1.20
* langs:
- alias-java: hasAttribute
Ensures the [Locator] points to an element with given attribute value.
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');
```
@ -957,76 +939,23 @@ var locator = Page.Locator("input");
await Expect(locator).ToHaveAttributeAsync("type", "text");
```
### param: LocatorAssertions.toHaveAttribute#1.name
### param: LocatorAssertions.toHaveAttribute.name
* since: v1.18
- `name` <[string]>
Attribute name.
### param: LocatorAssertions.toHaveAttribute#1.value
### param: LocatorAssertions.toHaveAttribute.value
* since: v1.18
- `value` <[string]|[RegExp]>
Expected attribute value.
### option: LocatorAssertions.toHaveAttribute#1.timeout = %%-js-assertions-timeout-%%
### option: LocatorAssertions.toHaveAttribute.timeout = %%-js-assertions-timeout-%%
* since: v1.18
### option: LocatorAssertions.toHaveAttribute#1.timeout = %%-csharp-java-python-assertions-timeout-%%
### option: LocatorAssertions.toHaveAttribute.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.18
## async method: LocatorAssertions.toHaveAttribute#2
* since: v1.26
* langs:
- alias-java: hasAttribute
Ensures the [Locator] points to an element with given attribute. The method will assert attribute
presence.
```js
const locator = page.locator('input');
// Assert attribute existence.
await expect(locator).toHaveAttribute('disabled');
await expect(locator).not.toHaveAttribute('open');
```
```java
assertThat(page.locator("input")).hasAttribute("disabled");
assertThat(page.locator("input")).not().hasAttribute("open");
```
```python async
from playwright.async_api import expect
locator = page.locator("input")
await expect(locator).to_have_attribute("disabled")
await expect(locator).not_to_have_attribute("open")
```
```python sync
from playwright.sync_api import expect
locator = page.locator("input")
expect(locator).to_have_attribute("disabled")
expect(locator).not_to_have_attribute("open")
```
```csharp
var locator = Page.Locator("input");
await Expect(locator).ToHaveAttributeAsync("disabled");
await Expect(locator).Not.ToHaveAttributeAsync("open");
```
### param: LocatorAssertions.toHaveAttribute#2.name
* since: v1.26
- `name` <[string]>
Attribute name.
### option: LocatorAssertions.toHaveAttribute#2.timeout = %%-js-assertions-timeout-%%
* since: v1.26
### option: LocatorAssertions.toHaveAttribute#2.timeout = %%-csharp-java-python-assertions-timeout-%%
* since: v1.26
## async method: LocatorAssertions.toHaveClass
* since: v1.20
* langs:

View file

@ -4,38 +4,6 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.26
### Assertions
- [`method: LocatorAssertions.toHaveAttribute#2`] can now be used for asserting attribute existence.
- New option `Enabled` for [`method: LocatorAssertions.toBeEnabled`].
- [`method: LocatorAssertions.toHaveText`] now pierces open shadow roots.
- New option `Editable` for [`method: LocatorAssertions.toBeEditable`].
- New option `Visible` for [`method: LocatorAssertions.toBeVisible`].
- [`method: APIResponseAssertions.toBeOK`] is now available.
### Other highlights
- New option `MaxRedirects` for [`method: APIRequestContext.get`] and others to limit redirect count.
- Codegen now supports NUnit and MSTest frameworks.
- ASP .NET is now supported.
### Behavior Change
A bunch of Playwright APIs already support the `WaitUntil: WaitUntilState.DOMContentLoaded` option.
For example:
```csharp
await Page.GotoAsync("https://playwright.dev", new() { WaitUntil = WaitUntilState.DOMContentLoaded });
```
Prior to 1.26, this would wait for all iframes to fire the `DOMContentLoaded`
event.
To align with web specification, the `WaitUntilState.DOMContentLoaded` value only waits for
the target frame to fire the `'DOMContentLoaded'` event. Use `WaitUntil: WaitUntilState.Load` to wait for all iframes.
## Version 1.25
### New .runsettings file support

View file

@ -4,36 +4,6 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.26
### Assertions
- [`method: LocatorAssertions.toHaveAttribute#2`] can now be used for asserting attribute existence.
- New option `enabled` for [`method: LocatorAssertions.toBeEnabled`].
- [`method: LocatorAssertions.toHaveText`] now pierces open shadow roots.
- New option `editable` for [`method: LocatorAssertions.toBeEditable`].
- New option `visible` for [`method: LocatorAssertions.toBeVisible`].
### Other highlights
- New option `setMaxRedirects` for [`method: APIRequestContext.get`] and others to limit redirect count.
- Docker images are now using OpenJDK 17.
### Behavior Change
A bunch of Playwright APIs already support the `setWaitUntil(WaitUntilState.DOMCONTENTLOADED)` option.
For example:
```js
page.navigate("https://playwright.dev", new Page.NavigateOptions().setWaitUntil(WaitUntilState.DOMCONTENTLOADED));
```
Prior to 1.26, this would wait for all iframes to fire the `DOMContentLoaded`
event.
To align with web specification, the `WaitUntilState.DOMCONTENTLOADED` value only waits for
the target frame to fire the `'DOMContentLoaded'` event. Use `setWaitUntil(WaitUntilState.LOAD)` to wait for all iframes.
## Version 1.25
### New APIs & changes

View file

@ -18,7 +18,6 @@ Read more in [our documentation](./docker#experimental-playwright-test-docker-in
### Assertions
- [`method: LocatorAssertions.toHaveAttribute#2`] can now be used for asserting attribute existence.
- New option `enabled` for [`method: LocatorAssertions.toBeEnabled`].
- [`method: LocatorAssertions.toHaveText`] now pierces open shadow roots.
- New option `editable` for [`method: LocatorAssertions.toBeEditable`].

View file

@ -4,36 +4,6 @@ title: "Release notes"
toc_max_heading_level: 2
---
## Version 1.26
### Assertions
- [`method: LocatorAssertions.toHaveAttribute#2`] can now be used for asserting attribute existence.
- New option `enabled` for [`method: LocatorAssertions.toBeEnabled`].
- [`method: LocatorAssertions.toHaveText`] now pierces open shadow roots.
- New option `editable` for [`method: LocatorAssertions.toBeEditable`].
- New option `visible` for [`method: LocatorAssertions.toBeVisible`].
### Other highlights
- New option `max_redirects` for [`method: APIRequestContext.get`] and others to limit redirect count.
- Python 3.11 is now supported.
### Behavior Change
A bunch of Playwright APIs already support the `wait_until: "domcontentloaded"` option.
For example:
```python
page.goto("https://playwright.dev", wait_until="domcontentloaded")
```
Prior to 1.26, this would wait for all iframes to fire the `DOMContentLoaded`
event.
To align with web specification, the `'domcontentloaded'` value only waits for
the target frame to fire the `'DOMContentLoaded'` event. Use `wait_until="load"` to wait for all iframes.
## Version 1.25
### Announcements

View file

@ -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();

View file

@ -17,7 +17,7 @@
import type { Locator, Page, APIResponse } from 'playwright-core';
import type { FrameExpectOptions } from 'playwright-core/lib/client/types';
import { colors } from 'playwright-core/lib/utilsBundle';
import { constructURLBasedOnBaseURL, isRegExp } from 'playwright-core/lib/utils';
import { constructURLBasedOnBaseURL } from 'playwright-core/lib/utils';
import type { Expect } from '../types';
import { expectTypes, callLogText } from '../util';
import { toBeTruthy } from './toBeTruthy';
@ -141,25 +141,13 @@ export function toHaveAttribute(
this: ReturnType<Expect['getState']>,
locator: LocatorEx,
name: string,
expected: string | RegExp | undefined | { timeout?: number},
expected: string | RegExp,
options?: { timeout?: number },
) {
if (!options) {
// Update params for the case toHaveAttribute(name, options);
if (typeof expected === 'object' && !isRegExp(expected)) {
options = expected;
expected = undefined;
}
}
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 as (string | RegExp)]);
return await locator._expect(customStackTrace, 'to.have.attribute.value', { expressionArg: name, expectedText, isNot, timeout });
}, expected as (string | RegExp), options);
const expectedText = toExpectedTextValues([expected]);
return await locator._expect(customStackTrace, 'to.have.attribute', { expressionArg: name, expectedText, isNot, timeout });
}, expected, options);
}
export function toHaveClass(

View file

@ -3450,11 +3450,10 @@ interface LocatorAssertions {
}): Promise<void>;
/**
* Ensures the [Locator] points to an element with given attribute value.
* 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');
* ```
*
@ -3469,26 +3468,6 @@ interface LocatorAssertions {
timeout?: number;
}): Promise<void>;
/**
* Ensures the [Locator] points to an element with given attribute. The method will assert attribute presence.
*
* ```js
* const locator = page.locator('input');
* // Assert attribute existence.
* await expect(locator).toHaveAttribute('disabled');
* await expect(locator).not.toHaveAttribute('open');
* ```
*
* @param name Attribute name.
* @param options
*/
toHaveAttribute(name: string, options?: {
/**
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
*/
timeout?: number;
}): Promise<void>;
/**
* Ensures the [Locator] points to an element with given CSS classes. This needs to be a full match or using a relaxed
* regular expression.

View file

@ -228,22 +228,10 @@ test.describe('toHaveURL', () => {
test.describe('toHaveAttribute', () => {
test('pass', async ({ page }) => {
await page.setContent('<div checked id=node>Text content</div>');
await page.setContent('<div id=node>Text content</div>');
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');
});
test('should support boolean attribute with options', async ({ page }) => {
await page.setContent('<div checked id=node>Text content</div>');
const locator = page.locator('#node');
await expect(locator).toHaveAttribute('id', { timeout: 5000 });
await expect(locator).toHaveAttribute('checked', { timeout: 5000 });
await expect(locator).not.toHaveAttribute('open', { timeout: 5000 });
await expect(locator).toHaveAttribute('id', 'node', { timeout: 5000 });
});
});
test.describe('toHaveCSS', () => {

View file

@ -299,26 +299,6 @@ test('should return void/Promise when appropriate', async ({ runTSC }) => {
expect(result.exitCode).toBe(0);
});
test('should suppport toHaveAttribute withou optional value', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `
const { test } = pwt;
test('custom matchers', async ({ page }) => {
const locator = page.locator('#node');
await test.expect(locator).toHaveAttribute('name', 'value');
await test.expect(locator).toHaveAttribute('name', 'value', { timeout: 10 });
await test.expect(locator).toHaveAttribute('disabled');
await test.expect(locator).toHaveAttribute('disabled', { timeout: 10 });
// @ts-expect-error
await test.expect(locator).toHaveAttribute('disabled', { foo: 1 });
// @ts-expect-error
await test.expect(locator).toHaveAttribute('name', 'value', 'opt');
});
`
});
expect(result.exitCode).toBe(0);
});
test.describe('helpful expect errors', () => {
test('top-level', async ({ runInlineTest }) => {
const result = await runInlineTest({