From db6c55af51044093d21d5f56a64a108702f56955 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Fri, 24 Sep 2021 12:54:33 -0700 Subject: [PATCH] chore: add a test for the log scale polling (#9136) --- src/server/frames.ts | 2 +- src/server/injected/injectedScript.ts | 12 +++++++++-- src/test/matchers/matchers.ts | 4 ++-- src/test/matchers/toBeTruthy.ts | 7 ++++--- src/test/matchers/toEqual.ts | 9 +++++---- src/test/matchers/toMatchText.ts | 18 +++++++++++++---- .../playwright.expect.misc.spec.ts | 20 +++++++++++++++++++ 7 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/server/frames.ts b/src/server/frames.ts index af1607f1d1..8d4045bf2e 100644 --- a/src/server/frames.ts +++ b/src/server/frames.ts @@ -1241,7 +1241,7 @@ export class Frame extends SdkObject { selector: string, body: DomTaskBody, taskData: T, - options: types.TimeoutOptions & types.StrictOptions & { mainWorld?: boolean } & { querySelectorAll?: boolean } & { logScale?: boolean } = {}): Promise { + options: types.TimeoutOptions & types.StrictOptions & { mainWorld?: boolean, querySelectorAll?: boolean, logScale?: boolean } = {}): Promise { const info = this._page.parseSelector(selector, options); const callbackText = body.toString(); diff --git a/src/server/injected/injectedScript.ts b/src/server/injected/injectedScript.ts index 8341875f8c..a089942a55 100644 --- a/src/server/injected/injectedScript.ts +++ b/src/server/injected/injectedScript.ts @@ -800,8 +800,11 @@ export class InjectedScript { throw injected.createStacklessError('Element is not a checkbox'); if (elementState === 'error:notconnected') throw injected.createStacklessError('Element is not connected'); - if (elementState === options.isNot) + if (elementState === options.isNot) { + progress.setIntermediateResult(elementState); + progress.log(` unexpected value "${elementState}"`); return continuePolling; + } return { pass: !options.isNot }; } } @@ -811,8 +814,11 @@ export class InjectedScript { if (expression === 'to.have.count') { const received = elements.length; const matches = received === options.expectedNumber; - if (matches === options.isNot) + if (matches === options.isNot) { + progress.setIntermediateResult(received); + progress.log(` unexpected value "${received}"`); return continuePolling; + } return { pass: !options.isNot, received }; } } @@ -824,6 +830,7 @@ export class InjectedScript { const matches = deepEquals(received, options.expectedValue); if (matches === options.isNot) { progress.setIntermediateResult(received); + progress.log(` unexpected value "${received}"`); return continuePolling; } return { received, pass: !options.isNot }; @@ -857,6 +864,7 @@ export class InjectedScript { const matcher = new ExpectedTextMatcher(options.expectedText[0]); if (matcher.matches(received) === options.isNot) { progress.setIntermediateResult(received); + progress.log(` unexpected value "${received}"`); return continuePolling; } return { received, pass: !options.isNot }; diff --git a/src/test/matchers/matchers.ts b/src/test/matchers/matchers.ts index 51d452ccd1..babf7814f0 100644 --- a/src/test/matchers/matchers.ts +++ b/src/test/matchers/matchers.ts @@ -23,7 +23,7 @@ import { toEqual } from './toEqual'; import { toExpectedTextValues, toMatchText } from './toMatchText'; interface LocatorEx extends Locator { - _expect(expression: string, options: channels.FrameExpectOptions): Promise<{ pass: boolean, received?: string, log?: string[] }>; + _expect(expression: string, options: channels.FrameExpectOptions): Promise<{ pass: boolean, received?: any, log?: string[] }>; } export function toBeChecked( @@ -115,7 +115,7 @@ export function toContainText( return toMatchText.call(this, 'toContainText', locator, 'Locator', async (isNot, timeout) => { const expectedText = toExpectedTextValues([expected], { matchSubstring: true, normalizeWhiteSpace: true }); return await locator._expect('to.have.text', { expectedText, isNot, useInnerText: options?.useInnerText, timeout }); - }, expected, { ...options, matchSubstring: true }); + }, expected, options); } export function toHaveAttribute( diff --git a/src/test/matchers/toBeTruthy.ts b/src/test/matchers/toBeTruthy.ts index 7d14a08b42..18ffee4bd8 100644 --- a/src/test/matchers/toBeTruthy.ts +++ b/src/test/matchers/toBeTruthy.ts @@ -17,13 +17,14 @@ import { currentTestInfo } from '../globals'; import type { Expect } from '../types'; import { expectType } from '../util'; +import { callLogText } from './toMatchText'; export async function toBeTruthy( this: ReturnType, matcherName: string, receiver: any, receiverType: string, - query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean }>, + query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, log?: string[] }>, options: { timeout?: number } = {}, ) { const testInfo = currentTestInfo(); @@ -41,10 +42,10 @@ export async function toBeTruthy( defaultExpectTimeout = 5000; const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; - const { pass } = await query(this.isNot, timeout); + const { pass, log } = await query(this.isNot, timeout); const message = () => { - return this.utils.matcherHint(matcherName, undefined, '', matcherOptions); + return this.utils.matcherHint(matcherName, undefined, '', matcherOptions) + callLogText(log); }; return { message, pass }; diff --git a/src/test/matchers/toEqual.ts b/src/test/matchers/toEqual.ts index 9e49d4934e..6b0a70d4cc 100644 --- a/src/test/matchers/toEqual.ts +++ b/src/test/matchers/toEqual.ts @@ -17,6 +17,7 @@ import { currentTestInfo } from '../globals'; import type { Expect } from '../types'; import { expectType } from '../util'; +import { callLogText } from './toMatchText'; // Omit colon and one or more spaces, so can call getLabelPrinter. const EXPECTED_LABEL = 'Expected'; @@ -30,7 +31,7 @@ export async function toEqual( matcherName: string, receiver: any, receiverType: string, - query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, received?: any }>, + query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, received?: any, log?: string[] }>, expected: T, options: { timeout?: number } = {}, ) { @@ -50,7 +51,7 @@ export async function toEqual( defaultExpectTimeout = 5000; const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; - const { pass, received } = await query(this.isNot, timeout); + const { pass, received, log } = await query(this.isNot, timeout); const message = pass ? () => @@ -59,7 +60,7 @@ export async function toEqual( `Expected: not ${this.utils.printExpected(expected)}\n` + (this.utils.stringify(expected) !== this.utils.stringify(received) ? `Received: ${this.utils.printReceived(received)}` - : '') + : '') + callLogText(log) : () => this.utils.matcherHint(matcherName, undefined, undefined, matcherOptions) + '\n\n' + @@ -69,7 +70,7 @@ export async function toEqual( EXPECTED_LABEL, RECEIVED_LABEL, isExpand(this.expand), - ); + ) + callLogText(log); // Passing the actual and expected objects so that a custom reporter // could access them, for example in order to display a custom visual diff, diff --git a/src/test/matchers/toMatchText.ts b/src/test/matchers/toMatchText.ts index 0d1738ee8e..fa71fc3baf 100644 --- a/src/test/matchers/toMatchText.ts +++ b/src/test/matchers/toMatchText.ts @@ -29,7 +29,7 @@ export async function toMatchText( matcherName: string, receiver: any, receiverType: string, - query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, received?: string }>, + query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, received?: string, log?: string[] }>, expected: string | RegExp, options: { timeout?: number, matchSubstring?: boolean } = {}, ) { @@ -63,7 +63,7 @@ export async function toMatchText( defaultExpectTimeout = 5000; const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; - const { pass, received } = await query(this.isNot, timeout); + const { pass, received, log } = await query(this.isNot, timeout); const stringSubstring = options.matchSubstring ? 'substring' : 'string'; const message = pass ? () => @@ -84,7 +84,7 @@ export async function toMatchText( typeof expected.exec === 'function' ? expected.exec(received!) : null, - )}` + )}` + callLogText(log) : () => { const labelExpected = `Expected ${typeof expected === 'string' ? stringSubstring : 'pattern' }`; @@ -99,7 +99,7 @@ export async function toMatchText( labelExpected, labelReceived, this.expand !== false, - )); + )) + callLogText(log); }; return { message, pass }; @@ -118,3 +118,13 @@ export function toExpectedTextValues(items: (string | RegExp)[], options: { matc normalizeWhiteSpace: options.normalizeWhiteSpace, })); } + +export function callLogText(log: string[] | undefined): string { + if (!log) + return ''; + return ` + +Call log: +${(log || []).join('\n')} +`; +} diff --git a/tests/playwright-test/playwright.expect.misc.spec.ts b/tests/playwright-test/playwright.expect.misc.spec.ts index 81c727457c..9ccb38fc56 100644 --- a/tests/playwright-test/playwright.expect.misc.spec.ts +++ b/tests/playwright-test/playwright.expect.misc.spec.ts @@ -220,3 +220,23 @@ test('should support respect expect.timeout', async ({ runInlineTest }) => { expect(result.failed).toBe(1); expect(result.exitCode).toBe(1); }); + +test('should log scale the time', async ({ runInlineTest }) => { + const result = await runInlineTest({ + 'a.test.ts': ` + const { test } = pwt; + + test('pass', async ({ page }) => { + await page.setContent('
Wrong
'); + await expect(page.locator('div')).toHaveText('Text', { timeout: 2000 }); + }); + `, + }, { workers: 1 }); + const output = stripAscii(result.output); + const tokens = output.split('unexpected value'); + // Log scale: 0, 100, 250, 500, 1000, 1000, should be less than 8. + expect(tokens.length).toBeGreaterThan(1); + expect(tokens.length).toBeLessThan(8); + expect(result.passed).toBe(0); + expect(result.exitCode).toBe(1); +});