fix(expect): produce "waiting for selector" log, corner cases (#9140)

This commit is contained in:
Dmitry Gozman 2021-09-24 18:55:45 -07:00 committed by GitHub
parent 45b365d958
commit f4aaebfba0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 11 deletions

View file

@ -1248,6 +1248,7 @@ export class Frame extends SdkObject {
const data = this._contextData.get(options.mainWorld ? 'main' : info.world)!;
return controller.run(async progress => {
progress.log(`waiting for selector "${selector}"`);
const rerunnableTask = new RerunnableTask(data, progress, injectedScript => {
return injectedScript.evaluateHandle((injected, { info, taskData, callbackText, querySelectorAll, logScale }) => {
const callback = injected.eval(callbackText) as DomTaskBody<T, R>;

View file

@ -65,6 +65,7 @@ export async function toMatchText(
const { pass, received, log } = await query(this.isNot, timeout);
const stringSubstring = options.matchSubstring ? 'substring' : 'string';
const receivedString = received || '';
const message = pass
? () =>
typeof expected === 'string'
@ -72,17 +73,17 @@ export async function toMatchText(
'\n\n' +
`Expected ${stringSubstring}: not ${this.utils.printExpected(expected)}\n` +
`Received string: ${printReceivedStringContainExpectedSubstring(
received!,
received!.indexOf(expected),
receivedString,
receivedString.indexOf(expected),
expected.length,
)}`
)}` + callLogText(log)
: this.utils.matcherHint(matcherName, undefined, undefined, matcherOptions) +
'\n\n' +
`Expected pattern: not ${this.utils.printExpected(expected)}\n` +
`Received string: ${printReceivedStringContainExpectedResult(
received!,
receivedString,
typeof expected.exec === 'function'
? expected.exec(received!)
? expected.exec(receivedString)
: null,
)}` + callLogText(log)
: () => {
@ -95,7 +96,7 @@ export async function toMatchText(
'\n\n' +
this.utils.printDiffOrStringify(
expected,
received,
receivedString,
labelExpected,
labelReceived,
this.expand !== false,
@ -105,10 +106,6 @@ export async function toMatchText(
return { message, pass };
}
export function normalizeWhiteSpace(s: string) {
return s.trim().replace(/\s+/g, ' ');
}
export function toExpectedTextValues(items: (string | RegExp)[], options: { matchSubstring?: boolean, normalizeWhiteSpace?: boolean } = {}): ExpectedTextValue[] {
return items.map(i => ({
string: isString(i) ? i : undefined,

View file

@ -225,6 +225,7 @@ it.describe('pause', () => {
expect(await sanitizeLog(recorderPage)).toEqual([
'page.pause- XXms',
'page.isChecked(button)- XXms',
'waiting for selector "button"',
'selector resolved to <button onclick=\"console.log(1)\">Submit</button>',
'error: Not a checkbox or radio button',
]);

View file

@ -81,6 +81,13 @@ it('innerText should throw', async ({ page, server }) => {
expect(error2.message).toContain('Not an HTMLElement');
});
it('innerText should produce log', async ({ page, server }) => {
await page.setContent(`<div>Hello</div>`);
const locator = page.locator('span');
const error = await locator.innerText({ timeout: 1000 }).catch(e => e);
expect(error.message).toContain('waiting for selector "span"');
});
it('textContent should work', async ({ page, server }) => {
await page.goto(`${server.PREFIX}/dom.html`);
const locator = page.locator('#inner');

View file

@ -312,5 +312,49 @@ test('should print nice error for toHaveText', async ({ runInlineTest }) => {
expect(output).toContain('Pending operations:');
expect(output).toContain('Error: expect(received).toHaveText(expected)');
expect(output).toContain('Expected string: "Text"');
expect(output).toContain('Received string: undefined');
expect(output).toContain('Received string: ""');
expect(output).toContain('waiting for selector "no-such-thing"');
});
test('should print expected/received on Ctrl+C', async ({ runInlineTest }) => {
test.skip(process.platform === 'win32', 'No sending SIGINT on Windows');
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test('times out waiting for text', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
const promise = expect(page.locator('#node')).toHaveText('Text 2');
await new Promise(f => setTimeout(f, 500));
console.log('\\n%%SEND-SIGINT%%');
await promise;
});
`,
}, { workers: 1 }, {}, { sendSIGINTAfter: 1 });
expect(result.exitCode).toBe(130);
expect(result.passed).toBe(0);
expect(result.skipped).toBe(1);
expect(stripAscii(result.output)).toContain('Expected string: "Text 2"');
expect(stripAscii(result.output)).toContain('Received string: "Text content"');
});
test('should support not.toHaveText when selector does not match', async ({ runInlineTest }) => {
const result = await runInlineTest({
'a.test.ts': `
const { test } = pwt;
test('fails', async ({ page }) => {
await page.setContent('<div>hello</div>');
await expect(page.locator('span')).not.toHaveText('hello', { timeout: 1000 });
});
`,
}, { workers: 1 });
expect(result.exitCode).toBe(1);
expect(result.passed).toBe(0);
expect(result.failed).toBe(1);
const output = stripAscii(result.output);
expect(output).toContain('Expected string: not "hello"');
expect(output).toContain('Received string: ""');
expect(output).toContain('waiting for selector "span"');
});