chore: introduce manual promise helper (#8533)

This commit is contained in:
Pavel Feldman 2021-08-29 11:21:06 -07:00 committed by GitHub
parent d3a8c38b7e
commit dd31f3bd43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 79 deletions

View file

@ -15,7 +15,7 @@
*/ */
import fs from 'fs'; import fs from 'fs';
import { assert } from '../utils/utils'; import { assert, ManualPromise } from '../utils/utils';
import { SdkObject } from './instrumentation'; import { SdkObject } from './instrumentation';
type SaveCallback = (localPath: string, error?: string) => Promise<void>; type SaveCallback = (localPath: string, error?: string) => Promise<void>;
@ -25,8 +25,7 @@ export class Artifact extends SdkObject {
private _localPath: string; private _localPath: string;
private _unaccessibleErrorMessage: string | undefined; private _unaccessibleErrorMessage: string | undefined;
private _cancelCallback: CancelCallback | undefined; private _cancelCallback: CancelCallback | undefined;
private _finishedCallback: () => void; private _finishedPromise = new ManualPromise<void>();
private _finishedPromise: Promise<void>;
private _saveCallbacks: SaveCallback[] = []; private _saveCallbacks: SaveCallback[] = [];
private _finished: boolean = false; private _finished: boolean = false;
private _deleted = false; private _deleted = false;
@ -37,8 +36,6 @@ export class Artifact extends SdkObject {
this._localPath = localPath; this._localPath = localPath;
this._unaccessibleErrorMessage = unaccessibleErrorMessage; this._unaccessibleErrorMessage = unaccessibleErrorMessage;
this._cancelCallback = cancelCallback; this._cancelCallback = cancelCallback;
this._finishedCallback = () => {};
this._finishedPromise = new Promise(f => this._finishedCallback = f);
} }
finishedPromise() { finishedPromise() {
@ -122,6 +119,6 @@ export class Artifact extends SdkObject {
} }
this._saveCallbacks = []; this._saveCallbacks = [];
this._finishedCallback(); this._finishedPromise.resolve();
} }
} }

View file

@ -19,7 +19,7 @@ import * as dialog from '../dialog';
import * as dom from '../dom'; import * as dom from '../dom';
import * as frames from '../frames'; import * as frames from '../frames';
import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper'; import { eventsHelper, RegisteredListener } from '../../utils/eventsHelper';
import { assert } from '../../utils/utils'; import { assert, ManualPromise } from '../../utils/utils';
import { Page, PageBinding, PageDelegate, Worker } from '../page'; import { Page, PageBinding, PageDelegate, Worker } from '../page';
import * as types from '../types'; import * as types from '../types';
import { getAccessibilityTree } from './ffAccessibility'; import { getAccessibilityTree } from './ffAccessibility';
@ -44,8 +44,7 @@ export class FFPage implements PageDelegate {
readonly _page: Page; readonly _page: Page;
readonly _networkManager: FFNetworkManager; readonly _networkManager: FFNetworkManager;
readonly _browserContext: FFBrowserContext; readonly _browserContext: FFBrowserContext;
private _pagePromise: Promise<Page | Error>; private _pagePromise = new ManualPromise<Page | Error>();
private _pageCallback: (pageOrError: Page | Error) => void = () => {};
_initializedPage: Page | null = null; _initializedPage: Page | null = null;
private _initializationFailed = false; private _initializationFailed = false;
readonly _opener: FFPage | null; readonly _opener: FFPage | null;
@ -95,7 +94,6 @@ export class FFPage implements PageDelegate {
eventsHelper.addEventListener(this._session, 'Page.screencastFrame', this._onScreencastFrame.bind(this)), eventsHelper.addEventListener(this._session, 'Page.screencastFrame', this._onScreencastFrame.bind(this)),
]; ];
this._pagePromise = new Promise(f => this._pageCallback = f);
session.once(FFSessionEvents.Disconnected, () => { session.once(FFSessionEvents.Disconnected, () => {
this._markAsError(new Error('Page closed')); this._markAsError(new Error('Page closed'));
this._page._didDisconnect(); this._page._didDisconnect();
@ -108,7 +106,7 @@ export class FFPage implements PageDelegate {
// so that anyone who awaits pageOrError got a ready and reported page. // so that anyone who awaits pageOrError got a ready and reported page.
this._initializedPage = this._page; this._initializedPage = this._page;
this._page.reportAsNew(); this._page.reportAsNew();
this._pageCallback(this._page); this._pagePromise.resolve(this._page);
}); });
// Ideally, we somehow ensure that utility world is created before Page.ready arrives, but currently it is racy. // Ideally, we somehow ensure that utility world is created before Page.ready arrives, but currently it is racy.
// Therefore, we can end up with an initialized page without utility world, although very unlikely. // Therefore, we can end up with an initialized page without utility world, although very unlikely.
@ -124,7 +122,7 @@ export class FFPage implements PageDelegate {
if (!this._initializedPage) { if (!this._initializedPage) {
await this._page.initOpener(this._opener); await this._page.initOpener(this._opener);
this._page.reportAsNew(error); this._page.reportAsNew(error);
this._pageCallback(error); this._pagePromise.resolve(error);
} }
} }

View file

@ -26,7 +26,7 @@ import { Page } from './page';
import * as types from './types'; import * as types from './types';
import { BrowserContext } from './browserContext'; import { BrowserContext } from './browserContext';
import { Progress, ProgressController } from './progress'; import { Progress, ProgressController } from './progress';
import { assert, constructURLBasedOnBaseURL, makeWaitForNextTask } from '../utils/utils'; import { assert, constructURLBasedOnBaseURL, makeWaitForNextTask, ManualPromise } from '../utils/utils';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { CallMetadata, internalCallMetadata, SdkObject } from './instrumentation'; import { CallMetadata, internalCallMetadata, SdkObject } from './instrumentation';
import { ElementStateWithoutStable } from './injected/injectedScript'; import { ElementStateWithoutStable } from './injected/injectedScript';
@ -1364,16 +1364,14 @@ class RerunnableTask {
class SignalBarrier { class SignalBarrier {
private _progress: Progress | null; private _progress: Progress | null;
private _protectCount = 0; private _protectCount = 0;
private _promise: Promise<void>; private _promise = new ManualPromise<void>();
private _promiseCallback = () => {};
constructor(progress: Progress | null) { constructor(progress: Progress | null) {
this._progress = progress; this._progress = progress;
this._promise = new Promise(f => this._promiseCallback = f);
this.retain(); this.retain();
} }
waitFor(): Promise<void> { waitFor(): PromiseLike<void> {
this.release(); this.release();
return this._promise; return this._promise;
} }
@ -1405,7 +1403,7 @@ class SignalBarrier {
release() { release() {
--this._protectCount; --this._protectCount;
if (!this._protectCount) if (!this._protectCount)
this._promiseCallback(); this._promise.resolve();
} }
} }

View file

@ -16,7 +16,7 @@
import * as frames from './frames'; import * as frames from './frames';
import * as types from './types'; import * as types from './types';
import { assert } from '../utils/utils'; import { assert, ManualPromise } from '../utils/utils';
import { SdkObject } from './instrumentation'; import { SdkObject } from './instrumentation';
export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): types.NetworkCookie[] { export function filterCookies(cookies: types.NetworkCookie[], urls: string[]): types.NetworkCookie[] {
@ -97,8 +97,7 @@ export class Request extends SdkObject {
private _headers: types.HeadersArray; private _headers: types.HeadersArray;
private _headersMap = new Map<string, string>(); private _headersMap = new Map<string, string>();
private _frame: frames.Frame; private _frame: frames.Frame;
private _waitForResponsePromise: Promise<Response | null>; private _waitForResponsePromise = new ManualPromise<Response | null>();
private _waitForResponsePromiseCallback: (value: Response | null) => void = () => {};
_responseEndTiming = -1; _responseEndTiming = -1;
_sizes: RequestSizes = { responseBodySize: 0, transferSize: 0 }; _sizes: RequestSizes = { responseBodySize: 0, transferSize: 0 };
@ -118,13 +117,12 @@ export class Request extends SdkObject {
this._headers = headers; this._headers = headers;
for (const { name, value } of this._headers) for (const { name, value } of this._headers)
this._headersMap.set(name.toLowerCase(), value); this._headersMap.set(name.toLowerCase(), value);
this._waitForResponsePromise = new Promise(f => this._waitForResponsePromiseCallback = f);
this._isFavicon = url.endsWith('/favicon.ico'); this._isFavicon = url.endsWith('/favicon.ico');
} }
_setFailureText(failureText: string) { _setFailureText(failureText: string) {
this._failureText = failureText; this._failureText = failureText;
this._waitForResponsePromiseCallback(null); this._waitForResponsePromise.resolve(null);
} }
url(): string { url(): string {
@ -151,7 +149,7 @@ export class Request extends SdkObject {
return this._headersMap.get(name); return this._headersMap.get(name);
} }
response(): Promise<Response | null> { response(): PromiseLike<Response | null> {
return this._waitForResponsePromise; return this._waitForResponsePromise;
} }
@ -161,7 +159,7 @@ export class Request extends SdkObject {
_setResponse(response: Response) { _setResponse(response: Response) {
this._response = response; this._response = response;
this._waitForResponsePromiseCallback(response); this._waitForResponsePromise.resolve(response);
} }
_finalRequest(): Request { _finalRequest(): Request {
@ -321,8 +319,7 @@ export type SecurityDetails = {
export class Response extends SdkObject { export class Response extends SdkObject {
private _request: Request; private _request: Request;
private _contentPromise: Promise<Buffer> | null = null; private _contentPromise: Promise<Buffer> | null = null;
_finishedPromise: Promise<{ error?: string }>; _finishedPromise = new ManualPromise<{ error?: string }>();
private _finishedPromiseCallback: (arg: { error?: string }) => void = () => {};
private _status: number; private _status: number;
private _statusText: string; private _statusText: string;
private _url: string; private _url: string;
@ -330,10 +327,8 @@ export class Response extends SdkObject {
private _headersMap = new Map<string, string>(); private _headersMap = new Map<string, string>();
private _getResponseBodyCallback: GetResponseBodyCallback; private _getResponseBodyCallback: GetResponseBodyCallback;
private _timing: ResourceTiming; private _timing: ResourceTiming;
private _serverAddrPromise: Promise<RemoteAddr|undefined>; private _serverAddrPromise = new ManualPromise<RemoteAddr | undefined>();
private _serverAddrPromiseCallback: (arg?: RemoteAddr) => void = () => {}; private _securityDetailsPromise = new ManualPromise<SecurityDetails | undefined>();
private _securityDetailsPromise: Promise<SecurityDetails|undefined>;
private _securityDetailsPromiseCallback: (arg?: SecurityDetails) => void = () => {};
private _httpVersion: string | undefined; private _httpVersion: string | undefined;
constructor(request: Request, status: number, statusText: string, headers: types.HeadersArray, timing: ResourceTiming, getResponseBodyCallback: GetResponseBodyCallback, httpVersion?: string) { constructor(request: Request, status: number, statusText: string, headers: types.HeadersArray, timing: ResourceTiming, getResponseBodyCallback: GetResponseBodyCallback, httpVersion?: string) {
@ -347,30 +342,21 @@ export class Response extends SdkObject {
for (const { name, value } of this._headers) for (const { name, value } of this._headers)
this._headersMap.set(name.toLowerCase(), value); this._headersMap.set(name.toLowerCase(), value);
this._getResponseBodyCallback = getResponseBodyCallback; this._getResponseBodyCallback = getResponseBodyCallback;
this._serverAddrPromise = new Promise(f => {
this._serverAddrPromiseCallback = f;
});
this._securityDetailsPromise = new Promise(f => {
this._securityDetailsPromiseCallback = f;
});
this._finishedPromise = new Promise(f => {
this._finishedPromiseCallback = f;
});
this._request._setResponse(this); this._request._setResponse(this);
this._httpVersion = httpVersion; this._httpVersion = httpVersion;
} }
_serverAddrFinished(addr?: RemoteAddr) { _serverAddrFinished(addr?: RemoteAddr) {
this._serverAddrPromiseCallback(addr); this._serverAddrPromise.resolve(addr);
} }
_securityDetailsFinished(securityDetails?: SecurityDetails) { _securityDetailsFinished(securityDetails?: SecurityDetails) {
this._securityDetailsPromiseCallback(securityDetails); this._securityDetailsPromise.resolve(securityDetails);
} }
_requestFinished(responseEndTiming: number, error?: string) { _requestFinished(responseEndTiming: number, error?: string) {
this._request._responseEndTiming = Math.max(responseEndTiming, this._timing.responseStart); this._request._responseEndTiming = Math.max(responseEndTiming, this._timing.responseStart);
this._finishedPromiseCallback({ error }); this._finishedPromise.resolve({ error });
} }
_setHttpVersion(httpVersion: string) { _setHttpVersion(httpVersion: string) {

View file

@ -28,7 +28,7 @@ import { ConsoleMessage } from './console';
import * as accessibility from './accessibility'; import * as accessibility from './accessibility';
import { FileChooser } from './fileChooser'; import { FileChooser } from './fileChooser';
import { Progress, ProgressController } from './progress'; import { Progress, ProgressController } from './progress';
import { assert, isError } from '../utils/utils'; import { assert, isError, ManualPromise } from '../utils/utils';
import { debugLogger } from '../utils/debugLogger'; import { debugLogger } from '../utils/debugLogger';
import { SelectorInfo, Selectors } from './selectors'; import { SelectorInfo, Selectors } from './selectors';
import { CallMetadata, SdkObject } from './instrumentation'; import { CallMetadata, SdkObject } from './instrumentation';
@ -115,14 +115,11 @@ export class Page extends SdkObject {
}; };
private _closedState: 'open' | 'closing' | 'closed' = 'open'; private _closedState: 'open' | 'closing' | 'closed' = 'open';
private _closedCallback: () => void; private _closedPromise = new ManualPromise<void>();
private _closedPromise: Promise<void>;
private _disconnected = false; private _disconnected = false;
private _initialized = false; private _initialized = false;
private _disconnectedCallback: (e: Error) => void; readonly _disconnectedPromise = new ManualPromise<Error>();
readonly _disconnectedPromise: Promise<Error>; readonly _crashedPromise = new ManualPromise<Error>();
private _crashedCallback: (e: Error) => void;
readonly _crashedPromise: Promise<Error>;
readonly _browserContext: BrowserContext; readonly _browserContext: BrowserContext;
readonly keyboard: input.Keyboard; readonly keyboard: input.Keyboard;
readonly mouse: input.Mouse; readonly mouse: input.Mouse;
@ -150,12 +147,6 @@ export class Page extends SdkObject {
super(browserContext, 'page'); super(browserContext, 'page');
this.attribution.page = this; this.attribution.page = this;
this._delegate = delegate; this._delegate = delegate;
this._closedCallback = () => {};
this._closedPromise = new Promise(f => this._closedCallback = f);
this._disconnectedCallback = () => {};
this._disconnectedPromise = new Promise(f => this._disconnectedCallback = f);
this._crashedCallback = () => {};
this._crashedPromise = new Promise(f => this._crashedCallback = f);
this._browserContext = browserContext; this._browserContext = browserContext;
this._state = { this._state = {
emulatedSize: browserContext._options.viewport ? { viewport: browserContext._options.viewport, screen: browserContext._options.screen || browserContext._options.viewport } : null, emulatedSize: browserContext._options.viewport ? { viewport: browserContext._options.viewport, screen: browserContext._options.screen || browserContext._options.viewport } : null,
@ -218,20 +209,20 @@ export class Page extends SdkObject {
assert(this._closedState !== 'closed', 'Page closed twice'); assert(this._closedState !== 'closed', 'Page closed twice');
this._closedState = 'closed'; this._closedState = 'closed';
this.emit(Page.Events.Close); this.emit(Page.Events.Close);
this._closedCallback(); this._closedPromise.resolve();
} }
_didCrash() { _didCrash() {
this._frameManager.dispose(); this._frameManager.dispose();
this.emit(Page.Events.Crash); this.emit(Page.Events.Crash);
this._crashedCallback(new Error('Page crashed')); this._crashedPromise.resolve(new Error('Page crashed'));
} }
_didDisconnect() { _didDisconnect() {
this._frameManager.dispose(); this._frameManager.dispose();
assert(!this._disconnected, 'Page disconnected twice'); assert(!this._disconnected, 'Page disconnected twice');
this._disconnected = true; this._disconnected = true;
this._disconnectedCallback(new Error('Page closed')); this._disconnectedPromise.resolve(new Error('Page closed'));
} }
async _onFileChooserOpened(handle: dom.ElementHandle) { async _onFileChooserOpened(handle: dom.ElementHandle) {

View file

@ -20,7 +20,7 @@ import * as network from '../network';
import * as types from '../types'; import * as types from '../types';
import { Protocol } from './protocol'; import { Protocol } from './protocol';
import { WKSession } from './wkConnection'; import { WKSession } from './wkConnection';
import { assert, headersObjectToArray, headersArrayToObject } from '../../utils/utils'; import { assert, headersObjectToArray, headersArrayToObject, ManualPromise } from '../../utils/utils';
import { InterceptedResponse } from '../network'; import { InterceptedResponse } from '../network';
import { WKPage } from './wkPage'; import { WKPage } from './wkPage';
@ -95,17 +95,14 @@ export class WKInterceptableRequest {
export class WKRouteImpl implements network.RouteDelegate { export class WKRouteImpl implements network.RouteDelegate {
private readonly _session: WKSession; private readonly _session: WKSession;
private readonly _requestId: string; private readonly _requestId: string;
_requestInterceptedCallback: () => void = () => {}; readonly _requestInterceptedPromise = new ManualPromise<void>();
private readonly _requestInterceptedPromise: Promise<unknown>; _responseInterceptedPromise: ManualPromise<{ response?: Protocol.Network.Response, error?: Protocol.Network.loadingFailedPayload }> | undefined;
_responseInterceptedCallback: ((payload: { response?: Protocol.Network.Response, error?: Protocol.Network.loadingFailedPayload }) => void) | undefined;
private _responseInterceptedPromise: Promise<{ response?: Protocol.Network.Response, error?: Protocol.Network.loadingFailedPayload }> | undefined;
private readonly _page: WKPage; private readonly _page: WKPage;
constructor(session: WKSession, page: WKPage, requestId: string) { constructor(session: WKSession, page: WKPage, requestId: string) {
this._session = session; this._session = session;
this._page = page; this._page = page;
this._requestId = requestId; this._requestId = requestId;
this._requestInterceptedPromise = new Promise<void>(f => this._requestInterceptedCallback = f);
} }
async responseBody(): Promise<Buffer> { async responseBody(): Promise<Buffer> {
@ -151,7 +148,7 @@ export class WKRouteImpl implements network.RouteDelegate {
async continue(request: network.Request, overrides: types.NormalizedContinueOverrides): Promise<network.InterceptedResponse|null> { async continue(request: network.Request, overrides: types.NormalizedContinueOverrides): Promise<network.InterceptedResponse|null> {
if (overrides.interceptResponse) { if (overrides.interceptResponse) {
await this._page._ensureResponseInterceptionEnabled(); await this._page._ensureResponseInterceptionEnabled();
this._responseInterceptedPromise = new Promise(f => this._responseInterceptedCallback = f); this._responseInterceptedPromise = new ManualPromise();
} }
await this._requestInterceptedPromise; await this._requestInterceptedPromise;
// In certain cases, protocol will return error if the request was already canceled // In certain cases, protocol will return error if the request was already canceled

View file

@ -19,7 +19,7 @@ import * as jpeg from 'jpeg-js';
import path from 'path'; import path from 'path';
import * as png from 'pngjs'; import * as png from 'pngjs';
import { splitErrorMessage } from '../../utils/stackTrace'; import { splitErrorMessage } from '../../utils/stackTrace';
import { assert, createGuid, debugAssert, headersArrayToObject, headersObjectToArray, hostPlatform } from '../../utils/utils'; import { assert, createGuid, debugAssert, headersArrayToObject, headersObjectToArray, hostPlatform, ManualPromise } from '../../utils/utils';
import * as accessibility from '../accessibility'; import * as accessibility from '../accessibility';
import * as dialog from '../dialog'; import * as dialog from '../dialog';
import * as dom from '../dom'; import * as dom from '../dom';
@ -52,8 +52,7 @@ export class WKPage implements PageDelegate {
_session: WKSession; _session: WKSession;
private _provisionalPage: WKProvisionalPage | null = null; private _provisionalPage: WKProvisionalPage | null = null;
readonly _page: Page; readonly _page: Page;
private readonly _pagePromise: Promise<Page | Error>; private readonly _pagePromise = new ManualPromise<Page | Error>();
private _pagePromiseCallback: (page: Page | Error) => void = () => {};
private readonly _pageProxySession: WKSession; private readonly _pageProxySession: WKSession;
readonly _opener: WKPage | null; readonly _opener: WKPage | null;
private readonly _requestIdToRequest = new Map<string, WKInterceptableRequest>(); private readonly _requestIdToRequest = new Map<string, WKInterceptableRequest>();
@ -96,7 +95,6 @@ export class WKPage implements PageDelegate {
eventsHelper.addEventListener(this._pageProxySession, 'Target.didCommitProvisionalTarget', this._onDidCommitProvisionalTarget.bind(this)), eventsHelper.addEventListener(this._pageProxySession, 'Target.didCommitProvisionalTarget', this._onDidCommitProvisionalTarget.bind(this)),
eventsHelper.addEventListener(this._pageProxySession, 'Screencast.screencastFrame', this._onScreencastFrame.bind(this)), eventsHelper.addEventListener(this._pageProxySession, 'Screencast.screencastFrame', this._onScreencastFrame.bind(this)),
]; ];
this._pagePromise = new Promise(f => this._pagePromiseCallback = f);
this._firstNonInitialNavigationCommittedPromise = new Promise((f, r) => { this._firstNonInitialNavigationCommittedPromise = new Promise((f, r) => {
this._firstNonInitialNavigationCommittedFulfill = f; this._firstNonInitialNavigationCommittedFulfill = f;
this._firstNonInitialNavigationCommittedReject = r; this._firstNonInitialNavigationCommittedReject = r;
@ -335,7 +333,7 @@ export class WKPage implements PageDelegate {
// so that anyone who awaits pageOrError got a ready and reported page. // so that anyone who awaits pageOrError got a ready and reported page.
this._initializedPage = pageOrError instanceof Page ? pageOrError : null; this._initializedPage = pageOrError instanceof Page ? pageOrError : null;
this._page.reportAsNew(pageOrError instanceof Page ? undefined : pageOrError); this._page.reportAsNew(pageOrError instanceof Page ? undefined : pageOrError);
this._pagePromiseCallback(pageOrError); this._pagePromise.resolve(pageOrError);
} else { } else {
assert(targetInfo.isProvisional); assert(targetInfo.isProvisional);
assert(!this._provisionalPage); assert(!this._provisionalPage);
@ -997,18 +995,18 @@ export class WKPage implements PageDelegate {
// Just continue. // Just continue.
session.sendMayFail('Network.interceptWithRequest', { requestId: request._requestId }); session.sendMayFail('Network.interceptWithRequest', { requestId: request._requestId });
} else { } else {
request._route._requestInterceptedCallback(); request._route._requestInterceptedPromise.resolve();
} }
} }
_onResponseIntercepted(session: WKSession, event: Protocol.Network.responseInterceptedPayload) { _onResponseIntercepted(session: WKSession, event: Protocol.Network.responseInterceptedPayload) {
const request = this._requestIdToRequest.get(event.requestId); const request = this._requestIdToRequest.get(event.requestId);
const route = request?._routeForRedirectChain(); const route = request?._routeForRedirectChain();
if (!route?._responseInterceptedCallback) { if (!route?._responseInterceptedPromise) {
session.sendMayFail('Network.interceptContinue', { requestId: event.requestId, stage: 'response' }); session.sendMayFail('Network.interceptContinue', { requestId: event.requestId, stage: 'response' });
return; return;
} }
route._responseInterceptedCallback({ response: event.response }); route._responseInterceptedPromise.resolve({ response: event.response });
} }
_onResponseReceived(event: Protocol.Network.responseReceivedPayload) { _onResponseReceived(event: Protocol.Network.responseReceivedPayload) {
@ -1068,8 +1066,8 @@ export class WKPage implements PageDelegate {
if (!request) if (!request)
return; return;
const route = request._routeForRedirectChain(); const route = request._routeForRedirectChain();
if (route?._responseInterceptedCallback) if (route?._responseInterceptedPromise)
route._responseInterceptedCallback({ error: event }); route._responseInterceptedPromise.resolve({ error: event });
const response = request.request._existingResponse(); const response = request.request._existingResponse();
if (response) { if (response) {
response._serverAddrFinished(); response._serverAddrFinished();

View file

@ -122,8 +122,8 @@ export class WorkerRunner extends EventEmitter {
} }
async run(runPayload: RunPayload) { async run(runPayload: RunPayload) {
let runFinishedCalback = () => {}; let runFinishedCallback = () => {};
this._runFinished = new Promise(f => runFinishedCalback = f); this._runFinished = new Promise(f => runFinishedCallback = f);
try { try {
this._entries = new Map(runPayload.entries.map(e => [ e.testId, e ])); this._entries = new Map(runPayload.entries.map(e => [ e.testId, e ]));
await this._loadIfNeeded(); await this._loadIfNeeded();
@ -146,7 +146,7 @@ export class WorkerRunner extends EventEmitter {
this.unhandledError(e); this.unhandledError(e);
} finally { } finally {
this._reportDone(); this._reportDone();
runFinishedCalback(); runFinishedCallback();
} }
} }

View file

@ -392,3 +392,35 @@ export function wrapInASCIIBox(text: string, padding = 0): string {
'╚' + '═'.repeat(maxLength + padding * 2) + '╝', '╚' + '═'.repeat(maxLength + padding * 2) + '╝',
].join('\n'); ].join('\n');
} }
export class ManualPromise<T> extends Promise<T> {
private _resolve!: (t: T) => void;
private _reject!: (e: Error) => void;
constructor() {
let resolve: (t: T) => void;
let reject: (e: Error) => void;
super((f, r) => {
resolve = f;
reject = r;
});
this._resolve = resolve!;
this._reject = reject!;
}
resolve(t: T) {
this._resolve(t);
}
reject(e: Error) {
this._reject(e);
}
static override get [Symbol.species]() {
return Promise;
}
override get [Symbol.toStringTag]() {
return 'ManualPromise';
}
}