mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: use utils via index export (3) (#13403)
This commit is contained in:
parent
5536e64538
commit
40d5e3a3c9
@ -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",
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 }[] = [];
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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}`);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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[]> {
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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[] };
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 } = {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
[*]
|
||||
./
|
||||
../third_party/diff_match_patch
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ManualPromise } from './manualPromise';
|
||||
import { monotonicTime } from './utils';
|
||||
import { monotonicTime } from './';
|
||||
|
||||
export class TimeoutRunnerError extends Error {}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { debugMode } from './utils';
|
||||
import { debugMode } from './';
|
||||
|
||||
export const DEFAULT_TIMEOUT = 30000;
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user