Merge branch 'microsoft:main' into cnm_dev

This commit is contained in:
Christopher Tangonan 2025-02-12 15:58:05 -08:00 committed by GitHub
commit 798f05eedd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
119 changed files with 907 additions and 729 deletions

View file

@ -334,6 +334,8 @@ Whether to populate `'git.commit.info'` field of the [`property: TestConfig.meta
This information will appear in the HTML and JSON reports and is available in the Reporter API. This information will appear in the HTML and JSON reports and is available in the Reporter API.
On Github Actions, this feature is enabled by default.
**Usage** **Usage**
```js title="playwright.config.ts" ```js title="playwright.config.ts"

View file

@ -15,7 +15,7 @@
--> -->
<!DOCTYPE html> <!DOCTYPE html>
<html> <html style='scrollbar-gutter: stable both-edges;'>
<head> <head>
<meta charset='UTF-8'> <meta charset='UTF-8'>
<meta name='color-scheme' content='dark light'> <meta name='color-scheme' content='dark light'>

View file

@ -14,4 +14,6 @@ utils/
client/ client/
protocol/ protocol/
utils/ utils/
common/ utils/isomorphic
server/utils
common/

View file

@ -16,7 +16,7 @@
import { PlaywrightServer } from './remote/playwrightServer'; import { PlaywrightServer } from './remote/playwrightServer';
import { createPlaywright } from './server/playwright'; import { createPlaywright } from './server/playwright';
import { createGuid } from './utils'; import { createGuid } from './server/utils/crypto';
import { ws } from './utilsBundle'; import { ws } from './utilsBundle';
import type { BrowserServer } from './client/browserType'; import type { BrowserServer } from './client/browserType';

View file

@ -20,7 +20,7 @@ import { PlaywrightServer } from './remote/playwrightServer';
import { helper } from './server/helper'; import { helper } from './server/helper';
import { serverSideCallMetadata } from './server/instrumentation'; import { serverSideCallMetadata } from './server/instrumentation';
import { createPlaywright } from './server/playwright'; import { createPlaywright } from './server/playwright';
import { createGuid } from './utils'; import { createGuid } from './server/utils/crypto';
import { rewriteErrorMessage } from './utils/stackTrace'; import { rewriteErrorMessage } from './utils/stackTrace';
import { ws } from './utilsBundle'; import { ws } from './utilsBundle';

View file

@ -19,7 +19,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as playwright from '../..'; import * as playwright from '../..';
import { PipeTransport } from '../protocol/transport'; import { PipeTransport } from '../utils/pipeTransport';
import { PlaywrightServer } from '../remote/playwrightServer'; import { PlaywrightServer } from '../remote/playwrightServer';
import { DispatcherConnection, PlaywrightDispatcher, RootDispatcher, createPlaywright } from '../server'; import { DispatcherConnection, PlaywrightDispatcher, RootDispatcher, createPlaywright } from '../server';
import { gracefullyProcessExitDoNotHang } from '../server/utils/processLauncher'; import { gracefullyProcessExitDoNotHang } from '../server/utils/processLauncher';

View file

@ -22,9 +22,9 @@ import { TargetClosedError, isTargetClosedError } from './errors';
import { Events } from './events'; import { Events } from './events';
import { Waiter } from './waiter'; import { Waiter } from './waiter';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { isRegExp, isString } from '../utils/rtti'; import { isRegExp, isString } from '../utils/isomorphic/rtti';
import { monotonicTime } from '../utils/time'; import { monotonicTime } from '../utils/isomorphic/time';
import { raceAgainstDeadline } from '../utils/timeoutRunner'; import { raceAgainstDeadline } from '../utils/isomorphic/timeoutRunner';
import type { Page } from './page'; import type { Page } from './page';
import type * as types from './types'; import type * as types from './types';

View file

@ -36,9 +36,9 @@ import { WebError } from './webError';
import { Worker } from './worker'; import { Worker } from './worker';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { mkdirIfNeeded } from '../utils/fileUtils'; import { mkdirIfNeeded } from '../utils/fileUtils';
import { headersObjectToArray } from '../utils/headers'; import { headersObjectToArray } from '../utils/isomorphic/headers';
import { urlMatchesEqual } from '../utils/isomorphic/urlMatch'; import { urlMatchesEqual } from '../utils/isomorphic/urlMatch';
import { isRegExp, isString } from '../utils/rtti'; import { isRegExp, isString } from '../utils/isomorphic/rtti';
import { rewriteErrorMessage } from '../utils/stackTrace'; import { rewriteErrorMessage } from '../utils/stackTrace';
import type { BrowserType } from './browserType'; import type { BrowserType } from './browserType';

View file

@ -22,9 +22,9 @@ import { ChannelOwner } from './channelOwner';
import { envObjectToArray } from './clientHelper'; import { envObjectToArray } from './clientHelper';
import { Events } from './events'; import { Events } from './events';
import { assert } from '../utils/debug'; import { assert } from '../utils/debug';
import { headersObjectToArray } from '../utils/headers'; import { headersObjectToArray } from '../utils/isomorphic/headers';
import { monotonicTime } from '../utils/time'; import { monotonicTime } from '../utils/isomorphic/time';
import { raceAgainstDeadline } from '../utils/timeoutRunner'; import { raceAgainstDeadline } from '../utils/isomorphic/timeoutRunner';
import type { Playwright } from './playwright'; import type { Playwright } from './playwright';
import type { ConnectOptions, LaunchOptions, LaunchPersistentContextOptions, LaunchServerOptions, Logger } from './types'; import type { ConnectOptions, LaunchOptions, LaunchPersistentContextOptions, LaunchServerOptions, Logger } from './types';
@ -100,7 +100,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs), ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
env: options.env ? envObjectToArray(options.env) : undefined, env: options.env ? envObjectToArray(options.env) : undefined,
channel: options.channel, channel: options.channel,
userDataDir: path.isAbsolute(userDataDir) ? userDataDir : path.resolve(userDataDir), userDataDir: (path.isAbsolute(userDataDir) || !userDataDir) ? userDataDir : path.resolve(userDataDir),
}; };
return await this._wrapApiCall(async () => { return await this._wrapApiCall(async () => {
const result = await this._channel.launchPersistentContext(persistentParams); const result = await this._channel.launchPersistentContext(persistentParams);

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { isString } from '../utils/rtti'; import { isString } from '../utils/isomorphic/rtti';
import type * as types from './types'; import type * as types from './types';
import type { Platform } from '../utils/platform'; import type { Platform } from '../utils/platform';

View file

@ -21,7 +21,7 @@ import { Frame } from './frame';
import { JSHandle, parseResult, serializeArgument } from './jsHandle'; import { JSHandle, parseResult, serializeArgument } from './jsHandle';
import { assert } from '../utils/debug'; import { assert } from '../utils/debug';
import { fileUploadSizeLimit, mkdirIfNeeded } from '../utils/fileUtils'; import { fileUploadSizeLimit, mkdirIfNeeded } from '../utils/fileUtils';
import { isString } from '../utils/rtti'; import { isString } from '../utils/isomorphic/rtti';
import { mime } from '../utilsBundle'; import { mime } from '../utilsBundle';
import { WritableStream } from './writableStream'; import { WritableStream } from './writableStream';

View file

@ -15,7 +15,7 @@
*/ */
import { parseSerializedValue, serializeValue } from '../protocol/serializers'; import { parseSerializedValue, serializeValue } from '../protocol/serializers';
import { isError } from '../utils/rtti'; import { isError } from '../utils/isomorphic/rtti';
import type { SerializedError } from '@protocol/channels'; import type { SerializedError } from '@protocol/channels';

View file

@ -21,8 +21,8 @@ import { RawHeaders } from './network';
import { Tracing } from './tracing'; import { Tracing } from './tracing';
import { assert } from '../utils/debug'; import { assert } from '../utils/debug';
import { mkdirIfNeeded } from '../utils/fileUtils'; import { mkdirIfNeeded } from '../utils/fileUtils';
import { headersObjectToArray } from '../utils/headers'; import { headersObjectToArray } from '../utils/isomorphic/headers';
import { isString } from '../utils/rtti'; import { isString } from '../utils/isomorphic/rtti';
import type { Playwright } from './playwright'; import type { Playwright } from './playwright';
import type { ClientCertificate, FilePayload, Headers, SetStorageState, StorageState } from './types'; import type { ClientCertificate, FilePayload, Headers, SetStorageState, StorageState } from './types';

View file

@ -51,7 +51,7 @@ export class LocalUtils extends ChannelOwner<channels.LocalUtilsChannel> {
} }
async harOpen(params: channels.LocalUtilsHarOpenParams): Promise<channels.LocalUtilsHarOpenResult> { async harOpen(params: channels.LocalUtilsHarOpenParams): Promise<channels.LocalUtilsHarOpenResult> {
return await localUtils.harOpen(this._harBackends, params); return await localUtils.harOpen(this._platform, this._harBackends, params);
} }
async harLookup(params: channels.LocalUtilsHarLookupParams): Promise<channels.LocalUtilsHarLookupResult> { async harLookup(params: channels.LocalUtilsHarLookupParams): Promise<channels.LocalUtilsHarLookupResult> {

View file

@ -19,8 +19,8 @@ import { parseResult, serializeArgument } from './jsHandle';
import { asLocator } from '../utils/isomorphic/locatorGenerators'; import { asLocator } from '../utils/isomorphic/locatorGenerators';
import { getByAltTextSelector, getByLabelSelector, getByPlaceholderSelector, getByRoleSelector, getByTestIdSelector, getByTextSelector, getByTitleSelector } from '../utils/isomorphic/locatorUtils'; import { getByAltTextSelector, getByLabelSelector, getByPlaceholderSelector, getByRoleSelector, getByTestIdSelector, getByTextSelector, getByTitleSelector } from '../utils/isomorphic/locatorUtils';
import { escapeForTextSelector } from '../utils/isomorphic/stringUtils'; import { escapeForTextSelector } from '../utils/isomorphic/stringUtils';
import { isString } from '../utils/rtti'; import { isString } from '../utils/isomorphic/rtti';
import { monotonicTime } from '../utils/time'; import { monotonicTime } from '../utils/isomorphic/time';
import type { Frame } from './frame'; import type { Frame } from './frame';
import type { FilePayload, FrameExpectParams, Rect, SelectOption, SelectOptionOptions, TimeoutOptions } from './types'; import type { FilePayload, FrameExpectParams, Rect, SelectOption, SelectOptionOptions, TimeoutOptions } from './types';

View file

@ -24,11 +24,11 @@ import { Frame } from './frame';
import { Waiter } from './waiter'; import { Waiter } from './waiter';
import { Worker } from './worker'; import { Worker } from './worker';
import { assert } from '../utils/debug'; import { assert } from '../utils/debug';
import { headersObjectToArray } from '../utils/headers'; import { headersObjectToArray } from '../utils/isomorphic/headers';
import { urlMatches } from '../utils/isomorphic/urlMatch'; import { urlMatches } from '../utils/isomorphic/urlMatch';
import { LongStandingScope, ManualPromise } from '../utils/manualPromise'; import { LongStandingScope, ManualPromise } from '../utils/isomorphic/manualPromise';
import { MultiMap } from '../utils/multimap'; import { MultiMap } from '../utils/isomorphic/multimap';
import { isRegExp, isString } from '../utils/rtti'; import { isRegExp, isString } from '../utils/isomorphic/rtti';
import { rewriteErrorMessage } from '../utils/stackTrace'; import { rewriteErrorMessage } from '../utils/stackTrace';
import { zones } from '../utils/zones'; import { zones } from '../utils/zones';
import { mime } from '../utilsBundle'; import { mime } from '../utilsBundle';

View file

@ -36,11 +36,11 @@ import { Worker } from './worker';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { assert } from '../utils/debug'; import { assert } from '../utils/debug';
import { mkdirIfNeeded } from '../utils/fileUtils'; import { mkdirIfNeeded } from '../utils/fileUtils';
import { headersObjectToArray } from '../utils/headers'; import { headersObjectToArray } from '../utils/isomorphic/headers';
import { trimStringWithEllipsis } from '../utils/isomorphic/stringUtils'; import { trimStringWithEllipsis } from '../utils/isomorphic/stringUtils';
import { urlMatches, urlMatchesEqual } from '../utils/isomorphic/urlMatch'; import { urlMatches, urlMatchesEqual } from '../utils/isomorphic/urlMatch';
import { LongStandingScope } from '../utils/manualPromise'; import { LongStandingScope } from '../utils/isomorphic/manualPromise';
import { isObject, isRegExp, isString } from '../utils/rtti'; import { isObject, isRegExp, isString } from '../utils/isomorphic/rtti';
import type { BrowserContext } from './browserContext'; import type { BrowserContext } from './browserContext';
import type { Clock } from './clock'; import type { Clock } from './clock';

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
import type { Artifact } from './artifact'; import type { Artifact } from './artifact';
import type { Connection } from './connection'; import type { Connection } from './connection';

View file

@ -15,7 +15,6 @@
*/ */
import { TimeoutError } from './errors'; import { TimeoutError } from './errors';
import { createGuid } from '../utils/crypto';
import { rewriteErrorMessage } from '../utils/stackTrace'; import { rewriteErrorMessage } from '../utils/stackTrace';
import { zones } from '../utils/zones'; import { zones } from '../utils/zones';
@ -35,7 +34,7 @@ export class Waiter {
private _savedZone: Zone; private _savedZone: Zone;
constructor(channelOwner: ChannelOwner<channels.EventTargetChannel>, event: string) { constructor(channelOwner: ChannelOwner<channels.EventTargetChannel>, event: string) {
this._waitId = createGuid(); this._waitId = channelOwner._platform.createGuid();
this._channelOwner = channelOwner; this._channelOwner = channelOwner;
this._savedZone = zones.current().without('apiZone'); this._savedZone = zones.current().without('apiZone');

View file

@ -18,7 +18,7 @@ import { ChannelOwner } from './channelOwner';
import { TargetClosedError } from './errors'; import { TargetClosedError } from './errors';
import { Events } from './events'; import { Events } from './events';
import { JSHandle, assertMaxArguments, parseResult, serializeArgument } from './jsHandle'; import { JSHandle, assertMaxArguments, parseResult, serializeArgument } from './jsHandle';
import { LongStandingScope } from '../utils/manualPromise'; import { LongStandingScope } from '../utils/isomorphic/manualPromise';
import type { BrowserContext } from './browserContext'; import type { BrowserContext } from './browserContext';
import type { Page } from './page'; import type { Page } from './page';

View file

@ -18,8 +18,8 @@ import * as childProcess from 'child_process';
import * as path from 'path'; import * as path from 'path';
import { Connection } from './client/connection'; import { Connection } from './client/connection';
import { PipeTransport } from './protocol/transport'; import { PipeTransport } from './utils/pipeTransport';
import { ManualPromise } from './utils/manualPromise'; import { ManualPromise } from './utils/isomorphic/manualPromise';
import { nodePlatform } from './utils/platform'; import { nodePlatform } from './utils/platform';
import type { Playwright } from './client/playwright'; import type { Playwright } from './client/playwright';

View file

@ -6,4 +6,5 @@
../server/dispatchers/ ../server/dispatchers/
../server/utils/ ../server/utils/
../utils/ ../utils/
../utils/isomorphic
../utilsBundle.ts ../utilsBundle.ts

View file

@ -17,7 +17,7 @@
import { PlaywrightConnection } from './playwrightConnection'; import { PlaywrightConnection } from './playwrightConnection';
import { createPlaywright } from '../server/playwright'; import { createPlaywright } from '../server/playwright';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { Semaphore } from '../utils/semaphore'; import { Semaphore } from '../utils/isomorphic/semaphore';
import { WSServer } from '../server/utils/wsServer'; import { WSServer } from '../server/utils/wsServer';
import { wrapInASCIIBox } from '../server/utils/ascii'; import { wrapInASCIIBox } from '../server/utils/ascii';
import { getPlaywrightVersion } from '../utils/userAgent'; import { getPlaywrightVersion } from '../utils/userAgent';

View file

@ -20,8 +20,11 @@ import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { TimeoutSettings } from '../../common/timeoutSettings'; import { TimeoutSettings } from '../../common/timeoutSettings';
import { PipeTransport } from '../../protocol/transport'; import { PipeTransport } from '../../utils/pipeTransport';
import { createGuid, getPackageManagerExecCommand, isUnderTest, makeWaitForNextTask } from '../../utils'; import { createGuid } from '../utils/crypto';
import { isUnderTest } from '../../utils/debug';
import { getPackageManagerExecCommand } from '../../utils/env';
import { makeWaitForNextTask } from '../../utils/task';
import { RecentLogsCollector } from '../../utils/debugLogger'; import { RecentLogsCollector } from '../../utils/debugLogger';
import { debug } from '../../utilsBundle'; import { debug } from '../../utilsBundle';
import { wsReceiver, wsSender } from '../../utilsBundle'; import { wsReceiver, wsSender } from '../../utilsBundle';

View file

@ -17,7 +17,8 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import * as net from 'net'; import * as net from 'net';
import { assert, createGuid } from '../../utils'; import { assert } from '../../utils/debug';
import { createGuid } from '../utils/crypto';
import { debug } from '../../utilsBundle'; import { debug } from '../../utilsBundle';
import type { Backend, DeviceBackend, SocketBackend } from './android'; import type { Backend, DeviceBackend, SocketBackend } from './android';

View file

@ -19,7 +19,7 @@ import * as fs from 'fs';
import { assert } from '../utils'; import { assert } from '../utils';
import { TargetClosedError } from './errors'; import { TargetClosedError } from './errors';
import { SdkObject } from './instrumentation'; import { SdkObject } from './instrumentation';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
type SaveCallback = (localPath: string, error?: Error) => Promise<void>; type SaveCallback = (localPath: string, error?: Error) => Promise<void>;
type CancelCallback = () => Promise<void>; type CancelCallback = () => Promise<void>;

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { Browser } from '../browser'; import { Browser } from '../browser';
import { BrowserContext, assertBrowserContextIsNotOwned } from '../browserContext'; import { BrowserContext, assertBrowserContextIsNotOwned } from '../browserContext';
import * as network from '../network'; import * as network from '../network';
@ -23,7 +23,7 @@ import { bidiBytesValueToString } from './bidiNetworkManager';
import { BidiPage } from './bidiPage'; import { BidiPage } from './bidiPage';
import * as bidi from './third_party/bidiProtocol'; import * as bidi from './third_party/bidiProtocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { BrowserOptions } from '../browser'; import type { BrowserOptions } from '../browser';
import type { SdkObject } from '../instrumentation'; import type { SdkObject } from '../instrumentation';
import type { InitScript, Page } from '../page'; import type { InitScript, Page } from '../page';

View file

@ -79,6 +79,9 @@ export class RawMouseImpl implements input.RawMouse {
} }
async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, forClick: boolean): Promise<void> { async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, forClick: boolean): Promise<void> {
// Bidi throws when x/y are not integers.
x = Math.floor(x);
y = Math.floor(y);
await this._performActions([{ type: 'pointerMove', x, y }]); await this._performActions([{ type: 'pointerMove', x, y }]);
} }
@ -91,6 +94,9 @@ export class RawMouseImpl implements input.RawMouse {
} }
async wheel(x: number, y: number, buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, deltaX: number, deltaY: number): Promise<void> { async wheel(x: number, y: number, buttons: Set<types.MouseButton>, modifiers: Set<types.KeyboardModifier>, deltaX: number, deltaY: number): Promise<void> {
// Bidi throws when x/y are not integers.
x = Math.floor(x);
y = Math.floor(y);
await this._session.send('input.performActions', { await this._session.send('input.performActions', {
context: this._session.sessionId, context: this._session.sessionId,
actions: [ actions: [

View file

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { parseRawCookie } from '../cookieStore'; import { parseRawCookie } from '../cookieStore';
import * as network from '../network'; import * as network from '../network';
import * as bidi from './third_party/bidiProtocol'; import * as bidi from './third_party/bidiProtocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { Page } from '../page'; import type { Page } from '../page';
import type * as types from '../types'; import type * as types from '../types';

View file

@ -15,7 +15,7 @@
*/ */
import { assert } from '../../utils'; import { assert } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { BrowserContext } from '../browserContext'; import { BrowserContext } from '../browserContext';
import * as dialog from '../dialog'; import * as dialog from '../dialog';
import * as dom from '../dom'; import * as dom from '../dom';
@ -26,7 +26,7 @@ import { BidiNetworkManager } from './bidiNetworkManager';
import { BidiPDF } from './bidiPdf'; import { BidiPDF } from './bidiPdf';
import * as bidi from './third_party/bidiProtocol'; import * as bidi from './third_party/bidiProtocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as accessibility from '../accessibility'; import type * as accessibility from '../accessibility';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { InitScript, PageDelegate } from '../page'; import type { InitScript, PageDelegate } from '../page';
@ -423,7 +423,22 @@ export class BidiPage implements PageDelegate {
} }
async getOwnerFrame(handle: dom.ElementHandle): Promise<string | null> { async getOwnerFrame(handle: dom.ElementHandle): Promise<string | null> {
throw new Error('Method not implemented.'); // TODO: switch to utility world?
const windowHandle = await handle.evaluateHandle(node => {
const doc = node.ownerDocument ?? node as Document;
return doc.defaultView;
});
if (!windowHandle)
return null;
if (!windowHandle._objectId)
return null;
const executionContext = toBidiExecutionContext(windowHandle._context as dom.FrameExecutionContext);
const contentWindow = await executionContext.rawCallFunction('e => e', { handle: windowHandle._objectId });
if (contentWindow.type === 'window') {
const frameId = contentWindow.value.context;
return frameId;
}
return null;
} }
isElementHandle(remoteObject: bidi.Script.RemoteValue): boolean { isElementHandle(remoteObject: bidi.Script.RemoteValue): boolean {
@ -515,11 +530,21 @@ export class BidiPage implements PageDelegate {
} }
async setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void> { async setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void> {
throw new Error('Method not implemented.'); throw new Error('Setting FilePayloads is not supported in Bidi.');
} }
async setInputFilePaths(handle: dom.ElementHandle<HTMLInputElement>, paths: string[]): Promise<void> { async setInputFilePaths(handle: dom.ElementHandle<HTMLInputElement>, paths: string[]): Promise<void> {
throw new Error('Method not implemented.'); const fromContext = toBidiExecutionContext(handle._context);
const shared = await fromContext.rawCallFunction('x => x', { handle: handle._objectId });
// TODO: store sharedId in the handle.
if (!('sharedId' in shared))
throw new Error('Element is not a node');
const sharedId = shared.sharedId!;
await this._session.send('input.setFiles', {
context: this._session.sessionId,
element: { sharedId },
files: paths,
});
} }
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> { async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {

View file

@ -19,7 +19,8 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { createGuid, debugMode } from '../utils'; import { createGuid } from './utils/crypto';
import { debugMode } from '../utils/debug';
import { Clock } from './clock'; import { Clock } from './clock';
import { Debugger } from './debugger'; import { Debugger } from './debugger';
import { BrowserContextAPIRequestContext } from './fetch'; import { BrowserContextAPIRequestContext } from './fetch';

View file

@ -26,7 +26,7 @@ import { TimeoutSettings } from '../../common/timeoutSettings';
import { debugMode, headersArrayToObject, headersObjectToArray, } from '../../utils'; import { debugMode, headersArrayToObject, headersObjectToArray, } from '../../utils';
import { wrapInASCIIBox } from '../utils/ascii'; import { wrapInASCIIBox } from '../utils/ascii';
import { RecentLogsCollector } from '../../utils/debugLogger'; import { RecentLogsCollector } from '../../utils/debugLogger';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { fetchData } from '../utils/network'; import { fetchData } from '../utils/network';
import { getUserAgent } from '../../utils/userAgent'; import { getUserAgent } from '../../utils/userAgent';
import { validateBrowserContextOptions } from '../browserContext'; import { validateBrowserContextOptions } from '../browserContext';

View file

@ -37,11 +37,10 @@ export const chromiumSwitches = [
// PaintHolding - https://github.com/microsoft/playwright/issues/28023 // PaintHolding - https://github.com/microsoft/playwright/issues/28023
// ThirdPartyStoragePartitioning - https://github.com/microsoft/playwright/issues/32230 // ThirdPartyStoragePartitioning - https://github.com/microsoft/playwright/issues/32230
// LensOverlay - Hides the Lens feature in the URL address bar. Its not working in unofficial builds. // LensOverlay - Hides the Lens feature in the URL address bar. Its not working in unofficial builds.
// PlzDedicatedWorker - https://github.com/microsoft/playwright/issues/31747
// DeferRendererTasksAfterInput - this makes Page.frameScheduledNavigation arrive much later after a click, // DeferRendererTasksAfterInput - this makes Page.frameScheduledNavigation arrive much later after a click,
// making our navigation auto-wait after click not working. Can be removed once we deperecate noWaitAfter. // making our navigation auto-wait after click not working. Can be removed once we deperecate noWaitAfter.
// See https://github.com/microsoft/playwright/pull/34372. // See https://github.com/microsoft/playwright/pull/34372.
'--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,HttpsUpgrades,PaintHolding,ThirdPartyStoragePartitioning,LensOverlay,PlzDedicatedWorker,DeferRendererTasksAfterInput', '--disable-features=ImprovedCookieControls,LazyFrameLoading,GlobalMediaControls,DestroyProfileOnBrowserClose,MediaRouter,DialMediaRouteProvider,AcceptCHFrame,AutoExpandDetailsElement,CertificateTransparencyComponentUpdater,AvoidUnnecessaryBeforeUnloadCheckSync,Translate,HttpsUpgrades,PaintHolding,ThirdPartyStoragePartitioning,LensOverlay,DeferRendererTasksAfterInput',
'--allow-pre-commit-input', '--allow-pre-commit-input',
'--disable-hang-monitor', '--disable-hang-monitor',
'--disable-ipc-flooding-protection', '--disable-ipc-flooding-protection',

View file

@ -17,7 +17,8 @@
import * as path from 'path'; import * as path from 'path';
import { assert, createGuid } from '../../utils'; import { assert } from '../../utils/debug';
import { createGuid } from '../utils/crypto';
import { Artifact } from '../artifact'; import { Artifact } from '../artifact';
import { Browser } from '../browser'; import { Browser } from '../browser';
import { BrowserContext, assertBrowserContextIsNotOwned, verifyGeolocation } from '../browserContext'; import { BrowserContext, assertBrowserContextIsNotOwned, verifyGeolocation } from '../browserContext';

View file

@ -16,11 +16,11 @@
*/ */
import { assert } from '../../utils'; import { assert } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import type { CRSession } from './crConnection'; import type { CRSession } from './crConnection';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -16,14 +16,14 @@
*/ */
import { assert, headersArrayToObject, headersObjectToArray } from '../../utils'; import { assert, headersArrayToObject, headersObjectToArray } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { helper } from '../helper'; import { helper } from '../helper';
import * as network from '../network'; import * as network from '../network';
import { isProtocolError, isSessionClosedError } from '../protocolError'; import { isProtocolError, isSessionClosedError } from '../protocolError';
import type { CRSession } from './crConnection'; import type { CRSession } from './crConnection';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as contexts from '../browserContext'; import type * as contexts from '../browserContext';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { Page } from '../page'; import type { Page } from '../page';

View file

@ -17,8 +17,9 @@
import * as path from 'path'; import * as path from 'path';
import { assert, createGuid } from '../../utils'; import { assert } from '../../utils/debug';
import { eventsHelper } from '../../utils/eventsHelper'; import { createGuid } from '../utils/crypto';
import { eventsHelper } from '../utils/eventsHelper';
import { rewriteErrorMessage } from '../../utils/stackTrace'; import { rewriteErrorMessage } from '../../utils/stackTrace';
import * as dialog from '../dialog'; import * as dialog from '../dialog';
import * as dom from '../dom'; import * as dom from '../dom';
@ -45,7 +46,7 @@ import { isSessionClosedError } from '../protocolError';
import type { CRSession } from './crConnection'; import type { CRSession } from './crConnection';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { InitScript, PageDelegate } from '../page'; import type { InitScript, PageDelegate } from '../page';
import type { Progress } from '../progress'; import type { Progress } from '../progress';
import type * as types from '../types'; import type * as types from '../types';

View file

@ -31,7 +31,8 @@ import { Recorder } from '../recorder';
import { TracingDispatcher } from './tracingDispatcher'; import { TracingDispatcher } from './tracingDispatcher';
import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher'; import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher';
import { WritableStreamDispatcher } from './writableStreamDispatcher'; import { WritableStreamDispatcher } from './writableStreamDispatcher';
import { createGuid, urlMatches } from '../../utils'; import { createGuid } from '../utils/crypto';
import { urlMatches } from '../../utils/isomorphic/urlMatch';
import { RecorderApp } from '../recorder/recorderApp'; import { RecorderApp } from '../recorder/recorderApp';
import type { Artifact } from '../artifact'; import type { Artifact } from '../artifact';

View file

@ -19,7 +19,7 @@ import { DebugController } from '../debugController';
import { Dispatcher } from './dispatcher'; import { Dispatcher } from './dispatcher';
import type { DispatcherConnection, RootDispatcher } from './dispatcher'; import type { DispatcherConnection, RootDispatcher } from './dispatcher';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -16,7 +16,7 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { eventsHelper } from '../..//utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { ValidationError, createMetadataValidator, findValidator } from '../../protocol/validator'; import { ValidationError, createMetadataValidator, findValidator } from '../../protocol/validator';
import { LongStandingScope, assert, compressCallLog, 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';
@ -25,7 +25,7 @@ import { isProtocolError } from '../protocolError';
import type { CallMetadata } from '../instrumentation'; import type { CallMetadata } from '../instrumentation';
import type { PlaywrightDispatcher } from './playwrightDispatcher'; import type { PlaywrightDispatcher } from './playwrightDispatcher';
import type { RegisteredListener } from '../..//utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { ValidatorContext } from '../../protocol/validator'; import type { ValidatorContext } from '../../protocol/validator';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -15,7 +15,7 @@
*/ */
import { Dispatcher } from './dispatcher'; import { Dispatcher } from './dispatcher';
import { createGuid } from '../../utils'; import { createGuid } from '../utils/crypto';
import type { LocalUtilsDispatcher } from './localUtilsDispatcher'; import type { LocalUtilsDispatcher } from './localUtilsDispatcher';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -54,7 +54,7 @@ export class LocalUtilsDispatcher extends Dispatcher<{ guid: string }, channels.
} }
async harOpen(params: channels.LocalUtilsHarOpenParams, metadata: CallMetadata): Promise<channels.LocalUtilsHarOpenResult> { async harOpen(params: channels.LocalUtilsHarOpenParams, metadata: CallMetadata): Promise<channels.LocalUtilsHarOpenResult> {
return await localUtils.harOpen(this._harBackends, params); return await localUtils.harOpen(nodePlatform, this._harBackends, params);
} }
async harLookup(params: channels.LocalUtilsHarLookupParams, metadata: CallMetadata): Promise<channels.LocalUtilsHarLookupResult> { async harLookup(params: channels.LocalUtilsHarLookupParams, metadata: CallMetadata): Promise<channels.LocalUtilsHarLookupResult> {

View file

@ -25,7 +25,8 @@ import { RequestDispatcher } from './networkDispatchers';
import { ResponseDispatcher } from './networkDispatchers'; import { ResponseDispatcher } from './networkDispatchers';
import { RouteDispatcher, WebSocketDispatcher } from './networkDispatchers'; import { RouteDispatcher, WebSocketDispatcher } from './networkDispatchers';
import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher'; import { WebSocketRouteDispatcher } from './webSocketRouteDispatcher';
import { createGuid, urlMatches } from '../../utils'; import { createGuid } from '../utils/crypto';
import { urlMatches } from '../../utils/isomorphic/urlMatch';
import type { Artifact } from '../artifact'; import type { Artifact } from '../artifact';
import type { BrowserContext } from '../browserContext'; import type { BrowserContext } from '../browserContext';

View file

@ -25,12 +25,12 @@ import { ElectronDispatcher } from './electronDispatcher';
import { LocalUtilsDispatcher } from './localUtilsDispatcher'; import { LocalUtilsDispatcher } from './localUtilsDispatcher';
import { APIRequestContextDispatcher } from './networkDispatchers'; import { APIRequestContextDispatcher } from './networkDispatchers';
import { SelectorsDispatcher } from './selectorsDispatcher'; import { SelectorsDispatcher } from './selectorsDispatcher';
import { createGuid } from '../../utils'; import { createGuid } from '../utils/crypto';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import type { RootDispatcher } from './dispatcher'; import type { RootDispatcher } from './dispatcher';
import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../utils/socksProxy'; import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../utils/socksProxy';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { AndroidDevice } from '../android/android'; import type { AndroidDevice } from '../android/android';
import type { Browser } from '../browser'; import type { Browser } from '../browser';
import type { Playwright } from '../playwright'; import type { Playwright } from '../playwright';

View file

@ -15,7 +15,8 @@
*/ */
import { Dispatcher } from './dispatcher'; import { Dispatcher } from './dispatcher';
import { ManualPromise, createGuid } from '../../utils'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { createGuid } from '../utils/crypto';
import type { ArtifactDispatcher } from './artifactDispatcher'; import type { ArtifactDispatcher } from './artifactDispatcher';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -18,8 +18,9 @@ import { Page } from '../page';
import { Dispatcher, existingDispatcher } from './dispatcher'; import { Dispatcher, existingDispatcher } from './dispatcher';
import { PageDispatcher } from './pageDispatcher'; import { PageDispatcher } from './pageDispatcher';
import * as webSocketMockSource from '../../generated/webSocketMockSource'; import * as webSocketMockSource from '../../generated/webSocketMockSource';
import { createGuid, urlMatches } from '../../utils'; import { createGuid } from '../utils/crypto';
import { eventsHelper } from '../../utils/eventsHelper'; import { urlMatches } from '../../utils/isomorphic/urlMatch';
import { eventsHelper } from '../utils/eventsHelper';
import type { BrowserContextDispatcher } from './browserContextDispatcher'; import type { BrowserContextDispatcher } from './browserContextDispatcher';
import type { BrowserContext } from '../browserContext'; import type { BrowserContext } from '../browserContext';

View file

@ -17,7 +17,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
import { Dispatcher } from './dispatcher'; import { Dispatcher } from './dispatcher';
import { createGuid } from '../../utils'; import { createGuid } from '../utils/crypto';
import type { BrowserContextDispatcher } from './browserContextDispatcher'; import type { BrowserContextDispatcher } from './browserContextDispatcher';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -23,7 +23,7 @@ import { TimeoutSettings } from '../../common/timeoutSettings';
import { ManualPromise } from '../../utils'; import { ManualPromise } from '../../utils';
import { wrapInASCIIBox } from '../utils/ascii'; import { wrapInASCIIBox } from '../utils/ascii';
import { RecentLogsCollector } from '../../utils/debugLogger'; import { RecentLogsCollector } from '../../utils/debugLogger';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { validateBrowserContextOptions } from '../browserContext'; import { validateBrowserContextOptions } from '../browserContext';
import { CRBrowser } from '../chromium/crBrowser'; import { CRBrowser } from '../chromium/crBrowser';
import { CRConnection } from '../chromium/crConnection'; import { CRConnection } from '../chromium/crConnection';

View file

@ -22,7 +22,8 @@ import * as url from 'url';
import * as zlib from 'zlib'; import * as zlib from 'zlib';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { assert, constructURLBasedOnBaseURL, createGuid, eventsHelper, monotonicTime } from '../utils'; import { assert, constructURLBasedOnBaseURL, eventsHelper, monotonicTime } from '../utils';
import { createGuid } from './utils/crypto';
import { getUserAgent } from '../utils/userAgent'; import { getUserAgent } from '../utils/userAgent';
import { HttpsProxyAgent, SocksProxyAgent } from '../utilsBundle'; import { HttpsProxyAgent, SocksProxyAgent } from '../utilsBundle';
import { BrowserContext, verifyClientCertificates } from './browserContext'; import { BrowserContext, verifyClientCertificates } from './browserContext';

View file

@ -15,12 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import * as network from '../network'; import * as network from '../network';
import type { FFSession } from './ffConnection'; import type { FFSession } from './ffConnection';
import type { HeadersArray } from '../../server/types'; import type { HeadersArray } from '../../server/types';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { Page } from '../page'; import type { Page } from '../page';
import type * as types from '../types'; import type * as types from '../types';

View file

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import * as dialog from '../dialog'; import * as dialog from '../dialog';
import * as dom from '../dom'; import * as dom from '../dom';
import { InitScript } from '../page'; import { InitScript } from '../page';
@ -33,7 +33,7 @@ import { TargetClosedError } from '../errors';
import type { Progress } from '../progress'; import type { Progress } from '../progress';
import type { FFBrowserContext } from './ffBrowser'; import type { FFBrowserContext } from './ffBrowser';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { PageDelegate } from '../page'; import type { PageDelegate } from '../page';
import type * as types from '../types'; import type * as types from '../types';

View file

@ -30,9 +30,9 @@ import * as types from './types';
import { LongStandingScope, asLocator, assert, compressCallLog, constructURLBasedOnBaseURL, makeWaitForNextTask, monotonicTime } from '../utils'; import { LongStandingScope, asLocator, assert, compressCallLog, constructURLBasedOnBaseURL, makeWaitForNextTask, monotonicTime } from '../utils';
import { isSessionClosedError } from './protocolError'; import { isSessionClosedError } from './protocolError';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { eventsHelper } from '../utils/eventsHelper'; import { eventsHelper } from './utils/eventsHelper';
import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser'; import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
import type { ConsoleMessage } from './console'; import type { ConsoleMessage } from './console';
import type { Dialog } from './dialog'; import type { Dialog } from './dialog';
@ -40,7 +40,7 @@ import type { ElementStateWithoutStable, FrameExpectParams, InjectedScript } fro
import type { CallMetadata } from './instrumentation'; import type { CallMetadata } from './instrumentation';
import type { Progress } from './progress'; import type { Progress } from './progress';
import type { ScreenshotOptions } from './screenshotter'; import type { ScreenshotOptions } from './screenshotter';
import type { RegisteredListener } from '../utils/eventsHelper'; import type { RegisteredListener } from './utils/eventsHelper';
import type { ParsedSelector } from '../utils/isomorphic/selectorParser'; import type { ParsedSelector } from '../utils/isomorphic/selectorParser';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';

View file

@ -19,8 +19,8 @@ import * as path from 'path';
import { Artifact } from '../artifact'; import { Artifact } from '../artifact';
import { HarTracer } from './harTracer'; import { HarTracer } from './harTracer';
import { createGuid } from '../../utils'; import { createGuid } from '../utils/crypto';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { yazl } from '../../zipBundle'; import { yazl } from '../../zipBundle';
import type { BrowserContext } from '../browserContext'; import type { BrowserContext } from '../browserContext';

View file

@ -16,8 +16,8 @@
import { assert, calculateSha1, monotonicTime } from '../../utils'; import { assert, calculateSha1, monotonicTime } from '../../utils';
import { getPlaywrightVersion, isTextualMimeType, urlMatches } from '../../utils'; import { getPlaywrightVersion, isTextualMimeType, urlMatches } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { mime } from '../../utilsBundle'; import { mime } from '../../utilsBundle';
import { BrowserContext } from '../browserContext'; import { BrowserContext } from '../browserContext';
import { APIRequestContext } from '../fetch'; import { APIRequestContext } from '../fetch';
@ -25,7 +25,7 @@ import { Frame } from '../frames';
import { helper } from '../helper'; import { helper } from '../helper';
import * as network from '../network'; import * as network from '../network';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { APIRequestEvent, APIRequestFinishedEvent } from '../fetch'; import type { APIRequestEvent, APIRequestFinishedEvent } from '../fetch';
import type { Page } from '../page'; import type { Page } from '../page';
import type { Worker } from '../page'; import type { Worker } from '../page';

View file

@ -16,11 +16,11 @@
*/ */
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { eventsHelper } from '../utils/eventsHelper'; import { eventsHelper } from './utils/eventsHelper';
import type { Progress } from './progress'; import type { Progress } from './progress';
import type * as types from './types'; import type * as types from './types';
import type { RegisteredListener } from '../utils/eventsHelper'; import type { RegisteredListener } from './utils/eventsHelper';
import type { EventEmitter } from 'events'; import type { EventEmitter } from 'events';

View file

@ -16,7 +16,7 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { createGuid } from '../utils'; import { createGuid } from './utils/crypto';
import type { Browser } from './browser'; import type { Browser } from './browser';
import type { BrowserContext } from './browserContext'; import type { BrowserContext } from './browserContext';

View file

@ -18,7 +18,7 @@ import { SdkObject } from './instrumentation';
import * as utilityScriptSource from '../generated/utilityScriptSource'; import * as utilityScriptSource from '../generated/utilityScriptSource';
import { isUnderTest } from '../utils'; import { isUnderTest } from '../utils';
import { serializeAsCallArgument } from './isomorphic/utilityScriptSerializers'; import { serializeAsCallArgument } from './isomorphic/utilityScriptSerializers';
import { LongStandingScope } from '../utils/manualPromise'; import { LongStandingScope } from '../utils/isomorphic/manualPromise';
import type * as dom from './dom'; import type * as dom from './dom';
import type { UtilityScript } from './injected/utilityScript'; import type { UtilityScript } from './injected/utilityScript';

View file

@ -18,7 +18,7 @@ import { assert } from '../utils';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import { APIRequestContext } from './fetch'; import { APIRequestContext } from './fetch';
import { SdkObject } from './instrumentation'; import { SdkObject } from './instrumentation';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
import type * as contexts from './browserContext'; import type * as contexts from './browserContext';
import type * as frames from './frames'; import type * as frames from './frames';

View file

@ -29,12 +29,13 @@ import * as js from './javascript';
import { ProgressController } from './progress'; import { ProgressController } from './progress';
import { Screenshotter, validateScreenshotOptions } from './screenshotter'; import { Screenshotter, validateScreenshotOptions } from './screenshotter';
import { TimeoutSettings } from '../common/timeoutSettings'; import { TimeoutSettings } from '../common/timeoutSettings';
import { LongStandingScope, assert, compressCallLog, createGuid, trimStringWithEllipsis } from '../utils'; import { LongStandingScope, assert, compressCallLog, trimStringWithEllipsis } from '../utils';
import { createGuid } from './utils/crypto';
import { asLocator } from '../utils'; import { asLocator } from '../utils';
import { getComparator } from './utils/comparators'; import { getComparator } from './utils/comparators';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser'; import { isInvalidSelectorError } from '../utils/isomorphic/selectorParser';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
import type { Artifact } from './artifact'; import type { Artifact } from './artifact';
import type * as dom from './dom'; import type * as dom from './dom';

View file

@ -16,7 +16,7 @@
import { TimeoutError } from './errors'; import { TimeoutError } from './errors';
import { assert, monotonicTime } from '../utils'; import { assert, monotonicTime } from '../utils';
import { ManualPromise } from '../utils/manualPromise'; import { ManualPromise } from '../utils/isomorphic/manualPromise';
import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation'; import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation';
import type { Progress as CommonProgress } from '../common/progress'; import type { Progress as CommonProgress } from '../common/progress';

View file

@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
import { RecorderCollection } from './recorderCollection'; import { RecorderCollection } from './recorderCollection';
import * as recorderSource from '../../generated/pollingRecorderSource'; import * as recorderSource from '../../generated/pollingRecorderSource';
import { eventsHelper, monotonicTime, quoteCSSAttributeValue } from '../../utils'; import { eventsHelper, monotonicTime, quoteCSSAttributeValue } from '../../utils';
import { raceAgainstDeadline } from '../../utils/timeoutRunner'; import { raceAgainstDeadline } from '../../utils/isomorphic/timeoutRunner';
import { BrowserContext } from '../browserContext'; import { BrowserContext } from '../browserContext';
import { languageSet } from '../codegen/languages'; import { languageSet } from '../codegen/languages';
import { Frame } from '../frames'; import { Frame } from '../frames';

View file

@ -19,7 +19,7 @@ import { EventEmitter } from 'events';
import { performAction } from './recorderRunner'; import { performAction } from './recorderRunner';
import { collapseActions } from './recorderUtils'; import { collapseActions } from './recorderUtils';
import { isUnderTest } from '../../utils/debug'; import { isUnderTest } from '../../utils/debug';
import { monotonicTime } from '../../utils/time'; import { monotonicTime } from '../../utils/isomorphic/time';
import type { Signal } from '../../../../recorder/src/actions'; import type { Signal } from '../../../../recorder/src/actions';
import type { Frame } from '../frames'; import type { Frame } from '../frames';

View file

@ -21,7 +21,7 @@ import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import { debugLogger } from '../../utils/debugLogger'; import { debugLogger } from '../../utils/debugLogger';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { getUserAgent } from '../../utils/userAgent'; import { getUserAgent } from '../../utils/userAgent';
import { colors, progress as ProgressBar } from '../../utilsBundle'; import { colors, progress as ProgressBar } from '../../utilsBundle';
import { existsAsync } from '../utils/fileUtils'; import { existsAsync } from '../utils/fileUtils';

View file

@ -17,7 +17,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { httpRequest } from '../utils/network'; import { httpRequest } from '../utils/network';
import { extract } from '../../zipBundle'; import { extract } from '../../zipBundle';

View file

@ -17,7 +17,7 @@
import { helper } from './helper'; import { helper } from './helper';
import { assert } from '../utils'; import { assert } from '../utils';
import { MultiMap } from '../utils/multimap'; import { MultiMap } from '../utils/isomorphic/multimap';
import type * as dom from './dom'; import type * as dom from './dom';
import type { Frame } from './frames'; import type { Frame } from './frames';

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { createGuid } from '../utils'; import { createGuid } from './utils/crypto';
import { InvalidSelectorError, parseSelector, stringifySelector, visitAllSelectorParts } from '../utils/isomorphic/selectorParser'; import { InvalidSelectorError, parseSelector, stringifySelector, visitAllSelectorParts } from '../utils/isomorphic/selectorParser';
import type { ParsedSelector } from '../utils/isomorphic/selectorParser'; import type { ParsedSelector } from '../utils/isomorphic/selectorParser';

View file

@ -5,6 +5,7 @@
../../../protocol/ ../../../protocol/
../../../utils/ ../../../utils/
../../../utilsBundle.ts ../../../utilsBundle.ts
../../../utils/isomorphic/
../../../zipBundle.ts ../../../zipBundle.ts
../../dispatchers/dispatcher.ts ../../dispatchers/dispatcher.ts
../../utils ../../utils

View file

@ -15,15 +15,16 @@
*/ */
import { frameSnapshotStreamer } from './snapshotterInjected'; import { frameSnapshotStreamer } from './snapshotterInjected';
import { calculateSha1, createGuid, monotonicTime } from '../../../utils'; import { monotonicTime } from '../../../utils/isomorphic/time';
import { calculateSha1, createGuid } from '../../utils/crypto';
import { debugLogger } from '../../../utils/debugLogger'; import { debugLogger } from '../../../utils/debugLogger';
import { eventsHelper } from '../../../utils/eventsHelper'; import { eventsHelper } from '../../utils/eventsHelper';
import { mime } from '../../../utilsBundle'; import { mime } from '../../../utilsBundle';
import { BrowserContext } from '../../browserContext'; import { BrowserContext } from '../../browserContext';
import { Page } from '../../page'; import { Page } from '../../page';
import type { SnapshotData } from './snapshotterInjected'; import type { SnapshotData } from './snapshotterInjected';
import type { RegisteredListener } from '../../../utils/eventsHelper'; import type { RegisteredListener } from '../../utils/eventsHelper';
import type { Frame } from '../../frames'; import type { Frame } from '../../frames';
import type { FrameSnapshot } from '@trace/snapshot'; import type { FrameSnapshot } from '@trace/snapshot';

View file

@ -20,7 +20,10 @@ import * as path from 'path';
import { Snapshotter } from './snapshotter'; import { Snapshotter } from './snapshotter';
import { commandsWithTracingSnapshots } from '../../../protocol/debug'; import { commandsWithTracingSnapshots } from '../../../protocol/debug';
import { assert, createGuid, eventsHelper, monotonicTime } from '../../../utils'; import { assert } from '../../../utils/debug';
import { monotonicTime } from '../../../utils/isomorphic/time';
import { eventsHelper } from '../../utils/eventsHelper';
import { createGuid } from '../../utils/crypto';
import { Artifact } from '../../artifact'; import { Artifact } from '../../artifact';
import { BrowserContext } from '../../browserContext'; import { BrowserContext } from '../../browserContext';
import { Dispatcher } from '../../dispatchers/dispatcher'; import { Dispatcher } from '../../dispatchers/dispatcher';

View file

@ -1,9 +1,9 @@
[*] [*]
../../utils ../../utils
../../utils/isomorphic
../../utilsBundle.ts ../../utilsBundle.ts
../../zipBundle.ts ../../zipBundle.ts
[comparators.ts] [comparators.ts]
./image_tools ./image_tools
../../third_party/pixelmatch ../../third_party/pixelmatch

View file

@ -16,7 +16,7 @@
import * as crypto from 'crypto'; import * as crypto from 'crypto';
import { assert } from './debug'; import { assert } from '../../utils/debug';
export function createGuid(): string { export function createGuid(): string {
return crypto.randomBytes(16).toString('hex'); return crypto.randomBytes(16).toString('hex');

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { isRegExp, isString } from './rtti'; import { isRegExp, isString } from '../../utils/isomorphic/rtti';
import type { ExpectedTextValue } from '@protocol/channels'; import type { ExpectedTextValue } from '@protocol/channels';

View file

@ -17,7 +17,7 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { yazl } from '../../zipBundle'; import { yazl } from '../../zipBundle';
import type { EventEmitter } from 'events'; import type { EventEmitter } from 'events';

View file

@ -21,8 +21,8 @@ import * as net from 'net';
import * as tls from 'tls'; import * as tls from 'tls';
import { assert } from '../../utils/debug'; import { assert } from '../../utils/debug';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { monotonicTime } from '../../utils/time'; import { monotonicTime } from '../../utils/isomorphic/time';
// Implementation(partial) of Happy Eyeballs 2 algorithm described in // Implementation(partial) of Happy Eyeballs 2 algorithm described in
// https://www.rfc-editor.org/rfc/rfc8305 // https://www.rfc-editor.org/rfc/rfc8305

View file

@ -18,9 +18,9 @@ import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { mime, wsServer } from '../../utilsBundle'; import { mime, wsServer } from '../../utilsBundle';
import { createGuid } from '../../utils/crypto'; import { createGuid } from './crypto';
import { assert } from '../../utils/debug'; import { assert } from '../../utils/debug';
import { ManualPromise } from '../../utils/manualPromise'; import { ManualPromise } from '../../utils/isomorphic/manualPromise';
import { createHttpServer } from './network'; import { createHttpServer } from './network';
import type http from 'http'; import type http from 'http';

View file

@ -17,7 +17,8 @@
import EventEmitter from 'events'; import EventEmitter from 'events';
import * as net from 'net'; import * as net from 'net';
import { assert, createGuid, } from '../../utils'; import { assert } from '../../utils/debug';
import { createGuid } from './crypto';
import { debugLogger } from '../../utils/debugLogger'; import { debugLogger } from '../../utils/debugLogger';
import { createSocket } from './happyEyeballs'; import { createSocket } from './happyEyeballs';

View file

@ -17,8 +17,10 @@
import * as path from 'path'; import * as path from 'path';
import { assert, createGuid, debugAssert, headersArrayToObject } from '../../utils'; import { assert, debugAssert } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { headersArrayToObject } from '../../utils/isomorphic/headers';
import { createGuid } from '../utils/crypto';
import { eventsHelper } from '../utils/eventsHelper';
import { hostPlatform } from '../../utils/hostPlatform'; import { hostPlatform } from '../../utils/hostPlatform';
import { splitErrorMessage } from '../../utils/stackTrace'; import { splitErrorMessage } from '../../utils/stackTrace';
import { PNG, jpegjs } from '../../utilsBundle'; import { PNG, jpegjs } from '../../utilsBundle';
@ -41,7 +43,7 @@ import { debugLogger } from '../../utils/debugLogger';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { WKBrowserContext } from './wkBrowser'; import type { WKBrowserContext } from './wkBrowser';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as accessibility from '../accessibility'; import type * as accessibility from '../accessibility';
import type * as frames from '../frames'; import type * as frames from '../frames';
import type { JSHandle } from '../javascript'; import type { JSHandle } from '../javascript';

View file

@ -15,12 +15,12 @@
*/ */
import { assert } from '../../utils'; import { assert } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { WKSession } from './wkConnection'; import type { WKSession } from './wkConnection';
import type { WKPage } from './wkPage'; import type { WKPage } from './wkPage';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type * as network from '../network'; import type * as network from '../network';
export class WKProvisionalPage { export class WKProvisionalPage {

View file

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { eventsHelper } from '../../utils/eventsHelper'; import { eventsHelper } from '../utils/eventsHelper';
import { Worker } from '../page'; import { Worker } from '../page';
import { WKSession } from './wkConnection'; import { WKSession } from './wkConnection';
import { WKExecutionContext } from './wkExecutionContext'; import { WKExecutionContext } from './wkExecutionContext';
import type { Protocol } from './protocol'; import type { Protocol } from './protocol';
import type { RegisteredListener } from '../../utils/eventsHelper'; import type { RegisteredListener } from '../utils/eventsHelper';
import type { Page } from '../page'; import type { Page } from '../page';
import type * as types from '../types'; import type * as types from '../types';

View file

@ -14,38 +14,39 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './utils/crypto'; export * from './utils/isomorphic/locatorGenerators';
export * from './utils/isomorphic/manualPromise';
export * from './utils/isomorphic/mimeType';
export * from './utils/isomorphic/multimap';
export * from './utils/isomorphic/rtti';
export * from './utils/isomorphic/stringUtils';
export * from './utils/isomorphic/time';
export * from './utils/isomorphic/timeoutRunner';
export * from './utils/isomorphic/urlMatch';
export * from './utils/debug'; export * from './utils/debug';
export * from './utils/debugLogger'; export * from './utils/debugLogger';
export * from './utils/env'; export * from './utils/env';
export * from './utils/eventsHelper';
export * from './utils/expectUtils';
export * from './utils/headers';
export * from './utils/hostPlatform'; export * from './utils/hostPlatform';
export * from './utils/manualPromise'; export * from './utils/isomorphic/headers';
export * from './utils/isomorphic/locatorGenerators'; export * from './utils/isomorphic/semaphore';
export * from './utils/isomorphic/mimeType'; export * from './utils/platform';
export * from './utils/isomorphic/stringUtils';
export * from './utils/isomorphic/urlMatch';
export * from './utils/multimap';
export * from './utils/rtti';
export * from './utils/semaphore';
export * from './utils/stackTrace'; export * from './utils/stackTrace';
export * from './utils/task'; export * from './utils/task';
export * from './utils/time';
export * from './utils/timeoutRunner';
export * from './utils/traceUtils';
export * from './utils/userAgent'; export * from './utils/userAgent';
export * from './utils/zipFile'; export * from './utils/zipFile';
export * from './utils/zones'; export * from './utils/zones';
export * from './server/utils/socksProxy';
export * from './server/utils/processLauncher';
export * from './server/utils/ascii'; export * from './server/utils/ascii';
export * from './server/utils/comparators'; export * from './server/utils/comparators';
export * from './server/utils/crypto';
export * from './server/utils/eventsHelper';
export * from './server/utils/expectUtils';
export * from './server/utils/fileUtils'; export * from './server/utils/fileUtils';
export * from './server/utils/httpServer'; export * from './server/utils/httpServer';
export * from './server/utils/network'; export * from './server/utils/network';
export * from './server/utils/processLauncher';
export * from './server/utils/profiler'; export * from './server/utils/profiler';
export * from './server/utils/wsServer'; export * from './server/utils/socksProxy';
export * from './server/utils/spawnAsync'; export * from './server/utils/spawnAsync';
export * from './server/utils/wsServer';

View file

@ -1,4 +1,6 @@
[*] [*]
./ ./
./isomorphic
../utilsBundle.ts ../utilsBundle.ts
../zipBundle.ts ../zipBundle.ts
../utils/isomorphic

View file

@ -14,24 +14,24 @@
* limitations under the License. * limitations under the License.
*/ */
import * as fs from 'fs';
import * as path from 'path';
import { createGuid } from './crypto';
import { ZipFile } from './zipFile'; import { ZipFile } from './zipFile';
import type { HeadersArray } from '../common/types'; import type { HeadersArray } from '../common/types';
import type * as har from '@trace/har'; import type * as har from '@trace/har';
import type { Platform } from './platform';
const redirectStatus = [301, 302, 303, 307, 308]; const redirectStatus = [301, 302, 303, 307, 308];
export class HarBackend { export class HarBackend {
readonly id = createGuid(); readonly id: string;
private _harFile: har.HARFile; private _harFile: har.HARFile;
private _zipFile: ZipFile | null; private _zipFile: ZipFile | null;
private _baseDir: string | null; private _baseDir: string | null;
private _platform: Platform;
constructor(harFile: har.HARFile, baseDir: string | null, zipFile: ZipFile | null) { constructor(platform: Platform, harFile: har.HARFile, baseDir: string | null, zipFile: ZipFile | null) {
this._platform = platform;
this.id = platform.createGuid();
this._harFile = harFile; this._harFile = harFile;
this._baseDir = baseDir; this._baseDir = baseDir;
this._zipFile = zipFile; this._zipFile = zipFile;
@ -79,7 +79,7 @@ export class HarBackend {
if (this._zipFile) if (this._zipFile)
buffer = await this._zipFile.read(file); buffer = await this._zipFile.read(file);
else else
buffer = await fs.promises.readFile(path.resolve(this._baseDir!, file)); buffer = await this._platform.fs().promises.readFile(this._platform.path().resolve(this._baseDir!, file));
} else { } else {
buffer = Buffer.from(content.text || '', content.encoding === 'base64' ? 'base64' : 'utf-8'); buffer = Buffer.from(content.text || '', content.encoding === 'base64' ? 'base64' : 'utf-8');
} }

View file

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { captureRawStack } from './stackTrace';
export class ManualPromise<T = void> extends Promise<T> { export class ManualPromise<T = void> extends Promise<T> {
private _resolve!: (t: T) => void; private _resolve!: (t: T) => void;
private _reject!: (e: Error) => void; private _reject!: (e: Error) => void;
@ -118,3 +116,12 @@ function cloneError(error: Error, frames: string[]) {
clone.stack = [error.name + ':' + error.message, ...frames].join('\n'); clone.stack = [error.name + ':' + error.message, ...frames].join('\n');
return clone; return clone;
} }
function captureRawStack(): string[] {
const stackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 50;
const error = new Error();
const stack = error.stack || '';
Error.stackTraceLimit = stackTraceLimit;
return stack.split('\n');
}

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
export { isString } from './isomorphic/stringUtils'; export { isString } from './stringUtils';
export function isRegExp(obj: any): obj is RegExp { export function isRegExp(obj: any): obj is RegExp {
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]'; return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';

View file

@ -0,0 +1,19 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export function monotonicTime(): number {
return (performance.now() * 1000 | 0) / 1000;
}

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { monotonicTime } from '../utils'; import { monotonicTime } from './time';
export async function raceAgainstDeadline<T>(cb: () => Promise<T>, deadline: number): Promise<{ result: T, timedOut: false } | { timedOut: true }> { export async function raceAgainstDeadline<T>(cb: () => Promise<T>, deadline: number): Promise<{ result: T, timedOut: false } | { timedOut: true }> {
let timer: NodeJS.Timeout | undefined; let timer: NodeJS.Timeout | undefined;

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
import type { StackFrame } from '@protocol/channels'; import type { ClientSideCallMetadata, StackFrame } from '@protocol/channels';
export type SerializedStackFrame = [number, number, number, string]; export type SerializedStackFrame = [number, number, number, string];
export type SerializedStack = [number, SerializedStackFrame[]]; export type SerializedStack = [number, SerializedStackFrame[]];
@ -33,3 +33,24 @@ export function parseClientSideCallMetadata(data: SerializedClientSideCallMetada
} }
return result; return result;
} }
export function serializeClientSideCallMetadata(metadatas: ClientSideCallMetadata[]): SerializedClientSideCallMetadata {
const fileNames = new Map<string, number>();
const stacks: SerializedStack[] = [];
for (const m of metadatas) {
if (!m.stack || !m.stack.length)
continue;
const stack: SerializedStackFrame[] = [];
for (const frame of m.stack) {
let ordinal = fileNames.get(frame.file);
if (typeof ordinal !== 'number') {
ordinal = fileNames.size;
fileNames.set(frame.file, ordinal);
}
const stackFrame: SerializedStackFrame = [ordinal, frame.line || 0, frame.column || 0, frame.function || ''];
stack.push(stackFrame);
}
stacks.push([m.id, stack]);
}
return { files: [...fileNames.keys()], stacks };
}

View file

@ -20,11 +20,11 @@ import * as path from 'path';
import { removeFolders } from './fileUtils'; import { removeFolders } from './fileUtils';
import { HarBackend } from './harBackend'; import { HarBackend } from './harBackend';
import { ManualPromise } from './manualPromise'; import { ManualPromise } from './isomorphic/manualPromise';
import { ZipFile } from './zipFile'; import { ZipFile } from './zipFile';
import { yauzl, yazl } from '../zipBundle'; import { yauzl, yazl } from '../zipBundle';
import { serializeClientSideCallMetadata } from '../utils'; import { serializeClientSideCallMetadata } from '../utils/isomorphic/traceUtils';
import { assert, calculateSha1 } from '../utils'; import { assert } from '../utils/debug';
import type { Platform } from './platform'; import type { Platform } from './platform';
import type * as channels from '@protocol/channels'; import type * as channels from '@protocol/channels';
@ -77,7 +77,7 @@ export async function zip(platform: Platform, stackSessions: Map<string, StackSe
sourceFiles.add(file); sourceFiles.add(file);
} }
for (const sourceFile of sourceFiles) for (const sourceFile of sourceFiles)
addFile(sourceFile, 'resources/src@' + calculateSha1(sourceFile) + '.txt'); addFile(sourceFile, 'resources/src@' + await platform.calculateSha1(sourceFile) + '.txt');
} }
if (params.mode === 'write') { if (params.mode === 'write') {
@ -137,7 +137,7 @@ async function deleteStackSession(platform: Platform, stackSessions: Map<string,
stackSessions.delete(stacksId!); stackSessions.delete(stacksId!);
} }
export async function harOpen(harBackends: Map<string, HarBackend>, params: channels.LocalUtilsHarOpenParams): Promise<channels.LocalUtilsHarOpenResult> { export async function harOpen(platform: Platform, harBackends: Map<string, HarBackend>, params: channels.LocalUtilsHarOpenParams): Promise<channels.LocalUtilsHarOpenResult> {
let harBackend: HarBackend; let harBackend: HarBackend;
if (params.file.endsWith('.zip')) { if (params.file.endsWith('.zip')) {
const zipFile = new ZipFile(params.file); const zipFile = new ZipFile(params.file);
@ -147,10 +147,10 @@ export async function harOpen(harBackends: Map<string, HarBackend>, params: chan
return { error: 'Specified archive does not have a .har file' }; return { error: 'Specified archive does not have a .har file' };
const har = await zipFile.read(harEntryName); const har = await zipFile.read(harEntryName);
const harFile = JSON.parse(har.toString()) as har.HARFile; const harFile = JSON.parse(har.toString()) as har.HARFile;
harBackend = new HarBackend(harFile, null, zipFile); harBackend = new HarBackend(platform, harFile, null, zipFile);
} else { } else {
const harFile = JSON.parse(await fs.promises.readFile(params.file, 'utf-8')) as har.HARFile; const harFile = JSON.parse(await fs.promises.readFile(params.file, 'utf-8')) as har.HARFile;
harBackend = new HarBackend(harFile, path.dirname(params.file), null); harBackend = new HarBackend(platform, harFile, path.dirname(params.file), null);
} }
harBackends.set(harBackend.id, harBackend); harBackends.set(harBackend.id, harBackend);
return { harId: harBackend.id }; return { harId: harBackend.id };

View file

@ -14,18 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
import { makeWaitForNextTask } from '../utils'; import { makeWaitForNextTask } from './task';
export interface WritableStream { interface WritableStream {
write(data: Buffer): void; write(data: Buffer): void;
} }
export interface ReadableStream { interface ReadableStream {
on(event: 'data', callback: (b: Buffer) => void): void; on(event: 'data', callback: (b: Buffer) => void): void;
on(event: 'close', callback: () => void): void; on(event: 'close', callback: () => void): void;
} }
export interface ClosableStream { interface ClosableStream {
close(): void; close(): void;
} }

View file

@ -14,36 +14,56 @@
* limitations under the License. * limitations under the License.
*/ */
import * as crypto from 'crypto';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as util from 'util'; import * as util from 'util';
export type Platform = { export type Platform = {
calculateSha1(text: string): Promise<string>;
createGuid: () => string;
fs: () => typeof fs; fs: () => typeof fs;
path: () => typeof path;
inspectCustom: symbol | undefined; inspectCustom: symbol | undefined;
path: () => typeof path;
ws?: (url: string) => WebSocket; ws?: (url: string) => WebSocket;
}; };
export const emptyPlatform: Platform = { export const nodePlatform: Platform = {
calculateSha1: (text: string) => {
const sha1 = crypto.createHash('sha1');
sha1.update(text);
return Promise.resolve(sha1.digest('hex'));
},
createGuid: () => crypto.randomBytes(16).toString('hex'),
fs: () => fs,
inspectCustom: util.inspect.custom,
path: () => path,
};
export const webPlatform: Platform = {
calculateSha1: async (text: string) => {
const bytes = new TextEncoder().encode(text);
const hashBuffer = await crypto.subtle.digest('SHA-1', bytes);
return Array.from(new Uint8Array(hashBuffer), b => b.toString(16).padStart(2, '0')).join('');
},
createGuid: () => {
return Array.from(crypto.getRandomValues(new Uint8Array(16)), b => b.toString(16).padStart(2, '0')).join('');
},
fs: () => { fs: () => {
throw new Error('File system is not available'); throw new Error('File system is not available');
}, },
inspectCustom: undefined,
path: () => { path: () => {
throw new Error('Path module is not available'); throw new Error('Path module is not available');
}, },
inspectCustom: undefined,
};
export const nodePlatform: Platform = {
fs: () => fs,
path: () => path,
inspectCustom: util.inspect.custom,
};
export const webPlatform: Platform = {
...emptyPlatform,
ws: (url: string) => new WebSocket(url), ws: (url: string) => new WebSocket(url),
}; };

View file

@ -17,15 +17,13 @@
import * as path from 'path'; import * as path from 'path';
import { colors } from '../utilsBundle'; import { colors } from '../utilsBundle';
import { findRepeatedSubsequences } from './sequence'; import { findRepeatedSubsequences } from './isomorphic/sequence';
import { StackUtils } from './stackUtils'; import { parseStackFrame } from './stackUtils';
import type { StackFrame } from '@protocol/channels'; import type { StackFrame } from '@protocol/channels';
const stackUtils = new StackUtils();
export function parseStackTraceLine(line: string): StackFrame | null { export function parseStackTraceLine(line: string): StackFrame | null {
const frame = stackUtils.parseLine(line); const frame = parseStackFrame(line);
if (!frame) if (!frame)
return null; return null;
if (!process.env.PWDEBUGIMPL && (frame.file?.startsWith('internal') || frame.file?.startsWith('node:'))) if (!process.env.PWDEBUGIMPL && (frame.file?.startsWith('internal') || frame.file?.startsWith('node:')))

View file

@ -35,84 +35,82 @@ type StackData = {
evalFile?: string | undefined; evalFile?: string | undefined;
}; };
export class StackUtils { export function parseStackFrame(line: string): StackData | null {
parseLine(line: string) { const match = line && line.match(re);
const match = line && line.match(re); if (!match)
if (!match) return null;
return null;
const ctor = match[1] === 'new'; const ctor = match[1] === 'new';
let fname = match[2]; let fname = match[2];
const evalOrigin = match[3]; const evalOrigin = match[3];
const evalFile = match[4]; const evalFile = match[4];
const evalLine = Number(match[5]); const evalLine = Number(match[5]);
const evalCol = Number(match[6]); const evalCol = Number(match[6]);
let file = match[7]; let file = match[7];
const lnum = match[8]; const lnum = match[8];
const col = match[9]; const col = match[9];
const native = match[10] === 'native'; const native = match[10] === 'native';
const closeParen = match[11] === ')'; const closeParen = match[11] === ')';
let method; let method;
const res: StackData = {}; const res: StackData = {};
if (lnum) if (lnum)
res.line = Number(lnum); res.line = Number(lnum);
if (col) if (col)
res.column = Number(col); res.column = Number(col);
if (closeParen && file) { if (closeParen && file) {
// make sure parens are balanced // make sure parens are balanced
// if we have a file like "asdf) [as foo] (xyz.js", then odds are // if we have a file like "asdf) [as foo] (xyz.js", then odds are
// that the fname should be += " (asdf) [as foo]" and the file // that the fname should be += " (asdf) [as foo]" and the file
// should be just "xyz.js" // should be just "xyz.js"
// walk backwards from the end to find the last unbalanced ( // walk backwards from the end to find the last unbalanced (
let closes = 0; let closes = 0;
for (let i = file.length - 1; i > 0; i--) { for (let i = file.length - 1; i > 0; i--) {
if (file.charAt(i) === ')') { if (file.charAt(i) === ')') {
closes++; closes++;
} else if (file.charAt(i) === '(' && file.charAt(i - 1) === ' ') { } else if (file.charAt(i) === '(' && file.charAt(i - 1) === ' ') {
closes--; closes--;
if (closes === -1 && file.charAt(i - 1) === ' ') { if (closes === -1 && file.charAt(i - 1) === ' ') {
const before = file.slice(0, i - 1); const before = file.slice(0, i - 1);
const after = file.slice(i + 1); const after = file.slice(i + 1);
file = after; file = after;
fname += ` (${before}`; fname += ` (${before}`;
break; break;
}
} }
} }
} }
if (fname) {
const methodMatch = fname.match(methodRe);
if (methodMatch) {
fname = methodMatch[1];
method = methodMatch[2];
}
}
setFile(res, file);
if (ctor)
res.isConstructor = true;
if (evalOrigin) {
res.evalOrigin = evalOrigin;
res.evalLine = evalLine;
res.evalColumn = evalCol;
res.evalFile = evalFile && evalFile.replace(/\\/g, '/');
}
if (native)
res.native = true;
if (fname)
res.function = fname;
if (method && fname !== method)
res.method = method;
return res;
} }
if (fname) {
const methodMatch = fname.match(methodRe);
if (methodMatch) {
fname = methodMatch[1];
method = methodMatch[2];
}
}
setFile(res, file);
if (ctor)
res.isConstructor = true;
if (evalOrigin) {
res.evalOrigin = evalOrigin;
res.evalLine = evalLine;
res.evalColumn = evalCol;
res.evalFile = evalFile && evalFile.replace(/\\/g, '/');
}
if (native)
res.native = true;
if (fname)
res.function = fname;
if (method && fname !== method)
res.method = method;
return res;
} }
function setFile(result: StackData, filename: string) { function setFile(result: StackData, filename: string) {

View file

@ -1,32 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// The `process.hrtime()` returns a time from some arbitrary
// date in the past; on certain systems, this is the time from the system boot.
// The `monotonicTime()` converts this to milliseconds.
//
// For a Linux server with uptime of 36 days, the `monotonicTime()` value
// will be 36 * 86400 * 1000 = 3_110_400_000, which is larger than
// the maximum value that `setTimeout` accepts as an argument: 2_147_483_647.
//
// To make the `monotonicTime()` a reasonable value, we anchor
// it to the time of the first import of this utility.
const initialTime = process.hrtime();
export function monotonicTime(): number {
const [seconds, nanoseconds] = process.hrtime(initialTime);
return seconds * 1000 + (nanoseconds / 1000 | 0) / 1000;
}

View file

@ -1,39 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { SerializedClientSideCallMetadata, SerializedStack, SerializedStackFrame } from './isomorphic/traceUtils';
import type { ClientSideCallMetadata } from '@protocol/channels';
export function serializeClientSideCallMetadata(metadatas: ClientSideCallMetadata[]): SerializedClientSideCallMetadata {
const fileNames = new Map<string, number>();
const stacks: SerializedStack[] = [];
for (const m of metadatas) {
if (!m.stack || !m.stack.length)
continue;
const stack: SerializedStackFrame[] = [];
for (const frame of m.stack) {
let ordinal = fileNames.get(frame.file);
if (typeof ordinal !== 'number') {
ordinal = fileNames.size;
fileNames.set(frame.file, ordinal);
}
const stackFrame: SerializedStackFrame = [ordinal, frame.line || 0, frame.column || 0, frame.function || ''];
stack.push(stackFrame);
}
stacks.push([m.id, stack]);
}
return { files: [...fileNames.keys()], stacks };
}

View file

@ -78,7 +78,7 @@ export class FullConfigInternal {
const privateConfiguration = (userConfig as any)['@playwright/test']; const privateConfiguration = (userConfig as any)['@playwright/test'];
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig); this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig);
this.populateGitInfo = takeFirst(userConfig.populateGitInfo, false); this.populateGitInfo = takeFirst(userConfig.populateGitInfo, defaultPopulateGitInfo);
this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined);
@ -301,6 +301,7 @@ function resolveScript(id: string | undefined, rootDir: string): string | undefi
export const defaultGrep = /.*/; export const defaultGrep = /.*/;
export const defaultReporter = process.env.CI ? 'dot' : 'list'; export const defaultReporter = process.env.CI ? 'dot' : 'list';
const defaultPopulateGitInfo = process.env.GITHUB_ACTIONS === 'true';
const configInternalSymbol = Symbol('configInternalSymbol'); const configInternalSymbol = Symbol('configInternalSymbol');

Some files were not shown because too many files have changed in this diff Show more