chore: use utils via index export (5) (#13413)

This commit is contained in:
Pavel Feldman 2022-04-07 19:18:22 -08:00 committed by GitHub
parent 155bb7fcae
commit e79b90f454
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 337 additions and 247 deletions

View file

@ -24,9 +24,16 @@
"./lib/outofprocess": "./lib/outofprocess.js",
"./lib/utils": "./lib/utils/index.js",
"./lib/utils/comparators": "./lib/utils/comparators.js",
"./lib/utils/eventsHelper": "./lib/utils/eventsHelper.js",
"./lib/utils/fileUtils": "./lib/utils/fileUtils.js",
"./lib/utils/httpServer": "./lib/utils/httpServer.js",
"./lib/utils/hostPlatform": "./lib/utils/hostPlatform.js",
"./lib/utils/manualPromise": "./lib/utils/manualPromise.js",
"./lib/utils/multimap": "./lib/utils/multimap.js",
"./lib/utils/processLauncher": "./lib/utils/processLauncher.js",
"./lib/utils/spawnAsync": "./lib/utils/spawnAsync.js",
"./lib/utils/stackTrace": "./lib/utils/stackTrace.js",
"./lib/utils/timeoutRunner": "./lib/utils/timeoutRunner.js",
"./lib/remote/playwrightServer": "./lib/remote/playwrightServer.js",
"./lib/remote/playwrightClient": "./lib/remote/playwrightClient.js",
"./lib/server": "./lib/server/index.js"

View file

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

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';
import { mkdirIfNeeded } from '../utils/fileUtils';
import { ChannelOwner } from './channelOwner';
import type { Readable } from 'stream';

View file

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

View file

@ -26,7 +26,7 @@ import { envObjectToArray } from './clientHelper';
import { assert, headersObjectToArray, monotonicTime } from '../utils';
import type * as api from '../../types/types';
import { kBrowserClosedError } from '../common/errors';
import { raceAgainstTimeout } from '../utils';
import { raceAgainstTimeout } from '../utils/timeoutRunner';
import type { Playwright } from './playwright';
export interface BrowserServerLauncher {

View file

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

View file

@ -23,7 +23,8 @@ 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';
import { assert, isString } from '../utils';
import { mkdirIfNeeded } from '../utils/fileUtils';
import type * as api from '../../types/types';
import type * as structs from '../../types/structs';
import type { BrowserContext } from './browserContext';

View file

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

View file

@ -22,14 +22,14 @@ import type { Headers, RemoteAddr, SecurityDetails, WaitForEventOptions } from '
import fs from 'fs';
import * as mime from 'mime';
import { isString, headersObjectToArray } from '../utils';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
import { Events } from './events';
import type { Page } from './page';
import { Waiter } from './waiter';
import type * as api from '../../types/types';
import type { HeadersArray, URLMatch } from '../common/types';
import { urlMatches } from './clientHelper';
import { MultiMap } from '../utils';
import { MultiMap } from '../utils/multimap';
import { APIResponse } from './fetch';
export type NetworkCookie = {

View file

@ -46,7 +46,8 @@ 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';
import { isString, isRegExp, isObject, headersObjectToArray } from '../utils';
import { mkdirIfNeeded } from '../utils/fileUtils';
import { isSafeCloseError } from '../common/errors';
import { Video } from './video';
import { Artifact } from './artifact';

View file

@ -19,7 +19,7 @@ import { IpcTransport } from './protocol/transport';
import type { Playwright } from './client/playwright';
import * as childProcess from 'child_process';
import * as path from 'path';
import { ManualPromise } from './utils';
import { ManualPromise } from './utils/manualPromise';
export async function start(env: any = {}): Promise<{ playwright: Playwright, stop: () => Promise<void> }> {
const client = new PlaywrightClient(env);

View file

@ -22,7 +22,8 @@ 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';
import { createGuid, makeWaitForNextTask } from '../../utils';
import { removeFolders } from '../../utils/fileUtils';
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
import type { BrowserContext } from '../browserContext';
import { validateBrowserContextOptions } from '../browserContext';

View file

@ -16,7 +16,7 @@
import fs from 'fs';
import { assert } from '../utils';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
import { SdkObject } from './instrumentation';
type SaveCallback = (localPath: string, error?: string) => Promise<void>;

View file

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

View file

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

View file

@ -33,7 +33,8 @@ import type * as types from '../types';
import type { HTTPRequestParams } from '../../common/netUtils';
import { fetchData } from '../../common/netUtils';
import { getUserAgent } from '../../common/userAgent';
import { debugMode, headersArrayToObject, removeFolders, streamToString, wrapInASCIIBox } from '../../utils';
import { debugMode, headersArrayToObject, streamToString, wrapInASCIIBox } from '../../utils';
import { removeFolders } from '../../utils/fileUtils';
import { RecentLogsCollector } from '../../common/debugLogger';
import type { Progress } from '../progress';
import { ProgressController } from '../progress';
@ -43,7 +44,7 @@ import type { CallMetadata } from '../instrumentation';
import http from 'http';
import https from 'https';
import { registry } from '../registry';
import { ManualPromise } from '../../utils';
import { ManualPromise } from '../../utils/manualPromise';
const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-');

View file

@ -16,8 +16,8 @@
*/
import type { CRSession } from './crConnection';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
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';

View file

@ -18,8 +18,8 @@
import type { CRSession } from './crConnection';
import type { Page } from '../page';
import { helper } from '../helper';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import type { Protocol } from './protocol';
import * as network from '../network';
import type * as frames from '../frames';

View file

@ -16,8 +16,8 @@
*/
import path from 'path';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
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';

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';
import { mkdirIfNeeded } from '../../utils/fileUtils';
import { splitErrorMessage } from '../../utils/stackTrace';
export function getExceptionMessage(exceptionDetails: Protocol.Runtime.ExceptionDetails): string {

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';
import { mkdirIfNeeded } from '../../utils/fileUtils';
import type { Artifact } from '../artifact';
export class ArtifactDispatcher extends Dispatcher<Artifact, channels.ArtifactChannel> implements channels.ArtifactChannel {

View file

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

View file

@ -34,7 +34,7 @@ import type { BrowserWindow } from 'electron';
import type { Progress } from '../progress';
import { ProgressController } from '../progress';
import { helper } from '../helper';
import { eventsHelper } from '../../utils';
import { eventsHelper } from '../../utils/eventsHelper';
import type { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser';
import type * as childProcess from 'child_process';
import * as readline from 'readline';

View file

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

View file

@ -18,8 +18,8 @@
import * as dialog from '../dialog';
import * as dom from '../dom';
import type * as frames from '../frames';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { assert } from '../../utils';
import type { PageBinding, PageDelegate } from '../page';
import { Page, Worker } from '../page';
@ -34,7 +34,7 @@ import type { Protocol } from './protocol';
import type { Progress } from '../progress';
import { splitErrorMessage } from '../../utils/stackTrace';
import { debugLogger } from '../../common/debugLogger';
import { ManualPromise } from '../../utils';
import { ManualPromise } from '../../utils/manualPromise';
export const UTILITY_WORLD_NAME = '__playwright_utility_world__';

View file

@ -19,8 +19,8 @@ import type * as channels from '../protocol/channels';
import type { ConsoleMessage } from './console';
import * as dom from './dom';
import { helper } from './helper';
import type { RegisteredListener } from '../utils';
import { eventsHelper } from '../utils';
import type { RegisteredListener } from '../utils/eventsHelper';
import { eventsHelper } from '../utils/eventsHelper';
import * as js from './javascript';
import * as network from './network';
import type { Dialog } from './dialog';
@ -30,7 +30,7 @@ import { BrowserContext } from './browserContext';
import type { Progress } from './progress';
import { ProgressController } from './progress';
import { assert, constructURLBasedOnBaseURL, makeWaitForNextTask } from '../utils';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
import { debugLogger } from '../common/debugLogger';
import type { CallMetadata } from './instrumentation';
import { serverSideCallMetadata, SdkObject } from './instrumentation';

View file

@ -19,8 +19,8 @@ import type { EventEmitter } from 'events';
import type * as types from './types';
import type { Progress } from './progress';
import { debugLogger } from '../common/debugLogger';
import type { RegisteredListener } from '../utils';
import { eventsHelper } from '../utils';
import type { RegisteredListener } from '../utils/eventsHelper';
import { eventsHelper } from '../utils/eventsHelper';
class Helper {
static completeUserURL(urlString: string): string {

View file

@ -19,7 +19,7 @@ import * as utilityScriptSource from '../generated/utilityScriptSource';
import { serializeAsCallArgument } from './common/utilityScriptSerializers';
import { type UtilityScript } from './injected/utilityScript';
import { SdkObject } from './instrumentation';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
export type ObjectId = string;
export type RemoteObject = {

View file

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

View file

@ -31,7 +31,7 @@ import { FileChooser } from './fileChooser';
import type { Progress } from './progress';
import { ProgressController } from './progress';
import { assert, isError } from '../utils';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
import { debugLogger } from '../common/debugLogger';
import type { ImageComparatorOptions } from '../utils/comparators';
import { getComparator } from '../utils/comparators';

View file

@ -19,7 +19,7 @@ import { assert, monotonicTime } from '../utils';
import type { LogName } from '../common/debugLogger';
import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation';
import type { ElementHandle } from './dom';
import { ManualPromise } from '../utils';
import { ManualPromise } from '../utils/manualPromise';
import type { LogEntry } from './injected/injectedScript';
export interface Progress {

View file

@ -20,7 +20,7 @@ import fs from 'fs';
import os from 'os';
import path from 'path';
import { getUserAgent } from '../../common/userAgent';
import { existsAsync } from '../../utils';
import { existsAsync } from '../../utils/fileUtils';
import { debugLogger } from '../../common/debugLogger';
import { download } from './download';

View file

@ -19,6 +19,8 @@ import path from 'path';
import * as os from 'os';
import childProcess from 'child_process';
import * as utils from '../../utils';
import { spawnAsync } from '../../utils/spawnAsync';
import { hostPlatform } from '../../utils/hostPlatform';
import { buildPlaywrightCLICommand } from '.';
import { deps } from './nativeDeps';
import { getUbuntuVersion } from '../../utils/ubuntuVersion';
@ -66,7 +68,7 @@ export async function installDependenciesWindows(targets: Set<DependencyGroup>,
console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console
return;
}
const { code } = await utils.spawnAsync(command, args, { cwd: BIN_DIRECTORY, stdio: 'inherit' });
const { code } = await spawnAsync(command, args, { cwd: BIN_DIRECTORY, stdio: 'inherit' });
if (code !== 0)
throw new Error('Failed to install windows dependencies!');
}
@ -77,7 +79,7 @@ export async function installDependenciesLinux(targets: Set<DependencyGroup>, dr
throw new Error(`Unsupported Linux distribution, only Ubuntu is supported!`);
const libraries: string[] = [];
for (const target of targets) {
const info = deps[utils.hostPlatform];
const info = deps[hostPlatform];
if (!info) {
console.warn('Cannot install dependencies for this linux distribution!'); // eslint-disable-line no-console
return;
@ -92,7 +94,7 @@ export async function installDependenciesLinux(targets: Set<DependencyGroup>, dr
commands.push(['apt-get', 'install', '-y', '--no-install-recommends',
...uniqueLibraries,
].join(' '));
const { command, args, elevatedPermissions } = await utils.transformCommandsForRoot(commands);
const { command, args, elevatedPermissions } = await transformCommandsForRoot(commands);
if (dryRun) {
console.log(`${command} ${quoteProcessArgs(args).join(' ')}`); // eslint-disable-line no-console
return;
@ -189,7 +191,7 @@ export async function validateDependenciesLinux(sdkLanguage: string, linuxLddDir
const missingPackages = new Set();
const libraryToPackageNameMapping = {
...(deps[utils.hostPlatform]?.lib2package || {}),
...(deps[hostPlatform]?.lib2package || {}),
...MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU,
};
// Translate missing dependencies to package names to install with apt.
@ -287,7 +289,7 @@ async function executablesOrSharedLibraries(directoryPath: string): Promise<stri
async function missingFileDependenciesWindows(filePath: string): Promise<Array<string>> {
const executable = path.join(__dirname, '..', '..', '..', 'bin', 'PrintDeps.exe');
const dirname = path.dirname(filePath);
const { stdout, code } = await utils.spawnAsync(executable, [filePath], {
const { stdout, code } = await spawnAsync(executable, [filePath], {
cwd: dirname,
env: {
...process.env,
@ -305,7 +307,7 @@ async function missingFileDependencies(filePath: string, extraLDPaths: string[])
let LD_LIBRARY_PATH = extraLDPaths.join(':');
if (process.env.LD_LIBRARY_PATH)
LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`;
const { stdout, code } = await utils.spawnAsync('ldd', [filePath], {
const { stdout, code } = await spawnAsync('ldd', [filePath], {
cwd: dirname,
env: {
...process.env,
@ -324,7 +326,7 @@ async function missingDLOPENLibraries(libraries: string[]): Promise<string[]> {
// NOTE: Using full-qualified path to `ldconfig` since `/sbin` is not part of the
// default PATH in CRON.
// @see https://github.com/microsoft/playwright/issues/3397
const { stdout, code, error } = await utils.spawnAsync('/sbin/ldconfig', ['-p'], {});
const { stdout, code, error } = await spawnAsync('/sbin/ldconfig', ['-p'], {});
if (code !== 0 || error)
return [];
const isLibraryAvailable = (library: string) => stdout.toLowerCase().includes(library.toLowerCase());
@ -346,3 +348,13 @@ function quoteProcessArgs(args: string[]): string[] {
return arg;
});
}
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 };
}

View file

@ -23,8 +23,12 @@ import lockfile from 'proper-lockfile';
import { getUbuntuVersion } from '../../utils/ubuntuVersion';
import { fetchData } from '../../common/netUtils';
import { getClientLanguage } from '../../common/userAgent';
import { getFromENV, getAsBooleanFromENV, calculateSha1, removeFolders, existsAsync, hostPlatform, canAccessFile, spawnAsync, wrapInASCIIBox, transformCommandsForRoot } from '../../utils';
import { getFromENV, getAsBooleanFromENV, calculateSha1, wrapInASCIIBox } from '../../utils';
import { removeFolders, existsAsync, canAccessFile } from '../../utils/fileUtils';
import { hostPlatform } from '../../utils/hostPlatform';
import { spawnAsync } from '../../utils/spawnAsync';
import type { DependencyGroup } from './dependencies';
import { transformCommandsForRoot } from './dependencies';
import { installDependenciesLinux, installDependenciesWindows, validateDependenciesLinux, validateDependenciesWindows } from './dependencies';
import { downloadBrowserWithProgressBar, logPolitely } from './browserFetcher';
export { writeDockerVersion } from './dependencies';

View file

@ -24,7 +24,7 @@ import type { ParsedSelector } from './common/selectorParser';
import type * as types from './types';
import type { Progress } from './progress';
import { assert } from '../utils';
import { MultiMap } from '../utils';
import { MultiMap } from '../utils/multimap';
declare global {
interface Window {

View file

@ -22,10 +22,10 @@ import * as network from '../../network';
import { Page } from '../../page';
import type * as har from './har';
import { calculateSha1, monotonicTime } from '../../../utils';
import type { RegisteredListener } from '../../../utils';
import { eventsHelper } from '../../../utils';
import type { RegisteredListener } from '../../../utils/eventsHelper';
import { eventsHelper } from '../../../utils/eventsHelper';
import * as mime from 'mime';
import { ManualPromise } from '../../../utils';
import { ManualPromise } from '../../../utils/manualPromise';
const FALLBACK_HTTP_VERSION = 'HTTP/1.1';

View file

@ -38,7 +38,7 @@ import { createGuid, monotonicTime } from '../../utils';
import { metadataToCallLog } from './recorder/recorderUtils';
import { Debugger } from './debugger';
import { EventEmitter } from 'events';
import { raceAgainstTimeout } from '../../utils';
import { raceAgainstTimeout } from '../../utils/timeoutRunner';
type BindingSource = { frame: Frame, page: Page };

View file

@ -16,8 +16,8 @@
import { BrowserContext } from '../../browserContext';
import { Page } from '../../page';
import type { RegisteredListener } from '../../../utils';
import { eventsHelper } from '../../../utils';
import type { RegisteredListener } from '../../../utils/eventsHelper';
import { eventsHelper } from '../../../utils/eventsHelper';
import { debugLogger } from '../../../common/debugLogger';
import type { Frame } from '../../frames';
import type { SnapshotData } from './snapshotterInjected';

View file

@ -22,10 +22,11 @@ import yazl from 'yazl';
import type { NameValue } from '../../../common/types';
import type { TracingTracingStopChunkParams } from '../../../protocol/channels';
import { commandsWithTracingSnapshots } from '../../../protocol/channels';
import { ManualPromise } from '../../../utils';
import type { RegisteredListener } from '../../../utils';
import { eventsHelper } from '../../../utils';
import { assert, calculateSha1, createGuid, mkdirIfNeeded, monotonicTime, removeFolders } from '../../../utils';
import { ManualPromise } from '../../../utils/manualPromise';
import type { RegisteredListener } from '../../../utils/eventsHelper';
import { eventsHelper } from '../../../utils/eventsHelper';
import { assert, calculateSha1, createGuid, monotonicTime } from '../../../utils';
import { mkdirIfNeeded, removeFolders } from '../../../utils/fileUtils';
import { Artifact } from '../../artifact';
import { BrowserContext } from '../../browserContext';
import { ElementHandle } from '../../dom';

View file

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

View file

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

View file

@ -19,13 +19,14 @@ 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';
import { assert, createGuid, debugAssert, headersArrayToObject, headersObjectToArray } from '../../utils';
import { hostPlatform } from '../../utils/hostPlatform';
import type * as accessibility from '../accessibility';
import * as dialog from '../dialog';
import * as dom from '../dom';
import type * as frames from '../frames';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import { helper } from '../helper';
import type { JSHandle } from '../javascript';
import * as network from '../network';
@ -43,7 +44,7 @@ import { WKInterceptableRequest, WKRouteImpl } from './wkInterceptableRequest';
import { WKProvisionalPage } from './wkProvisionalPage';
import { WKWorkers } from './wkWorkers';
import { debugLogger } from '../../common/debugLogger';
import { ManualPromise } from '../../utils';
import { ManualPromise } from '../../utils/manualPromise';
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
const BINDING_CALL_MESSAGE = '__playwright_binding_call__';

View file

@ -16,8 +16,8 @@
import type { WKSession } from './wkConnection';
import type { WKPage } from './wkPage';
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import type { Protocol } from './protocol';
import { assert } from '../../utils';

View file

@ -14,8 +14,8 @@
* limitations under the License.
*/
import type { RegisteredListener } from '../../utils';
import { eventsHelper } from '../../utils';
import type { RegisteredListener } from '../../utils/eventsHelper';
import { eventsHelper } from '../../utils/eventsHelper';
import type { Page } from '../page';
import { Worker } from '../page';
import type { Protocol } from './protocol';

View file

@ -0,0 +1,48 @@
/**
* 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 fs from 'fs';
import path from 'path';
import removeFolder from 'rimraf';
export const existsAsync = (path: string): Promise<boolean> => new Promise(resolve => fs.stat(path, err => resolve(!err)));
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(() => {});
}
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;
}
}

View file

@ -0,0 +1,66 @@
/**
* 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 os from 'os';
import { getUbuntuVersionSync } from './ubuntuVersion';
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>';
})();

View file

@ -14,41 +14,14 @@
* limitations under the License.
*/
import type { SpawnOptions } from 'child_process';
import { 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 } from './ubuntuVersion';
export { eventsHelper } from './eventsHelper';
export type { RegisteredListener } from './eventsHelper';
export { ManualPromise } from './manualPromise';
export { MultiMap } from './multimap';
export { raceAgainstTimeout, TimeoutRunner, TimeoutRunnerError } from './timeoutRunner';
export { zones } from './zones';
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 }));
});
}
type NameValue = {
name: string,
value: string,
};
// See https://joel.tools/microtasks/
export function makeWaitForNextTask() {
@ -149,11 +122,6 @@ export function getAsBooleanFromENV(name: string): boolean {
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 };
@ -214,28 +182,6 @@ 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;
}
}
export function constructURLBasedOnBaseURL(baseURL: string | undefined, givenURL: string): string {
try {
return (new URL.URL(givenURL, baseURL)).toString();
@ -244,54 +190,6 @@ export function constructURLBasedOnBaseURL(baseURL: string | undefined, 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));
@ -314,56 +212,3 @@ export function streamToString(stream: stream.Readable): Promise<string> {
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,8 @@
import * as childProcess from 'child_process';
import * as readline from 'readline';
import { eventsHelper } from './eventsHelper';
import { isUnderTest, removeFolders } from './';
import { isUnderTest } from './';
import { removeFolders } from './fileUtils';
import rimraf from 'rimraf';
export type Env = {[key: string]: string | number | boolean | undefined};

View file

@ -0,0 +1,33 @@
/**
* 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 { spawn } from 'child_process';
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 }));
});
}

View file

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

View file

@ -29,7 +29,8 @@ 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';
import { createGuid } from 'playwright-core/lib/utils';
import { hostPlatform } from 'playwright-core/lib/utils/hostPlatform';
import { fileIsModule } from './loader';
const defaultTimeout = 30000;

View file

@ -21,7 +21,7 @@ import type { RunPayload, TestBeginPayload, TestEndPayload, DonePayload, TestOut
import type { TestResult, Reporter, TestStep, TestError } from '../types/testReporter';
import type { Suite, TestCase } from './test';
import type { Loader } from './loader';
import { ManualPromise } from 'playwright-core/lib/utils';
import { ManualPromise } from 'playwright-core/lib/utils/manualPromise';
export type TestGroup = {
workerHash: string;

View file

@ -15,7 +15,7 @@
*/
import expectLibrary from 'expect';
import { raceAgainstTimeout } from 'playwright-core/lib/utils';
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
import path from 'path';
import {
INVERTED_COLOR,

View file

@ -17,7 +17,7 @@
import { formatLocation, debugTest } from './util';
import * as crypto from 'crypto';
import type { FixturesWithLocation, Location, WorkerInfo } from './types';
import { ManualPromise } from 'playwright-core/lib/utils';
import { ManualPromise } from 'playwright-core/lib/utils/manualPromise';
import type { TestInfoImpl } from './testInfo';
import type { FixtureDescription, TimeoutManager } from './timeoutManager';

View file

@ -19,7 +19,8 @@ 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';
import { createGuid, debugMode } from 'playwright-core/lib/utils';
import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
import { GridClient } from 'playwright-core/lib/grid/gridClient';
export { expect } from './expect';
export const _baseTest: TestType<{}, {}> = rootTestType.test;

View file

@ -22,7 +22,8 @@ import type { TransformCallback } from 'stream';
import { Transform } from 'stream';
import type { FullConfig, Suite, Reporter } from '../../types/testReporter';
import { HttpServer } from 'playwright-core/lib/utils/httpServer';
import { assert, calculateSha1, removeFolders } from 'playwright-core/lib/utils';
import { assert, calculateSha1 } from 'playwright-core/lib/utils';
import { removeFolders } from 'playwright-core/lib/utils/fileUtils';
import type { JsonAttachment, JsonReport, JsonSuite, JsonTestCase, JsonTestResult, JsonTestStep } from './raw';
import RawReporter from './raw';
import yazl from 'yazl';

View file

@ -21,7 +21,7 @@ import { assert, calculateSha1 } from 'playwright-core/lib/utils';
import { sanitizeForFilePath } from '../util';
import { formatResultFailure } from './base';
import { toPosixPath, serializePatterns } from './json';
import { MultiMap } from 'playwright-core/lib/utils';
import { MultiMap } from 'playwright-core/lib/utils/multimap';
import { codeFrameColumns } from '@babel/code-frame';
import type { FullConfigInternal } from '../types';

View file

@ -42,8 +42,8 @@ import { Minimatch } from 'minimatch';
import type { Config } from './types';
import type { FullConfigInternal } from './types';
import { WebServer } from './webServer';
import { raceAgainstTimeout } from 'playwright-core/lib/utils';
import { SigIntWatcher } from 'playwright-core/lib/utils';
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
import { SigIntWatcher } from './sigIntWatcher';
const removeFolderAsync = promisify(rimraf);
const readDirAsync = promisify(fs.readdir);

View file

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

@ -15,7 +15,7 @@
*/
import colors from 'colors/safe';
import { TimeoutRunner, TimeoutRunnerError } from 'playwright-core/lib/utils';
import { TimeoutRunner, TimeoutRunnerError } from 'playwright-core/lib/utils/timeoutRunner';
import type { TestError } from '../types/test';
import type { Location } from './types';

View file

@ -18,7 +18,7 @@ import http from 'http';
import https from 'https';
import net from 'net';
import debug from 'debug';
import { raceAgainstTimeout } from 'playwright-core/lib/utils';
import { raceAgainstTimeout } from 'playwright-core/lib/utils/timeoutRunner';
import type { WebServerConfig } from './types';
import { launchProcess } from 'playwright-core/lib/utils/processLauncher';
import type { Reporter } from '../types/testReporter';

View file

@ -26,7 +26,7 @@ import type { Suite, TestCase } from './test';
import type { Annotation, TestError, TestStepInternal } from './types';
import type { ProjectImpl } from './project';
import { FixtureRunner } from './fixtures';
import { ManualPromise } from 'playwright-core/lib/utils';
import { ManualPromise } from 'playwright-core/lib/utils/manualPromise';
import { TestInfoImpl } from './testInfo';
import type { TimeSlot } from './timeoutManager';
import { TimeoutManager } from './timeoutManager';

View file

@ -19,7 +19,7 @@ import * as os from 'os';
import type { PageTestFixtures, PageWorkerFixtures } from '../page/pageTestApi';
import * as path from 'path';
import type { BrowserContext, BrowserContextOptions, BrowserType, Page } from 'playwright-core';
import { removeFolders } from '../../packages/playwright-core/lib/utils';
import { removeFolders } from '../../packages/playwright-core/lib/utils/fileUtils';
import { baseTest } from './baseTest';
import type { RemoteServerOptions } from './remoteServer';
import { RemoteServer } from './remoteServer';

View file

@ -18,7 +18,7 @@ import fs from 'fs';
import { test as baseTest, expect, createImage } from './playwright-test-fixtures';
import type { HttpServer } from '../../packages/playwright-core/lib/utils/httpServer';
import { startHtmlReportServer } from '../../packages/playwright-test/lib/reporters/html';
import { spawnAsync } from 'playwright-core/lib/utils';
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync';
const test = baseTest.extend<{ showReport: () => Promise<void> }>({
showReport: async ({ page }, use, testInfo) => {