mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore(expect): polish matcher names, remote arguable ones (#8060)
This commit is contained in:
parent
efb4af8489
commit
3424f59e67
@ -85,32 +85,12 @@ Refer to [configuration](./test-configuration.md) section for configuring test r
|
||||
|
||||
## Writing assertions
|
||||
|
||||
Playwright Test uses [expect](https://jestjs.io/docs/expect) library for test assertions. It provides a lot of matchers like `toEqual`, `toContain`, `toMatch`, `toMatchSnapshot` and many more. Playwright also extends this set with the following matchers:
|
||||
Playwright Test uses [expect](https://jestjs.io/docs/expect) library for test assertions. It extends it with the Playwright-specific matchers to achieve greater testing ergonomics.
|
||||
|
||||
- `toBeChecked`
|
||||
- `toBeDisabled`
|
||||
- `toBeEditable`
|
||||
- `toBeEmpty`
|
||||
- `toBeEnabled`
|
||||
- `toBeFocused`
|
||||
- `toBeHidden`
|
||||
- `toBeSelected`
|
||||
- `toBeVisible`
|
||||
- `toContainText`
|
||||
- `toHaveAttr`
|
||||
- `toHaveClass`
|
||||
- `toHaveCount`
|
||||
- `toHaveCSS`
|
||||
- `toHaveData`
|
||||
- `toHaveId`
|
||||
- `toHaveProp`
|
||||
- `toHaveText`
|
||||
- `toHaveTitle`
|
||||
- `toHaveURL`
|
||||
- `toHaveValue`
|
||||
- `toMatchSnapshot`
|
||||
Learn more about [test assertions here](./test-assertions.md).
|
||||
|
||||
Here is a quick example of using them:
|
||||
|
||||
- Find out more in the [assertions](./assertions.md) guide
|
||||
|
||||
```js js-flavor=js
|
||||
// example.spec.js
|
||||
@ -123,7 +103,7 @@ test('my test', async ({ page }) => {
|
||||
await expect(page).toHaveTitle('Playwright');
|
||||
|
||||
// Expect an attribute "to be strictly equal" to the value.
|
||||
await expect(page.locator('text=Get Started').toHaveAttr('href', '/docs/intro');
|
||||
await expect(page.locator('text=Get Started').toHaveAttribute('href', '/docs/intro');
|
||||
|
||||
// Expect an element "to be visible".
|
||||
await expect(page.locator('text=Learn more')).toBeVisible();
|
||||
@ -148,7 +128,7 @@ test('my test', async ({ page }) => {
|
||||
await expect(page).toHaveTitle('Playwright');
|
||||
|
||||
// Expect an attribute "to be strictly equal" to the value.
|
||||
await expect(page.locator('text=Get Started').toHaveAttr('href', '/docs/intro');
|
||||
await expect(page.locator('text=Get Started').toHaveAttribute('href', '/docs/intro');
|
||||
|
||||
// Expect an element "to be visible".
|
||||
await expect(page.locator('text=Learn more')).toBeVisible();
|
||||
|
@ -107,17 +107,6 @@ const locator = await page.locator('.my-element');
|
||||
await expect(locator).toBeHidden();
|
||||
```
|
||||
|
||||
## expect(locator).toBeSelected
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
|
||||
Ensures [Locator] points to a selected option.
|
||||
|
||||
```js
|
||||
const locator = await page.locator('option[value=Three]');
|
||||
await expect(locator).toBeSelected();
|
||||
```
|
||||
|
||||
## expect(locator).toBeVisible
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
@ -142,7 +131,7 @@ const locator = await page.locator('.title');
|
||||
await expect(locator).toContainText('substring');
|
||||
```
|
||||
|
||||
## expect(locator).toHaveAttr(name, value)
|
||||
## expect(locator).toHaveAttribute(name, value)
|
||||
- `name`: <[string]> Attribute name
|
||||
- `value`: <[string]|[RegExp]> Attribute value
|
||||
- `options`
|
||||
@ -152,7 +141,7 @@ Ensures [Locator] points to an element with given attribute.
|
||||
|
||||
```js
|
||||
const locator = await page.locator('input');
|
||||
await expect(locator).toHaveAttr('type', 'text');
|
||||
await expect(locator).toHaveAttribute('type', 'text');
|
||||
```
|
||||
|
||||
## expect(locator).toHaveClass(expected)
|
||||
@ -199,19 +188,6 @@ const locator = await page.locator('button');
|
||||
await expect(locator).toHaveCSS('display', 'flex');
|
||||
```
|
||||
|
||||
## expect(locator).toHaveData(name, value)
|
||||
- `name`: <[string]> Data attribute name
|
||||
- `value`: <[string]|[RegExp]> Data value
|
||||
- `options`
|
||||
- `timeout`: <[number]> Time to retry assertion for, defaults to [`property: Fixtures.actionTimeout`].
|
||||
|
||||
Ensures [Locator] points to an element with given data binding.
|
||||
|
||||
```js
|
||||
const locator = await page.locator('input');
|
||||
await expect(locator).toHaveData('mydata', 'myvalue');
|
||||
```
|
||||
|
||||
## expect(locator).toHaveId(id)
|
||||
- `id`: <[string]> Element id
|
||||
- `options`
|
||||
@ -224,7 +200,7 @@ const locator = await page.locator('input');
|
||||
await expect(locator).toHaveId('lastname');
|
||||
```
|
||||
|
||||
## expect(locator).toHaveProp(name, value)
|
||||
## expect(locator).toHaveJSProperty(name, value)
|
||||
- `name`: <[string]> Property name
|
||||
- `value`: <[any]> Property value
|
||||
- `options`
|
||||
@ -235,7 +211,7 @@ of a primitive type as well as a plain serializable JavaScript object.
|
||||
|
||||
```js
|
||||
const locator = await page.locator('.component');
|
||||
await expect(locator).toHaveProp('loaded', true);
|
||||
await expect(locator).toHaveJSProperty('loaded', true);
|
||||
```
|
||||
|
||||
## expect(locator).toHaveText(expected, options)
|
||||
|
@ -23,16 +23,14 @@ import {
|
||||
toBeEnabled,
|
||||
toBeFocused,
|
||||
toBeHidden,
|
||||
toBeSelected,
|
||||
toBeVisible,
|
||||
toContainText,
|
||||
toHaveAttr,
|
||||
toHaveAttribute,
|
||||
toHaveClass,
|
||||
toHaveCount,
|
||||
toHaveCSS,
|
||||
toHaveData,
|
||||
toHaveId,
|
||||
toHaveProp,
|
||||
toHaveJSProperty,
|
||||
toHaveText,
|
||||
toHaveTitle,
|
||||
toHaveURL,
|
||||
@ -54,16 +52,14 @@ const customMatchers = {
|
||||
toBeEnabled,
|
||||
toBeFocused,
|
||||
toBeHidden,
|
||||
toBeSelected,
|
||||
toBeVisible,
|
||||
toContainText,
|
||||
toHaveAttr,
|
||||
toHaveAttribute,
|
||||
toHaveClass,
|
||||
toHaveCount,
|
||||
toHaveCSS,
|
||||
toHaveData,
|
||||
toHaveId,
|
||||
toHaveProp,
|
||||
toHaveJSProperty,
|
||||
toHaveText,
|
||||
toHaveTitle,
|
||||
toHaveURL,
|
||||
|
@ -96,18 +96,6 @@ export function toBeHidden(
|
||||
}, options);
|
||||
}
|
||||
|
||||
export function toBeSelected(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
return toBeTruthy.call(this, 'toBeSelected', locator, 'Locator', async timeout => {
|
||||
return await locator.evaluate(element => {
|
||||
return (element as HTMLOptionElement).selected;
|
||||
}, { timeout });
|
||||
}, options);
|
||||
}
|
||||
|
||||
export function toBeVisible(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
@ -131,14 +119,14 @@ export function toContainText(
|
||||
}, expected, { ...options, matchSubstring: true });
|
||||
}
|
||||
|
||||
export function toHaveAttr(
|
||||
export function toHaveAttribute(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
name: string,
|
||||
expected: string | RegExp,
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
return toMatchText.call(this, 'toHaveAttr', locator, 'Locator', async timeout => {
|
||||
return toMatchText.call(this, 'toHaveAttribute', locator, 'Locator', async timeout => {
|
||||
return await locator.getAttribute(name, { timeout }) || '';
|
||||
}, expected, options);
|
||||
}
|
||||
@ -185,18 +173,6 @@ export function toHaveCSS(
|
||||
}, expected, options);
|
||||
}
|
||||
|
||||
export function toHaveData(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
name: string,
|
||||
expected: string | RegExp,
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
return toMatchText.call(this, 'toHaveData', locator, 'Locator', async timeout => {
|
||||
return await locator.getAttribute('data-' + name, { timeout }) || '';
|
||||
}, expected, options);
|
||||
}
|
||||
|
||||
export function toHaveId(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
@ -208,14 +184,14 @@ export function toHaveId(
|
||||
}, expected, options);
|
||||
}
|
||||
|
||||
export function toHaveProp(
|
||||
export function toHaveJSProperty(
|
||||
this: ReturnType<Expect['getState']>,
|
||||
locator: Locator,
|
||||
name: string,
|
||||
expected: any,
|
||||
options?: { timeout?: number },
|
||||
) {
|
||||
return toEqual.call(this, 'toHaveProp', locator, 'Locator', async timeout => {
|
||||
return toEqual.call(this, 'toHaveJSProperty', locator, 'Locator', async timeout => {
|
||||
return await locator.evaluate((element, name) => (element as any)[name], name, { timeout });
|
||||
}, expected, options);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ test('should support toHaveCount', async ({ runInlineTest }) => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support toHaveProp', async ({ runInlineTest }) => {
|
||||
test('should support toHaveJSProperty', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -41,14 +41,14 @@ test('should support toHaveProp', async ({ runInlineTest }) => {
|
||||
await page.setContent('<div></div>');
|
||||
await page.$eval('div', e => e.foo = { a: 1, b: 'string', c: new Date(1627503992000) });
|
||||
const locator = page.locator('div');
|
||||
await expect(locator).toHaveProp('foo', { a: 1, b: 'string', c: new Date(1627503992000) });
|
||||
await expect(locator).toHaveJSProperty('foo', { a: 1, b: 'string', c: new Date(1627503992000) });
|
||||
});
|
||||
|
||||
test('fail', async ({ page }) => {
|
||||
await page.setContent('<div></div>');
|
||||
await page.$eval('div', e => e.foo = { a: 1, b: 'string', c: new Date(1627503992000) });
|
||||
const locator = page.locator('div');
|
||||
await expect(locator).toHaveProp('foo', { a: 1, b: 'string', c: new Date(1627503992001) }, { timeout: 1000 });
|
||||
await expect(locator).toHaveJSProperty('foo', { a: 1, b: 'string', c: new Date(1627503992001) }, { timeout: 1000 });
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
@ -141,7 +141,7 @@ test('should support toHaveText with innerText', async ({ runInlineTest }) => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support toHaveAttr', async ({ runInlineTest }) => {
|
||||
test('should support toHaveAttribute', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -149,23 +149,7 @@ test('should support toHaveAttr', async ({ runInlineTest }) => {
|
||||
test('pass', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const locator = page.locator('#node');
|
||||
await expect(locator).toHaveAttr('id', 'node');
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support toHaveData', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
|
||||
test('pass', async ({ page }) => {
|
||||
await page.setContent('<div id=node>Text content</div>');
|
||||
const locator = page.locator('#node');
|
||||
await expect(locator).toHaveAttr('id', 'node');
|
||||
await expect(locator).toHaveAttribute('id', 'node');
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
@ -128,7 +128,7 @@ test('should support toBeVisible, toBeHidden', async ({ runInlineTest }) => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support toBeFocused, toBeSelected', async ({ runInlineTest }) => {
|
||||
test('should support toBeFocused', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'a.test.ts': `
|
||||
const { test } = pwt;
|
||||
@ -139,23 +139,8 @@ test('should support toBeFocused, toBeSelected', async ({ runInlineTest }) => {
|
||||
await locator.focus();
|
||||
await expect(locator).toBeFocused({ timeout: 1000 });
|
||||
});
|
||||
|
||||
test('selected', async ({ page }) => {
|
||||
await page.setContent('<select><option>One</option></select>');
|
||||
const locator = page.locator('option');
|
||||
await expect(locator).toBeSelected();
|
||||
});
|
||||
|
||||
test('fail on strict option', async ({ page }) => {
|
||||
await page.setContent('<select><option>One</option><option>Two</option></select>');
|
||||
const locator = page.locator('option');
|
||||
await expect(locator).toBeSelected();
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
const output = stripAscii(result.output);
|
||||
expect(output).toContain('strict mode violation');
|
||||
expect(result.passed).toBe(2);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.passed).toBe(1);
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
14
types/testExpect.d.ts
vendored
14
types/testExpect.d.ts
vendored
@ -109,11 +109,6 @@ declare global {
|
||||
*/
|
||||
toBeVisible(options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts given select option is selected
|
||||
*/
|
||||
toBeSelected(options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts element's text content matches given pattern or contains given substring.
|
||||
*/
|
||||
@ -122,7 +117,7 @@ declare global {
|
||||
/**
|
||||
* Asserts element's attributes `name` matches expected value.
|
||||
*/
|
||||
toHaveAttr(expected: string | RegExp, name: string, options?: { timeout?: number }): Promise<R>;
|
||||
toHaveAttribute(expected: string | RegExp, name: string, options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts that DOM node has a given CSS class.
|
||||
@ -139,11 +134,6 @@ declare global {
|
||||
*/
|
||||
toHaveCSS(expected: string | RegExp, name: string, options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts element's data attribute data-`name` matches expected value.
|
||||
*/
|
||||
toHaveData(expected: string | RegExp, name: string, options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts element's `id` attribute matches expected value.
|
||||
*/
|
||||
@ -152,7 +142,7 @@ declare global {
|
||||
/**
|
||||
* Asserts JavaScript object that corresponds to the Node has a property with given value.
|
||||
*/
|
||||
toHaveProp(name: string, value: any, options?: { timeout?: number }): Promise<R>;
|
||||
toHaveJSProperty(name: string, value: any, options?: { timeout?: number }): Promise<R>;
|
||||
|
||||
/**
|
||||
* Asserts element's text content.
|
||||
|
Loading…
x
Reference in New Issue
Block a user