parent
0b170ddc12
commit
6929214dbf
|
|
@ -86,6 +86,20 @@ assertThat(locator).not().containsText("error");
|
||||||
await Expect(locator).Not.ToContainTextAsync("error");
|
await Expect(locator).Not.ToContainTextAsync("error");
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## async method: LocatorAssertions.NotToBeAttached
|
||||||
|
* since: v1.33
|
||||||
|
* langs: python
|
||||||
|
|
||||||
|
The opposite of [`method: LocatorAssertions.toBeAttached`].
|
||||||
|
|
||||||
|
### option: LocatorAssertions.NotToBeAttached.attached
|
||||||
|
* since: v1.33
|
||||||
|
- `attached` <[boolean]>
|
||||||
|
|
||||||
|
### option: LocatorAssertions.NotToBeAttached.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
* since: v1.33
|
||||||
|
|
||||||
|
|
||||||
## async method: LocatorAssertions.NotToBeChecked
|
## async method: LocatorAssertions.NotToBeChecked
|
||||||
* since: v1.20
|
* since: v1.20
|
||||||
* langs: python
|
* langs: python
|
||||||
|
|
@ -377,6 +391,47 @@ Expected options currently selected.
|
||||||
### option: LocatorAssertions.NotToHaveValues.timeout = %%-csharp-java-python-assertions-timeout-%%
|
### option: LocatorAssertions.NotToHaveValues.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
* since: v1.23
|
* since: v1.23
|
||||||
|
|
||||||
|
|
||||||
|
## async method: LocatorAssertions.toBeAttached
|
||||||
|
* since: v1.33
|
||||||
|
* langs:
|
||||||
|
- alias-java: isAttached
|
||||||
|
|
||||||
|
Ensures that [Locator] points to an [attached](../actionability.md#attached) DOM node.
|
||||||
|
|
||||||
|
**Usage**
|
||||||
|
|
||||||
|
```js
|
||||||
|
await expect(page.getByText('Hidden text')).toBeAttached();
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
assertThat(page.getByText("Hidden text")).isAttached();
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
await expect(page.get_by_text("Hidden text")).to_be_attached()
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
expect(page.get_by_text("Hidden text")).to_be_attached()
|
||||||
|
```
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
await Expect(Page.GetByText("Hidden text")).ToBeAttachedAsync();
|
||||||
|
```
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toBeAttached.attached
|
||||||
|
* since: v1.33
|
||||||
|
- `attached` <[boolean]>
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toBeAttached.timeout = %%-js-assertions-timeout-%%
|
||||||
|
* since: v1.33
|
||||||
|
|
||||||
|
### option: LocatorAssertions.toBeAttached.timeout = %%-csharp-java-python-assertions-timeout-%%
|
||||||
|
* since: v1.33
|
||||||
|
|
||||||
|
|
||||||
## async method: LocatorAssertions.toBeChecked
|
## async method: LocatorAssertions.toBeChecked
|
||||||
* since: v1.20
|
* since: v1.20
|
||||||
* langs:
|
* langs:
|
||||||
|
|
@ -781,31 +836,23 @@ Ensures that [Locator] points to an [attached](../actionability.md#attached) and
|
||||||
**Usage**
|
**Usage**
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const locator = page.locator('.my-element');
|
await expect(page.getByText('Welcome')).toBeVisible();
|
||||||
await expect(locator).toBeVisible();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
assertThat(page.locator(".my-element")).isVisible();
|
assertThat(page.getByText("Welcome")).isVisible();
|
||||||
```
|
```
|
||||||
|
|
||||||
```python async
|
```python async
|
||||||
from playwright.async_api import expect
|
await expect(page.get_by_text("Welcome")).to_be_visible()
|
||||||
|
|
||||||
locator = page.locator('.my-element')
|
|
||||||
await expect(locator).to_be_visible()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```python sync
|
```python sync
|
||||||
from playwright.sync_api import expect
|
expect(page.get_by_text("Welcome")).to_be_visible()
|
||||||
|
|
||||||
locator = page.locator('.my-element')
|
|
||||||
expect(locator).to_be_visible()
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var locator = Page.Locator(".my-element");
|
await Expect(Page.GetByText("Welcome")).ToBeVisibleAsync();
|
||||||
await Expect(locator).ToBeVisibleAsync();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### option: LocatorAssertions.toBeVisible.visible
|
### option: LocatorAssertions.toBeVisible.visible
|
||||||
|
|
|
||||||
|
|
@ -1153,6 +1153,12 @@ export class InjectedScript {
|
||||||
// expect(locator).not.toBeVisible() passes when there is no element.
|
// expect(locator).not.toBeVisible() passes when there is no element.
|
||||||
if (options.isNot && options.expression === 'to.be.visible')
|
if (options.isNot && options.expression === 'to.be.visible')
|
||||||
return { matches: false };
|
return { matches: false };
|
||||||
|
// expect(locator).toBeAttached({ attached: false }) passes when there is no element.
|
||||||
|
if (!options.isNot && options.expression === 'to.be.detached')
|
||||||
|
return { matches: true };
|
||||||
|
// expect(locator).not.toBeAttached() passes when there is no element.
|
||||||
|
if (options.isNot && options.expression === 'to.be.attached')
|
||||||
|
return { matches: false };
|
||||||
// expect(locator).not.toBeInViewport() passes when there is no element.
|
// expect(locator).not.toBeInViewport() passes when there is no element.
|
||||||
if (options.isNot && options.expression === 'to.be.in.viewport')
|
if (options.isNot && options.expression === 'to.be.in.viewport')
|
||||||
return { matches: false };
|
return { matches: false };
|
||||||
|
|
@ -1191,6 +1197,10 @@ export class InjectedScript {
|
||||||
elementState = this.elementState(element, 'hidden');
|
elementState = this.elementState(element, 'hidden');
|
||||||
} else if (expression === 'to.be.visible') {
|
} else if (expression === 'to.be.visible') {
|
||||||
elementState = this.elementState(element, 'visible');
|
elementState = this.elementState(element, 'visible');
|
||||||
|
} else if (expression === 'to.be.attached') {
|
||||||
|
elementState = true;
|
||||||
|
} else if (expression === 'to.be.detached') {
|
||||||
|
elementState = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementState !== undefined) {
|
if (elementState !== undefined) {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
pollAgainstTimeout } from 'playwright-core/lib/utils';
|
pollAgainstTimeout } from 'playwright-core/lib/utils';
|
||||||
import type { ExpectZone } from 'playwright-core/lib/utils';
|
import type { ExpectZone } from 'playwright-core/lib/utils';
|
||||||
import {
|
import {
|
||||||
|
toBeAttached,
|
||||||
toBeChecked,
|
toBeChecked,
|
||||||
toBeDisabled,
|
toBeDisabled,
|
||||||
toBeEditable,
|
toBeEditable,
|
||||||
|
|
@ -130,6 +131,7 @@ expect.poll = (actual: unknown, messageOrOptions: ExpectMessageOrOptions) => {
|
||||||
|
|
||||||
expectLibrary.setState({ expand: false });
|
expectLibrary.setState({ expand: false });
|
||||||
const customMatchers = {
|
const customMatchers = {
|
||||||
|
toBeAttached,
|
||||||
toBeChecked,
|
toBeChecked,
|
||||||
toBeDisabled,
|
toBeDisabled,
|
||||||
toBeEditable,
|
toBeEditable,
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,17 @@ interface APIResponseEx extends APIResponse {
|
||||||
_fetchLog(): Promise<string[]>;
|
_fetchLog(): Promise<string[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toBeAttached(
|
||||||
|
this: ReturnType<Expect['getState']>,
|
||||||
|
locator: LocatorEx,
|
||||||
|
options?: { attached?: boolean, timeout?: number },
|
||||||
|
) {
|
||||||
|
return toBeTruthy.call(this, 'toBeAttached', locator, 'Locator', async (isNot, timeout) => {
|
||||||
|
const attached = !options || options.attached === undefined || options.attached === true;
|
||||||
|
return await locator._expect(attached ? 'to.be.attached' : 'to.be.detached', { isNot, timeout });
|
||||||
|
}, options);
|
||||||
|
}
|
||||||
|
|
||||||
export function toBeChecked(
|
export function toBeChecked(
|
||||||
this: ReturnType<Expect['getState']>,
|
this: ReturnType<Expect['getState']>,
|
||||||
locator: LocatorEx,
|
locator: LocatorEx,
|
||||||
|
|
|
||||||
23
packages/playwright-test/types/test.d.ts
vendored
23
packages/playwright-test/types/test.d.ts
vendored
|
|
@ -4321,6 +4321,26 @@ interface APIResponseAssertions {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
interface LocatorAssertions {
|
interface LocatorAssertions {
|
||||||
|
/**
|
||||||
|
* Ensures that [Locator] points to an [attached](https://playwright.dev/docs/actionability#attached) DOM node.
|
||||||
|
*
|
||||||
|
* **Usage**
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* await expect(page.getByText('Hidden text')).toBeAttached();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
toBeAttached(options?: {
|
||||||
|
attached?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to retry the assertion for. Defaults to `timeout` in `TestConfig.expect`.
|
||||||
|
*/
|
||||||
|
timeout?: number;
|
||||||
|
}): Promise<void>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures the [Locator] points to a checked input.
|
* Ensures the [Locator] points to a checked input.
|
||||||
*
|
*
|
||||||
|
|
@ -4503,8 +4523,7 @@ interface LocatorAssertions {
|
||||||
* **Usage**
|
* **Usage**
|
||||||
*
|
*
|
||||||
* ```js
|
* ```js
|
||||||
* const locator = page.locator('.my-element');
|
* await expect(page.getByText('Welcome')).toBeVisible();
|
||||||
* await expect(locator).toBeVisible();
|
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param options
|
* @param options
|
||||||
|
|
|
||||||
|
|
@ -523,3 +523,106 @@ test.describe(() => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.describe('toBeAttached', () => {
|
||||||
|
test('default', async ({ page }) => {
|
||||||
|
await page.setContent('<input></input>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
await expect(locator).toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with hidden element', async ({ page }) => {
|
||||||
|
await page.setContent('<button style="display:none">hello</button>');
|
||||||
|
const locator = page.locator('button');
|
||||||
|
await expect(locator).toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with not', async ({ page }) => {
|
||||||
|
await page.setContent('<button>hello</button>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
await expect(locator).not.toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with attached:true', async ({ page }) => {
|
||||||
|
await page.setContent('<button>hello</button>');
|
||||||
|
const locator = page.locator('button');
|
||||||
|
await expect(locator).toBeAttached({ attached: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with attached:false', async ({ page }) => {
|
||||||
|
await page.setContent('<button>hello</button>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
await expect(locator).toBeAttached({ attached: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with not and attached:false', async ({ page }) => {
|
||||||
|
await page.setContent('<button>hello</button>');
|
||||||
|
const locator = page.locator('button');
|
||||||
|
await expect(locator).not.toBeAttached({ attached: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('eventually', async ({ page }) => {
|
||||||
|
await page.setContent('<div></div>');
|
||||||
|
const locator = page.locator('span');
|
||||||
|
setTimeout(() => {
|
||||||
|
page.$eval('div', div => div.innerHTML = '<span>Hello</span>').catch(() => {});
|
||||||
|
}, 0);
|
||||||
|
await expect(locator).toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('eventually with not', async ({ page }) => {
|
||||||
|
await page.setContent('<div><span>Hello</span></div>');
|
||||||
|
const locator = page.locator('span');
|
||||||
|
setTimeout(() => {
|
||||||
|
page.$eval('div', div => div.textContent = '').catch(() => {});
|
||||||
|
}, 0);
|
||||||
|
await expect(locator).not.toBeAttached();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fail', async ({ page }) => {
|
||||||
|
await page.setContent('<button>Hello</button>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
const error = await expect(locator).toBeAttached({ timeout: 1000 }).catch(e => e);
|
||||||
|
expect(error.message).not.toContain(`locator resolved to`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fail with not', async ({ page }) => {
|
||||||
|
await page.setContent('<input></input>');
|
||||||
|
const locator = page.locator('input');
|
||||||
|
const error = await expect(locator).not.toBeAttached({ timeout: 1000 }).catch(e => e);
|
||||||
|
expect(error.message).toContain(`locator resolved to <input/>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with impossible timeout', async ({ page }) => {
|
||||||
|
await page.setContent('<div id=node>Text content</div>');
|
||||||
|
await expect(page.locator('#node')).toBeAttached({ timeout: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with impossible timeout .not', async ({ page }) => {
|
||||||
|
await page.setContent('<div id=node>Text content</div>');
|
||||||
|
await expect(page.locator('no-such-thing')).not.toBeAttached({ timeout: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with frameLocator', async ({ page }) => {
|
||||||
|
await page.setContent('<div></div>');
|
||||||
|
const locator = page.frameLocator('iframe').locator('input');
|
||||||
|
let done = false;
|
||||||
|
const promise = expect(locator).toBeAttached().then(() => done = true);
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
expect(done).toBe(false);
|
||||||
|
await page.setContent('<iframe srcdoc="<input>"></iframe>');
|
||||||
|
await promise;
|
||||||
|
expect(done).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('over navigation', async ({ page, server }) => {
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
let done = false;
|
||||||
|
const promise = expect(page.locator('input')).toBeAttached().then(() => done = true);
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
expect(done).toBe(false);
|
||||||
|
await page.goto(server.PREFIX + '/input/checkbox.html');
|
||||||
|
await promise;
|
||||||
|
expect(done).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue