chore: add a test for the log scale polling (#9136)

This commit is contained in:
Pavel Feldman 2021-09-24 12:54:33 -07:00 committed by GitHub
parent 1db41c330a
commit db6c55af51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 56 additions and 16 deletions

View file

@ -1241,7 +1241,7 @@ export class Frame extends SdkObject {
selector: string, selector: string,
body: DomTaskBody<T, R>, body: DomTaskBody<T, R>,
taskData: T, taskData: T,
options: types.TimeoutOptions & types.StrictOptions & { mainWorld?: boolean } & { querySelectorAll?: boolean } & { logScale?: boolean } = {}): Promise<R> { options: types.TimeoutOptions & types.StrictOptions & { mainWorld?: boolean, querySelectorAll?: boolean, logScale?: boolean } = {}): Promise<R> {
const info = this._page.parseSelector(selector, options); const info = this._page.parseSelector(selector, options);
const callbackText = body.toString(); const callbackText = body.toString();

View file

@ -800,8 +800,11 @@ export class InjectedScript {
throw injected.createStacklessError('Element is not a checkbox'); throw injected.createStacklessError('Element is not a checkbox');
if (elementState === 'error:notconnected') if (elementState === 'error:notconnected')
throw injected.createStacklessError('Element is not connected'); 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 continuePolling;
}
return { pass: !options.isNot }; return { pass: !options.isNot };
} }
} }
@ -811,8 +814,11 @@ export class InjectedScript {
if (expression === 'to.have.count') { if (expression === 'to.have.count') {
const received = elements.length; const received = elements.length;
const matches = received === options.expectedNumber; const matches = received === options.expectedNumber;
if (matches === options.isNot) if (matches === options.isNot) {
progress.setIntermediateResult(received);
progress.log(` unexpected value "${received}"`);
return continuePolling; return continuePolling;
}
return { pass: !options.isNot, received }; return { pass: !options.isNot, received };
} }
} }
@ -824,6 +830,7 @@ export class InjectedScript {
const matches = deepEquals(received, options.expectedValue); const matches = deepEquals(received, options.expectedValue);
if (matches === options.isNot) { if (matches === options.isNot) {
progress.setIntermediateResult(received); progress.setIntermediateResult(received);
progress.log(` unexpected value "${received}"`);
return continuePolling; return continuePolling;
} }
return { received, pass: !options.isNot }; return { received, pass: !options.isNot };
@ -857,6 +864,7 @@ export class InjectedScript {
const matcher = new ExpectedTextMatcher(options.expectedText[0]); const matcher = new ExpectedTextMatcher(options.expectedText[0]);
if (matcher.matches(received) === options.isNot) { if (matcher.matches(received) === options.isNot) {
progress.setIntermediateResult(received); progress.setIntermediateResult(received);
progress.log(` unexpected value "${received}"`);
return continuePolling; return continuePolling;
} }
return { received, pass: !options.isNot }; return { received, pass: !options.isNot };

View file

@ -23,7 +23,7 @@ import { toEqual } from './toEqual';
import { toExpectedTextValues, toMatchText } from './toMatchText'; import { toExpectedTextValues, toMatchText } from './toMatchText';
interface LocatorEx extends Locator { 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( export function toBeChecked(
@ -115,7 +115,7 @@ export function toContainText(
return toMatchText.call(this, 'toContainText', locator, 'Locator', async (isNot, timeout) => { return toMatchText.call(this, 'toContainText', locator, 'Locator', async (isNot, timeout) => {
const expectedText = toExpectedTextValues([expected], { matchSubstring: true, normalizeWhiteSpace: true }); const expectedText = toExpectedTextValues([expected], { matchSubstring: true, normalizeWhiteSpace: true });
return await locator._expect('to.have.text', { expectedText, isNot, useInnerText: options?.useInnerText, timeout }); return await locator._expect('to.have.text', { expectedText, isNot, useInnerText: options?.useInnerText, timeout });
}, expected, { ...options, matchSubstring: true }); }, expected, options);
} }
export function toHaveAttribute( export function toHaveAttribute(

View file

@ -17,13 +17,14 @@
import { currentTestInfo } from '../globals'; import { currentTestInfo } from '../globals';
import type { Expect } from '../types'; import type { Expect } from '../types';
import { expectType } from '../util'; import { expectType } from '../util';
import { callLogText } from './toMatchText';
export async function toBeTruthy( export async function toBeTruthy(
this: ReturnType<Expect['getState']>, this: ReturnType<Expect['getState']>,
matcherName: string, matcherName: string,
receiver: any, receiver: any,
receiverType: string, receiverType: string,
query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean }>, query: (isNot: boolean, timeout: number) => Promise<{ pass: boolean, log?: string[] }>,
options: { timeout?: number } = {}, options: { timeout?: number } = {},
) { ) {
const testInfo = currentTestInfo(); const testInfo = currentTestInfo();
@ -41,10 +42,10 @@ export async function toBeTruthy(
defaultExpectTimeout = 5000; defaultExpectTimeout = 5000;
const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; 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 = () => { const message = () => {
return this.utils.matcherHint(matcherName, undefined, '', matcherOptions); return this.utils.matcherHint(matcherName, undefined, '', matcherOptions) + callLogText(log);
}; };
return { message, pass }; return { message, pass };

View file

@ -17,6 +17,7 @@
import { currentTestInfo } from '../globals'; import { currentTestInfo } from '../globals';
import type { Expect } from '../types'; import type { Expect } from '../types';
import { expectType } from '../util'; import { expectType } from '../util';
import { callLogText } from './toMatchText';
// Omit colon and one or more spaces, so can call getLabelPrinter. // Omit colon and one or more spaces, so can call getLabelPrinter.
const EXPECTED_LABEL = 'Expected'; const EXPECTED_LABEL = 'Expected';
@ -30,7 +31,7 @@ export async function toEqual<T>(
matcherName: string, matcherName: string,
receiver: any, receiver: any,
receiverType: string, 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, expected: T,
options: { timeout?: number } = {}, options: { timeout?: number } = {},
) { ) {
@ -50,7 +51,7 @@ export async function toEqual<T>(
defaultExpectTimeout = 5000; defaultExpectTimeout = 5000;
const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; 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 const message = pass
? () => ? () =>
@ -59,7 +60,7 @@ export async function toEqual<T>(
`Expected: not ${this.utils.printExpected(expected)}\n` + `Expected: not ${this.utils.printExpected(expected)}\n` +
(this.utils.stringify(expected) !== this.utils.stringify(received) (this.utils.stringify(expected) !== this.utils.stringify(received)
? `Received: ${this.utils.printReceived(received)}` ? `Received: ${this.utils.printReceived(received)}`
: '') : '') + callLogText(log)
: () => : () =>
this.utils.matcherHint(matcherName, undefined, undefined, matcherOptions) + this.utils.matcherHint(matcherName, undefined, undefined, matcherOptions) +
'\n\n' + '\n\n' +
@ -69,7 +70,7 @@ export async function toEqual<T>(
EXPECTED_LABEL, EXPECTED_LABEL,
RECEIVED_LABEL, RECEIVED_LABEL,
isExpand(this.expand), isExpand(this.expand),
); ) + callLogText(log);
// Passing the actual and expected objects so that a custom reporter // Passing the actual and expected objects so that a custom reporter
// could access them, for example in order to display a custom visual diff, // could access them, for example in order to display a custom visual diff,

View file

@ -29,7 +29,7 @@ export async function toMatchText(
matcherName: string, matcherName: string,
receiver: any, receiver: any,
receiverType: string, 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, expected: string | RegExp,
options: { timeout?: number, matchSubstring?: boolean } = {}, options: { timeout?: number, matchSubstring?: boolean } = {},
) { ) {
@ -63,7 +63,7 @@ export async function toMatchText(
defaultExpectTimeout = 5000; defaultExpectTimeout = 5000;
const timeout = options.timeout === 0 ? 0 : options.timeout || defaultExpectTimeout; 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 stringSubstring = options.matchSubstring ? 'substring' : 'string';
const message = pass const message = pass
? () => ? () =>
@ -84,7 +84,7 @@ export async function toMatchText(
typeof expected.exec === 'function' typeof expected.exec === 'function'
? expected.exec(received!) ? expected.exec(received!)
: null, : null,
)}` )}` + callLogText(log)
: () => { : () => {
const labelExpected = `Expected ${typeof expected === 'string' ? stringSubstring : 'pattern' const labelExpected = `Expected ${typeof expected === 'string' ? stringSubstring : 'pattern'
}`; }`;
@ -99,7 +99,7 @@ export async function toMatchText(
labelExpected, labelExpected,
labelReceived, labelReceived,
this.expand !== false, this.expand !== false,
)); )) + callLogText(log);
}; };
return { message, pass }; return { message, pass };
@ -118,3 +118,13 @@ export function toExpectedTextValues(items: (string | RegExp)[], options: { matc
normalizeWhiteSpace: options.normalizeWhiteSpace, normalizeWhiteSpace: options.normalizeWhiteSpace,
})); }));
} }
export function callLogText(log: string[] | undefined): string {
if (!log)
return '';
return `
Call log:
${(log || []).join('\n')}
`;
}

View file

@ -220,3 +220,23 @@ test('should support respect expect.timeout', async ({ runInlineTest }) => {
expect(result.failed).toBe(1); expect(result.failed).toBe(1);
expect(result.exitCode).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('<div id=div>Wrong</div>');
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);
});