flashwright-core 1.64.1-flashwright.1 → 1.64.1-flashwright.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -13,4 +13,6 @@ npx playwright install chromium
|
|
|
13
13
|
|
|
14
14
|
Without the test runner, `playwright` is `flashwright` and `playwright-core` is `flashwright-core`. See the [project page](https://github.com/xcodebeast/flashwright) for benchmarks, speed options and the differences from Playwright.
|
|
15
15
|
|
|
16
|
+
Re-running tests, like an agent checking its work? Outside CI, a warm session keeps the browser between runs, so one test re-runs in about 0.1 s instead of 0.7 s with Playwright ([warm session](https://github.com/xcodebeast/flashwright#warm-session); `FLASHWRIGHT_SESSION=0` turns it off).
|
|
17
|
+
|
|
16
18
|
Flashwright is an independent fork and is not affiliated with Microsoft. Apache-2.0, like Playwright.
|
package/lib/coreBundle.js
CHANGED
|
@@ -2292,6 +2292,7 @@ var init_manualPromise = __esm({
|
|
|
2292
2292
|
// packages/utils/stackTrace.ts
|
|
2293
2293
|
var stackTrace_exports = {};
|
|
2294
2294
|
__export(stackTrace_exports, {
|
|
2295
|
+
captureFilteredStackTrace: () => captureFilteredStackTrace,
|
|
2295
2296
|
captureRawStack: () => captureRawStack,
|
|
2296
2297
|
coreDir: () => coreDir,
|
|
2297
2298
|
filterStackFile: () => filterStackFile,
|
|
@@ -2459,6 +2460,25 @@ function filteredStackTrace(rawStack) {
|
|
|
2459
2460
|
}
|
|
2460
2461
|
return frames;
|
|
2461
2462
|
}
|
|
2463
|
+
function captureFilteredStackTrace() {
|
|
2464
|
+
const formatter = rawStackFormatter;
|
|
2465
|
+
if (!formatter)
|
|
2466
|
+
return filteredStackTrace(captureRawStack());
|
|
2467
|
+
const stackTraceLimit = Error.stackTraceLimit;
|
|
2468
|
+
Error.stackTraceLimit = 50;
|
|
2469
|
+
const prepareStackTrace = Error.prepareStackTrace;
|
|
2470
|
+
Error.prepareStackTrace = (error, callSites) => {
|
|
2471
|
+
const kept = callSites.filter((callSite) => {
|
|
2472
|
+
const fileName = callSite.getFileName();
|
|
2473
|
+
return !fileName || filterStackFile(fileURLToPath(fileName));
|
|
2474
|
+
});
|
|
2475
|
+
return kept.length ? formatter(error, kept) : "";
|
|
2476
|
+
};
|
|
2477
|
+
const stack = new Error().stack || "";
|
|
2478
|
+
Error.prepareStackTrace = prepareStackTrace;
|
|
2479
|
+
Error.stackTraceLimit = stackTraceLimit;
|
|
2480
|
+
return stack ? filteredStackTrace(stack.split("\n")) : [];
|
|
2481
|
+
}
|
|
2462
2482
|
function fileURLToPath(fileUrl) {
|
|
2463
2483
|
if (!fileUrl.startsWith("file://"))
|
|
2464
2484
|
return fileUrl;
|
|
@@ -3043,6 +3063,7 @@ var init_httpServer = __esm({
|
|
|
3043
3063
|
// packages/utils/processLauncher.ts
|
|
3044
3064
|
var processLauncher_exports = {};
|
|
3045
3065
|
__export(processLauncher_exports, {
|
|
3066
|
+
adoptProcess: () => adoptProcess,
|
|
3046
3067
|
envArrayToObject: () => envArrayToObject,
|
|
3047
3068
|
gracefullyCloseAll: () => gracefullyCloseAll,
|
|
3048
3069
|
gracefullyCloseSet: () => gracefullyCloseSet,
|
|
@@ -3149,10 +3170,13 @@ async function launchProcess(options) {
|
|
|
3149
3170
|
options.log(`[pid=${spawnedProcess.pid}][err] ` + data);
|
|
3150
3171
|
});
|
|
3151
3172
|
let processClosed = false;
|
|
3173
|
+
let released = false;
|
|
3152
3174
|
let fulfillCleanup = () => {
|
|
3153
3175
|
};
|
|
3154
3176
|
const waitForCleanup = new Promise((f) => fulfillCleanup = f);
|
|
3155
3177
|
spawnedProcess.once("close", (exitCode, signal) => {
|
|
3178
|
+
if (released)
|
|
3179
|
+
return;
|
|
3156
3180
|
options.log(`[pid=${spawnedProcess.pid}] <process did exit: exitCode=${exitCode}, signal=${signal}>`);
|
|
3157
3181
|
processClosed = true;
|
|
3158
3182
|
gracefullyCloseSet.delete(gracefullyClose);
|
|
@@ -3219,7 +3243,103 @@ async function launchProcess(options) {
|
|
|
3219
3243
|
killProcess();
|
|
3220
3244
|
return waitForCleanup;
|
|
3221
3245
|
}
|
|
3222
|
-
|
|
3246
|
+
function release() {
|
|
3247
|
+
released = true;
|
|
3248
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3249
|
+
killSet.delete(killProcessAndCleanup);
|
|
3250
|
+
removeProcessHandlersIfNeeded();
|
|
3251
|
+
stdout.close();
|
|
3252
|
+
stderr.close();
|
|
3253
|
+
spawnedProcess.unref();
|
|
3254
|
+
options.log(`[pid=${spawnedProcess.pid}] <released>`);
|
|
3255
|
+
return { pid: spawnedProcess.pid, tempDirectories: options.tempDirectories };
|
|
3256
|
+
}
|
|
3257
|
+
return { launchedProcess: spawnedProcess, gracefullyClose, kill: killAndWait, killAndCleanup: killProcessAndCleanup, release };
|
|
3258
|
+
}
|
|
3259
|
+
function adoptProcess(options) {
|
|
3260
|
+
const { pid } = options;
|
|
3261
|
+
let processClosed = false;
|
|
3262
|
+
let released = false;
|
|
3263
|
+
let fulfillCleanup = () => {
|
|
3264
|
+
};
|
|
3265
|
+
const waitForCleanup = new Promise((f) => fulfillCleanup = f);
|
|
3266
|
+
options.log(`<adopted> pid=${pid}`);
|
|
3267
|
+
void options.exited.then(async () => {
|
|
3268
|
+
if (released)
|
|
3269
|
+
return;
|
|
3270
|
+
options.log(`[pid=${pid}] <process did exit>`);
|
|
3271
|
+
processClosed = true;
|
|
3272
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3273
|
+
killSet.delete(killProcessAndCleanup);
|
|
3274
|
+
removeProcessHandlersIfNeeded();
|
|
3275
|
+
options.onExit();
|
|
3276
|
+
const errors = await removeFolders(options.tempDirectories);
|
|
3277
|
+
for (let i = 0; i < options.tempDirectories.length; ++i) {
|
|
3278
|
+
if (errors[i])
|
|
3279
|
+
options.log(`[pid=${pid}] exception while removing ${options.tempDirectories[i]}: ${errors[i]}`);
|
|
3280
|
+
}
|
|
3281
|
+
fulfillCleanup();
|
|
3282
|
+
});
|
|
3283
|
+
addProcessHandlerIfNeeded("exit");
|
|
3284
|
+
if (options.handleSIGINT)
|
|
3285
|
+
addProcessHandlerIfNeeded("SIGINT");
|
|
3286
|
+
if (options.handleSIGTERM)
|
|
3287
|
+
addProcessHandlerIfNeeded("SIGTERM");
|
|
3288
|
+
if (options.handleSIGHUP)
|
|
3289
|
+
addProcessHandlerIfNeeded("SIGHUP");
|
|
3290
|
+
gracefullyCloseSet.add(gracefullyClose);
|
|
3291
|
+
killSet.add(killProcessAndCleanup);
|
|
3292
|
+
let gracefullyClosing = false;
|
|
3293
|
+
async function gracefullyClose() {
|
|
3294
|
+
if (gracefullyClosing) {
|
|
3295
|
+
killProcess();
|
|
3296
|
+
await waitForCleanup;
|
|
3297
|
+
return;
|
|
3298
|
+
}
|
|
3299
|
+
gracefullyClosing = true;
|
|
3300
|
+
await options.attemptToGracefullyClose().catch(() => killProcess());
|
|
3301
|
+
await waitForCleanup;
|
|
3302
|
+
}
|
|
3303
|
+
function killProcess() {
|
|
3304
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3305
|
+
killSet.delete(killProcessAndCleanup);
|
|
3306
|
+
removeProcessHandlersIfNeeded();
|
|
3307
|
+
if (processClosed)
|
|
3308
|
+
return;
|
|
3309
|
+
options.log(`[pid=${pid}] <will force kill>`);
|
|
3310
|
+
try {
|
|
3311
|
+
process.kill(-pid, "SIGKILL");
|
|
3312
|
+
} catch (e) {
|
|
3313
|
+
options.log(`[pid=${pid}] exception while trying to kill process: ${e}`);
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
function killProcessAndCleanup() {
|
|
3317
|
+
killProcess();
|
|
3318
|
+
for (const dir of options.tempDirectories) {
|
|
3319
|
+
try {
|
|
3320
|
+
import_fs6.default.rmSync(dir, { force: true, recursive: true, maxRetries: 5 });
|
|
3321
|
+
} catch (e) {
|
|
3322
|
+
options.log(`[pid=${pid}] exception while removing ${dir}: ${e}`);
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
function release() {
|
|
3327
|
+
released = true;
|
|
3328
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3329
|
+
killSet.delete(killProcessAndCleanup);
|
|
3330
|
+
removeProcessHandlersIfNeeded();
|
|
3331
|
+
options.log(`[pid=${pid}] <released>`);
|
|
3332
|
+
return { pid, tempDirectories: options.tempDirectories };
|
|
3333
|
+
}
|
|
3334
|
+
return {
|
|
3335
|
+
gracefullyClose,
|
|
3336
|
+
kill: () => {
|
|
3337
|
+
killProcess();
|
|
3338
|
+
return waitForCleanup;
|
|
3339
|
+
},
|
|
3340
|
+
killAndCleanup: killProcessAndCleanup,
|
|
3341
|
+
release
|
|
3342
|
+
};
|
|
3223
3343
|
}
|
|
3224
3344
|
function killProcessTree(pid) {
|
|
3225
3345
|
try {
|
|
@@ -5102,7 +5222,6 @@ var ProtocolError;
|
|
|
5102
5222
|
var init_protocolError = __esm({
|
|
5103
5223
|
"packages/playwright-core/src/server/protocolError.ts"() {
|
|
5104
5224
|
"use strict";
|
|
5105
|
-
init_stackTrace();
|
|
5106
5225
|
ProtocolError = class extends Error {
|
|
5107
5226
|
constructor(type3, method2, logs) {
|
|
5108
5227
|
super();
|
|
@@ -5110,8 +5229,12 @@ var init_protocolError = __esm({
|
|
|
5110
5229
|
this.method = method2;
|
|
5111
5230
|
this.logs = logs;
|
|
5112
5231
|
}
|
|
5232
|
+
// Flashwright: called once the browser answered with an error, before anything read this
|
|
5233
|
+
// error's stack. The stack is formatted with the current message when it is read, so it is not
|
|
5234
|
+
// formatted now: most of these errors are expected and never shown, and formatting a stack
|
|
5235
|
+
// through source map support takes milliseconds.
|
|
5113
5236
|
setMessage(message) {
|
|
5114
|
-
|
|
5237
|
+
this.message = `Protocol error (${this.method}): ${message}`;
|
|
5115
5238
|
}
|
|
5116
5239
|
browserLogMessage() {
|
|
5117
5240
|
return this.logs ? "\nBrowser logs:\n" + this.logs : "";
|
|
@@ -33792,6 +33915,85 @@ var init_chromiumSwitches = __esm({
|
|
|
33792
33915
|
}
|
|
33793
33916
|
});
|
|
33794
33917
|
|
|
33918
|
+
// packages/playwright-core/src/server/pipeTransport.ts
|
|
33919
|
+
var PipeTransport2;
|
|
33920
|
+
var init_pipeTransport2 = __esm({
|
|
33921
|
+
"packages/playwright-core/src/server/pipeTransport.ts"() {
|
|
33922
|
+
"use strict";
|
|
33923
|
+
init_debugLogger();
|
|
33924
|
+
PipeTransport2 = class {
|
|
33925
|
+
constructor(pipeWrite, pipeRead) {
|
|
33926
|
+
this._pendingBuffers = [];
|
|
33927
|
+
this._closed = false;
|
|
33928
|
+
this._pipeRead = pipeRead;
|
|
33929
|
+
this._pipeWrite = pipeWrite;
|
|
33930
|
+
pipeRead.on("data", (buffer) => this._dispatch(buffer));
|
|
33931
|
+
pipeRead.on("close", () => {
|
|
33932
|
+
this._closed = true;
|
|
33933
|
+
if (this._onclose)
|
|
33934
|
+
this._onclose.call(null);
|
|
33935
|
+
});
|
|
33936
|
+
pipeRead.on("error", (e) => debugLogger.log("error", e));
|
|
33937
|
+
pipeWrite.on("error", (e) => debugLogger.log("error", e));
|
|
33938
|
+
this.onmessage = void 0;
|
|
33939
|
+
}
|
|
33940
|
+
get onclose() {
|
|
33941
|
+
return this._onclose;
|
|
33942
|
+
}
|
|
33943
|
+
set onclose(onclose) {
|
|
33944
|
+
this._onclose = onclose;
|
|
33945
|
+
if (onclose && !this._pipeRead.readable)
|
|
33946
|
+
onclose();
|
|
33947
|
+
}
|
|
33948
|
+
send(message) {
|
|
33949
|
+
if (this._closed)
|
|
33950
|
+
throw new Error("Pipe has been closed");
|
|
33951
|
+
this._pipeWrite.write(JSON.stringify(message) + "\0");
|
|
33952
|
+
}
|
|
33953
|
+
close() {
|
|
33954
|
+
throw new Error("unimplemented");
|
|
33955
|
+
}
|
|
33956
|
+
// Flashwright: stops reading and gives the pipes to another owner, who continues the stream of
|
|
33957
|
+
// messages (see browserHandoff.ts). Only possible between two messages: returns undefined when
|
|
33958
|
+
// part of one has already been read.
|
|
33959
|
+
release() {
|
|
33960
|
+
if (this._closed || this._pendingBuffers.some((buffer) => buffer.length))
|
|
33961
|
+
return;
|
|
33962
|
+
this._closed = true;
|
|
33963
|
+
this._pipeRead.removeAllListeners("data");
|
|
33964
|
+
this._pipeRead.removeAllListeners("close");
|
|
33965
|
+
this._pipeRead.pause();
|
|
33966
|
+
return { write: this._pipeWrite, read: this._pipeRead };
|
|
33967
|
+
}
|
|
33968
|
+
_dispatch(buffer) {
|
|
33969
|
+
let end = buffer.indexOf("\0");
|
|
33970
|
+
if (end === -1) {
|
|
33971
|
+
this._pendingBuffers.push(buffer);
|
|
33972
|
+
return;
|
|
33973
|
+
}
|
|
33974
|
+
this._pendingBuffers.push(buffer.slice(0, end));
|
|
33975
|
+
const message = Buffer.concat(this._pendingBuffers).toString();
|
|
33976
|
+
setImmediate(() => {
|
|
33977
|
+
if (this.onmessage)
|
|
33978
|
+
this.onmessage.call(null, JSON.parse(message));
|
|
33979
|
+
});
|
|
33980
|
+
let start3 = end + 1;
|
|
33981
|
+
end = buffer.indexOf("\0", start3);
|
|
33982
|
+
while (end !== -1) {
|
|
33983
|
+
const message2 = buffer.toString(void 0, start3, end);
|
|
33984
|
+
setImmediate(() => {
|
|
33985
|
+
if (this.onmessage)
|
|
33986
|
+
this.onmessage.call(null, JSON.parse(message2));
|
|
33987
|
+
});
|
|
33988
|
+
start3 = end + 1;
|
|
33989
|
+
end = buffer.indexOf("\0", start3);
|
|
33990
|
+
}
|
|
33991
|
+
this._pendingBuffers = [buffer.slice(start3)];
|
|
33992
|
+
}
|
|
33993
|
+
};
|
|
33994
|
+
}
|
|
33995
|
+
});
|
|
33996
|
+
|
|
33795
33997
|
// packages/playwright-core/src/server/chromium/crConnection.ts
|
|
33796
33998
|
var ConnectionEvents, kBrowserCloseMessageId, CRConnection, CRSession, CDPSession;
|
|
33797
33999
|
var init_crConnection = __esm({
|
|
@@ -33852,6 +34054,9 @@ var init_crConnection = __esm({
|
|
|
33852
34054
|
if (!this._closed)
|
|
33853
34055
|
this._transport.close();
|
|
33854
34056
|
}
|
|
34057
|
+
transport() {
|
|
34058
|
+
return this._transport;
|
|
34059
|
+
}
|
|
33855
34060
|
async createBrowserSession() {
|
|
33856
34061
|
const { sessionId } = await this.rootSession.send("Target.attachToBrowserTarget");
|
|
33857
34062
|
return new CDPSession(this.rootSession, sessionId);
|
|
@@ -37355,6 +37560,7 @@ var init_crBrowser = __esm({
|
|
|
37355
37560
|
init_frames();
|
|
37356
37561
|
init_network2();
|
|
37357
37562
|
init_page();
|
|
37563
|
+
init_pipeTransport2();
|
|
37358
37564
|
init_crConnection();
|
|
37359
37565
|
init_crPage();
|
|
37360
37566
|
init_crProtocolHelper();
|
|
@@ -37367,6 +37573,7 @@ var init_crBrowser = __esm({
|
|
|
37367
37573
|
this._crPages = /* @__PURE__ */ new Map();
|
|
37368
37574
|
this._serviceWorkers = /* @__PURE__ */ new Map();
|
|
37369
37575
|
this._isConnecting = false;
|
|
37576
|
+
this._handingOff = false;
|
|
37370
37577
|
this._version = "";
|
|
37371
37578
|
this._majorVersion = 0;
|
|
37372
37579
|
this._revision = "";
|
|
@@ -37400,7 +37607,16 @@ var init_crBrowser = __esm({
|
|
|
37400
37607
|
browser._userAgent = version3.userAgent;
|
|
37401
37608
|
browser.options.headful = !version3.userAgent.includes("Headless");
|
|
37402
37609
|
if (!options.persistent) {
|
|
37610
|
+
const adopted = options.adoptContext && await browser.adoptHandedOverContext(options.adoptContext).then(() => true, () => false);
|
|
37611
|
+
if (options.adoptContext && !adopted)
|
|
37612
|
+
await session.send("Target.disposeBrowserContext", { browserContextId: options.adoptContext.id }).catch(() => {
|
|
37613
|
+
});
|
|
37403
37614
|
await session.send("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true });
|
|
37615
|
+
if (adopted) {
|
|
37616
|
+
await session.send("Target.getTargetInfo");
|
|
37617
|
+
await browser._waitForAllPagesToBeInitialized();
|
|
37618
|
+
browser.startAdoptedContextRecycle();
|
|
37619
|
+
}
|
|
37404
37620
|
return browser;
|
|
37405
37621
|
}
|
|
37406
37622
|
browser._defaultContext = new CRBrowserContext(browser, void 0, options.persistent);
|
|
@@ -37437,6 +37653,29 @@ var init_crBrowser = __esm({
|
|
|
37437
37653
|
this._contexts.set(browserContextId, context);
|
|
37438
37654
|
return context;
|
|
37439
37655
|
}
|
|
37656
|
+
async doAdoptContext(browserContextId, options) {
|
|
37657
|
+
const context = new CRBrowserContext(this, browserContextId, options);
|
|
37658
|
+
await context.initialize();
|
|
37659
|
+
this._contexts.set(browserContextId, context);
|
|
37660
|
+
return context;
|
|
37661
|
+
}
|
|
37662
|
+
// Flashwright: leaves the browser as a new DevTools client would find it, attached to nothing,
|
|
37663
|
+
// and gives up its pipe (see Browser.handoffForSession).
|
|
37664
|
+
async doDetachForHandoff() {
|
|
37665
|
+
const transport = this._connection.transport();
|
|
37666
|
+
if (!(transport instanceof PipeTransport2))
|
|
37667
|
+
return;
|
|
37668
|
+
this._handingOff = true;
|
|
37669
|
+
const sessionIds = [...this._connection._sessions.keys()].filter((sessionId) => !!sessionId);
|
|
37670
|
+
const stopAttaching = this._session.send("Target.setAutoAttach", { autoAttach: false, waitForDebuggerOnStart: false, flatten: true });
|
|
37671
|
+
const detached = sessionIds.map((sessionId) => this._session.send("Target.detachFromTarget", { sessionId }).catch(() => {
|
|
37672
|
+
}));
|
|
37673
|
+
const lastReply = this._session.send("Browser.getVersion");
|
|
37674
|
+
await Promise.all([stopAttaching, ...detached, lastReply]);
|
|
37675
|
+
const pipes = transport.release();
|
|
37676
|
+
this._connection._onClose("Browser handed over");
|
|
37677
|
+
return pipes;
|
|
37678
|
+
}
|
|
37440
37679
|
contexts() {
|
|
37441
37680
|
return Array.from(this._contexts.values());
|
|
37442
37681
|
}
|
|
@@ -37499,6 +37738,8 @@ var init_crBrowser = __esm({
|
|
|
37499
37738
|
});
|
|
37500
37739
|
}
|
|
37501
37740
|
_onDetachedFromTarget(payload) {
|
|
37741
|
+
if (this._handingOff)
|
|
37742
|
+
return;
|
|
37502
37743
|
const targetId = payload.targetId;
|
|
37503
37744
|
const crPage = this._crPages.get(targetId);
|
|
37504
37745
|
if (crPage) {
|
|
@@ -38453,70 +38694,25 @@ var init_backendAdb = __esm({
|
|
|
38453
38694
|
}
|
|
38454
38695
|
});
|
|
38455
38696
|
|
|
38456
|
-
// packages/playwright-core/src/server/
|
|
38457
|
-
|
|
38458
|
-
|
|
38459
|
-
|
|
38697
|
+
// packages/playwright-core/src/server/browserHandoff.ts
|
|
38698
|
+
function browserLaunchKey(browserName, options) {
|
|
38699
|
+
const entries = Object.entries(options).filter(([key, value2]) => value2 !== void 0 && !kIgnoredLaunchOptions.has(key) && !key.startsWith("__testHook"));
|
|
38700
|
+
entries.sort(([a], [b]) => a < b ? -1 : 1);
|
|
38701
|
+
return JSON.stringify([browserName, entries]);
|
|
38702
|
+
}
|
|
38703
|
+
function takeBrowserOffer(browserName, options) {
|
|
38704
|
+
const offer = globalThis[offerKey];
|
|
38705
|
+
if (!offer || offer.metadata.browserName !== browserName || offer.metadata.launchKey !== browserLaunchKey(browserName, options))
|
|
38706
|
+
return;
|
|
38707
|
+
delete globalThis[offerKey];
|
|
38708
|
+
return offer;
|
|
38709
|
+
}
|
|
38710
|
+
var offerKey, kIgnoredLaunchOptions;
|
|
38711
|
+
var init_browserHandoff = __esm({
|
|
38712
|
+
"packages/playwright-core/src/server/browserHandoff.ts"() {
|
|
38460
38713
|
"use strict";
|
|
38461
|
-
|
|
38462
|
-
|
|
38463
|
-
constructor(pipeWrite, pipeRead) {
|
|
38464
|
-
this._pendingBuffers = [];
|
|
38465
|
-
this._closed = false;
|
|
38466
|
-
this._pipeRead = pipeRead;
|
|
38467
|
-
this._pipeWrite = pipeWrite;
|
|
38468
|
-
pipeRead.on("data", (buffer) => this._dispatch(buffer));
|
|
38469
|
-
pipeRead.on("close", () => {
|
|
38470
|
-
this._closed = true;
|
|
38471
|
-
if (this._onclose)
|
|
38472
|
-
this._onclose.call(null);
|
|
38473
|
-
});
|
|
38474
|
-
pipeRead.on("error", (e) => debugLogger.log("error", e));
|
|
38475
|
-
pipeWrite.on("error", (e) => debugLogger.log("error", e));
|
|
38476
|
-
this.onmessage = void 0;
|
|
38477
|
-
}
|
|
38478
|
-
get onclose() {
|
|
38479
|
-
return this._onclose;
|
|
38480
|
-
}
|
|
38481
|
-
set onclose(onclose) {
|
|
38482
|
-
this._onclose = onclose;
|
|
38483
|
-
if (onclose && !this._pipeRead.readable)
|
|
38484
|
-
onclose();
|
|
38485
|
-
}
|
|
38486
|
-
send(message) {
|
|
38487
|
-
if (this._closed)
|
|
38488
|
-
throw new Error("Pipe has been closed");
|
|
38489
|
-
this._pipeWrite.write(JSON.stringify(message) + "\0");
|
|
38490
|
-
}
|
|
38491
|
-
close() {
|
|
38492
|
-
throw new Error("unimplemented");
|
|
38493
|
-
}
|
|
38494
|
-
_dispatch(buffer) {
|
|
38495
|
-
let end = buffer.indexOf("\0");
|
|
38496
|
-
if (end === -1) {
|
|
38497
|
-
this._pendingBuffers.push(buffer);
|
|
38498
|
-
return;
|
|
38499
|
-
}
|
|
38500
|
-
this._pendingBuffers.push(buffer.slice(0, end));
|
|
38501
|
-
const message = Buffer.concat(this._pendingBuffers).toString();
|
|
38502
|
-
setImmediate(() => {
|
|
38503
|
-
if (this.onmessage)
|
|
38504
|
-
this.onmessage.call(null, JSON.parse(message));
|
|
38505
|
-
});
|
|
38506
|
-
let start3 = end + 1;
|
|
38507
|
-
end = buffer.indexOf("\0", start3);
|
|
38508
|
-
while (end !== -1) {
|
|
38509
|
-
const message2 = buffer.toString(void 0, start3, end);
|
|
38510
|
-
setImmediate(() => {
|
|
38511
|
-
if (this.onmessage)
|
|
38512
|
-
this.onmessage.call(null, JSON.parse(message2));
|
|
38513
|
-
});
|
|
38514
|
-
start3 = end + 1;
|
|
38515
|
-
end = buffer.indexOf("\0", start3);
|
|
38516
|
-
}
|
|
38517
|
-
this._pendingBuffers = [buffer.slice(start3)];
|
|
38518
|
-
}
|
|
38519
|
-
};
|
|
38714
|
+
offerKey = /* @__PURE__ */ Symbol.for("flashwright.browserOffer");
|
|
38715
|
+
kIgnoredLaunchOptions = /* @__PURE__ */ new Set(["artifactsDir", "tracesDir", "downloadsPath", "timeout", "slowMo", "handleSIGINT", "handleSIGTERM", "handleSIGHUP"]);
|
|
38520
38716
|
}
|
|
38521
38717
|
});
|
|
38522
38718
|
|
|
@@ -38687,6 +38883,20 @@ function copyTestHooks(from, to) {
|
|
|
38687
38883
|
to[key] = value2;
|
|
38688
38884
|
}
|
|
38689
38885
|
}
|
|
38886
|
+
async function closeOrKillProcess(gracefullyClose, kill, timeout) {
|
|
38887
|
+
let timer;
|
|
38888
|
+
try {
|
|
38889
|
+
await Promise.race([
|
|
38890
|
+
gracefullyClose(),
|
|
38891
|
+
new Promise((resolve, reject) => timer = setTimeout(reject, timeout))
|
|
38892
|
+
]);
|
|
38893
|
+
} catch (ignored) {
|
|
38894
|
+
await kill().catch((ignored2) => {
|
|
38895
|
+
});
|
|
38896
|
+
} finally {
|
|
38897
|
+
clearTimeout(timer);
|
|
38898
|
+
}
|
|
38899
|
+
}
|
|
38690
38900
|
var import_fs22, import_os10, import_path21, kNoXServerRunningError, BrowserType;
|
|
38691
38901
|
var init_browserType = __esm({
|
|
38692
38902
|
"packages/playwright-core/src/server/browserType.ts"() {
|
|
@@ -38702,6 +38912,7 @@ var init_browserType = __esm({
|
|
|
38702
38912
|
init_processLauncher();
|
|
38703
38913
|
init_debugLogger();
|
|
38704
38914
|
init_browserContext();
|
|
38915
|
+
init_browserHandoff();
|
|
38705
38916
|
init_helper();
|
|
38706
38917
|
init_instrumentation();
|
|
38707
38918
|
init_pipeTransport2();
|
|
@@ -38768,7 +38979,8 @@ var init_browserType = __esm({
|
|
|
38768
38979
|
async _innerLaunch(progress2, options, persistent, protocolLogger, maybeUserDataDir) {
|
|
38769
38980
|
options.proxy = options.proxy ? normalizeProxySettings(options.proxy) : void 0;
|
|
38770
38981
|
const browserLogsCollector = new RecentLogsCollector();
|
|
38771
|
-
const
|
|
38982
|
+
const offer = persistent ? void 0 : takeBrowserOffer(this._name, options);
|
|
38983
|
+
const { browserProcess, userDataDir, artifactsDir, transport, wsEndpoint } = offer ? await this._adoptProcess(progress2, offer, options, browserLogsCollector) : await this._launchProcess(progress2, options, !!persistent, browserLogsCollector, maybeUserDataDir);
|
|
38772
38984
|
try {
|
|
38773
38985
|
if (options.__testHookBeforeCreateBrowser)
|
|
38774
38986
|
await progress2.race(options.__testHookBeforeCreateBrowser());
|
|
@@ -38789,7 +39001,9 @@ var init_browserType = __esm({
|
|
|
38789
39001
|
browserLogsCollector,
|
|
38790
39002
|
wsEndpoint,
|
|
38791
39003
|
originalLaunchOptions: options,
|
|
38792
|
-
userDataDir: persistent ? userDataDir : void 0
|
|
39004
|
+
userDataDir: persistent ? userDataDir : void 0,
|
|
39005
|
+
launchKey: browserLaunchKey(this._name, options),
|
|
39006
|
+
adoptContext: offer?.metadata.context
|
|
38793
39007
|
};
|
|
38794
39008
|
if (persistent)
|
|
38795
39009
|
validateBrowserContextOptions(persistent, browserOptions);
|
|
@@ -38859,7 +39073,7 @@ var init_browserType = __esm({
|
|
|
38859
39073
|
let transport = void 0;
|
|
38860
39074
|
let browserProcess = void 0;
|
|
38861
39075
|
const exitPromise = new ManualPromise();
|
|
38862
|
-
const { launchedProcess, gracefullyClose, kill, killAndCleanup } = await progress2.race(launchProcess({
|
|
39076
|
+
const { launchedProcess, gracefullyClose, kill, killAndCleanup, release } = await progress2.race(launchProcess({
|
|
38863
39077
|
command: prepared.executable,
|
|
38864
39078
|
args: prepared.browserArguments,
|
|
38865
39079
|
env: this.amendEnvironment(env, prepared.userDataDir, isPersistent, options),
|
|
@@ -38887,26 +39101,14 @@ var init_browserType = __esm({
|
|
|
38887
39101
|
browserProcess.onclose(exitCode, signal);
|
|
38888
39102
|
}
|
|
38889
39103
|
}));
|
|
38890
|
-
|
|
38891
|
-
let timer;
|
|
38892
|
-
try {
|
|
38893
|
-
await Promise.race([
|
|
38894
|
-
gracefullyClose(),
|
|
38895
|
-
new Promise((resolve, reject) => timer = setTimeout(reject, timeout))
|
|
38896
|
-
]);
|
|
38897
|
-
} catch (ignored) {
|
|
38898
|
-
await kill().catch((ignored2) => {
|
|
38899
|
-
});
|
|
38900
|
-
} finally {
|
|
38901
|
-
clearTimeout(timer);
|
|
38902
|
-
}
|
|
38903
|
-
}
|
|
39104
|
+
const closeOrKill = (timeout) => closeOrKillProcess(gracefullyClose, kill, timeout);
|
|
38904
39105
|
browserProcess = {
|
|
38905
39106
|
onclose: void 0,
|
|
38906
39107
|
process: launchedProcess,
|
|
38907
39108
|
close: () => closeOrKill(options.__testHookBrowserCloseTimeout || DEFAULT_PLAYWRIGHT_TIMEOUT),
|
|
38908
39109
|
kill,
|
|
38909
|
-
killAndCleanup
|
|
39110
|
+
killAndCleanup,
|
|
39111
|
+
release
|
|
38910
39112
|
};
|
|
38911
39113
|
try {
|
|
38912
39114
|
const { wsEndpoint } = await progress2.race([
|
|
@@ -38933,6 +39135,46 @@ ${updatedLog}`);
|
|
|
38933
39135
|
throw error;
|
|
38934
39136
|
}
|
|
38935
39137
|
}
|
|
39138
|
+
// Flashwright: takes over a running browser that another process launched with the same options
|
|
39139
|
+
// and handed over (see browserHandoff.ts), instead of launching one.
|
|
39140
|
+
async _adoptProcess(progress2, offer, options, browserLogsCollector) {
|
|
39141
|
+
const { metadata } = offer;
|
|
39142
|
+
const tempDirectories = [...metadata.tempDirectories];
|
|
39143
|
+
let artifactsDir = options.artifactsDir;
|
|
39144
|
+
if (!artifactsDir) {
|
|
39145
|
+
artifactsDir = await progress2.race(import_fs22.default.promises.mkdtemp(import_path21.default.join(import_os10.default.tmpdir(), "playwright-artifacts-")));
|
|
39146
|
+
tempDirectories.push(artifactsDir);
|
|
39147
|
+
}
|
|
39148
|
+
const transport = new PipeTransport2(offer.write, offer.read);
|
|
39149
|
+
const exited = new Promise((resolve) => {
|
|
39150
|
+
if (!offer.read.readable)
|
|
39151
|
+
resolve();
|
|
39152
|
+
offer.read.once("close", () => resolve());
|
|
39153
|
+
});
|
|
39154
|
+
let browserProcess = void 0;
|
|
39155
|
+
const { gracefullyClose, kill, killAndCleanup, release } = adoptProcess({
|
|
39156
|
+
pid: metadata.pid,
|
|
39157
|
+
tempDirectories,
|
|
39158
|
+
exited,
|
|
39159
|
+
handleSIGINT: options.handleSIGINT ?? true,
|
|
39160
|
+
handleSIGTERM: options.handleSIGTERM ?? true,
|
|
39161
|
+
handleSIGHUP: options.handleSIGHUP ?? true,
|
|
39162
|
+
attemptToGracefullyClose: async () => this.attemptToGracefullyCloseBrowser(transport),
|
|
39163
|
+
onExit: () => browserProcess?.onclose?.(0, null),
|
|
39164
|
+
log: (message) => {
|
|
39165
|
+
progress2.log(message);
|
|
39166
|
+
browserLogsCollector.log(message);
|
|
39167
|
+
}
|
|
39168
|
+
});
|
|
39169
|
+
browserProcess = {
|
|
39170
|
+
onclose: void 0,
|
|
39171
|
+
close: () => closeOrKillProcess(gracefullyClose, kill, options.__testHookBrowserCloseTimeout || DEFAULT_PLAYWRIGHT_TIMEOUT),
|
|
39172
|
+
kill,
|
|
39173
|
+
killAndCleanup,
|
|
39174
|
+
release
|
|
39175
|
+
};
|
|
39176
|
+
return { browserProcess, artifactsDir, userDataDir: "", transport };
|
|
39177
|
+
}
|
|
38936
39178
|
async connectOverCDP(progress2, params2) {
|
|
38937
39179
|
throw new Error("CDP connections are only supported by Chromium");
|
|
38938
39180
|
}
|
|
@@ -50598,6 +50840,13 @@ function raceWithTimeout(promise, timeout, timeoutValue) {
|
|
|
50598
50840
|
const timedOut = new Promise((f) => timer = setTimeout(() => f(timeoutValue), timeout));
|
|
50599
50841
|
return Promise.race([promise, timedOut]).finally(() => clearTimeout(timer));
|
|
50600
50842
|
}
|
|
50843
|
+
function isPlainJSON(value2) {
|
|
50844
|
+
if (value2 === null || ["string", "number", "boolean", "undefined"].includes(typeof value2))
|
|
50845
|
+
return true;
|
|
50846
|
+
if (Array.isArray(value2))
|
|
50847
|
+
return value2.every(isPlainJSON);
|
|
50848
|
+
return typeof value2 === "object" && Object.getPrototypeOf(value2) === Object.prototype && Object.values(value2).every(isPlainJSON);
|
|
50849
|
+
}
|
|
50601
50850
|
var import_fs28, BrowserContextEvent, BrowserContext, kRecycledPageTimeout, kRecycleTimeout, paramsThatAllowContextReuse, defaultNewContextParamValues;
|
|
50602
50851
|
var init_browserContext = __esm({
|
|
50603
50852
|
"packages/playwright-core/src/server/browserContext.ts"() {
|
|
@@ -50756,6 +51005,32 @@ if (self.ServiceWorkerContainer) ServiceWorkerContainer.prototype.register = asy
|
|
|
50756
51005
|
this._pendingRecycle.catch(() => {
|
|
50757
51006
|
});
|
|
50758
51007
|
}
|
|
51008
|
+
// Flashwright: the context of a browser handed over by another process (see browserHandoff.ts)
|
|
51009
|
+
// clears the storage of the origins the previous process's tests used on its next reset.
|
|
51010
|
+
addVisitedOrigins(origins) {
|
|
51011
|
+
for (const origin of origins)
|
|
51012
|
+
this._origins.add(origin);
|
|
51013
|
+
}
|
|
51014
|
+
// Flashwright: called before the browser is handed over to another process. Waits for the reset
|
|
51015
|
+
// that started when the last test ended and describes the context for the process that adopts it,
|
|
51016
|
+
// or returns undefined when it cannot move: it holds state that lives in this process (a client
|
|
51017
|
+
// certificate proxy, a HAR recording, a video) or that a reset cannot clear.
|
|
51018
|
+
async prepareForHandoff() {
|
|
51019
|
+
const params2 = this.reuseParams;
|
|
51020
|
+
if (!this._recycleMode || !this.supportsRecycling() || !params2 || !this._browserContextId || this._closedStatus !== "open" || this._recyclingPrevented)
|
|
51021
|
+
return;
|
|
51022
|
+
if (this._clientCertificatesProxy || this.tracing.harRecorders.size || params2.recordVideo)
|
|
51023
|
+
return;
|
|
51024
|
+
const pending = this._pendingRecycle;
|
|
51025
|
+
this._pendingRecycle = void 0;
|
|
51026
|
+
if (!await (pending ?? this._recycle(nullProgress)))
|
|
51027
|
+
return;
|
|
51028
|
+
const rest = { ...params2 };
|
|
51029
|
+
delete rest.storageState;
|
|
51030
|
+
if (!isPlainJSON(rest))
|
|
51031
|
+
return;
|
|
51032
|
+
return { id: this._browserContextId, params: rest, origins: [...this._origins] };
|
|
51033
|
+
}
|
|
50759
51034
|
static reusableContextHash(params2) {
|
|
50760
51035
|
const paramsCopy = { ...params2 };
|
|
50761
51036
|
if (paramsCopy.selectorEngines?.length === 0)
|
|
@@ -51910,6 +52185,13 @@ var init_browser = __esm({
|
|
|
51910
52185
|
Disconnected: "disconnected"
|
|
51911
52186
|
};
|
|
51912
52187
|
}
|
|
52188
|
+
// Flashwright: see handoffForSession and adoptHandedOverContext.
|
|
52189
|
+
doAdoptContext(contextId4, options) {
|
|
52190
|
+
throw new Error("Not supported");
|
|
52191
|
+
}
|
|
52192
|
+
async doDetachForHandoff() {
|
|
52193
|
+
return void 0;
|
|
52194
|
+
}
|
|
51913
52195
|
sdkLanguage() {
|
|
51914
52196
|
return this.options.sdkLanguage || this.attribution.playwright.options.sdkLanguage;
|
|
51915
52197
|
}
|
|
@@ -51964,6 +52246,7 @@ var init_browser = __esm({
|
|
|
51964
52246
|
await this._contextForReuse.context.close(progress2, { reason: "Context reused" });
|
|
51965
52247
|
}
|
|
51966
52248
|
const context = await this.newContext(progress2, params2, recycle);
|
|
52249
|
+
context.reuseParams = params2;
|
|
51967
52250
|
this._contextForReuse = { context, hash };
|
|
51968
52251
|
return context;
|
|
51969
52252
|
}
|
|
@@ -51976,8 +52259,12 @@ var init_browser = __esm({
|
|
|
51976
52259
|
// (newContextForReuse), which also applies the test's storage state; a test asking for a different
|
|
51977
52260
|
// context gets a new one and this one closes.
|
|
51978
52261
|
async prepareRecycledContext(params2, options = {}) {
|
|
51979
|
-
|
|
52262
|
+
const reuse = this._contextForReuse;
|
|
52263
|
+
if (reuse) {
|
|
52264
|
+
if (reuse.prepared && options.storageState && reuse.hash === BrowserContext.reusableContextHash(params2) + ":recycle")
|
|
52265
|
+
reuse.context.prepareStorageStatePage();
|
|
51980
52266
|
return;
|
|
52267
|
+
}
|
|
51981
52268
|
const context = await this.newContext(
|
|
51982
52269
|
nullProgress,
|
|
51983
52270
|
params2,
|
|
@@ -51985,11 +52272,61 @@ var init_browser = __esm({
|
|
|
51985
52272
|
false
|
|
51986
52273
|
/* announce */
|
|
51987
52274
|
);
|
|
52275
|
+
context.reuseParams = params2;
|
|
51988
52276
|
this._contextForReuse = { context, hash: BrowserContext.reusableContextHash(params2) + ":recycle", prepared: true };
|
|
51989
52277
|
context.startRecycle();
|
|
51990
52278
|
if (options.storageState)
|
|
51991
52279
|
context.prepareStorageStatePage();
|
|
51992
52280
|
}
|
|
52281
|
+
// Flashwright: a browser handed over by another process brings the context its tests used, with
|
|
52282
|
+
// the tab that keeps the renderer warm. It becomes the prepared recycled context, like
|
|
52283
|
+
// prepareRecycledContext's, and is reset once more before a test takes it.
|
|
52284
|
+
async adoptHandedOverContext(handedOver) {
|
|
52285
|
+
const params2 = { ...handedOver.params };
|
|
52286
|
+
const options = { ...params2 };
|
|
52287
|
+
validateBrowserContextOptions(options, this.options);
|
|
52288
|
+
const context = await this.doAdoptContext(handedOver.id, options);
|
|
52289
|
+
context.reuseParams = params2;
|
|
52290
|
+
context.setRecycleMode(true);
|
|
52291
|
+
context.addVisitedOrigins(handedOver.origins);
|
|
52292
|
+
this._contextForReuse = { context, hash: BrowserContext.reusableContextHash(params2) + ":recycle", prepared: true };
|
|
52293
|
+
}
|
|
52294
|
+
// Called once the handed-over context's existing tab is attached.
|
|
52295
|
+
startAdoptedContextRecycle() {
|
|
52296
|
+
if (this._contextForReuse?.prepared)
|
|
52297
|
+
this._contextForReuse.context.startRecycle();
|
|
52298
|
+
}
|
|
52299
|
+
// Flashwright: in a warm test session, the worker that launched this browser hands it to the
|
|
52300
|
+
// next run instead of closing it (see browserHandoff.ts). Only a browser whose one open context
|
|
52301
|
+
// is the recycled one, reset and healthy, is handed over; anything else returns undefined and
|
|
52302
|
+
// the caller closes the browser as usual. Afterwards this object is disconnected from it.
|
|
52303
|
+
// A headed browser is not handed over: its window would stay open between runs.
|
|
52304
|
+
async handoffForSession() {
|
|
52305
|
+
const reuse = this._contextForReuse;
|
|
52306
|
+
const release = this.options.browserProcess.release;
|
|
52307
|
+
if (!release || !this.options.launchKey || this.options.persistent || this.options.headful || this._startedClosing || !this.isConnected())
|
|
52308
|
+
return;
|
|
52309
|
+
if (!reuse || !reuse.hash.endsWith(":recycle") || this.contexts().some((context) => context !== reuse.context))
|
|
52310
|
+
return;
|
|
52311
|
+
const handedOverContext = await reuse.context.prepareForHandoff();
|
|
52312
|
+
if (!handedOverContext)
|
|
52313
|
+
return;
|
|
52314
|
+
const pipes = await this.doDetachForHandoff().catch(() => void 0);
|
|
52315
|
+
if (!pipes)
|
|
52316
|
+
return;
|
|
52317
|
+
const { pid, tempDirectories } = release();
|
|
52318
|
+
this._startedClosing = true;
|
|
52319
|
+
return {
|
|
52320
|
+
...pipes,
|
|
52321
|
+
metadata: {
|
|
52322
|
+
browserName: this.options.name,
|
|
52323
|
+
launchKey: this.options.launchKey,
|
|
52324
|
+
pid,
|
|
52325
|
+
tempDirectories,
|
|
52326
|
+
context: handedOverContext
|
|
52327
|
+
}
|
|
52328
|
+
};
|
|
52329
|
+
}
|
|
51993
52330
|
// Flashwright: see BrowserContext.outputDirsChanged.
|
|
51994
52331
|
async setOutputDirs(artifactsDir, tracesDir) {
|
|
51995
52332
|
this.options.artifactsDir = artifactsDir;
|
|
@@ -74532,9 +74869,11 @@ __export(utils_exports, {
|
|
|
74532
74869
|
ZipFile: () => ZipFile,
|
|
74533
74870
|
Zone: () => Zone,
|
|
74534
74871
|
addSuffixToFilePath: () => addSuffixToFilePath,
|
|
74872
|
+
adoptProcess: () => adoptProcess,
|
|
74535
74873
|
blendWithWhite: () => blendWithWhite,
|
|
74536
74874
|
calculateSha1: () => calculateSha1,
|
|
74537
74875
|
canAccessFile: () => canAccessFile,
|
|
74876
|
+
captureFilteredStackTrace: () => captureFilteredStackTrace,
|
|
74538
74877
|
captureRawStack: () => captureRawStack,
|
|
74539
74878
|
colorDeltaE94: () => colorDeltaE94,
|
|
74540
74879
|
compare: () => compare,
|
|
@@ -79231,10 +79570,10 @@ var utilsFacade = [
|
|
|
79231
79570
|
[["hostPlatform", "isOfficiallySupportedPlatform", "shortPlatform"], () => (init_hostPlatform(), __toCommonJS(hostPlatform_exports))],
|
|
79232
79571
|
[["HttpServer", "computeAllowedHosts", "isAllowedHost", "serveFolder", "urlHostFromAddress"], () => (init_httpServer(), __toCommonJS(httpServer_exports))],
|
|
79233
79572
|
[["NET_DEFAULT_TIMEOUT", "createHttp2Server", "createHttpServer", "createHttpsServer", "createProxyAgent", "createSocket", "decorateServer", "flattenAggregateError", "happyEyeballsOptions", "httpRequest", "isURLAvailable", "proxySettingsFromString", "startHttpServer"], () => (init_network(), __toCommonJS(network_exports))],
|
|
79234
|
-
[["envArrayToObject", "gracefullyCloseAll", "gracefullyCloseSet", "gracefullyProcessExitDoNotHang", "killProcessTree", "launchProcess", "spawnAsync"], () => (init_processLauncher(), __toCommonJS(processLauncher_exports))],
|
|
79573
|
+
[["adoptProcess", "envArrayToObject", "gracefullyCloseAll", "gracefullyCloseSet", "gracefullyProcessExitDoNotHang", "killProcessTree", "launchProcess", "spawnAsync"], () => (init_processLauncher(), __toCommonJS(processLauncher_exports))],
|
|
79235
79574
|
[["SerializedFS"], () => (init_serializedFS(), __toCommonJS(serializedFS_exports))],
|
|
79236
79575
|
[["SocksProxy", "SocksProxyHandler", "parsePattern"], () => (init_socksProxy(), __toCommonJS(socksProxy_exports))],
|
|
79237
|
-
[["captureRawStack", "coreDir", "filterStackFile", "filteredStackTrace", "parseErrorStack", "parseStackFrame", "rewriteErrorMessage", "setBoxedStackPrefixes", "setCoreDir", "setRawStackFormatter", "showInternalStackFrames", "splitErrorMessage", "stringifyStackFrames", "withShallowStack"], () => (init_stackTrace(), __toCommonJS(stackTrace_exports))],
|
|
79576
|
+
[["captureFilteredStackTrace", "captureRawStack", "coreDir", "filterStackFile", "filteredStackTrace", "parseErrorStack", "parseStackFrame", "rewriteErrorMessage", "setBoxedStackPrefixes", "setCoreDir", "setRawStackFormatter", "showInternalStackFrames", "splitErrorMessage", "stringifyStackFrames", "withShallowStack"], () => (init_stackTrace(), __toCommonJS(stackTrace_exports))],
|
|
79238
79577
|
[["fitToWidth", "stringWidth"], () => (init_stringWidth(), __toCommonJS(stringWidth_exports))],
|
|
79239
79578
|
[["WSServer", "perMessageDeflate"], () => (init_wsServer(), __toCommonJS(wsServer_exports))],
|
|
79240
79579
|
[["ZipFile"], () => (init_zipFile(), __toCommonJS(zipFile_exports))],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{D as e,_ as t,b as n,g as r,i,k as a,n as o,o as s,r as c,s as l,t as u,v as d}from"./assets/defaultSettingsView-DoonTZ3z.js";import"./assets/urlMatch-L3liM589.js";var f=a(e(),1),p=a(d(),1),m=r(),h=()=>{let[e,n]=f.useState(!1),[r,a]=f.useState(),[d,p]=f.useState(),[h,_]=f.useState(g),[v,y]=f.useState({done:0,total:0}),[b,x]=f.useState(!1),[S,C]=f.useState(null),[w,T]=f.useState(null),[E,D]=f.useState(!1),O=f.useCallback(e=>{let t=new URL(window.location.href);if(!e.length)return;let n=e.item(0),r=URL.createObjectURL(n);t.searchParams.append(`trace`,r);let i=t.toString();window.history.pushState({},``,i),a(r),p(n.name),x(!1),C(null)},[]);f.useEffect(()=>{let e=async e=>{if(!e.clipboardData?.files.length)return;let t=[`application/zip`,`application/x-zip-compressed`];for(let n of e.clipboardData.files)if(!t.includes(n.type))return;e.preventDefault(),O(e.clipboardData.files)};return document.addEventListener(`paste`,e),()=>document.removeEventListener(`paste`,e)}),f.useEffect(()=>{let e=e=>{let{method:t,params:n}=e.data;if(t!==`load`||!(n?.trace instanceof Blob))return;let r=new File([n.trace],`trace.zip`,{type:`application/zip`}),i=new DataTransfer;i.items.add(r),O(i.files)};return window.addEventListener(`message`,e),window.opener?.postMessage({method:`ready`},`*`),window.parent!==window&&window.parent.postMessage({method:`ready`},`*`),()=>window.removeEventListener(`message`,e)},[O]);let k=f.useCallback(e=>{e.preventDefault(),O(e.dataTransfer.files)},[O]),A=f.useCallback(e=>{e.preventDefault(),e.target.files&&O(e.target.files)},[O]);f.useEffect(()=>{let e=new URL(window.location.href).searchParams,t=e.get(`trace`);if(n(e.has(`isServer`)),t?.startsWith(`file:`)){T(t||null);return}if(e.has(`isServer`)){let e=new URLSearchParams(window.location.search).get(`ws`),t=new URL(`../${e}`,window.location.toString());t.protocol=window.location.protocol===`https:`?`wss:`:`ws:`;let n=new o(new c(t));n.onLoadTraceRequested(async e=>{a(e.traceUrl),x(!1),C(null)}),n.initialize({}).catch(()=>{})}else t&&!t.startsWith(`blob:`)&&a(t)},[]);let j=f.useCallback(async e=>{let n=new URLSearchParams;n.set(`trace`,e);let r=await fetch(`contexts?${n.toString()}`);if(!r.ok){let{error:e}=await r.json();return C(e),e}let i=new t(e,await r.json());y({done:0,total:0}),C(null),_(i)},[]);f.useEffect(()=>{(async()=>{if(!r){_(g);return}let t=e=>{e.data.method===`progress`&&y(e.data.params)};try{navigator.serviceWorker.addEventListener(`message`,t),y({done:0,total:1});let n=await j(r);n?.includes(`please grant permission for Local Network Access`)&&(await fetch(r,{method:`HEAD`,headers:{"x-pw-serviceworker":`skip`}}),n=await j(r)),n&&(e||a(void 0))}finally{navigator.serviceWorker.removeEventListener(`message`,t)}})()},[e,r,d,j]);let M=v.done!==v.total&&v.total!==0&&!S;f.useEffect(()=>{if(M){let e=setTimeout(()=>{D(!0)},200);return()=>clearTimeout(e)}else D(!1)},[M]);let N=!!(!e&&!b&&!w&&(!r||S));return(0,m.jsxs)(`div`,{className:`vbox workbench-loader`,onDragOver:e=>{e.preventDefault(),e.dataTransfer.types.includes(`Files`)&&x(!0)},children:[(0,m.jsxs)(`div`,{className:`hbox workbench-loader-header`,...N?{inert:!0}:{},children:[(0,m.jsx)(`div`,{className:`logo`,children:(0,m.jsx)(`img`,{src:`playwright-logo.svg`,alt:`Playwright logo`})}),(0,m.jsx)(`div`,{className:`product`,children:`Playwright`}),h.title&&(0,m.jsx)(`div`,{className:`title`,children:h.title}),(0,m.jsx)(`div`,{className:`spacer`}),(0,m.jsx)(s,{icon:`settings-gear`,title:`Settings`,dialogDataTestId:`settings-toolbar-dialog`,children:(0,m.jsx)(u,{location:`trace-viewer`,model:h})})]}),(0,m.jsx)(i,{model:h,inert:N}),w&&(0,m.jsxs)(`div`,{className:`drop-target`,children:[(0,m.jsx)(`div`,{children:`Trace Viewer uses Service Workers to show traces. To view trace:`}),(0,m.jsxs)(`div`,{style:{paddingTop:20},children:[(0,m.jsxs)(`div`,{children:[`1. Click `,(0,m.jsx)(`a`,{href:w,children:`here`}),` to put your trace into the download shelf`]}),(0,m.jsxs)(`div`,{children:[`2. Go to `,(0,m.jsx)(`a`,{href:`https://trace.playwright.dev`,children:`trace.playwright.dev`})]}),(0,m.jsx)(`div`,{children:`3. Drop the trace from the download shelf into the page`})]})]}),(0,m.jsx)(l,{open:E,isModal:!0,className:`progress-dialog`,children:(0,m.jsxs)(`div`,{className:`progress-content`,children:[(0,m.jsx)(`div`,{className:`title`,role:`heading`,"aria-level":1,children:`Loading Playwright Trace...`}),(0,m.jsx)(`div`,{className:`progress-wrapper`,children:(0,m.jsx)(`div`,{className:`inner-progress`,style:{width:v.total?100*v.done/v.total+`%`:0}})})]})}),N&&(0,m.jsxs)(`div`,{className:`drop-target`,children:[(0,m.jsx)(`div`,{className:`processing-error`,role:`alert`,children:S}),(0,m.jsx)(`div`,{className:`title`,role:`heading`,"aria-level":1,children:`Drop Playwright Trace to load`}),(0,m.jsx)(`div`,{children:`or`}),(0,m.jsx)(`button`,{onClick:()=>{let e=document.createElement(`input`);e.type=`file`,e.click(),e.addEventListener(`change`,e=>A(e))},type:`button`,children:`Select file`}),(0,m.jsx)(`div`,{className:`info`,children:`Playwright Trace Viewer is a Progressive Web App, it does not send your trace anywhere, it opens it locally.`}),(0,m.jsxs)(`div`,{className:`version`,children:[`Playwright v
|
|
1
|
+
import{D as e,_ as t,b as n,g as r,i,k as a,n as o,o as s,r as c,s as l,t as u,v as d}from"./assets/defaultSettingsView-DoonTZ3z.js";import"./assets/urlMatch-L3liM589.js";var f=a(e(),1),p=a(d(),1),m=r(),h=()=>{let[e,n]=f.useState(!1),[r,a]=f.useState(),[d,p]=f.useState(),[h,_]=f.useState(g),[v,y]=f.useState({done:0,total:0}),[b,x]=f.useState(!1),[S,C]=f.useState(null),[w,T]=f.useState(null),[E,D]=f.useState(!1),O=f.useCallback(e=>{let t=new URL(window.location.href);if(!e.length)return;let n=e.item(0),r=URL.createObjectURL(n);t.searchParams.append(`trace`,r);let i=t.toString();window.history.pushState({},``,i),a(r),p(n.name),x(!1),C(null)},[]);f.useEffect(()=>{let e=async e=>{if(!e.clipboardData?.files.length)return;let t=[`application/zip`,`application/x-zip-compressed`];for(let n of e.clipboardData.files)if(!t.includes(n.type))return;e.preventDefault(),O(e.clipboardData.files)};return document.addEventListener(`paste`,e),()=>document.removeEventListener(`paste`,e)}),f.useEffect(()=>{let e=e=>{let{method:t,params:n}=e.data;if(t!==`load`||!(n?.trace instanceof Blob))return;let r=new File([n.trace],`trace.zip`,{type:`application/zip`}),i=new DataTransfer;i.items.add(r),O(i.files)};return window.addEventListener(`message`,e),window.opener?.postMessage({method:`ready`},`*`),window.parent!==window&&window.parent.postMessage({method:`ready`},`*`),()=>window.removeEventListener(`message`,e)},[O]);let k=f.useCallback(e=>{e.preventDefault(),O(e.dataTransfer.files)},[O]),A=f.useCallback(e=>{e.preventDefault(),e.target.files&&O(e.target.files)},[O]);f.useEffect(()=>{let e=new URL(window.location.href).searchParams,t=e.get(`trace`);if(n(e.has(`isServer`)),t?.startsWith(`file:`)){T(t||null);return}if(e.has(`isServer`)){let e=new URLSearchParams(window.location.search).get(`ws`),t=new URL(`../${e}`,window.location.toString());t.protocol=window.location.protocol===`https:`?`wss:`:`ws:`;let n=new o(new c(t));n.onLoadTraceRequested(async e=>{a(e.traceUrl),x(!1),C(null)}),n.initialize({}).catch(()=>{})}else t&&!t.startsWith(`blob:`)&&a(t)},[]);let j=f.useCallback(async e=>{let n=new URLSearchParams;n.set(`trace`,e);let r=await fetch(`contexts?${n.toString()}`);if(!r.ok){let{error:e}=await r.json();return C(e),e}let i=new t(e,await r.json());y({done:0,total:0}),C(null),_(i)},[]);f.useEffect(()=>{(async()=>{if(!r){_(g);return}let t=e=>{e.data.method===`progress`&&y(e.data.params)};try{navigator.serviceWorker.addEventListener(`message`,t),y({done:0,total:1});let n=await j(r);n?.includes(`please grant permission for Local Network Access`)&&(await fetch(r,{method:`HEAD`,headers:{"x-pw-serviceworker":`skip`}}),n=await j(r)),n&&(e||a(void 0))}finally{navigator.serviceWorker.removeEventListener(`message`,t)}})()},[e,r,d,j]);let M=v.done!==v.total&&v.total!==0&&!S;f.useEffect(()=>{if(M){let e=setTimeout(()=>{D(!0)},200);return()=>clearTimeout(e)}else D(!1)},[M]);let N=!!(!e&&!b&&!w&&(!r||S));return(0,m.jsxs)(`div`,{className:`vbox workbench-loader`,onDragOver:e=>{e.preventDefault(),e.dataTransfer.types.includes(`Files`)&&x(!0)},children:[(0,m.jsxs)(`div`,{className:`hbox workbench-loader-header`,...N?{inert:!0}:{},children:[(0,m.jsx)(`div`,{className:`logo`,children:(0,m.jsx)(`img`,{src:`playwright-logo.svg`,alt:`Playwright logo`})}),(0,m.jsx)(`div`,{className:`product`,children:`Playwright`}),h.title&&(0,m.jsx)(`div`,{className:`title`,children:h.title}),(0,m.jsx)(`div`,{className:`spacer`}),(0,m.jsx)(s,{icon:`settings-gear`,title:`Settings`,dialogDataTestId:`settings-toolbar-dialog`,children:(0,m.jsx)(u,{location:`trace-viewer`,model:h})})]}),(0,m.jsx)(i,{model:h,inert:N}),w&&(0,m.jsxs)(`div`,{className:`drop-target`,children:[(0,m.jsx)(`div`,{children:`Trace Viewer uses Service Workers to show traces. To view trace:`}),(0,m.jsxs)(`div`,{style:{paddingTop:20},children:[(0,m.jsxs)(`div`,{children:[`1. Click `,(0,m.jsx)(`a`,{href:w,children:`here`}),` to put your trace into the download shelf`]}),(0,m.jsxs)(`div`,{children:[`2. Go to `,(0,m.jsx)(`a`,{href:`https://trace.playwright.dev`,children:`trace.playwright.dev`})]}),(0,m.jsx)(`div`,{children:`3. Drop the trace from the download shelf into the page`})]})]}),(0,m.jsx)(l,{open:E,isModal:!0,className:`progress-dialog`,children:(0,m.jsxs)(`div`,{className:`progress-content`,children:[(0,m.jsx)(`div`,{className:`title`,role:`heading`,"aria-level":1,children:`Loading Playwright Trace...`}),(0,m.jsx)(`div`,{className:`progress-wrapper`,children:(0,m.jsx)(`div`,{className:`inner-progress`,style:{width:v.total?100*v.done/v.total+`%`:0}})})]})}),N&&(0,m.jsxs)(`div`,{className:`drop-target`,children:[(0,m.jsx)(`div`,{className:`processing-error`,role:`alert`,children:S}),(0,m.jsx)(`div`,{className:`title`,role:`heading`,"aria-level":1,children:`Drop Playwright Trace to load`}),(0,m.jsx)(`div`,{children:`or`}),(0,m.jsx)(`button`,{onClick:()=>{let e=document.createElement(`input`);e.type=`file`,e.click(),e.addEventListener(`change`,e=>A(e))},type:`button`,children:`Select file`}),(0,m.jsx)(`div`,{className:`info`,children:`Playwright Trace Viewer is a Progressive Web App, it does not send your trace anywhere, it opens it locally.`}),(0,m.jsxs)(`div`,{className:`version`,children:[`Playwright v`,`1.64.1`]})]}),e&&!r&&(0,m.jsx)(`div`,{className:`drop-target`,children:(0,m.jsx)(`div`,{className:`title`,children:`Select test to see the trace`})}),b&&(0,m.jsx)(`div`,{className:`drop-target`,onDragLeave:()=>{x(!1)},onDrop:e=>k(e),children:(0,m.jsx)(`div`,{className:`title`,children:`Release to analyse the Playwright Trace`})})]})},g=new t(``,[]),_=({traceJson:e})=>{let[n,r]=f.useState(void 0),[a,o]=f.useState(0),s=f.useRef(null);return f.useEffect(()=>(s.current&&clearTimeout(s.current),s.current=setTimeout(async()=>{try{r(await v(e))}catch{r(new t(``,[]))}finally{o(a+1)}},500),()=>{s.current&&clearTimeout(s.current)}),[e,a]),(0,m.jsx)(i,{isLive:!0,model:n})};async function v(e){let n=new URLSearchParams;return n.set(`trace`,e),new t(e,await(await fetch(`contexts?${n.toString()}`)).json())}(async()=>{let e=new URLSearchParams(window.location.search);if(n(),window.location.protocol!==`file:`){if(!navigator.serviceWorker)throw Error(`Service workers are not supported.\nMake sure to serve the Trace Viewer (${window.location}) via HTTPS or localhost.`);navigator.serviceWorker.register(`sw.bundle.js`),navigator.serviceWorker.controller||await new Promise(e=>{navigator.serviceWorker.oncontrollerchange=()=>e()}),setInterval(function(){fetch(`ping`)},1e4)}let t=e.get(`trace`),r=t?.endsWith(`.json`)?(0,m.jsx)(_,{traceJson:t}):(0,m.jsx)(h,{});p.createRoot(document.querySelector(`#root`)).render(r)})();
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="icon" href="./playwright-logo.svg" type="image/svg+xml">
|
|
8
8
|
<link rel="manifest" href="./manifest.webmanifest">
|
|
9
9
|
<title>Playwright Trace Viewer</title>
|
|
10
|
-
<script type="module" crossorigin src="./index.
|
|
10
|
+
<script type="module" crossorigin src="./index.B5jyRlOV.js"></script>
|
|
11
11
|
<link rel="modulepreload" crossorigin href="./assets/urlMatch-L3liM589.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="./assets/defaultSettingsView-DoonTZ3z.js">
|
|
13
13
|
<link rel="stylesheet" crossorigin href="./defaultSettingsView.C8BeHuxd.css">
|
package/package.json
CHANGED