chore: move compress call log to server (#33399)
This commit is contained in:
parent
fc0ce7046b
commit
c76f004ec3
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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`);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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 = {
|
||||||
|
|
|
||||||
|
|
@ -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/);
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue