fix(expect): toHaveText, toContainText and toHaveTitle normalize whitespace (#8929)

This commit is contained in:
Dmitry Gozman 2021-09-14 19:24:29 -07:00 committed by GitHub
parent c58f34fb2e
commit b8a46580dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 18 deletions

View File

@ -15,12 +15,12 @@
*/
import { Locator, Page } from '../../..';
import { constructURLBasedOnBaseURL } from '../../utils/utils';
import { constructURLBasedOnBaseURL, isString } from '../../utils/utils';
import { currentTestInfo } from '../globals';
import type { Expect } from '../types';
import { toBeTruthy } from './toBeTruthy';
import { toEqual } from './toEqual';
import { toMatchText } from './toMatchText';
import { normalizeWhiteSpace, toMatchText } from './toMatchText';
export function toBeChecked(
this: ReturnType<Expect['getState']>,
@ -118,7 +118,7 @@ export function toContainText(
if (options?.useInnerText)
return await locator.innerText({ timeout });
return await locator.textContent() || '';
}, expected, { ...options, matchSubstring: true });
}, expected, { ...options, matchSubstring: true, normalizeWhiteSpace: true });
}
export function toHaveAttribute(
@ -202,20 +202,23 @@ export function toHaveText(
this: ReturnType<Expect['getState']>,
locator: Locator,
expected: string | RegExp | (string | RegExp)[],
options?: { timeout?: number, useInnerText?: boolean },
options: { timeout?: number, useInnerText?: boolean } = {},
) {
if (Array.isArray(expected)) {
const expectedArray = expected.map(e => isString(e) ? normalizeWhiteSpace(e) : e);
return toEqual.call(this, 'toHaveText', locator, 'Locator', async () => {
return locator.evaluateAll((ee, useInnerText) => {
const texts = await locator.evaluateAll((ee, useInnerText) => {
return ee.map(e => useInnerText ? (e as HTMLElement).innerText : e.textContent || '');
}, options?.useInnerText);
}, expected, options);
// Normalize those values that have string expectations.
return texts.map((s, index) => isString(expectedArray[index]) ? normalizeWhiteSpace(s) : s);
}, expectedArray, options);
} else {
return toMatchText.call(this, 'toHaveText', locator, 'Locator', async timeout => {
if (options?.useInnerText)
return await locator.innerText({ timeout });
return await locator.textContent() || '';
}, expected, options);
}, expected, { ...options, normalizeWhiteSpace: true });
}
}
@ -223,11 +226,11 @@ export function toHaveTitle(
this: ReturnType<Expect['getState']>,
page: Page,
expected: string | RegExp,
options?: { timeout?: number },
options: { timeout?: number } = {},
) {
return toMatchText.call(this, 'toHaveTitle', page, 'Page', async () => {
return await page.title();
}, expected, options);
}, expected, { ...options, normalizeWhiteSpace: true });
}
export function toHaveURL(

View File

@ -18,7 +18,7 @@ import {
printReceivedStringContainExpectedResult,
printReceivedStringContainExpectedSubstring
} from 'expect/build/print';
import { isString } from '../../utils/utils';
import { currentTestInfo } from '../globals';
import type { Expect } from '../types';
import { expectType, pollUntilDeadline } from '../util';
@ -30,7 +30,7 @@ export async function toMatchText(
receiverType: string,
query: (timeout: number) => Promise<string>,
expected: string | RegExp,
options: { timeout?: number, matchSubstring?: boolean } = {},
options: { timeout?: number, matchSubstring?: boolean, normalizeWhiteSpace?: boolean } = {},
) {
const testInfo = currentTestInfo();
if (!testInfo)
@ -59,9 +59,13 @@ export async function toMatchText(
let received: string;
let pass = false;
if (options.normalizeWhiteSpace && isString(expected))
expected = normalizeWhiteSpace(expected);
await pollUntilDeadline(testInfo, async remainingTime => {
received = await query(remainingTime);
if (options.normalizeWhiteSpace && isString(expected))
received = normalizeWhiteSpace(received);
if (options.matchSubstring)
pass = received.includes(expected as string);
else if (typeof expected === 'string')
@ -112,3 +116,7 @@ export async function toMatchText(
return { message, pass };
}
export function normalizeWhiteSpace(s: string) {
return s.trim().replace(/\s+/g, ' ');
}

View File

@ -124,8 +124,8 @@ test('should support toHaveTitle', async ({ runInlineTest }) => {
const { test } = pwt;
test('pass', async ({ page }) => {
await page.setContent('<title>Hello</title>');
await expect(page).toHaveTitle('Hello');
await page.setContent('<title> Hello world</title>');
await expect(page).toHaveTitle('Hello world');
});
test('fail', async ({ page }) => {

View File

@ -22,9 +22,12 @@ test('should support toHaveText w/ regex', async ({ runInlineTest }) => {
const { test } = pwt;
test('pass', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
await page.setContent('<div id=node>Text content</div>');
const locator = page.locator('#node');
await expect(locator).toHaveText(/Text/);
// Should not normalize whitespace.
await expect(locator).toHaveText(/Text content/);
});
test('fail', async ({ page }) => {
@ -50,15 +53,18 @@ test('should support toHaveText w/ text', async ({ runInlineTest }) => {
const { test } = pwt;
test('pass', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
await page.setContent('<div id=node><span></span>Text \\ncontent&nbsp; </div>');
const locator = page.locator('#node');
await expect(locator).toHaveText('Text content');
// Should normalize whitespace.
await expect(locator).toHaveText('Text content');
});
test('pass contain', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
const locator = page.locator('#node');
await expect(locator).toContainText('Text');
// Should normalize whitespace.
await expect(locator).toContainText(' Text content\\n ');
});
test('fail', async ({ page }) => {
@ -84,9 +90,10 @@ test('should support toHaveText w/ array', async ({ runInlineTest }) => {
const { test } = pwt;
test('pass', async ({ page }) => {
await page.setContent('<div>Text 1</div><div>Text 2a</div>');
await page.setContent('<div>Text \\n1</div><div>Text 2a</div>');
const locator = page.locator('div');
await expect(locator).toHaveText(['Text 1', /Text \\d+a/]);
// Should only normalize whitespace in the first item.
await expect(locator).toHaveText(['Text 1', /Text \\d+a/]);
});
test('fail', async ({ page }) => {