flashwright-core 1.64.1-flashwright.1 → 1.64.1-flashwright.2
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
|
@@ -3043,6 +3043,7 @@ var init_httpServer = __esm({
|
|
|
3043
3043
|
// packages/utils/processLauncher.ts
|
|
3044
3044
|
var processLauncher_exports = {};
|
|
3045
3045
|
__export(processLauncher_exports, {
|
|
3046
|
+
adoptProcess: () => adoptProcess,
|
|
3046
3047
|
envArrayToObject: () => envArrayToObject,
|
|
3047
3048
|
gracefullyCloseAll: () => gracefullyCloseAll,
|
|
3048
3049
|
gracefullyCloseSet: () => gracefullyCloseSet,
|
|
@@ -3149,10 +3150,13 @@ async function launchProcess(options) {
|
|
|
3149
3150
|
options.log(`[pid=${spawnedProcess.pid}][err] ` + data);
|
|
3150
3151
|
});
|
|
3151
3152
|
let processClosed = false;
|
|
3153
|
+
let released = false;
|
|
3152
3154
|
let fulfillCleanup = () => {
|
|
3153
3155
|
};
|
|
3154
3156
|
const waitForCleanup = new Promise((f) => fulfillCleanup = f);
|
|
3155
3157
|
spawnedProcess.once("close", (exitCode, signal) => {
|
|
3158
|
+
if (released)
|
|
3159
|
+
return;
|
|
3156
3160
|
options.log(`[pid=${spawnedProcess.pid}] <process did exit: exitCode=${exitCode}, signal=${signal}>`);
|
|
3157
3161
|
processClosed = true;
|
|
3158
3162
|
gracefullyCloseSet.delete(gracefullyClose);
|
|
@@ -3219,7 +3223,103 @@ async function launchProcess(options) {
|
|
|
3219
3223
|
killProcess();
|
|
3220
3224
|
return waitForCleanup;
|
|
3221
3225
|
}
|
|
3222
|
-
|
|
3226
|
+
function release() {
|
|
3227
|
+
released = true;
|
|
3228
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3229
|
+
killSet.delete(killProcessAndCleanup);
|
|
3230
|
+
removeProcessHandlersIfNeeded();
|
|
3231
|
+
stdout.close();
|
|
3232
|
+
stderr.close();
|
|
3233
|
+
spawnedProcess.unref();
|
|
3234
|
+
options.log(`[pid=${spawnedProcess.pid}] <released>`);
|
|
3235
|
+
return { pid: spawnedProcess.pid, tempDirectories: options.tempDirectories };
|
|
3236
|
+
}
|
|
3237
|
+
return { launchedProcess: spawnedProcess, gracefullyClose, kill: killAndWait, killAndCleanup: killProcessAndCleanup, release };
|
|
3238
|
+
}
|
|
3239
|
+
function adoptProcess(options) {
|
|
3240
|
+
const { pid } = options;
|
|
3241
|
+
let processClosed = false;
|
|
3242
|
+
let released = false;
|
|
3243
|
+
let fulfillCleanup = () => {
|
|
3244
|
+
};
|
|
3245
|
+
const waitForCleanup = new Promise((f) => fulfillCleanup = f);
|
|
3246
|
+
options.log(`<adopted> pid=${pid}`);
|
|
3247
|
+
void options.exited.then(async () => {
|
|
3248
|
+
if (released)
|
|
3249
|
+
return;
|
|
3250
|
+
options.log(`[pid=${pid}] <process did exit>`);
|
|
3251
|
+
processClosed = true;
|
|
3252
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3253
|
+
killSet.delete(killProcessAndCleanup);
|
|
3254
|
+
removeProcessHandlersIfNeeded();
|
|
3255
|
+
options.onExit();
|
|
3256
|
+
const errors = await removeFolders(options.tempDirectories);
|
|
3257
|
+
for (let i = 0; i < options.tempDirectories.length; ++i) {
|
|
3258
|
+
if (errors[i])
|
|
3259
|
+
options.log(`[pid=${pid}] exception while removing ${options.tempDirectories[i]}: ${errors[i]}`);
|
|
3260
|
+
}
|
|
3261
|
+
fulfillCleanup();
|
|
3262
|
+
});
|
|
3263
|
+
addProcessHandlerIfNeeded("exit");
|
|
3264
|
+
if (options.handleSIGINT)
|
|
3265
|
+
addProcessHandlerIfNeeded("SIGINT");
|
|
3266
|
+
if (options.handleSIGTERM)
|
|
3267
|
+
addProcessHandlerIfNeeded("SIGTERM");
|
|
3268
|
+
if (options.handleSIGHUP)
|
|
3269
|
+
addProcessHandlerIfNeeded("SIGHUP");
|
|
3270
|
+
gracefullyCloseSet.add(gracefullyClose);
|
|
3271
|
+
killSet.add(killProcessAndCleanup);
|
|
3272
|
+
let gracefullyClosing = false;
|
|
3273
|
+
async function gracefullyClose() {
|
|
3274
|
+
if (gracefullyClosing) {
|
|
3275
|
+
killProcess();
|
|
3276
|
+
await waitForCleanup;
|
|
3277
|
+
return;
|
|
3278
|
+
}
|
|
3279
|
+
gracefullyClosing = true;
|
|
3280
|
+
await options.attemptToGracefullyClose().catch(() => killProcess());
|
|
3281
|
+
await waitForCleanup;
|
|
3282
|
+
}
|
|
3283
|
+
function killProcess() {
|
|
3284
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3285
|
+
killSet.delete(killProcessAndCleanup);
|
|
3286
|
+
removeProcessHandlersIfNeeded();
|
|
3287
|
+
if (processClosed)
|
|
3288
|
+
return;
|
|
3289
|
+
options.log(`[pid=${pid}] <will force kill>`);
|
|
3290
|
+
try {
|
|
3291
|
+
process.kill(-pid, "SIGKILL");
|
|
3292
|
+
} catch (e) {
|
|
3293
|
+
options.log(`[pid=${pid}] exception while trying to kill process: ${e}`);
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
function killProcessAndCleanup() {
|
|
3297
|
+
killProcess();
|
|
3298
|
+
for (const dir of options.tempDirectories) {
|
|
3299
|
+
try {
|
|
3300
|
+
import_fs6.default.rmSync(dir, { force: true, recursive: true, maxRetries: 5 });
|
|
3301
|
+
} catch (e) {
|
|
3302
|
+
options.log(`[pid=${pid}] exception while removing ${dir}: ${e}`);
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
function release() {
|
|
3307
|
+
released = true;
|
|
3308
|
+
gracefullyCloseSet.delete(gracefullyClose);
|
|
3309
|
+
killSet.delete(killProcessAndCleanup);
|
|
3310
|
+
removeProcessHandlersIfNeeded();
|
|
3311
|
+
options.log(`[pid=${pid}] <released>`);
|
|
3312
|
+
return { pid, tempDirectories: options.tempDirectories };
|
|
3313
|
+
}
|
|
3314
|
+
return {
|
|
3315
|
+
gracefullyClose,
|
|
3316
|
+
kill: () => {
|
|
3317
|
+
killProcess();
|
|
3318
|
+
return waitForCleanup;
|
|
3319
|
+
},
|
|
3320
|
+
killAndCleanup: killProcessAndCleanup,
|
|
3321
|
+
release
|
|
3322
|
+
};
|
|
3223
3323
|
}
|
|
3224
3324
|
function killProcessTree(pid) {
|
|
3225
3325
|
try {
|
|
@@ -33792,6 +33892,85 @@ var init_chromiumSwitches = __esm({
|
|
|
33792
33892
|
}
|
|
33793
33893
|
});
|
|
33794
33894
|
|
|
33895
|
+
// packages/playwright-core/src/server/pipeTransport.ts
|
|
33896
|
+
var PipeTransport2;
|
|
33897
|
+
var init_pipeTransport2 = __esm({
|
|
33898
|
+
"packages/playwright-core/src/server/pipeTransport.ts"() {
|
|
33899
|
+
"use strict";
|
|
33900
|
+
init_debugLogger();
|
|
33901
|
+
PipeTransport2 = class {
|
|
33902
|
+
constructor(pipeWrite, pipeRead) {
|
|
33903
|
+
this._pendingBuffers = [];
|
|
33904
|
+
this._closed = false;
|
|
33905
|
+
this._pipeRead = pipeRead;
|
|
33906
|
+
this._pipeWrite = pipeWrite;
|
|
33907
|
+
pipeRead.on("data", (buffer) => this._dispatch(buffer));
|
|
33908
|
+
pipeRead.on("close", () => {
|
|
33909
|
+
this._closed = true;
|
|
33910
|
+
if (this._onclose)
|
|
33911
|
+
this._onclose.call(null);
|
|
33912
|
+
});
|
|
33913
|
+
pipeRead.on("error", (e) => debugLogger.log("error", e));
|
|
33914
|
+
pipeWrite.on("error", (e) => debugLogger.log("error", e));
|
|
33915
|
+
this.onmessage = void 0;
|
|
33916
|
+
}
|
|
33917
|
+
get onclose() {
|
|
33918
|
+
return this._onclose;
|
|
33919
|
+
}
|
|
33920
|
+
set onclose(onclose) {
|
|
33921
|
+
this._onclose = onclose;
|
|
33922
|
+
if (onclose && !this._pipeRead.readable)
|
|
33923
|
+
onclose();
|
|
33924
|
+
}
|
|
33925
|
+
send(message) {
|
|
33926
|
+
if (this._closed)
|
|
33927
|
+
throw new Error("Pipe has been closed");
|
|
33928
|
+
this._pipeWrite.write(JSON.stringify(message) + "\0");
|
|
33929
|
+
}
|
|
33930
|
+
close() {
|
|
33931
|
+
throw new Error("unimplemented");
|
|
33932
|
+
}
|
|
33933
|
+
// Flashwright: stops reading and gives the pipes to another owner, who continues the stream of
|
|
33934
|
+
// messages (see browserHandoff.ts). Only possible between two messages: returns undefined when
|
|
33935
|
+
// part of one has already been read.
|
|
33936
|
+
release() {
|
|
33937
|
+
if (this._closed || this._pendingBuffers.some((buffer) => buffer.length))
|
|
33938
|
+
return;
|
|
33939
|
+
this._closed = true;
|
|
33940
|
+
this._pipeRead.removeAllListeners("data");
|
|
33941
|
+
this._pipeRead.removeAllListeners("close");
|
|
33942
|
+
this._pipeRead.pause();
|
|
33943
|
+
return { write: this._pipeWrite, read: this._pipeRead };
|
|
33944
|
+
}
|
|
33945
|
+
_dispatch(buffer) {
|
|
33946
|
+
let end = buffer.indexOf("\0");
|
|
33947
|
+
if (end === -1) {
|
|
33948
|
+
this._pendingBuffers.push(buffer);
|
|
33949
|
+
return;
|
|
33950
|
+
}
|
|
33951
|
+
this._pendingBuffers.push(buffer.slice(0, end));
|
|
33952
|
+
const message = Buffer.concat(this._pendingBuffers).toString();
|
|
33953
|
+
setImmediate(() => {
|
|
33954
|
+
if (this.onmessage)
|
|
33955
|
+
this.onmessage.call(null, JSON.parse(message));
|
|
33956
|
+
});
|
|
33957
|
+
let start3 = end + 1;
|
|
33958
|
+
end = buffer.indexOf("\0", start3);
|
|
33959
|
+
while (end !== -1) {
|
|
33960
|
+
const message2 = buffer.toString(void 0, start3, end);
|
|
33961
|
+
setImmediate(() => {
|
|
33962
|
+
if (this.onmessage)
|
|
33963
|
+
this.onmessage.call(null, JSON.parse(message2));
|
|
33964
|
+
});
|
|
33965
|
+
start3 = end + 1;
|
|
33966
|
+
end = buffer.indexOf("\0", start3);
|
|
33967
|
+
}
|
|
33968
|
+
this._pendingBuffers = [buffer.slice(start3)];
|
|
33969
|
+
}
|
|
33970
|
+
};
|
|
33971
|
+
}
|
|
33972
|
+
});
|
|
33973
|
+
|
|
33795
33974
|
// packages/playwright-core/src/server/chromium/crConnection.ts
|
|
33796
33975
|
var ConnectionEvents, kBrowserCloseMessageId, CRConnection, CRSession, CDPSession;
|
|
33797
33976
|
var init_crConnection = __esm({
|
|
@@ -33852,6 +34031,9 @@ var init_crConnection = __esm({
|
|
|
33852
34031
|
if (!this._closed)
|
|
33853
34032
|
this._transport.close();
|
|
33854
34033
|
}
|
|
34034
|
+
transport() {
|
|
34035
|
+
return this._transport;
|
|
34036
|
+
}
|
|
33855
34037
|
async createBrowserSession() {
|
|
33856
34038
|
const { sessionId } = await this.rootSession.send("Target.attachToBrowserTarget");
|
|
33857
34039
|
return new CDPSession(this.rootSession, sessionId);
|
|
@@ -37355,6 +37537,7 @@ var init_crBrowser = __esm({
|
|
|
37355
37537
|
init_frames();
|
|
37356
37538
|
init_network2();
|
|
37357
37539
|
init_page();
|
|
37540
|
+
init_pipeTransport2();
|
|
37358
37541
|
init_crConnection();
|
|
37359
37542
|
init_crPage();
|
|
37360
37543
|
init_crProtocolHelper();
|
|
@@ -37367,6 +37550,7 @@ var init_crBrowser = __esm({
|
|
|
37367
37550
|
this._crPages = /* @__PURE__ */ new Map();
|
|
37368
37551
|
this._serviceWorkers = /* @__PURE__ */ new Map();
|
|
37369
37552
|
this._isConnecting = false;
|
|
37553
|
+
this._handingOff = false;
|
|
37370
37554
|
this._version = "";
|
|
37371
37555
|
this._majorVersion = 0;
|
|
37372
37556
|
this._revision = "";
|
|
@@ -37400,7 +37584,16 @@ var init_crBrowser = __esm({
|
|
|
37400
37584
|
browser._userAgent = version3.userAgent;
|
|
37401
37585
|
browser.options.headful = !version3.userAgent.includes("Headless");
|
|
37402
37586
|
if (!options.persistent) {
|
|
37587
|
+
const adopted = options.adoptContext && await browser.adoptHandedOverContext(options.adoptContext).then(() => true, () => false);
|
|
37588
|
+
if (options.adoptContext && !adopted)
|
|
37589
|
+
await session.send("Target.disposeBrowserContext", { browserContextId: options.adoptContext.id }).catch(() => {
|
|
37590
|
+
});
|
|
37403
37591
|
await session.send("Target.setAutoAttach", { autoAttach: true, waitForDebuggerOnStart: true, flatten: true });
|
|
37592
|
+
if (adopted) {
|
|
37593
|
+
await session.send("Target.getTargetInfo");
|
|
37594
|
+
await browser._waitForAllPagesToBeInitialized();
|
|
37595
|
+
browser.startAdoptedContextRecycle();
|
|
37596
|
+
}
|
|
37404
37597
|
return browser;
|
|
37405
37598
|
}
|
|
37406
37599
|
browser._defaultContext = new CRBrowserContext(browser, void 0, options.persistent);
|
|
@@ -37437,6 +37630,29 @@ var init_crBrowser = __esm({
|
|
|
37437
37630
|
this._contexts.set(browserContextId, context);
|
|
37438
37631
|
return context;
|
|
37439
37632
|
}
|
|
37633
|
+
async doAdoptContext(browserContextId, options) {
|
|
37634
|
+
const context = new CRBrowserContext(this, browserContextId, options);
|
|
37635
|
+
await context.initialize();
|
|
37636
|
+
this._contexts.set(browserContextId, context);
|
|
37637
|
+
return context;
|
|
37638
|
+
}
|
|
37639
|
+
// Flashwright: leaves the browser as a new DevTools client would find it, attached to nothing,
|
|
37640
|
+
// and gives up its pipe (see Browser.handoffForSession).
|
|
37641
|
+
async doDetachForHandoff() {
|
|
37642
|
+
const transport = this._connection.transport();
|
|
37643
|
+
if (!(transport instanceof PipeTransport2))
|
|
37644
|
+
return;
|
|
37645
|
+
this._handingOff = true;
|
|
37646
|
+
const sessionIds = [...this._connection._sessions.keys()].filter((sessionId) => !!sessionId);
|
|
37647
|
+
const stopAttaching = this._session.send("Target.setAutoAttach", { autoAttach: false, waitForDebuggerOnStart: false, flatten: true });
|
|
37648
|
+
const detached = sessionIds.map((sessionId) => this._session.send("Target.detachFromTarget", { sessionId }).catch(() => {
|
|
37649
|
+
}));
|
|
37650
|
+
const lastReply = this._session.send("Browser.getVersion");
|
|
37651
|
+
await Promise.all([stopAttaching, ...detached, lastReply]);
|
|
37652
|
+
const pipes = transport.release();
|
|
37653
|
+
this._connection._onClose("Browser handed over");
|
|
37654
|
+
return pipes;
|
|
37655
|
+
}
|
|
37440
37656
|
contexts() {
|
|
37441
37657
|
return Array.from(this._contexts.values());
|
|
37442
37658
|
}
|
|
@@ -37499,6 +37715,8 @@ var init_crBrowser = __esm({
|
|
|
37499
37715
|
});
|
|
37500
37716
|
}
|
|
37501
37717
|
_onDetachedFromTarget(payload) {
|
|
37718
|
+
if (this._handingOff)
|
|
37719
|
+
return;
|
|
37502
37720
|
const targetId = payload.targetId;
|
|
37503
37721
|
const crPage = this._crPages.get(targetId);
|
|
37504
37722
|
if (crPage) {
|
|
@@ -38453,70 +38671,25 @@ var init_backendAdb = __esm({
|
|
|
38453
38671
|
}
|
|
38454
38672
|
});
|
|
38455
38673
|
|
|
38456
|
-
// packages/playwright-core/src/server/
|
|
38457
|
-
|
|
38458
|
-
|
|
38459
|
-
|
|
38674
|
+
// packages/playwright-core/src/server/browserHandoff.ts
|
|
38675
|
+
function browserLaunchKey(browserName, options) {
|
|
38676
|
+
const entries = Object.entries(options).filter(([key, value2]) => value2 !== void 0 && !kIgnoredLaunchOptions.has(key) && !key.startsWith("__testHook"));
|
|
38677
|
+
entries.sort(([a], [b]) => a < b ? -1 : 1);
|
|
38678
|
+
return JSON.stringify([browserName, entries]);
|
|
38679
|
+
}
|
|
38680
|
+
function takeBrowserOffer(browserName, options) {
|
|
38681
|
+
const offer = globalThis[offerKey];
|
|
38682
|
+
if (!offer || offer.metadata.browserName !== browserName || offer.metadata.launchKey !== browserLaunchKey(browserName, options))
|
|
38683
|
+
return;
|
|
38684
|
+
delete globalThis[offerKey];
|
|
38685
|
+
return offer;
|
|
38686
|
+
}
|
|
38687
|
+
var offerKey, kIgnoredLaunchOptions;
|
|
38688
|
+
var init_browserHandoff = __esm({
|
|
38689
|
+
"packages/playwright-core/src/server/browserHandoff.ts"() {
|
|
38460
38690
|
"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
|
-
};
|
|
38691
|
+
offerKey = /* @__PURE__ */ Symbol.for("flashwright.browserOffer");
|
|
38692
|
+
kIgnoredLaunchOptions = /* @__PURE__ */ new Set(["artifactsDir", "tracesDir", "downloadsPath", "timeout", "slowMo", "handleSIGINT", "handleSIGTERM", "handleSIGHUP"]);
|
|
38520
38693
|
}
|
|
38521
38694
|
});
|
|
38522
38695
|
|
|
@@ -38687,6 +38860,20 @@ function copyTestHooks(from, to) {
|
|
|
38687
38860
|
to[key] = value2;
|
|
38688
38861
|
}
|
|
38689
38862
|
}
|
|
38863
|
+
async function closeOrKillProcess(gracefullyClose, kill, timeout) {
|
|
38864
|
+
let timer;
|
|
38865
|
+
try {
|
|
38866
|
+
await Promise.race([
|
|
38867
|
+
gracefullyClose(),
|
|
38868
|
+
new Promise((resolve, reject) => timer = setTimeout(reject, timeout))
|
|
38869
|
+
]);
|
|
38870
|
+
} catch (ignored) {
|
|
38871
|
+
await kill().catch((ignored2) => {
|
|
38872
|
+
});
|
|
38873
|
+
} finally {
|
|
38874
|
+
clearTimeout(timer);
|
|
38875
|
+
}
|
|
38876
|
+
}
|
|
38690
38877
|
var import_fs22, import_os10, import_path21, kNoXServerRunningError, BrowserType;
|
|
38691
38878
|
var init_browserType = __esm({
|
|
38692
38879
|
"packages/playwright-core/src/server/browserType.ts"() {
|
|
@@ -38702,6 +38889,7 @@ var init_browserType = __esm({
|
|
|
38702
38889
|
init_processLauncher();
|
|
38703
38890
|
init_debugLogger();
|
|
38704
38891
|
init_browserContext();
|
|
38892
|
+
init_browserHandoff();
|
|
38705
38893
|
init_helper();
|
|
38706
38894
|
init_instrumentation();
|
|
38707
38895
|
init_pipeTransport2();
|
|
@@ -38768,7 +38956,8 @@ var init_browserType = __esm({
|
|
|
38768
38956
|
async _innerLaunch(progress2, options, persistent, protocolLogger, maybeUserDataDir) {
|
|
38769
38957
|
options.proxy = options.proxy ? normalizeProxySettings(options.proxy) : void 0;
|
|
38770
38958
|
const browserLogsCollector = new RecentLogsCollector();
|
|
38771
|
-
const
|
|
38959
|
+
const offer = persistent ? void 0 : takeBrowserOffer(this._name, options);
|
|
38960
|
+
const { browserProcess, userDataDir, artifactsDir, transport, wsEndpoint } = offer ? await this._adoptProcess(progress2, offer, options, browserLogsCollector) : await this._launchProcess(progress2, options, !!persistent, browserLogsCollector, maybeUserDataDir);
|
|
38772
38961
|
try {
|
|
38773
38962
|
if (options.__testHookBeforeCreateBrowser)
|
|
38774
38963
|
await progress2.race(options.__testHookBeforeCreateBrowser());
|
|
@@ -38789,7 +38978,9 @@ var init_browserType = __esm({
|
|
|
38789
38978
|
browserLogsCollector,
|
|
38790
38979
|
wsEndpoint,
|
|
38791
38980
|
originalLaunchOptions: options,
|
|
38792
|
-
userDataDir: persistent ? userDataDir : void 0
|
|
38981
|
+
userDataDir: persistent ? userDataDir : void 0,
|
|
38982
|
+
launchKey: browserLaunchKey(this._name, options),
|
|
38983
|
+
adoptContext: offer?.metadata.context
|
|
38793
38984
|
};
|
|
38794
38985
|
if (persistent)
|
|
38795
38986
|
validateBrowserContextOptions(persistent, browserOptions);
|
|
@@ -38859,7 +39050,7 @@ var init_browserType = __esm({
|
|
|
38859
39050
|
let transport = void 0;
|
|
38860
39051
|
let browserProcess = void 0;
|
|
38861
39052
|
const exitPromise = new ManualPromise();
|
|
38862
|
-
const { launchedProcess, gracefullyClose, kill, killAndCleanup } = await progress2.race(launchProcess({
|
|
39053
|
+
const { launchedProcess, gracefullyClose, kill, killAndCleanup, release } = await progress2.race(launchProcess({
|
|
38863
39054
|
command: prepared.executable,
|
|
38864
39055
|
args: prepared.browserArguments,
|
|
38865
39056
|
env: this.amendEnvironment(env, prepared.userDataDir, isPersistent, options),
|
|
@@ -38887,26 +39078,14 @@ var init_browserType = __esm({
|
|
|
38887
39078
|
browserProcess.onclose(exitCode, signal);
|
|
38888
39079
|
}
|
|
38889
39080
|
}));
|
|
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
|
-
}
|
|
39081
|
+
const closeOrKill = (timeout) => closeOrKillProcess(gracefullyClose, kill, timeout);
|
|
38904
39082
|
browserProcess = {
|
|
38905
39083
|
onclose: void 0,
|
|
38906
39084
|
process: launchedProcess,
|
|
38907
39085
|
close: () => closeOrKill(options.__testHookBrowserCloseTimeout || DEFAULT_PLAYWRIGHT_TIMEOUT),
|
|
38908
39086
|
kill,
|
|
38909
|
-
killAndCleanup
|
|
39087
|
+
killAndCleanup,
|
|
39088
|
+
release
|
|
38910
39089
|
};
|
|
38911
39090
|
try {
|
|
38912
39091
|
const { wsEndpoint } = await progress2.race([
|
|
@@ -38933,6 +39112,46 @@ ${updatedLog}`);
|
|
|
38933
39112
|
throw error;
|
|
38934
39113
|
}
|
|
38935
39114
|
}
|
|
39115
|
+
// Flashwright: takes over a running browser that another process launched with the same options
|
|
39116
|
+
// and handed over (see browserHandoff.ts), instead of launching one.
|
|
39117
|
+
async _adoptProcess(progress2, offer, options, browserLogsCollector) {
|
|
39118
|
+
const { metadata } = offer;
|
|
39119
|
+
const tempDirectories = [...metadata.tempDirectories];
|
|
39120
|
+
let artifactsDir = options.artifactsDir;
|
|
39121
|
+
if (!artifactsDir) {
|
|
39122
|
+
artifactsDir = await progress2.race(import_fs22.default.promises.mkdtemp(import_path21.default.join(import_os10.default.tmpdir(), "playwright-artifacts-")));
|
|
39123
|
+
tempDirectories.push(artifactsDir);
|
|
39124
|
+
}
|
|
39125
|
+
const transport = new PipeTransport2(offer.write, offer.read);
|
|
39126
|
+
const exited = new Promise((resolve) => {
|
|
39127
|
+
if (!offer.read.readable)
|
|
39128
|
+
resolve();
|
|
39129
|
+
offer.read.once("close", () => resolve());
|
|
39130
|
+
});
|
|
39131
|
+
let browserProcess = void 0;
|
|
39132
|
+
const { gracefullyClose, kill, killAndCleanup, release } = adoptProcess({
|
|
39133
|
+
pid: metadata.pid,
|
|
39134
|
+
tempDirectories,
|
|
39135
|
+
exited,
|
|
39136
|
+
handleSIGINT: options.handleSIGINT ?? true,
|
|
39137
|
+
handleSIGTERM: options.handleSIGTERM ?? true,
|
|
39138
|
+
handleSIGHUP: options.handleSIGHUP ?? true,
|
|
39139
|
+
attemptToGracefullyClose: async () => this.attemptToGracefullyCloseBrowser(transport),
|
|
39140
|
+
onExit: () => browserProcess?.onclose?.(0, null),
|
|
39141
|
+
log: (message) => {
|
|
39142
|
+
progress2.log(message);
|
|
39143
|
+
browserLogsCollector.log(message);
|
|
39144
|
+
}
|
|
39145
|
+
});
|
|
39146
|
+
browserProcess = {
|
|
39147
|
+
onclose: void 0,
|
|
39148
|
+
close: () => closeOrKillProcess(gracefullyClose, kill, options.__testHookBrowserCloseTimeout || DEFAULT_PLAYWRIGHT_TIMEOUT),
|
|
39149
|
+
kill,
|
|
39150
|
+
killAndCleanup,
|
|
39151
|
+
release
|
|
39152
|
+
};
|
|
39153
|
+
return { browserProcess, artifactsDir, userDataDir: "", transport };
|
|
39154
|
+
}
|
|
38936
39155
|
async connectOverCDP(progress2, params2) {
|
|
38937
39156
|
throw new Error("CDP connections are only supported by Chromium");
|
|
38938
39157
|
}
|
|
@@ -50598,6 +50817,13 @@ function raceWithTimeout(promise, timeout, timeoutValue) {
|
|
|
50598
50817
|
const timedOut = new Promise((f) => timer = setTimeout(() => f(timeoutValue), timeout));
|
|
50599
50818
|
return Promise.race([promise, timedOut]).finally(() => clearTimeout(timer));
|
|
50600
50819
|
}
|
|
50820
|
+
function isPlainJSON(value2) {
|
|
50821
|
+
if (value2 === null || ["string", "number", "boolean", "undefined"].includes(typeof value2))
|
|
50822
|
+
return true;
|
|
50823
|
+
if (Array.isArray(value2))
|
|
50824
|
+
return value2.every(isPlainJSON);
|
|
50825
|
+
return typeof value2 === "object" && Object.getPrototypeOf(value2) === Object.prototype && Object.values(value2).every(isPlainJSON);
|
|
50826
|
+
}
|
|
50601
50827
|
var import_fs28, BrowserContextEvent, BrowserContext, kRecycledPageTimeout, kRecycleTimeout, paramsThatAllowContextReuse, defaultNewContextParamValues;
|
|
50602
50828
|
var init_browserContext = __esm({
|
|
50603
50829
|
"packages/playwright-core/src/server/browserContext.ts"() {
|
|
@@ -50756,6 +50982,32 @@ if (self.ServiceWorkerContainer) ServiceWorkerContainer.prototype.register = asy
|
|
|
50756
50982
|
this._pendingRecycle.catch(() => {
|
|
50757
50983
|
});
|
|
50758
50984
|
}
|
|
50985
|
+
// Flashwright: the context of a browser handed over by another process (see browserHandoff.ts)
|
|
50986
|
+
// clears the storage of the origins the previous process's tests used on its next reset.
|
|
50987
|
+
addVisitedOrigins(origins) {
|
|
50988
|
+
for (const origin of origins)
|
|
50989
|
+
this._origins.add(origin);
|
|
50990
|
+
}
|
|
50991
|
+
// Flashwright: called before the browser is handed over to another process. Waits for the reset
|
|
50992
|
+
// that started when the last test ended and describes the context for the process that adopts it,
|
|
50993
|
+
// or returns undefined when it cannot move: it holds state that lives in this process (a client
|
|
50994
|
+
// certificate proxy, a HAR recording, a video) or that a reset cannot clear.
|
|
50995
|
+
async prepareForHandoff() {
|
|
50996
|
+
const params2 = this.reuseParams;
|
|
50997
|
+
if (!this._recycleMode || !this.supportsRecycling() || !params2 || !this._browserContextId || this._closedStatus !== "open" || this._recyclingPrevented)
|
|
50998
|
+
return;
|
|
50999
|
+
if (this._clientCertificatesProxy || this.tracing.harRecorders.size || params2.recordVideo)
|
|
51000
|
+
return;
|
|
51001
|
+
const pending = this._pendingRecycle;
|
|
51002
|
+
this._pendingRecycle = void 0;
|
|
51003
|
+
if (!await (pending ?? this._recycle(nullProgress)))
|
|
51004
|
+
return;
|
|
51005
|
+
const rest = { ...params2 };
|
|
51006
|
+
delete rest.storageState;
|
|
51007
|
+
if (!isPlainJSON(rest))
|
|
51008
|
+
return;
|
|
51009
|
+
return { id: this._browserContextId, params: rest, origins: [...this._origins] };
|
|
51010
|
+
}
|
|
50759
51011
|
static reusableContextHash(params2) {
|
|
50760
51012
|
const paramsCopy = { ...params2 };
|
|
50761
51013
|
if (paramsCopy.selectorEngines?.length === 0)
|
|
@@ -51910,6 +52162,13 @@ var init_browser = __esm({
|
|
|
51910
52162
|
Disconnected: "disconnected"
|
|
51911
52163
|
};
|
|
51912
52164
|
}
|
|
52165
|
+
// Flashwright: see handoffForSession and adoptHandedOverContext.
|
|
52166
|
+
doAdoptContext(contextId4, options) {
|
|
52167
|
+
throw new Error("Not supported");
|
|
52168
|
+
}
|
|
52169
|
+
async doDetachForHandoff() {
|
|
52170
|
+
return void 0;
|
|
52171
|
+
}
|
|
51913
52172
|
sdkLanguage() {
|
|
51914
52173
|
return this.options.sdkLanguage || this.attribution.playwright.options.sdkLanguage;
|
|
51915
52174
|
}
|
|
@@ -51964,6 +52223,7 @@ var init_browser = __esm({
|
|
|
51964
52223
|
await this._contextForReuse.context.close(progress2, { reason: "Context reused" });
|
|
51965
52224
|
}
|
|
51966
52225
|
const context = await this.newContext(progress2, params2, recycle);
|
|
52226
|
+
context.reuseParams = params2;
|
|
51967
52227
|
this._contextForReuse = { context, hash };
|
|
51968
52228
|
return context;
|
|
51969
52229
|
}
|
|
@@ -51976,8 +52236,12 @@ var init_browser = __esm({
|
|
|
51976
52236
|
// (newContextForReuse), which also applies the test's storage state; a test asking for a different
|
|
51977
52237
|
// context gets a new one and this one closes.
|
|
51978
52238
|
async prepareRecycledContext(params2, options = {}) {
|
|
51979
|
-
|
|
52239
|
+
const reuse = this._contextForReuse;
|
|
52240
|
+
if (reuse) {
|
|
52241
|
+
if (reuse.prepared && options.storageState && reuse.hash === BrowserContext.reusableContextHash(params2) + ":recycle")
|
|
52242
|
+
reuse.context.prepareStorageStatePage();
|
|
51980
52243
|
return;
|
|
52244
|
+
}
|
|
51981
52245
|
const context = await this.newContext(
|
|
51982
52246
|
nullProgress,
|
|
51983
52247
|
params2,
|
|
@@ -51985,11 +52249,61 @@ var init_browser = __esm({
|
|
|
51985
52249
|
false
|
|
51986
52250
|
/* announce */
|
|
51987
52251
|
);
|
|
52252
|
+
context.reuseParams = params2;
|
|
51988
52253
|
this._contextForReuse = { context, hash: BrowserContext.reusableContextHash(params2) + ":recycle", prepared: true };
|
|
51989
52254
|
context.startRecycle();
|
|
51990
52255
|
if (options.storageState)
|
|
51991
52256
|
context.prepareStorageStatePage();
|
|
51992
52257
|
}
|
|
52258
|
+
// Flashwright: a browser handed over by another process brings the context its tests used, with
|
|
52259
|
+
// the tab that keeps the renderer warm. It becomes the prepared recycled context, like
|
|
52260
|
+
// prepareRecycledContext's, and is reset once more before a test takes it.
|
|
52261
|
+
async adoptHandedOverContext(handedOver) {
|
|
52262
|
+
const params2 = { ...handedOver.params };
|
|
52263
|
+
const options = { ...params2 };
|
|
52264
|
+
validateBrowserContextOptions(options, this.options);
|
|
52265
|
+
const context = await this.doAdoptContext(handedOver.id, options);
|
|
52266
|
+
context.reuseParams = params2;
|
|
52267
|
+
context.setRecycleMode(true);
|
|
52268
|
+
context.addVisitedOrigins(handedOver.origins);
|
|
52269
|
+
this._contextForReuse = { context, hash: BrowserContext.reusableContextHash(params2) + ":recycle", prepared: true };
|
|
52270
|
+
}
|
|
52271
|
+
// Called once the handed-over context's existing tab is attached.
|
|
52272
|
+
startAdoptedContextRecycle() {
|
|
52273
|
+
if (this._contextForReuse?.prepared)
|
|
52274
|
+
this._contextForReuse.context.startRecycle();
|
|
52275
|
+
}
|
|
52276
|
+
// Flashwright: in a warm test session, the worker that launched this browser hands it to the
|
|
52277
|
+
// next run instead of closing it (see browserHandoff.ts). Only a browser whose one open context
|
|
52278
|
+
// is the recycled one, reset and healthy, is handed over; anything else returns undefined and
|
|
52279
|
+
// the caller closes the browser as usual. Afterwards this object is disconnected from it.
|
|
52280
|
+
// A headed browser is not handed over: its window would stay open between runs.
|
|
52281
|
+
async handoffForSession() {
|
|
52282
|
+
const reuse = this._contextForReuse;
|
|
52283
|
+
const release = this.options.browserProcess.release;
|
|
52284
|
+
if (!release || !this.options.launchKey || this.options.persistent || this.options.headful || this._startedClosing || !this.isConnected())
|
|
52285
|
+
return;
|
|
52286
|
+
if (!reuse || !reuse.hash.endsWith(":recycle") || this.contexts().some((context) => context !== reuse.context))
|
|
52287
|
+
return;
|
|
52288
|
+
const handedOverContext = await reuse.context.prepareForHandoff();
|
|
52289
|
+
if (!handedOverContext)
|
|
52290
|
+
return;
|
|
52291
|
+
const pipes = await this.doDetachForHandoff().catch(() => void 0);
|
|
52292
|
+
if (!pipes)
|
|
52293
|
+
return;
|
|
52294
|
+
const { pid, tempDirectories } = release();
|
|
52295
|
+
this._startedClosing = true;
|
|
52296
|
+
return {
|
|
52297
|
+
...pipes,
|
|
52298
|
+
metadata: {
|
|
52299
|
+
browserName: this.options.name,
|
|
52300
|
+
launchKey: this.options.launchKey,
|
|
52301
|
+
pid,
|
|
52302
|
+
tempDirectories,
|
|
52303
|
+
context: handedOverContext
|
|
52304
|
+
}
|
|
52305
|
+
};
|
|
52306
|
+
}
|
|
51993
52307
|
// Flashwright: see BrowserContext.outputDirsChanged.
|
|
51994
52308
|
async setOutputDirs(artifactsDir, tracesDir) {
|
|
51995
52309
|
this.options.artifactsDir = artifactsDir;
|
|
@@ -74532,6 +74846,7 @@ __export(utils_exports, {
|
|
|
74532
74846
|
ZipFile: () => ZipFile,
|
|
74533
74847
|
Zone: () => Zone,
|
|
74534
74848
|
addSuffixToFilePath: () => addSuffixToFilePath,
|
|
74849
|
+
adoptProcess: () => adoptProcess,
|
|
74535
74850
|
blendWithWhite: () => blendWithWhite,
|
|
74536
74851
|
calculateSha1: () => calculateSha1,
|
|
74537
74852
|
canAccessFile: () => canAccessFile,
|
|
@@ -79231,7 +79546,7 @@ var utilsFacade = [
|
|
|
79231
79546
|
[["hostPlatform", "isOfficiallySupportedPlatform", "shortPlatform"], () => (init_hostPlatform(), __toCommonJS(hostPlatform_exports))],
|
|
79232
79547
|
[["HttpServer", "computeAllowedHosts", "isAllowedHost", "serveFolder", "urlHostFromAddress"], () => (init_httpServer(), __toCommonJS(httpServer_exports))],
|
|
79233
79548
|
[["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))],
|
|
79549
|
+
[["adoptProcess", "envArrayToObject", "gracefullyCloseAll", "gracefullyCloseSet", "gracefullyProcessExitDoNotHang", "killProcessTree", "launchProcess", "spawnAsync"], () => (init_processLauncher(), __toCommonJS(processLauncher_exports))],
|
|
79235
79550
|
[["SerializedFS"], () => (init_serializedFS(), __toCommonJS(serializedFS_exports))],
|
|
79236
79551
|
[["SocksProxy", "SocksProxyHandler", "parsePattern"], () => (init_socksProxy(), __toCommonJS(socksProxy_exports))],
|
|
79237
79552
|
[["captureRawStack", "coreDir", "filterStackFile", "filteredStackTrace", "parseErrorStack", "parseStackFrame", "rewriteErrorMessage", "setBoxedStackPrefixes", "setCoreDir", "setRawStackFormatter", "showInternalStackFrames", "splitErrorMessage", "stringifyStackFrames", "withShallowStack"], () => (init_stackTrace(), __toCommonJS(stackTrace_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