chore: move compress call log to server (#33399)

This commit is contained in:
Pavel Feldman 2024-11-01 13:38:01 -07:00 committed by GitHub
parent fc0ce7046b
commit c76f004ec3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 34 additions and 12 deletions

View file

@ -17,7 +17,7 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';
import { findValidator, ValidationError, createMetadataValidator, type ValidatorContext } from '../../protocol/validator'; import { findValidator, ValidationError, createMetadataValidator, type ValidatorContext } from '../../protocol/validator';
import { LongStandingScope, assert, isUnderTest, monotonicTime, rewriteErrorMessage } from '../../utils'; import { LongStandingScope, assert, compressCallLog, isUnderTest, monotonicTime, rewriteErrorMessage } from '../../utils';
import { TargetClosedError, isTargetClosedError, serializeError } from '../errors'; import { TargetClosedError, isTargetClosedError, serializeError } from '../errors';
import type { CallMetadata } from '../instrumentation'; import type { CallMetadata } from '../instrumentation';
import { SdkObject } from '../instrumentation'; import { SdkObject } from '../instrumentation';
@ -357,7 +357,7 @@ export class DispatcherConnection {
} }
if (response.error) if (response.error)
response.log = callMetadata.log; response.log = compressCallLog(callMetadata.log);
this.onmessage(response); this.onmessage(response);
} }
} }

View file

@ -299,7 +299,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
while (progress.isRunning()) { while (progress.isRunning()) {
if (retry) { if (retry) {
progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}, attempt #${retry}`); progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}`);
const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)]; const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)];
if (timeout) { if (timeout) {
progress.log(` waiting ${timeout}ms`); progress.log(` waiting ${timeout}ms`);

View file

@ -29,7 +29,7 @@ import * as types from './types';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import type { Progress } from './progress'; import type { Progress } from './progress';
import { ProgressController } from './progress'; import { ProgressController } from './progress';
import { LongStandingScope, assert, constructURLBasedOnBaseURL, makeWaitForNextTask, monotonicTime, asLocator } from '../utils'; import { LongStandingScope, assert, constructURLBasedOnBaseURL, makeWaitForNextTask, monotonicTime, asLocator, compressCallLog } from '../utils';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/manualPromise';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import type { CallMetadata } from './instrumentation'; import type { CallMetadata } from './instrumentation';
@ -1452,7 +1452,7 @@ export class Frame extends SdkObject {
timeout -= elapsed; timeout -= elapsed;
} }
if (timeout < 0) if (timeout < 0)
return { matches: options.isNot, log: metadata.log, timedOut: true, received: lastIntermediateResult.received }; return { matches: options.isNot, log: compressCallLog(metadata.log), timedOut: true, received: lastIntermediateResult.received };
// Step 3: auto-retry expect with increasing timeouts. Bounded by the total remaining time. // Step 3: auto-retry expect with increasing timeouts. Bounded by the total remaining time.
return await (new ProgressController(metadata, this)).run(async progress => { return await (new ProgressController(metadata, this)).run(async progress => {
@ -1473,7 +1473,7 @@ export class Frame extends SdkObject {
// A: We want user to receive a friendly message containing the last intermediate result. // A: We want user to receive a friendly message containing the last intermediate result.
if (js.isJavaScriptErrorInEvaluate(e) || isInvalidSelectorError(e)) if (js.isJavaScriptErrorInEvaluate(e) || isInvalidSelectorError(e))
throw e; throw e;
const result: { matches: boolean, received?: any, log?: string[], timedOut?: boolean } = { matches: options.isNot, log: metadata.log }; const result: { matches: boolean, received?: any, log?: string[], timedOut?: boolean } = { matches: options.isNot, log: compressCallLog(metadata.log) };
if (lastIntermediateResult.isSet) if (lastIntermediateResult.isSet)
result.received = lastIntermediateResult.received; result.received = lastIntermediateResult.received;
if (e instanceof TimeoutError) if (e instanceof TimeoutError)

View file

@ -31,7 +31,7 @@ import * as accessibility from './accessibility';
import { FileChooser } from './fileChooser'; import { FileChooser } from './fileChooser';
import type { Progress } from './progress'; import type { Progress } from './progress';
import { ProgressController } from './progress'; import { ProgressController } from './progress';
import { LongStandingScope, assert, createGuid, trimStringWithEllipsis } from '../utils'; import { LongStandingScope, assert, compressCallLog, createGuid, trimStringWithEllipsis } from '../utils';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/manualPromise';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import type { ImageComparatorOptions } from '../utils/comparators'; import type { ImageComparatorOptions } from '../utils/comparators';
@ -676,7 +676,7 @@ export class Page extends SdkObject {
if (e instanceof TimeoutError && intermediateResult?.previous) if (e instanceof TimeoutError && intermediateResult?.previous)
errorMessage = `Failed to take two consecutive stable screenshots.`; errorMessage = `Failed to take two consecutive stable screenshots.`;
return { return {
log: e.message ? [...metadata.log, e.message] : metadata.log, log: compressCallLog(e.message ? [...metadata.log, e.message] : metadata.log),
...intermediateResult, ...intermediateResult,
errorMessage, errorMessage,
timedOut: (e instanceof TimeoutError), timedOut: (e instanceof TimeoutError),

View file

@ -131,7 +131,13 @@ export function splitErrorMessage(message: string): { name: string, message: str
export function formatCallLog(log: string[] | undefined): string { export function formatCallLog(log: string[] | undefined): string {
if (!log || !log.some(l => !!l)) if (!log || !log.some(l => !!l))
return ''; return '';
return `
Call log:
${colors.dim(log.join('\n'))}
`;
}
export function compressCallLog(log: string[]): string[] {
const lines: string[] = []; const lines: string[] = [];
for (const block of findRepeatedSubsequences(log)) { for (const block of findRepeatedSubsequences(log)) {
@ -148,10 +154,7 @@ export function formatCallLog(log: string[] | undefined): string {
lines.push(whitespacePrefix + '- ' + line.trim()); lines.push(whitespacePrefix + '- ' + line.trim());
} }
} }
return ` return lines;
Call log:
${colors.dim(lines.join('\n'))}
`;
} }
export type ExpectZone = { export type ExpectZone = {

View file

@ -15,6 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { stripAnsi } from 'tests/config/utils';
import type { TestServer } from '../config/testserver'; import type { TestServer } from '../config/testserver';
import { test as it, expect } from './pageTest'; import { test as it, expect } from './pageTest';
@ -139,3 +140,21 @@ it('should report navigation in the log when clicking anchor', async ({ page, se
expect(error.message).toContain('waiting for scheduled navigations to finish'); expect(error.message).toContain('waiting for scheduled navigations to finish');
expect(error.message).toContain(`navigated to "${server.PREFIX + '/frames/one-frame.html'}"`); expect(error.message).toContain(`navigated to "${server.PREFIX + '/frames/one-frame.html'}"`);
}); });
it('should report and collapse log in action', async ({ page, server, mode }) => {
await page.setContent(`<input id='checkbox' type='checkbox' style="visibility: hidden"></input>`);
const error = await page.locator('input').click({ timeout: 5000 }).catch(e => e);
const message = stripAnsi(error.message);
expect(message).toContain(`Call log:`);
expect(message).toMatch(/\d+ × waiting for/);
const logLines = message.substring(message.indexOf('Call log:')).split('\n');
expect(logLines.length).toBeLessThan(30);
});
it('should report and collapse log in expect', async ({ page, server, mode }) => {
await page.setContent(`<input id='checkbox' type='checkbox' style="visibility: hidden"></input>`);
const error = await expect(page.locator('input')).toBeVisible({ timeout: 5000 }).catch(e => e);
const message = stripAnsi(error.message);
expect(message).toContain(`Call log:`);
expect(message).toMatch(/\d+ × locator resolved to/);
});