feat(expect): support array of RegExp objects in toHaveText/toHaveClass (#8667)

This commit is contained in:
Dmitry Gozman 2021-09-02 15:48:04 -07:00 committed by GitHub
parent e691b649de
commit 620712a5d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 20 additions and 16 deletions

View File

@ -145,7 +145,7 @@ await expect(locator).toHaveAttribute('type', 'text');
```
## expect(locator).toHaveClass(expected)
- `expected`: <[string] | [RegExp] | [Array]<[string]>>
- `expected`: <[string] | [RegExp] | [Array]<[string]|[RegExp]>>
- `options`
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
@ -159,7 +159,7 @@ await expect(locator).toHaveClass(/selected/);
Note that if array is passed as an expected value, entire lists can be asserted:
```js
const locator = page.locator('list > #component');
const locator = page.locator('list > .component');
await expect(locator).toHaveClass(['component', 'component selected', 'component']);
```
@ -215,7 +215,7 @@ await expect(locator).toHaveJSProperty('loaded', true);
```
## expect(locator).toHaveText(expected, options)
- `expected`: <[string] | [RegExp] | [Array]<[string]>>
- `expected`: <[string] | [RegExp] | [Array]<[string]|[RegExp]>>
- `options`
- `timeout`: <[number]> Time to retry assertion for, defaults to `timeout` in [`property: TestProject.expect`].
- `useInnerText`: <[boolean]> Whether to use `element.innerText` instead of `element.textContent` when retrieving DOM node text.

View File

@ -134,7 +134,7 @@ export function toHaveAttribute(
export function toHaveClass(
this: ReturnType<Expect['getState']>,
locator: Locator,
expected: string | RegExp | string[],
expected: string | RegExp | (string | RegExp)[],
options?: { timeout?: number },
) {
if (Array.isArray(expected)) {
@ -199,7 +199,7 @@ export function toHaveJSProperty(
export function toHaveText(
this: ReturnType<Expect['getState']>,
locator: Locator,
expected: string | RegExp | string[],
expected: string | RegExp | (string | RegExp)[],
options?: { timeout?: number, useInnerText?: boolean },
) {
if (Array.isArray(expected)) {

View File

@ -43,7 +43,6 @@ export async function toBeTruthy<T>(
let received: T;
let pass = false;
// TODO: interrupt on timeout for nice message.
await pollUntilDeadline(testInfo, async remainingTime => {
received = await query(remainingTime);
pass = !!received;

View File

@ -36,6 +36,13 @@ const RECEIVED_LABEL = 'Received';
// The optional property of matcher context is true if undefined.
const isExpand = (expand?: boolean): boolean => expand !== false;
function regExpTester(a: any, b: any): boolean | undefined {
if (typeof a === 'string' && b instanceof RegExp) {
b.lastIndex = 0;
return b.test(a);
}
}
export async function toEqual<T>(
this: ReturnType<Expect['getState']>,
matcherName: string,
@ -59,10 +66,9 @@ export async function toEqual<T>(
let received: T | undefined = undefined;
let pass = false;
// TODO: interrupt on timeout for nice message.
await pollUntilDeadline(testInfo, async remainingTime => {
received = await query(remainingTime);
pass = equals(received, expected, [iterableEquality]);
pass = equals(received, expected, [iterableEquality, regExpTester]);
return pass === !matcherOptions.isNot;
}, options.timeout, testInfo._testFinished);

View File

@ -68,7 +68,6 @@ export async function toMatchText(
let received: string;
let pass = false;
// TODO: interrupt on timeout for nice message.
await pollUntilDeadline(testInfo, async remainingTime => {
received = await query(remainingTime);
if (options.matchSubstring)

View File

@ -93,19 +93,19 @@ test('should support toHaveClass w/ array', async ({ runInlineTest }) => {
test('pass', async ({ page }) => {
await page.setContent('<div class="foo"></div><div class="bar"></div><div class="baz"></div>');
const locator = page.locator('div');
await expect(locator).toHaveClass(['foo', 'bar', 'baz']);
await expect(locator).toHaveClass(['foo', 'bar', /[a-z]az/]);
});
test('fail', async ({ page }) => {
await page.setContent('<div class="foo"></div><div class="bar"></div><div class="bar"></div>');
const locator = page.locator('div');
await expect(locator).toHaveClass(['foo', 'bar', 'baz'], { timeout: 1000 });
await expect(locator).toHaveClass(['foo', 'bar', /[a-z]az/], { timeout: 1000 });
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
expect(output).toContain('expect(received).toHaveClass(expected)');
expect(output).toContain('- \"baz\",');
expect(output).toContain('- /[a-z]az/,');
expect(result.passed).toBe(1);
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);

View File

@ -84,22 +84,22 @@ test('should support toHaveText w/ array', async ({ runInlineTest }) => {
const { test } = pwt;
test('pass', async ({ page }) => {
await page.setContent('<div>Text 1</div><div>Text 2</div>');
await page.setContent('<div>Text 1</div><div>Text 2a</div>');
const locator = page.locator('div');
await expect(locator).toHaveText(['Text 1', 'Text 2']);
await expect(locator).toHaveText(['Text 1', /Text \\d+a/]);
});
test('fail', async ({ page }) => {
await page.setContent('<div>Text 1</div><div>Text 3</div>');
const locator = page.locator('div');
await expect(locator).toHaveText(['Text 1', 'Text 2'], { timeout: 1000 });
await expect(locator).toHaveText(['Text 1', /Text \\d+a/], { timeout: 1000 });
});
`,
}, { workers: 1 });
const output = stripAscii(result.output);
expect(output).toContain('Error: expect(received).toHaveText(expected) // deep equality');
expect(output).toContain('await expect(locator).toHaveText');
expect(output).toContain('- \"Text 2\"');
expect(output).toContain('- /Text \\d+a/');
expect(result.passed).toBe(1);
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);