fix(expect): report received when timedOut during oneShot (#20806)

This commit is contained in:
Dmitry Gozman 2023-02-10 14:59:21 -08:00 committed by GitHub
parent 8a1612ceec
commit 789b1c75e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 15 additions and 7 deletions

View File

@ -1402,7 +1402,7 @@ export class Frame extends SdkObject {
timeout -= elapsed;
}
if (timeout < 0)
return { matches: options.isNot, log: metadata.log, timedOut: true };
return { matches: options.isNot, log: metadata.log, timedOut: true, received: lastIntermediateResult.received };
return await this._expectInternal(metadata, selector, options, false, timeout, lastIntermediateResult);
}
@ -1422,7 +1422,7 @@ export class Frame extends SdkObject {
const injected = await context.injectedScript();
progress.throwIfAborted();
const { log, matches, received } = await injected.evaluate(async (injected, { info, options, snapshotName }) => {
const { log, matches, received, missingRecevied } = await injected.evaluate(async (injected, { info, options, snapshotName }) => {
const elements = info ? injected.querySelectorAll(info.parsed, document) : [];
const isArray = options.expression === 'to.have.count' || options.expression.endsWith('.array');
let log = '';
@ -1439,7 +1439,8 @@ export class Frame extends SdkObject {
if (log)
progress.log(log);
if (matches === options.isNot) {
// Note: missingReceived avoids `unexpected value "undefined"` when element was not found.
if (matches === options.isNot && !missingRecevied) {
lastIntermediateResult.received = received;
lastIntermediateResult.isSet = true;
if (!Array.isArray(received))

View File

@ -1119,7 +1119,7 @@ export class InjectedScript {
this.onGlobalListenersRemoved.add(addHitTargetInterceptorListeners);
}
async expect(element: Element | undefined, options: FrameExpectParams, elements: Element[]) {
async expect(element: Element | undefined, options: FrameExpectParams, elements: Element[]): Promise<{ matches: boolean, received?: any, missingRecevied?: boolean }> {
const isArray = options.expression === 'to.have.count' || options.expression.endsWith('.array');
if (isArray)
return this.expectArray(elements, options);
@ -1134,7 +1134,7 @@ export class InjectedScript {
if (options.isNot && options.expression === 'to.be.in.viewport')
return { matches: false };
// When none of the above applies, expect does not match.
return { matches: options.isNot };
return { matches: options.isNot, missingRecevied: true };
}
return await this.expectSingleElement(element, options);
}

View File

@ -128,6 +128,13 @@ test.describe('toHaveText with text', () => {
await expect(page.locator('div')).not.toHaveText('some text', { useInnerText: true });
await expect(page.locator('div')).not.toContainText('text', { useInnerText: true });
});
test('fail with impossible timeout', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
const error = await expect(page.locator('#node')).toHaveText('Text', { timeout: 1 }).catch(e => e);
expect(stripAnsi(error.message)).toContain('Expected string: "Text"');
expect(stripAnsi(error.message)).toContain('Received string: "Text content"');
});
});
test.describe('not.toHaveText', () => {

View File

@ -640,14 +640,14 @@ test('should print timed out error message', async ({ runInlineTest }) => {
test('fail', async ({ page }) => {
await page.setContent('<div id=node>Text content</div>');
await expect(page.locator('no-such-thing')).toBeChecked({ timeout: 1 });
await expect(page.locator('no-such-thing')).toHaveText('hey', { timeout: 1000 });
});
`,
}, { workers: 1 });
expect(result.failed).toBe(1);
expect(result.exitCode).toBe(1);
const output = result.output;
expect(output).toContain('Timed out 1ms waiting for expect(received).toBeChecked()');
expect(output).toContain('Timed out 1000ms waiting for expect(received).toHaveText(expected)');
});
test('should not leak long expect message strings', async ({ runInlineTest }) => {