chore: use utils via index export (3) (#13403)

This commit is contained in:
Pavel Feldman 2022-04-07 12:55:44 -08:00 committed by GitHub
parent 5536e64538
commit 40d5e3a3c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
115 changed files with 520 additions and 535 deletions

View File

@ -26,7 +26,6 @@
"./lib/utils/comparators": "./lib/utils/comparators.js",
"./lib/utils/httpServer": "./lib/utils/httpServer.js",
"./lib/utils/processLauncher": "./lib/utils/processLauncher.js",
"./lib/utils/utils": "./lib/utils/utils.js",
"./lib/utils/stackTrace": "./lib/utils/stackTrace.js",
"./lib/remote/playwrightServer": "./lib/remote/playwrightServer.js",
"./lib/remote/playwrightClient": "./lib/remote/playwrightClient.js",

View File

@ -18,7 +18,7 @@ import type { LaunchServerOptions, Logger } from './client/types';
import { EventEmitter } from 'ws';
import type { BrowserServerLauncher, BrowserServer } from './client/browserType';
import { envObjectToArray } from './client/clientHelper';
import { createGuid } from './utils/utils';
import { createGuid } from './utils';
import type { ProtocolLogger } from './server/types';
import { serverSideCallMetadata } from './server/instrumentation';
import { createPlaywright } from './server/playwright';

View File

@ -32,7 +32,7 @@ import type { Page } from '../client/page';
import type { BrowserType } from '../client/browserType';
import type { BrowserContextOptions, LaunchOptions } from '../client/types';
import { spawn } from 'child_process';
import { spawnAsync, getPlaywrightVersion, wrapInASCIIBox } from '../utils/utils';
import { spawnAsync, getPlaywrightVersion, wrapInASCIIBox } from '../utils';
import { launchGridAgent } from '../grid/gridAgent';
import type { GridFactory } from '../grid/gridServer';
import { GridServer } from '../grid/gridServer';

View File

@ -15,7 +15,7 @@
*/
import fs from 'fs';
import { isString, isRegExp } from '../utils/utils';
import { isString, isRegExp } from '../utils';
import type * as channels from '../protocol/channels';
import { Events } from './events';
import { BrowserContext, prepareBrowserContextParams } from './browserContext';

View File

@ -17,7 +17,7 @@
import type * as channels from '../protocol/channels';
import * as fs from 'fs';
import { Stream } from './stream';
import { mkdirIfNeeded } from '../utils/utils';
import { mkdirIfNeeded } from '../utils';
import { ChannelOwner } from './channelOwner';
import type { Readable } from 'stream';

View File

@ -28,7 +28,7 @@ import { Events } from './events';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { Waiter } from './waiter';
import type { URLMatch, Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions } from './types';
import { headersObjectToArray, mkdirIfNeeded } from '../utils/utils';
import { headersObjectToArray, mkdirIfNeeded } from '../utils';
import { isSafeCloseError } from '../utils/errors';
import type * as api from '../../types/types';
import type * as structs from '../../types/structs';

View File

@ -23,7 +23,7 @@ import { Connection } from './connection';
import { Events } from './events';
import type { ChildProcess } from 'child_process';
import { envObjectToArray } from './clientHelper';
import { assert, headersObjectToArray, monotonicTime } from '../utils/utils';
import { assert, headersObjectToArray, monotonicTime } from '../utils';
import type * as api from '../../types/types';
import { kBrowserClosedError } from '../utils/errors';
import { raceAgainstTimeout } from '../utils';

View File

@ -21,7 +21,7 @@ import { createScheme, ValidationError } from '../protocol/validator';
import { debugLogger } from '../utils/debugLogger';
import type { ParsedStackTrace } from '../utils/stackTrace';
import { captureRawStack, captureStackTrace } from '../utils/stackTrace';
import { isUnderTest } from '../utils/utils';
import { isUnderTest } from '../utils';
import { zones } from '../utils/zones';
import type { ClientInstrumentation } from './clientInstrumentation';
import type { Connection } from './connection';

View File

@ -17,7 +17,7 @@
import type * as types from './types';
import fs from 'fs';
import { isString, isRegExp, constructURLBasedOnBaseURL } from '../utils/utils';
import { isString, isRegExp, constructURLBasedOnBaseURL } from '../utils';
export function envObjectToArray(env: types.Env): { name: string, value: string }[] {
const result: { name: string, value: string }[] = [];

View File

@ -20,7 +20,7 @@ import type * as structs from '../../types/structs';
import type * as api from '../../types/types';
import type * as channels from '../protocol/channels';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { headersObjectToArray } from '../utils/utils';
import { headersObjectToArray } from '../utils';
import { BrowserContext } from './browserContext';
import { ChannelOwner } from './channelOwner';
import { envObjectToArray } from './clientHelper';

View File

@ -23,7 +23,7 @@ import type { SelectOption, FilePayload, Rect, SelectOptionOptions } from './typ
import fs from 'fs';
import * as mime from 'mime';
import path from 'path';
import { assert, isString, mkdirIfNeeded } from '../utils/utils';
import { assert, isString, mkdirIfNeeded } from '../utils';
import type * as api from '../../types/types';
import type * as structs from '../../types/structs';
import type { BrowserContext } from './browserContext';

View File

@ -22,7 +22,7 @@ import type * as api from '../../types/types';
import type { HeadersArray } from '../common/types';
import type * as channels from '../protocol/channels';
import { kBrowserOrContextClosedError } from '../utils/errors';
import { assert, headersObjectToArray, isFilePayload, isString, mkdirIfNeeded, objectToArray } from '../utils/utils';
import { assert, headersObjectToArray, isFilePayload, isString, mkdirIfNeeded, objectToArray } from '../utils';
import { ChannelOwner } from './channelOwner';
import * as network from './network';
import { RawHeaders } from './network';

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { assert } from '../utils/utils';
import { assert } from '../utils';
import type * as channels from '../protocol/channels';
import { ChannelOwner } from './channelOwner';
import { FrameLocator, Locator } from './locator';

View File

@ -19,7 +19,7 @@ import type * as api from '../../types/types';
import type * as channels from '../protocol/channels';
import type { ParsedStackTrace } from '../utils/stackTrace';
import * as util from 'util';
import { isRegExp, monotonicTime } from '../utils/utils';
import { isRegExp, monotonicTime } from '../utils';
import { ElementHandle } from './elementHandle';
import type { Frame } from './frame';
import type { FilePayload, FrameExpectOptions, Rect, SelectOption, SelectOptionOptions, TimeoutOptions } from './types';

View File

@ -21,7 +21,7 @@ import { Frame } from './frame';
import type { Headers, RemoteAddr, SecurityDetails, WaitForEventOptions } from './types';
import fs from 'fs';
import * as mime from 'mime';
import { isString, headersObjectToArray } from '../utils/utils';
import { isString, headersObjectToArray } from '../utils';
import { ManualPromise } from '../utils';
import { Events } from './events';
import type { Page } from './page';

View File

@ -16,7 +16,7 @@
*/
import { Events } from './events';
import { assert } from '../utils/utils';
import { assert } from '../utils';
import { TimeoutSettings } from '../utils/timeoutSettings';
import type { ParsedStackTrace } from '../utils/stackTrace';
import type * as channels from '../protocol/channels';
@ -46,7 +46,7 @@ import fs from 'fs';
import path from 'path';
import type { Size, URLMatch, Headers, LifecycleEvent, WaitForEventOptions, SelectOption, SelectOptionOptions, FilePayload, WaitForFunctionOptions } from './types';
import { evaluationScript, urlMatches } from './clientHelper';
import { isString, isRegExp, isObject, mkdirIfNeeded, headersObjectToArray } from '../utils/utils';
import { isString, isRegExp, isObject, mkdirIfNeeded, headersObjectToArray } from '../utils';
import { isSafeCloseError } from '../utils/errors';
import { Video } from './video';
import { Artifact } from './artifact';

View File

@ -17,7 +17,7 @@
import type { EventEmitter } from 'events';
import { rewriteErrorMessage } from '../utils/stackTrace';
import { TimeoutError } from '../utils/errors';
import { createGuid } from '../utils/utils';
import { createGuid } from '../utils';
import type * as channels from '../protocol/channels';
import type { ChannelOwner } from './channelOwner';

View File

@ -17,7 +17,7 @@
import http from 'http';
import os from 'os';
import type { GridAgentLaunchOptions, GridFactory } from './gridServer';
import * as utils from '../utils/utils';
import * as utils from '../utils';
const dockerFactory: GridFactory = {
name: 'Agents launched inside Docker container',

View File

@ -17,7 +17,7 @@
import debug from 'debug';
import WebSocket from 'ws';
import { fork } from 'child_process';
import { getPlaywrightVersion } from '../utils/utils';
import { getPlaywrightVersion } from '../utils';
export function launchGridAgent(agentId: string, gridURL: string) {
const log = debug(`pw:grid:agent:${agentId}`);

View File

@ -17,7 +17,7 @@
import WebSocket from 'ws';
import { Connection } from '../client/connection';
import type { Playwright } from '../client/playwright';
import { getPlaywrightVersion } from '../utils/utils';
import { getPlaywrightVersion } from '../utils';
export class GridClient {
private _ws: WebSocket;

View File

@ -20,7 +20,7 @@ import { URL } from 'url';
import type { Server as WebSocketServer } from 'ws';
import type WebSocket from 'ws';
import { HttpServer } from '../utils/httpServer';
import { assert, createGuid, getPlaywrightVersion } from '../utils/utils';
import { assert, createGuid, getPlaywrightVersion } from '../utils';
export type GridAgentLaunchOptions = {
agentId: string,

View File

@ -15,7 +15,7 @@
*/
import type { ChildProcess } from 'child_process';
import { makeWaitForNextTask } from '../utils/utils';
import { makeWaitForNextTask } from '../utils';
export interface WritableStream {
write(data: Buffer): void;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { isUnderTest } from '../utils/utils';
import { isUnderTest } from '../utils';
export class ValidationError extends Error {}
export type Validator = (arg: any, path: string) => any;

View File

@ -17,7 +17,7 @@
import WebSocket from 'ws';
import { Connection } from '../client/connection';
import type { Playwright } from '../client/playwright';
import { makeWaitForNextTask } from '../utils/utils';
import { makeWaitForNextTask } from '../utils';
// TODO: this file should be removed because it uses the old protocol.

View File

@ -22,7 +22,7 @@ import os from 'os';
import path from 'path';
import type * as stream from 'stream';
import * as ws from 'ws';
import { createGuid, makeWaitForNextTask, removeFolders } from '../../utils/utils';
import { createGuid, makeWaitForNextTask, removeFolders } from '../../utils';
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
import type { BrowserContext } from '../browserContext';
import { validateBrowserContextOptions } from '../browserContext';

View File

@ -19,7 +19,7 @@ import type * as types from '../types';
import * as net from 'net';
import { EventEmitter } from 'events';
import type { Backend, DeviceBackend, SocketBackend } from './android';
import { assert, createGuid } from '../../utils/utils';
import { assert, createGuid } from '../../utils';
export class AdbBackend implements Backend {
async devices(options: types.AndroidDeviceOptions = {}): Promise<DeviceBackend[]> {

View File

@ -15,7 +15,7 @@
*/
import fs from 'fs';
import { assert } from '../utils/utils';
import { assert } from '../utils';
import { ManualPromise } from '../utils';
import { SdkObject } from './instrumentation';

View File

@ -17,7 +17,7 @@
import * as os from 'os';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { debugMode, mkdirIfNeeded, createGuid } from '../utils/utils';
import { debugMode, mkdirIfNeeded, createGuid } from '../utils';
import type { Browser, BrowserOptions } from './browser';
import type { Download } from './download';
import type * as frames from './frames';

View File

@ -31,7 +31,7 @@ import type { Progress } from './progress';
import { ProgressController } from './progress';
import type * as types from './types';
import { DEFAULT_TIMEOUT, TimeoutSettings } from '../utils/timeoutSettings';
import { debugMode, existsAsync } from '../utils/utils';
import { debugMode, existsAsync } from '../utils';
import { helper } from './helper';
import { RecentLogsCollector } from '../utils/debugLogger';
import type { CallMetadata } from './instrumentation';

View File

@ -32,7 +32,7 @@ import { Browser } from '../browser';
import type * as types from '../types';
import type { HTTPRequestParams } from '../../utils';
import { fetchData } from '../../utils';
import { debugMode, getUserAgent, headersArrayToObject, removeFolders, streamToString, wrapInASCIIBox } from '../../utils/utils';
import { debugMode, getUserAgent, headersArrayToObject, removeFolders, streamToString, wrapInASCIIBox } from '../../utils';
import { RecentLogsCollector } from '../../utils/debugLogger';
import type { Progress } from '../progress';
import { ProgressController } from '../progress';

View File

@ -18,7 +18,7 @@
import type { BrowserOptions } from '../browser';
import { Browser } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, verifyGeolocation } from '../browserContext';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import * as network from '../network';
import type { PageBinding, PageDelegate } from '../page';
import { Page, Worker } from '../page';

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport';
import type { Protocol } from './protocol';
import { EventEmitter } from 'events';

View File

@ -20,7 +20,7 @@ import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import type { Protocol } from './protocol';
import type * as types from '../types';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
export class CRCoverage {
private _jsCoverage: JSCoverage;

View File

@ -15,7 +15,7 @@
*/
import type { CRPage } from './crPage';
import type * as types from '../types';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { Protocol } from './protocol';
import { toModifiersMask } from './crProtocolHelper';

View File

@ -19,7 +19,7 @@ import * as input from '../input';
import type * as types from '../types';
import type { CRSession } from './crConnection';
import { macEditingCommands } from '../macEditingCommands';
import { isString } from '../../utils/utils';
import { isString } from '../../utils';
import type { DragManager } from './crDragDrop';
import type { CRPage } from './crPage';
import { toButtonsMask, toModifiersMask } from './crProtocolHelper';

View File

@ -25,7 +25,7 @@ import * as network from '../network';
import type * as frames from '../frames';
import type * as types from '../types';
import type { CRPage } from './crPage';
import { assert, headersObjectToArray } from '../../utils/utils';
import { assert, headersObjectToArray } from '../../utils';
export class CRNetworkManager {
private _client: CRSession;

View File

@ -20,7 +20,7 @@ import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { registry } from '../registry';
import { rewriteErrorMessage } from '../../utils/stackTrace';
import { assert, createGuid, headersArrayToObject } from '../../utils/utils';
import { assert, createGuid, headersArrayToObject } from '../../utils';
import * as dialog from '../dialog';
import * as dom from '../dom';
import type * as frames from '../frames';

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type * as types from '../types';
import type { CRSession } from './crConnection';
import { readProtocolStream } from './crProtocolHelper';

View File

@ -19,7 +19,7 @@ import type { CRSession } from './crConnection';
import type { Protocol } from './protocol';
import fs from 'fs';
import type * as types from '../types';
import { mkdirIfNeeded } from '../../utils/utils';
import { mkdirIfNeeded } from '../../utils';
import { splitErrorMessage } from '../../utils/stackTrace';
export function getExceptionMessage(exceptionDetails: Protocol.Runtime.ExceptionDetails): string {

View File

@ -15,7 +15,7 @@
*/
import type { ChildProcess } from 'child_process';
import { assert, monotonicTime } from '../../utils/utils';
import { assert, monotonicTime } from '../../utils';
import { Page } from '../page';
import { launchProcess } from '../../utils/processLauncher';
import type { Progress } from '../progress';

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { assert } from '../utils/utils';
import { assert } from '../utils';
import type { Page } from './page';
import { SdkObject } from './instrumentation';

View File

@ -19,7 +19,7 @@ import type { DispatcherScope } from './dispatcher';
import { Dispatcher } from './dispatcher';
import { StreamDispatcher } from './streamDispatcher';
import fs from 'fs';
import { mkdirIfNeeded } from '../../utils/utils';
import { mkdirIfNeeded } from '../../utils';
import type { Artifact } from '../artifact';
export class ArtifactDispatcher extends Dispatcher<Artifact, channels.ArtifactChannel> implements channels.ArtifactChannel {

View File

@ -31,7 +31,7 @@ import type { Request, Response } from '../network';
import { TracingDispatcher } from './tracingDispatcher';
import * as fs from 'fs';
import * as path from 'path';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
import { WritableStreamDispatcher } from './writableStreamDispatcher';
export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channels.BrowserContextChannel> implements channels.BrowserContextChannel {

View File

@ -22,7 +22,7 @@ import { Dispatcher } from './dispatcher';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import type { CallMetadata } from '../instrumentation';
import { JsonPipeDispatcher } from '../dispatchers/jsonPipeDispatcher';
import { getUserAgent } from '../../utils/utils';
import { getUserAgent } from '../../utils';
import * as socks from '../../utils/socksProxy';
import EventEmitter from 'events';
import { ProgressController } from '../progress';

View File

@ -19,7 +19,7 @@ import type * as channels from '../../protocol/channels';
import { serializeError } from '../../protocol/serializers';
import type { Validator } from '../../protocol/validator';
import { createScheme, ValidationError } from '../../protocol/validator';
import { assert, debugAssert, isUnderTest, monotonicTime } from '../../utils/utils';
import { assert, debugAssert, isUnderTest, monotonicTime } from '../../utils';
import { tOptional } from '../../protocol/validatorPrimitives';
import { kBrowserOrContextClosedError } from '../../utils/errors';
import type { CallMetadata } from '../instrumentation';

View File

@ -17,7 +17,7 @@
import type * as channels from '../../protocol/channels';
import type { DispatcherScope } from './dispatcher';
import { Dispatcher } from './dispatcher';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
import { serializeError } from '../../protocol/serializers';
export class JsonPipeDispatcher extends Dispatcher<{ guid: string }, channels.JsonPipeChannel> implements channels.JsonPipeChannel {

View File

@ -21,7 +21,7 @@ import yauzl from 'yauzl';
import yazl from 'yazl';
import type * as channels from '../../protocol/channels';
import { ManualPromise } from '../../utils';
import { assert, createGuid } from '../../utils/utils';
import { assert, createGuid } from '../../utils';
import type { DispatcherScope } from './dispatcher';
import { Dispatcher } from './dispatcher';

View File

@ -35,7 +35,7 @@ import type { CallMetadata } from '../instrumentation';
import type { Artifact } from '../artifact';
import { ArtifactDispatcher } from './artifactDispatcher';
import type { Download } from '../download';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
export class PageDispatcher extends Dispatcher<Page, channels.PageChannel> implements channels.PageChannel {
_type_EventTarget = true;

View File

@ -30,7 +30,7 @@ import { LocalUtilsDispatcher } from './localUtilsDispatcher';
import { APIRequestContextDispatcher } from './networkDispatchers';
import { SelectorsDispatcher } from './selectorsDispatcher';
import { ConnectedBrowserDispatcher } from './browserDispatcher';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
export class PlaywrightDispatcher extends Dispatcher<Playwright, channels.PlaywrightChannel> implements channels.PlaywrightChannel {
_type_Playwright;

View File

@ -18,7 +18,7 @@ import type * as channels from '../../protocol/channels';
import type { DispatcherScope } from './dispatcher';
import { Dispatcher } from './dispatcher';
import type * as stream from 'stream';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
export class StreamDispatcher extends Dispatcher<{ guid: string, stream: stream.Readable }, channels.StreamChannel> implements channels.StreamChannel {
_type_Stream = true;

View File

@ -18,7 +18,7 @@ import type * as channels from '../../protocol/channels';
import type { DispatcherScope } from './dispatcher';
import { Dispatcher } from './dispatcher';
import type * as fs from 'fs';
import { createGuid } from '../../utils/utils';
import { createGuid } from '../../utils';
export class WritableStreamDispatcher extends Dispatcher<{ guid: string, stream: fs.WriteStream }, channels.WritableStreamChannel> implements channels.WritableStreamChannel {
_type_WritableStream = true;

View File

@ -29,7 +29,7 @@ import { ProgressController } from './progress';
import type { SelectorInfo } from './selectors';
import type * as types from './types';
import type { TimeoutOptions } from '../common/types';
import { experimentalFeaturesEnabled, isUnderTest } from '../utils/utils';
import { experimentalFeaturesEnabled, isUnderTest } from '../utils';
type SetInputFilesFiles = channels.ElementHandleSetInputFilesParams['files'];
export type InputFilesItems = { files?: SetInputFilesFiles, localPaths?: string[] };

View File

@ -16,7 +16,7 @@
import path from 'path';
import { Page } from './page';
import { assert } from '../utils/utils';
import { assert } from '../utils';
import { Artifact } from './artifact';
export class Download {

View File

@ -26,7 +26,7 @@ import { CRExecutionContext } from '../chromium/crExecutionContext';
import * as js from '../javascript';
import type { Page } from '../page';
import { TimeoutSettings } from '../../utils/timeoutSettings';
import { wrapInASCIIBox } from '../../utils/utils';
import { wrapInASCIIBox } from '../../utils';
import { WebSocketTransport } from '../transport';
import { launchProcess, envArrayToObject } from '../../utils/processLauncher';
import { BrowserContext, validateBrowserContextOptions } from '../browserContext';

View File

@ -25,7 +25,7 @@ import zlib from 'zlib';
import type { HTTPCredentials } from '../../types/types';
import type * as channels from '../protocol/channels';
import { TimeoutSettings } from '../utils/timeoutSettings';
import { assert, createGuid, getUserAgent, monotonicTime } from '../utils/utils';
import { assert, createGuid, getUserAgent, monotonicTime } from '../utils';
import { BrowserContext } from './browserContext';
import { CookieStore, domainMatches } from './cookieStore';
import { MultipartFormData } from './formData';

View File

@ -16,7 +16,7 @@
*/
import { kBrowserClosedError } from '../../utils/errors';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { BrowserOptions } from '../browser';
import { Browser } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, verifyGeolocation } from '../browserContext';

View File

@ -16,7 +16,7 @@
*/
import { EventEmitter } from 'events';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport';
import type { Protocol } from './protocol';
import { rewriteErrorMessage } from '../../utils/stackTrace';

View File

@ -20,7 +20,7 @@ import * as dom from '../dom';
import type * as frames from '../frames';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { PageBinding, PageDelegate } from '../page';
import { Page, Worker } from '../page';
import type * as types from '../types';

View File

@ -26,7 +26,7 @@ import type { ConnectionTransport } from '../transport';
import type { BrowserOptions, PlaywrightOptions } from '../browser';
import type * as types from '../types';
import { rewriteErrorMessage } from '../../utils/stackTrace';
import { wrapInASCIIBox } from '../../utils/utils';
import { wrapInASCIIBox } from '../../utils';
export class Firefox extends BrowserType {
constructor(playwrightOptions: PlaywrightOptions) {

View File

@ -29,7 +29,7 @@ import * as types from './types';
import { BrowserContext } from './browserContext';
import type { Progress } from './progress';
import { ProgressController } from './progress';
import { assert, constructURLBasedOnBaseURL, makeWaitForNextTask } from '../utils/utils';
import { assert, constructURLBasedOnBaseURL, makeWaitForNextTask } from '../utils';
import { ManualPromise } from '../utils';
import { debugLogger } from '../utils/debugLogger';
import type { CallMetadata } from './instrumentation';

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { assert } from '../utils/utils';
import { assert } from '../utils';
import * as keyboardLayout from './usKeyboardLayout';
import type * as types from './types';
import type { Page } from './page';

View File

@ -15,7 +15,7 @@
*/
import { EventEmitter } from 'events';
import { createGuid } from '../utils/utils';
import { createGuid } from '../utils';
import type { APIRequestContext } from './fetch';
import type { Browser } from './browser';
import type { BrowserContext } from './browserContext';

View File

@ -17,7 +17,7 @@
import type * as frames from './frames';
import type * as types from './types';
import type * as channels from '../protocol/channels';
import { assert } from '../utils/utils';
import { assert } from '../utils';
import { ManualPromise } from '../utils';
import { SdkObject } from './instrumentation';
import type { NameValue } from '../common/types';

View File

@ -30,7 +30,7 @@ import * as accessibility from './accessibility';
import { FileChooser } from './fileChooser';
import type { Progress } from './progress';
import { ProgressController } from './progress';
import { assert, isError } from '../utils/utils';
import { assert, isError } from '../utils';
import { ManualPromise } from '../utils';
import { debugLogger } from '../utils/debugLogger';
import type { ImageComparatorOptions } from '../utils/comparators';

View File

@ -16,7 +16,7 @@
*/
import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from './transport';
import { makeWaitForNextTask } from '../utils/utils';
import { makeWaitForNextTask } from '../utils';
import { debugLogger } from '../utils/debugLogger';
export class PipeTransport implements ConnectionTransport {

View File

@ -15,7 +15,7 @@
*/
import { TimeoutError } from '../utils/errors';
import { assert, monotonicTime } from '../utils/utils';
import { assert, monotonicTime } from '../utils';
import type { LogName } from '../utils/debugLogger';
import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation';
import type { ElementHandle } from './dom';

View File

@ -19,7 +19,7 @@ import extract from 'extract-zip';
import fs from 'fs';
import os from 'os';
import path from 'path';
import { existsAsync, getUserAgent } from '../../utils/utils';
import { existsAsync, getUserAgent } from '../../utils';
import { debugLogger } from '../../utils/debugLogger';
import { download } from './download';

View File

@ -18,7 +18,7 @@ import fs from 'fs';
import path from 'path';
import * as os from 'os';
import childProcess from 'child_process';
import * as utils from '../../utils/utils';
import * as utils from '../../utils';
import { buildPlaywrightCLICommand } from '.';
import { deps } from './nativeDeps';
import { getUbuntuVersion } from '../../utils/ubuntuVersion';

View File

@ -22,7 +22,7 @@ import * as fs from 'fs';
import lockfile from 'proper-lockfile';
import { getUbuntuVersion } from '../../utils/ubuntuVersion';
import { fetchData } from '../../utils';
import { getFromENV, getAsBooleanFromENV, getClientLanguage, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, wrapInASCIIBox, transformCommandsForRoot } from '../../utils/utils';
import { getFromENV, getAsBooleanFromENV, getClientLanguage, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, wrapInASCIIBox, transformCommandsForRoot } from '../../utils';
import type { DependencyGroup } from './dependencies';
import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';

View File

@ -23,7 +23,7 @@ import type { Frame } from './frames';
import type { ParsedSelector } from './common/selectorParser';
import type * as types from './types';
import type { Progress } from './progress';
import { assert } from '../utils/utils';
import { assert } from '../utils';
import { MultiMap } from '../utils';
declare global {

View File

@ -20,7 +20,7 @@ import type * as js from './javascript';
import type * as types from './types';
import type { ParsedSelector } from './common/selectorParser';
import { allEngineNames, InvalidSelectorError, parseSelector, stringifySelector } from './common/selectorParser';
import { createGuid, experimentalFeaturesEnabled } from '../utils/utils';
import { createGuid, experimentalFeaturesEnabled } from '../utils';
export type SelectorInfo = {
parsed: ParsedSelector,

View File

@ -15,7 +15,7 @@
*/
import { EventEmitter } from 'events';
import { debugMode, isUnderTest, monotonicTime } from '../../utils/utils';
import { debugMode, isUnderTest, monotonicTime } from '../../utils';
import type { BrowserContext } from '../browserContext';
import type { CallMetadata, InstrumentationListener, SdkObject } from '../instrumentation';
import { commandsWithTracingSnapshots, pausesBeforeInputActions } from '../../protocol/channels';

View File

@ -21,7 +21,7 @@ import { helper } from '../../helper';
import * as network from '../../network';
import { Page } from '../../page';
import type * as har from './har';
import { calculateSha1, monotonicTime } from '../../../utils/utils';
import { calculateSha1, monotonicTime } from '../../../utils';
import type { RegisteredListener } from '../../../utils/eventsHelper';
import { eventsHelper } from '../../../utils/eventsHelper';
import * as mime from 'mime';

View File

@ -21,7 +21,7 @@ import { ProgressController } from '../../progress';
import { EventEmitter } from 'events';
import { serverSideCallMetadata } from '../../instrumentation';
import type { CallLog, EventData, Mode, Source } from './recorderTypes';
import { isUnderTest } from '../../../utils/utils';
import { isUnderTest } from '../../../utils';
import * as mime from 'mime';
import { installAppIcon } from '../../chromium/crApp';
import { findChromiumChannel } from '../../registry';

View File

@ -34,7 +34,7 @@ import { RecorderApp } from './recorder/recorderApp';
import type { CallMetadata, InstrumentationListener, SdkObject } from '../instrumentation';
import type { Point } from '../../common/types';
import type { CallLog, CallLogStatus, EventData, Mode, Source, UIState } from './recorder/recorderTypes';
import { createGuid, monotonicTime } from '../../utils/utils';
import { createGuid, monotonicTime } from '../../utils';
import { metadataToCallLog } from './recorder/recorderUtils';
import { Debugger } from './debugger';
import { EventEmitter } from 'events';

View File

@ -22,7 +22,7 @@ import { debugLogger } from '../../../utils/debugLogger';
import type { Frame } from '../../frames';
import type { SnapshotData } from './snapshotterInjected';
import { frameSnapshotStreamer } from './snapshotterInjected';
import { calculateSha1, createGuid, monotonicTime } from '../../../utils/utils';
import { calculateSha1, createGuid, monotonicTime } from '../../../utils';
import type { FrameSnapshot } from '../common/snapshotTypes';
import type { ElementHandle } from '../../dom';
import * as mime from 'mime';

View File

@ -25,7 +25,7 @@ import { commandsWithTracingSnapshots } from '../../../protocol/channels';
import { ManualPromise } from '../../../utils';
import type { RegisteredListener } from '../../../utils/eventsHelper';
import { eventsHelper } from '../../../utils/eventsHelper';
import { assert, calculateSha1, createGuid, mkdirIfNeeded, monotonicTime, removeFolders } from '../../../utils/utils';
import { assert, calculateSha1, createGuid, mkdirIfNeeded, monotonicTime, removeFolders } from '../../../utils';
import { Artifact } from '../../artifact';
import { BrowserContext } from '../../browserContext';
import { ElementHandle } from '../../dom';

View File

@ -19,7 +19,7 @@ import fs from 'fs';
import * as consoleApiSource from '../../../generated/consoleApiSource';
import { HttpServer } from '../../../utils/httpServer';
import { findChromiumChannel } from '../../registry';
import { isUnderTest } from '../../../utils/utils';
import { isUnderTest } from '../../../utils';
import type { BrowserContext } from '../../browserContext';
import { installAppIcon } from '../../chromium/crApp';
import { serverSideCallMetadata } from '../../instrumentation';

View File

@ -17,7 +17,7 @@
import WebSocket from 'ws';
import type { Progress } from './progress';
import { makeWaitForNextTask } from '../utils/utils';
import { makeWaitForNextTask } from '../utils';
export type ProtocolRequest = {
id: number;

View File

@ -24,7 +24,7 @@ import type { ConnectionTransport } from '../transport';
import type { BrowserOptions, PlaywrightOptions } from '../browser';
import type * as types from '../types';
import { rewriteErrorMessage } from '../../utils/stackTrace';
import { wrapInASCIIBox } from '../../utils/utils';
import { wrapInASCIIBox } from '../../utils';
export class WebKit extends BrowserType {
constructor(playwrightOptions: PlaywrightOptions) {

View File

@ -20,7 +20,7 @@ import { Browser } from '../browser';
import { assertBrowserContextIsNotOwned, BrowserContext, verifyGeolocation } from '../browserContext';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import * as network from '../network';
import type { Page, PageBinding, PageDelegate } from '../page';
import type { ConnectionTransport } from '../transport';

View File

@ -16,7 +16,7 @@
*/
import { EventEmitter } from 'events';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
import type { ConnectionTransport, ProtocolRequest, ProtocolResponse } from '../transport';
import type { Protocol } from './protocol';
import { rewriteErrorMessage } from '../../utils/stackTrace';

View File

@ -19,7 +19,7 @@ import * as input from '../input';
import type * as types from '../types';
import { macEditingCommands } from '../macEditingCommands';
import type { WKSession } from './wkConnection';
import { isString } from '../../utils/utils';
import { isString } from '../../utils';
import type { Page } from '../page';
function toModifiersMask(modifiers: Set<types.KeyboardModifier>): number {

View File

@ -20,7 +20,7 @@ import * as network from '../network';
import type * as types from '../types';
import type { Protocol } from './protocol';
import type { WKSession } from './wkConnection';
import { assert, headersObjectToArray, headersArrayToObject } from '../../utils/utils';
import { assert, headersObjectToArray, headersArrayToObject } from '../../utils';
import { ManualPromise } from '../../utils';
const errorReasons: { [reason: string]: Protocol.Network.ResourceErrorType } = {

View File

@ -19,7 +19,7 @@ import * as jpeg from 'jpeg-js';
import path from 'path';
import * as png from 'pngjs';
import { splitErrorMessage } from '../../utils/stackTrace';
import { assert, createGuid, debugAssert, headersArrayToObject, headersObjectToArray, hostPlatform } from '../../utils/utils';
import { assert, createGuid, debugAssert, headersArrayToObject, headersObjectToArray, hostPlatform } from '../../utils';
import type * as accessibility from '../accessibility';
import * as dialog from '../dialog';
import * as dom from '../dom';

View File

@ -19,7 +19,7 @@ import type { WKPage } from './wkPage';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import type { Protocol } from './protocol';
import { assert } from '../../utils/utils';
import { assert } from '../../utils';
export class WKProvisionalPage {
readonly _session: WKSession;

View File

@ -1,2 +1,3 @@
[*]
./
../third_party/diff_match_patch

View File

@ -19,7 +19,7 @@ import fs from 'fs';
import path from 'path';
import { Server as WebSocketServer } from 'ws';
import * as mime from 'mime';
import { assert } from './utils';
import { assert } from './';
export type ServerRouteHandler = (request: http.IncomingMessage, response: http.ServerResponse) => boolean;

View File

@ -14,8 +14,415 @@
* limitations under the License.
*/
import type { SpawnOptions } from 'child_process';
import { execSync, spawn } from 'child_process';
import * as crypto from 'crypto';
import fs from 'fs';
import os from 'os';
import path from 'path';
import removeFolder from 'rimraf';
import type stream from 'stream';
import * as URL from 'url';
import type { NameValue } from '../protocol/channels';
import { getUbuntuVersionSync, parseOSReleaseText } from './ubuntuVersion';
export { ManualPromise } from './manualPromise';
export { MultiMap } from './multimap';
export { raceAgainstTimeout, TimeoutRunner, TimeoutRunnerError } from './timeoutRunner';
export type { HTTPRequestParams } from './netUtils';
export { httpRequest, fetchData } from './netUtils';
export const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
export function spawnAsync(cmd: string, args: string[], options: SpawnOptions = {}): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> {
const process = spawn(cmd, args, Object.assign({ windowsHide: true }, options));
return new Promise(resolve => {
let stdout = '';
let stderr = '';
if (process.stdout)
process.stdout.on('data', data => stdout += data);
if (process.stderr)
process.stderr.on('data', data => stderr += data);
process.on('close', code => resolve({ stdout, stderr, code }));
process.on('error', error => resolve({ stdout, stderr, code: 0, error }));
});
}
// See https://joel.tools/microtasks/
export function makeWaitForNextTask() {
// As of Mar 2021, Electron v12 doesn't create new task with `setImmediate` despite
// using Node 14 internally, so we fallback to `setTimeout(0)` instead.
// @see https://github.com/electron/electron/issues/28261
if ((process.versions as any).electron)
return (callback: () => void) => setTimeout(callback, 0);
if (parseInt(process.versions.node, 10) >= 11)
return setImmediate;
// Unlike Node 11, Node 10 and less have a bug with Task and MicroTask execution order:
// - https://github.com/nodejs/node/issues/22257
//
// So we can't simply run setImmediate to dispatch code in a following task.
// However, we can run setImmediate from-inside setImmediate to make sure we're getting
// in the following task.
let spinning = false;
const callbacks: (() => void)[] = [];
const loop = () => {
const callback = callbacks.shift();
if (!callback) {
spinning = false;
return;
}
setImmediate(loop);
// Make sure to call callback() as the last thing since it's
// untrusted code that might throw.
callback();
};
return (callback: () => void) => {
callbacks.push(callback);
if (!spinning) {
spinning = true;
setImmediate(loop);
}
};
}
export function assert(value: any, message?: string): asserts value {
if (!value)
throw new Error(message || 'Assertion error');
}
export function debugAssert(value: any, message?: string): asserts value {
if (isUnderTest() && !value)
throw new Error(message);
}
export function isString(obj: any): obj is string {
return typeof obj === 'string' || obj instanceof String;
}
export function isRegExp(obj: any): obj is RegExp {
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';
}
export function isObject(obj: any): obj is NonNullable<object> {
return typeof obj === 'object' && obj !== null;
}
export function isError(obj: any): obj is Error {
return obj instanceof Error || (obj && obj.__proto__ && obj.__proto__.name === 'Error');
}
const debugEnv = getFromENV('PWDEBUG') || '';
export function debugMode() {
if (debugEnv === 'console')
return 'console';
if (debugEnv === '0' || debugEnv === 'false')
return '';
return debugEnv ? 'inspector' : '';
}
let _isUnderTest = false;
export function setUnderTest() {
_isUnderTest = true;
}
export function isUnderTest(): boolean {
return _isUnderTest;
}
export function experimentalFeaturesEnabled() {
return isUnderTest() || !!process.env.PLAYWRIGHT_EXPERIMENTAL_FEATURES;
}
export function getFromENV(name: string): string | undefined {
let value = process.env[name];
value = value === undefined ? process.env[`npm_config_${name.toLowerCase()}`] : value;
value = value === undefined ? process.env[`npm_package_config_${name.toLowerCase()}`] : value;
return value;
}
export function getAsBooleanFromENV(name: string): boolean {
const value = getFromENV(name);
return !!value && value !== 'false' && value !== '0';
}
export async function mkdirIfNeeded(filePath: string) {
// This will harmlessly throw on windows if the dirname is the root directory.
await fs.promises.mkdir(path.dirname(filePath), { recursive: true }).catch(() => {});
}
type HeadersArray = { name: string, value: string }[];
type HeadersObject = { [key: string]: string };
export function headersObjectToArray(headers: HeadersObject, separator?: string, setCookieSeparator?: string): HeadersArray {
if (!setCookieSeparator)
setCookieSeparator = separator;
const result: HeadersArray = [];
for (const name in headers) {
const values = headers[name];
if (separator) {
const sep = name.toLowerCase() === 'set-cookie' ? setCookieSeparator : separator;
for (const value of values.split(sep!))
result.push({ name, value: value.trim() });
} else {
result.push({ name, value: values });
}
}
return result;
}
export function headersArrayToObject(headers: HeadersArray, lowerCase: boolean): HeadersObject {
const result: HeadersObject = {};
for (const { name, value } of headers)
result[lowerCase ? name.toLowerCase() : name] = value;
return result;
}
export function monotonicTime(): number {
const [seconds, nanoseconds] = process.hrtime();
return seconds * 1000 + (nanoseconds / 1000 | 0) / 1000;
}
export function objectToArray(map?: { [key: string]: any }): NameValue[] | undefined {
if (!map)
return undefined;
const result = [];
for (const [name, value] of Object.entries(map))
result.push({ name, value: String(value) });
return result;
}
export function arrayToObject(array?: NameValue[]): { [key: string]: string } | undefined {
if (!array)
return undefined;
const result: { [key: string]: string } = {};
for (const { name, value } of array)
result[name] = value;
return result;
}
export function calculateSha1(buffer: Buffer | string): string {
const hash = crypto.createHash('sha1');
hash.update(buffer);
return hash.digest('hex');
}
export function createGuid(): string {
return crypto.randomBytes(16).toString('hex');
}
export async function removeFolders(dirs: string[]): Promise<Array<Error|null|undefined>> {
return await Promise.all(dirs.map((dir: string) => {
return new Promise<Error|null|undefined>(fulfill => {
removeFolder(dir, { maxBusyTries: 10 }, error => {
fulfill(error ?? undefined);
});
});
}));
}
export function canAccessFile(file: string) {
if (!file)
return false;
try {
fs.accessSync(file);
return true;
} catch (e) {
return false;
}
}
let cachedUserAgent: string | undefined;
export function getUserAgent(): string {
if (cachedUserAgent)
return cachedUserAgent;
try {
cachedUserAgent = determineUserAgent();
} catch (e) {
cachedUserAgent = 'Playwright/unknown';
}
return cachedUserAgent;
}
function determineUserAgent(): string {
let osIdentifier = 'unknown';
let osVersion = 'unknown';
if (process.platform === 'win32') {
const version = os.release().split('.');
osIdentifier = 'windows';
osVersion = `${version[0]}.${version[1]}`;
} else if (process.platform === 'darwin') {
const version = execSync('sw_vers -productVersion', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim().split('.');
osIdentifier = 'macOS';
osVersion = `${version[0]}.${version[1]}`;
} else if (process.platform === 'linux') {
try {
// List of /etc/os-release values for different distributions could be
// found here: https://gist.github.com/aslushnikov/8ceddb8288e4cf9db3039c02e0f4fb75
const osReleaseText = fs.readFileSync('/etc/os-release', 'utf8');
const fields = parseOSReleaseText(osReleaseText);
osIdentifier = fields.get('id') || 'unknown';
osVersion = fields.get('version_id') || 'unknown';
} catch (e) {
// Linux distribution without /etc/os-release.
// Default to linux/unknown.
osIdentifier = 'linux';
}
}
const { langName, langVersion } = getClientLanguage();
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${langName}/${langVersion}`;
}
export function getClientLanguage(): { langName: string, langVersion: string } {
let langName = 'unknown';
let langVersion = 'unknown';
if (!process.env.PW_LANG_NAME) {
langName = 'node';
langVersion = process.version.substring(1).split('.').slice(0, 2).join('.');
} else if (['node', 'python', 'java', 'csharp'].includes(process.env.PW_LANG_NAME)) {
langName = process.env.PW_LANG_NAME;
langVersion = process.env.PW_LANG_NAME_VERSION ?? 'unknown';
}
return { langName, langVersion };
}
export function getPlaywrightVersion(majorMinorOnly = false) {
const packageJson = require('./../../package.json');
return majorMinorOnly ? packageJson.version.split('.').slice(0, 2).join('.') : packageJson.version;
}
export function constructURLBasedOnBaseURL(baseURL: string | undefined, givenURL: string): string {
try {
return (new URL.URL(givenURL, baseURL)).toString();
} catch (e) {
return givenURL;
}
}
export type HostPlatform = 'win64' |
'mac10.13' |
'mac10.14' |
'mac10.15' |
'mac11' | 'mac11-arm64' |
'mac12' | 'mac12-arm64' |
'ubuntu18.04' | 'ubuntu18.04-arm64' |
'ubuntu20.04' | 'ubuntu20.04-arm64' |
'generic-linux' | 'generic-linux-arm64' |
'<unknown>';
export const hostPlatform = ((): HostPlatform => {
const platform = os.platform();
if (platform === 'darwin') {
const ver = os.release().split('.').map((a: string) => parseInt(a, 10));
let macVersion = '';
if (ver[0] < 18) {
// Everything before 10.14 is considered 10.13.
macVersion = 'mac10.13';
} else if (ver[0] === 18) {
macVersion = 'mac10.14';
} else if (ver[0] === 19) {
macVersion = 'mac10.15';
} else {
// ver[0] >= 20
const LAST_STABLE_MAC_MAJOR_VERSION = 12;
// Best-effort support for MacOS beta versions.
macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MAC_MAJOR_VERSION);
// BigSur is the first version that might run on Apple Silicon.
if (os.cpus().some(cpu => cpu.model.includes('Apple')))
macVersion += '-arm64';
}
return macVersion as HostPlatform;
}
if (platform === 'linux') {
const archSuffix = os.arch() === 'arm64' ? '-arm64' : '';
const ubuntuVersion = getUbuntuVersionSync();
if (!ubuntuVersion)
return ('generic-linux' + archSuffix) as HostPlatform;
if (parseInt(ubuntuVersion, 10) <= 19)
return ('ubuntu18.04' + archSuffix) as HostPlatform;
return ('ubuntu20.04' + archSuffix) as HostPlatform;
}
if (platform === 'win32')
return 'win64';
return '<unknown>';
})();
export function wrapInASCIIBox(text: string, padding = 0): string {
const lines = text.split('\n');
const maxLength = Math.max(...lines.map(line => line.length));
return [
'╔' + '═'.repeat(maxLength + padding * 2) + '╗',
...lines.map(line => '║' + ' '.repeat(padding) + line + ' '.repeat(maxLength - line.length + padding) + '║'),
'╚' + '═'.repeat(maxLength + padding * 2) + '╝',
].join('\n');
}
export function isFilePayload(value: any): boolean {
return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
}
export function streamToString(stream: stream.Readable): Promise<string> {
return new Promise<string>((resolve, reject) => {
const chunks: Buffer[] = [];
stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
stream.on('error', reject);
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
}
export async function transformCommandsForRoot(commands: string[]): Promise<{ command: string, args: string[], elevatedPermissions: boolean}> {
const isRoot = process.getuid() === 0;
if (isRoot)
return { command: 'sh', args: ['-c', `${commands.join('&& ')}`], elevatedPermissions: false };
const sudoExists = await spawnAsync('which', ['sudo']);
if (sudoExists.code === 0)
return { command: 'sudo', args: ['--', 'sh', '-c', `${commands.join('&& ')}`], elevatedPermissions: true };
return { command: 'su', args: ['root', '-c', `${commands.join('&& ')}`], elevatedPermissions: true };
}
export class SigIntWatcher {
private _hadSignal: boolean = false;
private _sigintPromise: Promise<void>;
private _sigintHandler: () => void;
constructor() {
let sigintCallback: () => void;
this._sigintPromise = new Promise<void>(f => sigintCallback = f);
this._sigintHandler = () => {
// We remove the handler so that second Ctrl+C immediately kills the runner
// via the default sigint handler. This is handy in the case where our shutdown
// takes a lot of time or is buggy.
//
// When running through NPM we might get multiple SIGINT signals
// for a single Ctrl+C - this is an NPM bug present since at least NPM v6.
// https://github.com/npm/cli/issues/1591
// https://github.com/npm/cli/issues/2124
//
// Therefore, removing the handler too soon will just kill the process
// with default handler without printing the results.
// We work around this by giving NPM 1000ms to send us duplicate signals.
// The side effect is that slow shutdown or bug in our runner will force
// the user to hit Ctrl+C again after at least a second.
setTimeout(() => process.off('SIGINT', this._sigintHandler), 1000);
this._hadSignal = true;
sigintCallback();
};
process.on('SIGINT', this._sigintHandler);
}
promise(): Promise<void> {
return this._sigintPromise;
}
hadSignal(): boolean {
return this._hadSignal;
}
disarm() {
process.off('SIGINT', this._sigintHandler);
}
}

View File

@ -18,7 +18,7 @@
import * as childProcess from 'child_process';
import * as readline from 'readline';
import { eventsHelper } from './eventsHelper';
import { isUnderTest, removeFolders } from './utils';
import { isUnderTest, removeFolders } from './';
import rimraf from 'rimraf';
export type Env = {[key: string]: string | number | boolean | undefined};

View File

@ -21,7 +21,7 @@ import net from 'net';
import util from 'util';
import { debugLogger } from './debugLogger';
import { createSocket } from './netUtils';
import { assert, createGuid } from './utils';
import { assert, createGuid } from './';
const dnsLookupAsync = util.promisify(dns.lookup);

View File

@ -17,7 +17,7 @@
import path from 'path';
import type { StackFrame } from '../protocol/channels';
import StackUtils from 'stack-utils';
import { isUnderTest } from './utils';
import { isUnderTest } from './';
const stackUtils = new StackUtils();

View File

@ -15,7 +15,7 @@
*/
import { ManualPromise } from './manualPromise';
import { monotonicTime } from './utils';
import { monotonicTime } from './';
export class TimeoutRunnerError extends Error {}

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { debugMode } from './utils';
import { debugMode } from './';
export const DEFAULT_TIMEOUT = 30000;

View File

@ -1,422 +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 { SpawnOptions } from 'child_process';
import { execSync, spawn } from 'child_process';
import * as crypto from 'crypto';
import fs from 'fs';
import os from 'os';
import path from 'path';
import removeFolder from 'rimraf';
import type stream from 'stream';
import * as URL from 'url';
import type { NameValue } from '../protocol/channels';
import { getUbuntuVersionSync, parseOSReleaseText } from './ubuntuVersion';
export const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
export function spawnAsync(cmd: string, args: string[], options: SpawnOptions = {}): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> {
const process = spawn(cmd, args, Object.assign({ windowsHide: true }, options));
return new Promise(resolve => {
let stdout = '';
let stderr = '';
if (process.stdout)
process.stdout.on('data', data => stdout += data);
if (process.stderr)
process.stderr.on('data', data => stderr += data);
process.on('close', code => resolve({ stdout, stderr, code }));
process.on('error', error => resolve({ stdout, stderr, code: 0, error }));
});
}
// See https://joel.tools/microtasks/
export function makeWaitForNextTask() {
// As of Mar 2021, Electron v12 doesn't create new task with `setImmediate` despite
// using Node 14 internally, so we fallback to `setTimeout(0)` instead.
// @see https://github.com/electron/electron/issues/28261
if ((process.versions as any).electron)
return (callback: () => void) => setTimeout(callback, 0);
if (parseInt(process.versions.node, 10) >= 11)
return setImmediate;
// Unlike Node 11, Node 10 and less have a bug with Task and MicroTask execution order:
// - https://github.com/nodejs/node/issues/22257
//
// So we can't simply run setImmediate to dispatch code in a following task.
// However, we can run setImmediate from-inside setImmediate to make sure we're getting
// in the following task.
let spinning = false;
const callbacks: (() => void)[] = [];
const loop = () => {
const callback = callbacks.shift();
if (!callback) {
spinning = false;
return;
}
setImmediate(loop);
// Make sure to call callback() as the last thing since it's
// untrusted code that might throw.
callback();
};
return (callback: () => void) => {
callbacks.push(callback);
if (!spinning) {
spinning = true;
setImmediate(loop);
}
};
}
export function assert(value: any, message?: string): asserts value {
if (!value)
throw new Error(message || 'Assertion error');
}
export function debugAssert(value: any, message?: string): asserts value {
if (isUnderTest() && !value)
throw new Error(message);
}
export function isString(obj: any): obj is string {
return typeof obj === 'string' || obj instanceof String;
}
export function isRegExp(obj: any): obj is RegExp {
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';
}
export function isObject(obj: any): obj is NonNullable<object> {
return typeof obj === 'object' && obj !== null;
}
export function isError(obj: any): obj is Error {
return obj instanceof Error || (obj && obj.__proto__ && obj.__proto__.name === 'Error');
}
const debugEnv = getFromENV('PWDEBUG') || '';
export function debugMode() {
if (debugEnv === 'console')
return 'console';
if (debugEnv === '0' || debugEnv === 'false')
return '';
return debugEnv ? 'inspector' : '';
}
let _isUnderTest = false;
export function setUnderTest() {
_isUnderTest = true;
}
export function isUnderTest(): boolean {
return _isUnderTest;
}
export function experimentalFeaturesEnabled() {
return isUnderTest() || !!process.env.PLAYWRIGHT_EXPERIMENTAL_FEATURES;
}
export function getFromENV(name: string): string | undefined {
let value = process.env[name];
value = value === undefined ? process.env[`npm_config_${name.toLowerCase()}`] : value;
value = value === undefined ? process.env[`npm_package_config_${name.toLowerCase()}`] : value;
return value;
}
export function getAsBooleanFromENV(name: string): boolean {
const value = getFromENV(name);
return !!value && value !== 'false' && value !== '0';
}
export async function mkdirIfNeeded(filePath: string) {
// This will harmlessly throw on windows if the dirname is the root directory.
await fs.promises.mkdir(path.dirname(filePath), { recursive: true }).catch(() => {});
}
type HeadersArray = { name: string, value: string }[];
type HeadersObject = { [key: string]: string };
export function headersObjectToArray(headers: HeadersObject, separator?: string, setCookieSeparator?: string): HeadersArray {
if (!setCookieSeparator)
setCookieSeparator = separator;
const result: HeadersArray = [];
for (const name in headers) {
const values = headers[name];
if (separator) {
const sep = name.toLowerCase() === 'set-cookie' ? setCookieSeparator : separator;
for (const value of values.split(sep!))
result.push({ name, value: value.trim() });
} else {
result.push({ name, value: values });
}
}
return result;
}
export function headersArrayToObject(headers: HeadersArray, lowerCase: boolean): HeadersObject {
const result: HeadersObject = {};
for (const { name, value } of headers)
result[lowerCase ? name.toLowerCase() : name] = value;
return result;
}
export function monotonicTime(): number {
const [seconds, nanoseconds] = process.hrtime();
return seconds * 1000 + (nanoseconds / 1000 | 0) / 1000;
}
export function objectToArray(map?: { [key: string]: any }): NameValue[] | undefined {
if (!map)
return undefined;
const result = [];
for (const [name, value] of Object.entries(map))
result.push({ name, value: String(value) });
return result;
}
export function arrayToObject(array?: NameValue[]): { [key: string]: string } | undefined {
if (!array)
return undefined;
const result: { [key: string]: string } = {};
for (const { name, value } of array)
result[name] = value;
return result;
}
export function calculateSha1(buffer: Buffer | string): string {
const hash = crypto.createHash('sha1');
hash.update(buffer);
return hash.digest('hex');
}
export function createGuid(): string {
return crypto.randomBytes(16).toString('hex');
}
export async function removeFolders(dirs: string[]): Promise<Array<Error|null|undefined>> {
return await Promise.all(dirs.map((dir: string) => {
return new Promise<Error|null|undefined>(fulfill => {
removeFolder(dir, { maxBusyTries: 10 }, error => {
fulfill(error ?? undefined);
});
});
}));
}
export function canAccessFile(file: string) {
if (!file)
return false;
try {
fs.accessSync(file);
return true;
} catch (e) {
return false;
}
}
let cachedUserAgent: string | undefined;
export function getUserAgent(): string {
if (cachedUserAgent)
return cachedUserAgent;
try {
cachedUserAgent = determineUserAgent();
} catch (e) {
cachedUserAgent = 'Playwright/unknown';
}
return cachedUserAgent;
}
function determineUserAgent(): string {
let osIdentifier = 'unknown';
let osVersion = 'unknown';
if (process.platform === 'win32') {
const version = os.release().split('.');
osIdentifier = 'windows';
osVersion = `${version[0]}.${version[1]}`;
} else if (process.platform === 'darwin') {
const version = execSync('sw_vers -productVersion', { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim().split('.');
osIdentifier = 'macOS';
osVersion = `${version[0]}.${version[1]}`;
} else if (process.platform === 'linux') {
try {
// List of /etc/os-release values for different distributions could be
// found here: https://gist.github.com/aslushnikov/8ceddb8288e4cf9db3039c02e0f4fb75
const osReleaseText = fs.readFileSync('/etc/os-release', 'utf8');
const fields = parseOSReleaseText(osReleaseText);
osIdentifier = fields.get('id') || 'unknown';
osVersion = fields.get('version_id') || 'unknown';
} catch (e) {
// Linux distribution without /etc/os-release.
// Default to linux/unknown.
osIdentifier = 'linux';
}
}
const { langName, langVersion } = getClientLanguage();
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${langName}/${langVersion}`;
}
export function getClientLanguage(): { langName: string, langVersion: string } {
let langName = 'unknown';
let langVersion = 'unknown';
if (!process.env.PW_LANG_NAME) {
langName = 'node';
langVersion = process.version.substring(1).split('.').slice(0, 2).join('.');
} else if (['node', 'python', 'java', 'csharp'].includes(process.env.PW_LANG_NAME)) {
langName = process.env.PW_LANG_NAME;
langVersion = process.env.PW_LANG_NAME_VERSION ?? 'unknown';
}
return { langName, langVersion };
}
export function getPlaywrightVersion(majorMinorOnly = false) {
const packageJson = require('./../../package.json');
return majorMinorOnly ? packageJson.version.split('.').slice(0, 2).join('.') : packageJson.version;
}
export function constructURLBasedOnBaseURL(baseURL: string | undefined, givenURL: string): string {
try {
return (new URL.URL(givenURL, baseURL)).toString();
} catch (e) {
return givenURL;
}
}
export type HostPlatform = 'win64' |
'mac10.13' |
'mac10.14' |
'mac10.15' |
'mac11' | 'mac11-arm64' |
'mac12' | 'mac12-arm64' |
'ubuntu18.04' | 'ubuntu18.04-arm64' |
'ubuntu20.04' | 'ubuntu20.04-arm64' |
'generic-linux' | 'generic-linux-arm64' |
'<unknown>';
export const hostPlatform = ((): HostPlatform => {
const platform = os.platform();
if (platform === 'darwin') {
const ver = os.release().split('.').map((a: string) => parseInt(a, 10));
let macVersion = '';
if (ver[0] < 18) {
// Everything before 10.14 is considered 10.13.
macVersion = 'mac10.13';
} else if (ver[0] === 18) {
macVersion = 'mac10.14';
} else if (ver[0] === 19) {
macVersion = 'mac10.15';
} else {
// ver[0] >= 20
const LAST_STABLE_MAC_MAJOR_VERSION = 12;
// Best-effort support for MacOS beta versions.
macVersion = 'mac' + Math.min(ver[0] - 9, LAST_STABLE_MAC_MAJOR_VERSION);
// BigSur is the first version that might run on Apple Silicon.
if (os.cpus().some(cpu => cpu.model.includes('Apple')))
macVersion += '-arm64';
}
return macVersion as HostPlatform;
}
if (platform === 'linux') {
const archSuffix = os.arch() === 'arm64' ? '-arm64' : '';
const ubuntuVersion = getUbuntuVersionSync();
if (!ubuntuVersion)
return ('generic-linux' + archSuffix) as HostPlatform;
if (parseInt(ubuntuVersion, 10) <= 19)
return ('ubuntu18.04' + archSuffix) as HostPlatform;
return ('ubuntu20.04' + archSuffix) as HostPlatform;
}
if (platform === 'win32')
return 'win64';
return '<unknown>';
})();
export function wrapInASCIIBox(text: string, padding = 0): string {
const lines = text.split('\n');
const maxLength = Math.max(...lines.map(line => line.length));
return [
'╔' + '═'.repeat(maxLength + padding * 2) + '╗',
...lines.map(line => '║' + ' '.repeat(padding) + line + ' '.repeat(maxLength - line.length + padding) + '║'),
'╚' + '═'.repeat(maxLength + padding * 2) + '╝',
].join('\n');
}
export function isFilePayload(value: any): boolean {
return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
}
export function streamToString(stream: stream.Readable): Promise<string> {
return new Promise<string>((resolve, reject) => {
const chunks: Buffer[] = [];
stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
stream.on('error', reject);
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
}
export async function transformCommandsForRoot(commands: string[]): Promise<{ command: string, args: string[], elevatedPermissions: boolean}> {
const isRoot = process.getuid() === 0;
if (isRoot)
return { command: 'sh', args: ['-c', `${commands.join('&& ')}`], elevatedPermissions: false };
const sudoExists = await spawnAsync('which', ['sudo']);
if (sudoExists.code === 0)
return { command: 'sudo', args: ['--', 'sh', '-c', `${commands.join('&& ')}`], elevatedPermissions: true };
return { command: 'su', args: ['root', '-c', `${commands.join('&& ')}`], elevatedPermissions: true };
}
export class SigIntWatcher {
private _hadSignal: boolean = false;
private _sigintPromise: Promise<void>;
private _sigintHandler: () => void;
constructor() {
let sigintCallback: () => void;
this._sigintPromise = new Promise<void>(f => sigintCallback = f);
this._sigintHandler = () => {
// We remove the handler so that second Ctrl+C immediately kills the runner
// via the default sigint handler. This is handy in the case where our shutdown
// takes a lot of time or is buggy.
//
// When running through NPM we might get multiple SIGINT signals
// for a single Ctrl+C - this is an NPM bug present since at least NPM v6.
// https://github.com/npm/cli/issues/1591
// https://github.com/npm/cli/issues/2124
//
// Therefore, removing the handler too soon will just kill the process
// with default handler without printing the results.
// We work around this by giving NPM 1000ms to send us duplicate signals.
// The side effect is that slow shutdown or bug in our runner will force
// the user to hit Ctrl+C again after at least a second.
setTimeout(() => process.off('SIGINT', this._sigintHandler), 1000);
this._hadSignal = true;
sigintCallback();
};
process.on('SIGINT', this._sigintHandler);
}
promise(): Promise<void> {
return this._sigintPromise;
}
hadSignal(): boolean {
return this._hadSignal;
}
disarm() {
process.off('SIGINT', this._sigintHandler);
}
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createGuid, spawnAsync } from 'playwright-core/lib/utils/utils';
import { createGuid, spawnAsync } from 'playwright-core/lib/utils';
const GIT_OPERATIONS_TIMEOUT_MS = 1500;
const kContentTypePlainText = 'text/plain';

View File

@ -29,7 +29,7 @@ import type { FilePatternFilter } from './util';
import { showHTMLReport } from './reporters/html';
import { GridServer } from 'playwright-core/lib/grid/gridServer';
import dockerFactory from 'playwright-core/lib/grid/dockerGridFactory';
import { createGuid, hostPlatform } from 'playwright-core/lib/utils/utils';
import { createGuid, hostPlatform } from 'playwright-core/lib/utils';
import { fileIsModule } from './loader';
const defaultTimeout = 30000;

View File

@ -48,7 +48,7 @@ import { toMatchSnapshot, toHaveScreenshot as _toHaveScreenshot } from './matche
import type { Expect } from './types';
import { currentTestInfo } from './globals';
import { serializeError, captureStackTrace, currentExpectTimeout } from './util';
import { monotonicTime } from 'playwright-core/lib/utils/utils';
import { monotonicTime } from 'playwright-core/lib/utils';
// from expect/build/types
export type SyncExpectationResult = {

View File

@ -19,7 +19,7 @@ import * as path from 'path';
import type { LaunchOptions, BrowserContextOptions, Page, BrowserContext, Video, APIRequestContext, Tracing } from 'playwright-core';
import type { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, TestInfo } from '../types/test';
import { rootTestType } from './testType';
import { createGuid, removeFolders, debugMode } from 'playwright-core/lib/utils/utils';
import { createGuid, removeFolders, debugMode } from 'playwright-core/lib/utils';
import { GridClient } from 'playwright-core/lib/grid/gridClient';
export { expect } from './expect';
export const _baseTest: TestType<{}, {}> = rootTestType.test;

View File

@ -28,7 +28,7 @@ import { ProjectImpl } from './project';
import type { Reporter } from '../types/testReporter';
import type { BuiltInReporter } from './runner';
import { builtInReporters } from './runner';
import { isRegExp } from 'playwright-core/lib/utils/utils';
import { isRegExp } from 'playwright-core/lib/utils';
import { serializeError } from './util';
// To allow multiple loaders in the same process without clearing require cache,

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