@stablyai/internal-playwright 0.1.0
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/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +168 -0
- package/ThirdPartyNotices.txt +6277 -0
- package/cli.js +19 -0
- package/index.d.ts +17 -0
- package/index.js +17 -0
- package/index.mjs +18 -0
- package/jsx-runtime.js +42 -0
- package/jsx-runtime.mjs +21 -0
- package/lib/agents/generateAgents.js +265 -0
- package/lib/agents/generator.md +102 -0
- package/lib/agents/healer.md +78 -0
- package/lib/agents/planner.md +135 -0
- package/lib/cli.js +274 -0
- package/lib/common/config.js +274 -0
- package/lib/common/config.js.map +7 -0
- package/lib/common/configLoader.js +377 -0
- package/lib/common/configLoader.js.map +7 -0
- package/lib/common/esmLoaderHost.js +102 -0
- package/lib/common/esmLoaderHost.js.map +7 -0
- package/lib/common/expectBundle.js +52 -0
- package/lib/common/expectBundle.js.map +7 -0
- package/lib/common/expectBundleImpl.js +389 -0
- package/lib/common/expectBundleImpl.js.map +7 -0
- package/lib/common/fixtures.js +302 -0
- package/lib/common/fixtures.js.map +7 -0
- package/lib/common/globals.js +58 -0
- package/lib/common/globals.js.map +7 -0
- package/lib/common/ipc.js +60 -0
- package/lib/common/ipc.js.map +7 -0
- package/lib/common/poolBuilder.js +85 -0
- package/lib/common/poolBuilder.js.map +7 -0
- package/lib/common/process.js +104 -0
- package/lib/common/process.js.map +7 -0
- package/lib/common/suiteUtils.js +140 -0
- package/lib/common/suiteUtils.js.map +7 -0
- package/lib/common/test.js +321 -0
- package/lib/common/test.js.map +7 -0
- package/lib/common/testLoader.js +100 -0
- package/lib/common/testLoader.js.map +7 -0
- package/lib/common/testType.js +310 -0
- package/lib/common/testType.js.map +7 -0
- package/lib/fsWatcher.js +67 -0
- package/lib/fsWatcher.js.map +7 -0
- package/lib/index.js +696 -0
- package/lib/index.js.map +7 -0
- package/lib/internalsForTest.js +42 -0
- package/lib/internalsForTest.js.map +7 -0
- package/lib/isomorphic/events.js +77 -0
- package/lib/isomorphic/events.js.map +7 -0
- package/lib/isomorphic/folders.js +30 -0
- package/lib/isomorphic/folders.js.map +7 -0
- package/lib/isomorphic/stringInternPool.js +69 -0
- package/lib/isomorphic/stringInternPool.js.map +7 -0
- package/lib/isomorphic/teleReceiver.js +507 -0
- package/lib/isomorphic/teleReceiver.js.map +7 -0
- package/lib/isomorphic/teleSuiteUpdater.js +137 -0
- package/lib/isomorphic/teleSuiteUpdater.js.map +7 -0
- package/lib/isomorphic/testServerConnection.js +211 -0
- package/lib/isomorphic/testServerConnection.js.map +7 -0
- package/lib/isomorphic/testServerInterface.js +16 -0
- package/lib/isomorphic/testServerInterface.js.map +7 -0
- package/lib/isomorphic/testTree.js +334 -0
- package/lib/isomorphic/testTree.js.map +7 -0
- package/lib/isomorphic/types.d.js +16 -0
- package/lib/isomorphic/types.d.js.map +7 -0
- package/lib/loader/loaderMain.js +59 -0
- package/lib/loader/loaderMain.js.map +7 -0
- package/lib/matchers/expect.js +325 -0
- package/lib/matchers/expect.js.map +7 -0
- package/lib/matchers/matcherHint.js +87 -0
- package/lib/matchers/matcherHint.js.map +7 -0
- package/lib/matchers/matchers.js +366 -0
- package/lib/matchers/matchers.js.map +7 -0
- package/lib/matchers/toBeTruthy.js +73 -0
- package/lib/matchers/toBeTruthy.js.map +7 -0
- package/lib/matchers/toEqual.js +99 -0
- package/lib/matchers/toEqual.js.map +7 -0
- package/lib/matchers/toHaveURL.js +102 -0
- package/lib/matchers/toHaveURL.js.map +7 -0
- package/lib/matchers/toMatchAriaSnapshot.js +159 -0
- package/lib/matchers/toMatchAriaSnapshot.js.map +7 -0
- package/lib/matchers/toMatchSnapshot.js +359 -0
- package/lib/matchers/toMatchSnapshot.js.map +7 -0
- package/lib/matchers/toMatchText.js +99 -0
- package/lib/matchers/toMatchText.js.map +7 -0
- package/lib/mcp/browser/actions.d.js +16 -0
- package/lib/mcp/browser/backend.js +93 -0
- package/lib/mcp/browser/backend.js.map +7 -0
- package/lib/mcp/browser/browserContextFactory.js +296 -0
- package/lib/mcp/browser/browserServerBackend.js +76 -0
- package/lib/mcp/browser/codegen.js +66 -0
- package/lib/mcp/browser/config.js +385 -0
- package/lib/mcp/browser/context.js +287 -0
- package/lib/mcp/browser/response.js +228 -0
- package/lib/mcp/browser/sessionLog.js +160 -0
- package/lib/mcp/browser/tab.js +277 -0
- package/lib/mcp/browser/tool.js +30 -0
- package/lib/mcp/browser/tool.js.map +7 -0
- package/lib/mcp/browser/tools/common.js +63 -0
- package/lib/mcp/browser/tools/console.js +44 -0
- package/lib/mcp/browser/tools/dialogs.js +60 -0
- package/lib/mcp/browser/tools/evaluate.js +70 -0
- package/lib/mcp/browser/tools/files.js +58 -0
- package/lib/mcp/browser/tools/form.js +74 -0
- package/lib/mcp/browser/tools/install.js +69 -0
- package/lib/mcp/browser/tools/keyboard.js +85 -0
- package/lib/mcp/browser/tools/mouse.js +107 -0
- package/lib/mcp/browser/tools/navigate.js +62 -0
- package/lib/mcp/browser/tools/network.js +54 -0
- package/lib/mcp/browser/tools/pdf.js +59 -0
- package/lib/mcp/browser/tools/screenshot.js +88 -0
- package/lib/mcp/browser/tools/snapshot.js +182 -0
- package/lib/mcp/browser/tools/tabs.js +67 -0
- package/lib/mcp/browser/tools/tool.js +49 -0
- package/lib/mcp/browser/tools/tracing.js +74 -0
- package/lib/mcp/browser/tools/utils.js +100 -0
- package/lib/mcp/browser/tools/verify.js +154 -0
- package/lib/mcp/browser/tools/wait.js +63 -0
- package/lib/mcp/browser/tools.js +80 -0
- package/lib/mcp/browser/tools.js.map +7 -0
- package/lib/mcp/browser/watchdog.js +44 -0
- package/lib/mcp/config.d.js +16 -0
- package/lib/mcp/extension/cdpRelay.js +351 -0
- package/lib/mcp/extension/extensionContextFactory.js +75 -0
- package/lib/mcp/extension/protocol.js +28 -0
- package/lib/mcp/index.js +61 -0
- package/lib/mcp/log.js +35 -0
- package/lib/mcp/program.js +96 -0
- package/lib/mcp/sdk/bundle.js +81 -0
- package/lib/mcp/sdk/bundle.js.map +7 -0
- package/lib/mcp/sdk/call.js +49 -0
- package/lib/mcp/sdk/call.js.map +7 -0
- package/lib/mcp/sdk/exports.js +32 -0
- package/lib/mcp/sdk/exports.js.map +7 -0
- package/lib/mcp/sdk/http.js +187 -0
- package/lib/mcp/sdk/http.js.map +7 -0
- package/lib/mcp/sdk/inProcessTransport.js +71 -0
- package/lib/mcp/sdk/inProcessTransport.js.map +7 -0
- package/lib/mcp/sdk/mdb.js +206 -0
- package/lib/mcp/sdk/mdb.js.map +7 -0
- package/lib/mcp/sdk/proxyBackend.js +128 -0
- package/lib/mcp/sdk/proxyBackend.js.map +7 -0
- package/lib/mcp/sdk/server.js +189 -0
- package/lib/mcp/sdk/server.js.map +7 -0
- package/lib/mcp/sdk/tool.js +51 -0
- package/lib/mcp/sdk/tool.js.map +7 -0
- package/lib/mcp/test/backend.js +67 -0
- package/lib/mcp/test/backend.js.map +7 -0
- package/lib/mcp/test/browserBackend.js +98 -0
- package/lib/mcp/test/context.js +48 -0
- package/lib/mcp/test/context.js.map +7 -0
- package/lib/mcp/test/generatorTools.js +122 -0
- package/lib/mcp/test/plannerTools.js +46 -0
- package/lib/mcp/test/seed.js +72 -0
- package/lib/mcp/test/streams.js +39 -0
- package/lib/mcp/test/streams.js.map +7 -0
- package/lib/mcp/test/testBackend.js +97 -0
- package/lib/mcp/test/testContext.js +176 -0
- package/lib/mcp/test/testTool.js +30 -0
- package/lib/mcp/test/testTools.js +115 -0
- package/lib/mcp/test/tool.js +30 -0
- package/lib/mcp/test/tool.js.map +7 -0
- package/lib/mcp/test/tools.js +150 -0
- package/lib/mcp/test/tools.js.map +7 -0
- package/lib/mcp/vscode/host.js +187 -0
- package/lib/mcp/vscode/main.js +77 -0
- package/lib/mcpBundleImpl.js +41 -0
- package/lib/mcpBundleImpl.js.map +7 -0
- package/lib/plugins/gitCommitInfoPlugin.js +198 -0
- package/lib/plugins/gitCommitInfoPlugin.js.map +7 -0
- package/lib/plugins/index.js +28 -0
- package/lib/plugins/index.js.map +7 -0
- package/lib/plugins/webServerPlugin.js +209 -0
- package/lib/plugins/webServerPlugin.js.map +7 -0
- package/lib/program.js +412 -0
- package/lib/program.js.map +7 -0
- package/lib/reporters/base.js +609 -0
- package/lib/reporters/base.js.map +7 -0
- package/lib/reporters/blob.js +135 -0
- package/lib/reporters/blob.js.map +7 -0
- package/lib/reporters/dot.js +82 -0
- package/lib/reporters/dot.js.map +7 -0
- package/lib/reporters/empty.js +32 -0
- package/lib/reporters/empty.js.map +7 -0
- package/lib/reporters/github.js +128 -0
- package/lib/reporters/github.js.map +7 -0
- package/lib/reporters/html.js +644 -0
- package/lib/reporters/html.js.map +7 -0
- package/lib/reporters/internalReporter.js +130 -0
- package/lib/reporters/internalReporter.js.map +7 -0
- package/lib/reporters/json.js +254 -0
- package/lib/reporters/json.js.map +7 -0
- package/lib/reporters/junit.js +230 -0
- package/lib/reporters/junit.js.map +7 -0
- package/lib/reporters/line.js +113 -0
- package/lib/reporters/line.js.map +7 -0
- package/lib/reporters/list.js +235 -0
- package/lib/reporters/list.js.map +7 -0
- package/lib/reporters/listModeReporter.js +69 -0
- package/lib/reporters/listModeReporter.js.map +7 -0
- package/lib/reporters/markdown.js +144 -0
- package/lib/reporters/markdown.js.map +7 -0
- package/lib/reporters/merge.js +535 -0
- package/lib/reporters/merge.js.map +7 -0
- package/lib/reporters/multiplexer.js +104 -0
- package/lib/reporters/multiplexer.js.map +7 -0
- package/lib/reporters/reporterV2.js +102 -0
- package/lib/reporters/reporterV2.js.map +7 -0
- package/lib/reporters/teleEmitter.js +297 -0
- package/lib/reporters/teleEmitter.js.map +7 -0
- package/lib/reporters/versions/blobV1.js +16 -0
- package/lib/reporters/versions/blobV1.js.map +7 -0
- package/lib/runner/dispatcher.js +491 -0
- package/lib/runner/dispatcher.js.map +7 -0
- package/lib/runner/failureTracker.js +72 -0
- package/lib/runner/failureTracker.js.map +7 -0
- package/lib/runner/lastRun.js +77 -0
- package/lib/runner/lastRun.js.map +7 -0
- package/lib/runner/loadUtils.js +333 -0
- package/lib/runner/loadUtils.js.map +7 -0
- package/lib/runner/loaderHost.js +89 -0
- package/lib/runner/loaderHost.js.map +7 -0
- package/lib/runner/processHost.js +161 -0
- package/lib/runner/processHost.js.map +7 -0
- package/lib/runner/projectUtils.js +241 -0
- package/lib/runner/projectUtils.js.map +7 -0
- package/lib/runner/rebase.js +189 -0
- package/lib/runner/rebase.js.map +7 -0
- package/lib/runner/reporters.js +137 -0
- package/lib/runner/reporters.js.map +7 -0
- package/lib/runner/runner.js +173 -0
- package/lib/runner/sigIntWatcher.js +96 -0
- package/lib/runner/sigIntWatcher.js.map +7 -0
- package/lib/runner/taskRunner.js +127 -0
- package/lib/runner/taskRunner.js.map +7 -0
- package/lib/runner/tasks.js +410 -0
- package/lib/runner/tasks.js.map +7 -0
- package/lib/runner/testGroups.js +117 -0
- package/lib/runner/testGroups.js.map +7 -0
- package/lib/runner/testRunner.js +390 -0
- package/lib/runner/testRunner.js.map +7 -0
- package/lib/runner/testServer.js +264 -0
- package/lib/runner/testServer.js.map +7 -0
- package/lib/runner/uiMode.js +271 -0
- package/lib/runner/uiModeReporter.js +30 -0
- package/lib/runner/uiModeReporter.js.map +7 -0
- package/lib/runner/vcs.js +72 -0
- package/lib/runner/vcs.js.map +7 -0
- package/lib/runner/watchMode.js +395 -0
- package/lib/runner/watchMode.js.map +7 -0
- package/lib/runner/workerHost.js +95 -0
- package/lib/runner/workerHost.js.map +7 -0
- package/lib/store.js +98 -0
- package/lib/third_party/pirates.js +62 -0
- package/lib/third_party/pirates.js.map +7 -0
- package/lib/third_party/tsconfig-loader.js +103 -0
- package/lib/third_party/tsconfig-loader.js.map +7 -0
- package/lib/transform/babelBundle.js +43 -0
- package/lib/transform/babelBundle.js.map +7 -0
- package/lib/transform/babelBundleImpl.js +461 -0
- package/lib/transform/babelBundleImpl.js.map +7 -0
- package/lib/transform/compilationCache.js +272 -0
- package/lib/transform/compilationCache.js.map +7 -0
- package/lib/transform/esmLoader.js +104 -0
- package/lib/transform/esmLoader.js.map +7 -0
- package/lib/transform/esmUtils.js +32 -0
- package/lib/transform/portTransport.js +67 -0
- package/lib/transform/portTransport.js.map +7 -0
- package/lib/transform/transform.js +293 -0
- package/lib/transform/transform.js.map +7 -0
- package/lib/util.js +403 -0
- package/lib/util.js.map +7 -0
- package/lib/utilsBundle.js +43 -0
- package/lib/utilsBundle.js.map +7 -0
- package/lib/utilsBundleImpl.js +100 -0
- package/lib/utilsBundleImpl.js.map +7 -0
- package/lib/worker/fixtureRunner.js +258 -0
- package/lib/worker/fixtureRunner.js.map +7 -0
- package/lib/worker/stepContext.js +34 -0
- package/lib/worker/testInfo.js +508 -0
- package/lib/worker/testInfo.js.map +7 -0
- package/lib/worker/testTracing.js +344 -0
- package/lib/worker/testTracing.js.map +7 -0
- package/lib/worker/timeoutManager.js +174 -0
- package/lib/worker/timeoutManager.js.map +7 -0
- package/lib/worker/util.js +31 -0
- package/lib/worker/util.js.map +7 -0
- package/lib/worker/workerMain.js +520 -0
- package/lib/worker/workerMain.js.map +7 -0
- package/package.json +74 -0
- package/test.d.ts +18 -0
- package/test.js +24 -0
- package/test.mjs +33 -0
- package/types/test.d.ts +10217 -0
- package/types/testReporter.d.ts +816 -0
@@ -0,0 +1,491 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __defProp = Object.defineProperty;
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
6
|
+
var __export = (target, all) => {
|
7
|
+
for (var name in all)
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
9
|
+
};
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
12
|
+
for (let key of __getOwnPropNames(from))
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
15
|
+
}
|
16
|
+
return to;
|
17
|
+
};
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
19
|
+
var dispatcher_exports = {};
|
20
|
+
__export(dispatcher_exports, {
|
21
|
+
Dispatcher: () => Dispatcher
|
22
|
+
});
|
23
|
+
module.exports = __toCommonJS(dispatcher_exports);
|
24
|
+
var import_utils = require("playwright-core/lib/utils");
|
25
|
+
var import_utils2 = require("playwright-core/lib/utils");
|
26
|
+
var import_rebase = require("./rebase");
|
27
|
+
var import_workerHost = require("./workerHost");
|
28
|
+
var import_ipc = require("../common/ipc");
|
29
|
+
class Dispatcher {
|
30
|
+
constructor(config, reporter, failureTracker) {
|
31
|
+
this._workerSlots = [];
|
32
|
+
this._queue = [];
|
33
|
+
this._workerLimitPerProjectId = /* @__PURE__ */ new Map();
|
34
|
+
this._queuedOrRunningHashCount = /* @__PURE__ */ new Map();
|
35
|
+
this._finished = new import_utils.ManualPromise();
|
36
|
+
this._isStopped = true;
|
37
|
+
this._extraEnvByProjectId = /* @__PURE__ */ new Map();
|
38
|
+
this._producedEnvByProjectId = /* @__PURE__ */ new Map();
|
39
|
+
this._config = config;
|
40
|
+
this._reporter = reporter;
|
41
|
+
this._failureTracker = failureTracker;
|
42
|
+
for (const project of config.projects) {
|
43
|
+
if (project.workers)
|
44
|
+
this._workerLimitPerProjectId.set(project.id, project.workers);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
_findFirstJobToRun() {
|
48
|
+
for (let index = 0; index < this._queue.length; index++) {
|
49
|
+
const job = this._queue[index];
|
50
|
+
const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);
|
51
|
+
if (!projectIdWorkerLimit)
|
52
|
+
return index;
|
53
|
+
const runningWorkersWithSameProjectId = this._workerSlots.filter((w) => w.busy && w.worker && w.worker.projectId() === job.projectId).length;
|
54
|
+
if (runningWorkersWithSameProjectId < projectIdWorkerLimit)
|
55
|
+
return index;
|
56
|
+
}
|
57
|
+
return -1;
|
58
|
+
}
|
59
|
+
_scheduleJob() {
|
60
|
+
if (this._isStopped)
|
61
|
+
return;
|
62
|
+
const jobIndex = this._findFirstJobToRun();
|
63
|
+
if (jobIndex === -1)
|
64
|
+
return;
|
65
|
+
const job = this._queue[jobIndex];
|
66
|
+
let workerIndex = this._workerSlots.findIndex((w) => !w.busy && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());
|
67
|
+
if (workerIndex === -1)
|
68
|
+
workerIndex = this._workerSlots.findIndex((w) => !w.busy);
|
69
|
+
if (workerIndex === -1) {
|
70
|
+
return;
|
71
|
+
}
|
72
|
+
this._queue.splice(jobIndex, 1);
|
73
|
+
const jobDispatcher = new JobDispatcher(job, this._reporter, this._failureTracker, () => this.stop().catch(() => {
|
74
|
+
}));
|
75
|
+
this._workerSlots[workerIndex].busy = true;
|
76
|
+
this._workerSlots[workerIndex].jobDispatcher = jobDispatcher;
|
77
|
+
void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {
|
78
|
+
this._workerSlots[workerIndex].jobDispatcher = void 0;
|
79
|
+
this._workerSlots[workerIndex].busy = false;
|
80
|
+
this._checkFinished();
|
81
|
+
this._scheduleJob();
|
82
|
+
});
|
83
|
+
}
|
84
|
+
async _runJobInWorker(index, jobDispatcher) {
|
85
|
+
const job = jobDispatcher.job;
|
86
|
+
if (jobDispatcher.skipWholeJob())
|
87
|
+
return;
|
88
|
+
let worker = this._workerSlots[index].worker;
|
89
|
+
if (worker && (worker.hash() !== job.workerHash || worker.didSendStop())) {
|
90
|
+
await worker.stop();
|
91
|
+
worker = void 0;
|
92
|
+
if (this._isStopped)
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
let startError;
|
96
|
+
if (!worker) {
|
97
|
+
worker = this._createWorker(job, index, (0, import_ipc.serializeConfig)(this._config, true));
|
98
|
+
this._workerSlots[index].worker = worker;
|
99
|
+
worker.on("exit", () => this._workerSlots[index].worker = void 0);
|
100
|
+
startError = await worker.start();
|
101
|
+
if (this._isStopped)
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
if (startError)
|
105
|
+
jobDispatcher.onExit(startError);
|
106
|
+
else
|
107
|
+
jobDispatcher.runInWorker(worker);
|
108
|
+
const result = await jobDispatcher.jobResult;
|
109
|
+
this._updateCounterForWorkerHash(job.workerHash, -1);
|
110
|
+
if (result.didFail)
|
111
|
+
void worker.stop(
|
112
|
+
true
|
113
|
+
/* didFail */
|
114
|
+
);
|
115
|
+
else if (this._isWorkerRedundant(worker))
|
116
|
+
void worker.stop();
|
117
|
+
if (!this._isStopped && result.newJob) {
|
118
|
+
this._queue.unshift(result.newJob);
|
119
|
+
this._updateCounterForWorkerHash(result.newJob.workerHash, 1);
|
120
|
+
}
|
121
|
+
}
|
122
|
+
_checkFinished() {
|
123
|
+
if (this._finished.isDone())
|
124
|
+
return;
|
125
|
+
if (this._queue.length && !this._isStopped)
|
126
|
+
return;
|
127
|
+
if (this._workerSlots.some((w) => w.busy))
|
128
|
+
return;
|
129
|
+
this._finished.resolve();
|
130
|
+
}
|
131
|
+
_isWorkerRedundant(worker) {
|
132
|
+
let workersWithSameHash = 0;
|
133
|
+
for (const slot of this._workerSlots) {
|
134
|
+
if (slot.worker && !slot.worker.didSendStop() && slot.worker.hash() === worker.hash())
|
135
|
+
workersWithSameHash++;
|
136
|
+
}
|
137
|
+
return workersWithSameHash > this._queuedOrRunningHashCount.get(worker.hash());
|
138
|
+
}
|
139
|
+
_updateCounterForWorkerHash(hash, delta) {
|
140
|
+
this._queuedOrRunningHashCount.set(hash, delta + (this._queuedOrRunningHashCount.get(hash) || 0));
|
141
|
+
}
|
142
|
+
async run(testGroups, extraEnvByProjectId) {
|
143
|
+
this._extraEnvByProjectId = extraEnvByProjectId;
|
144
|
+
this._queue = testGroups;
|
145
|
+
for (const group of testGroups)
|
146
|
+
this._updateCounterForWorkerHash(group.workerHash, 1);
|
147
|
+
this._isStopped = false;
|
148
|
+
this._workerSlots = [];
|
149
|
+
if (this._failureTracker.hasReachedMaxFailures())
|
150
|
+
void this.stop();
|
151
|
+
for (let i = 0; i < this._config.config.workers; i++)
|
152
|
+
this._workerSlots.push({ busy: false });
|
153
|
+
for (let i = 0; i < this._workerSlots.length; i++)
|
154
|
+
this._scheduleJob();
|
155
|
+
this._checkFinished();
|
156
|
+
await this._finished;
|
157
|
+
}
|
158
|
+
_createWorker(testGroup, parallelIndex, loaderData) {
|
159
|
+
const projectConfig = this._config.projects.find((p) => p.id === testGroup.projectId);
|
160
|
+
const outputDir = projectConfig.project.outputDir;
|
161
|
+
const worker = new import_workerHost.WorkerHost(testGroup, {
|
162
|
+
parallelIndex,
|
163
|
+
config: loaderData,
|
164
|
+
extraEnv: this._extraEnvByProjectId.get(testGroup.projectId) || {},
|
165
|
+
outputDir,
|
166
|
+
pauseOnError: this._failureTracker.pauseOnError(),
|
167
|
+
pauseAtEnd: this._failureTracker.pauseAtEnd(projectConfig)
|
168
|
+
});
|
169
|
+
const handleOutput = (params) => {
|
170
|
+
const chunk = chunkFromParams(params);
|
171
|
+
if (worker.didFail()) {
|
172
|
+
return { chunk };
|
173
|
+
}
|
174
|
+
const currentlyRunning = this._workerSlots[parallelIndex].jobDispatcher?.currentlyRunning();
|
175
|
+
if (!currentlyRunning)
|
176
|
+
return { chunk };
|
177
|
+
return { chunk, test: currentlyRunning.test, result: currentlyRunning.result };
|
178
|
+
};
|
179
|
+
worker.on("stdOut", (params) => {
|
180
|
+
const { chunk, test, result } = handleOutput(params);
|
181
|
+
result?.stdout.push(chunk);
|
182
|
+
this._reporter.onStdOut?.(chunk, test, result);
|
183
|
+
});
|
184
|
+
worker.on("stdErr", (params) => {
|
185
|
+
const { chunk, test, result } = handleOutput(params);
|
186
|
+
result?.stderr.push(chunk);
|
187
|
+
this._reporter.onStdErr?.(chunk, test, result);
|
188
|
+
});
|
189
|
+
worker.on("teardownErrors", (params) => {
|
190
|
+
this._failureTracker.onWorkerError();
|
191
|
+
for (const error of params.fatalErrors)
|
192
|
+
this._reporter.onError?.(error);
|
193
|
+
});
|
194
|
+
worker.on("exit", () => {
|
195
|
+
const producedEnv = this._producedEnvByProjectId.get(testGroup.projectId) || {};
|
196
|
+
this._producedEnvByProjectId.set(testGroup.projectId, { ...producedEnv, ...worker.producedEnv() });
|
197
|
+
});
|
198
|
+
return worker;
|
199
|
+
}
|
200
|
+
producedEnvByProjectId() {
|
201
|
+
return this._producedEnvByProjectId;
|
202
|
+
}
|
203
|
+
async stop() {
|
204
|
+
if (this._isStopped)
|
205
|
+
return;
|
206
|
+
this._isStopped = true;
|
207
|
+
await Promise.all(this._workerSlots.map(({ worker }) => worker?.stop()));
|
208
|
+
this._checkFinished();
|
209
|
+
}
|
210
|
+
}
|
211
|
+
class JobDispatcher {
|
212
|
+
constructor(job, reporter, failureTracker, stopCallback) {
|
213
|
+
this.jobResult = new import_utils.ManualPromise();
|
214
|
+
this._listeners = [];
|
215
|
+
this._failedTests = /* @__PURE__ */ new Set();
|
216
|
+
this._failedWithNonRetriableError = /* @__PURE__ */ new Set();
|
217
|
+
this._remainingByTestId = /* @__PURE__ */ new Map();
|
218
|
+
this._dataByTestId = /* @__PURE__ */ new Map();
|
219
|
+
this._parallelIndex = 0;
|
220
|
+
this._workerIndex = 0;
|
221
|
+
this.job = job;
|
222
|
+
this._reporter = reporter;
|
223
|
+
this._failureTracker = failureTracker;
|
224
|
+
this._stopCallback = stopCallback;
|
225
|
+
this._remainingByTestId = new Map(this.job.tests.map((e) => [e.id, e]));
|
226
|
+
}
|
227
|
+
_onTestBegin(params) {
|
228
|
+
const test = this._remainingByTestId.get(params.testId);
|
229
|
+
if (!test) {
|
230
|
+
return;
|
231
|
+
}
|
232
|
+
const result = test._appendTestResult();
|
233
|
+
this._dataByTestId.set(test.id, { test, result, steps: /* @__PURE__ */ new Map() });
|
234
|
+
result.parallelIndex = this._parallelIndex;
|
235
|
+
result.workerIndex = this._workerIndex;
|
236
|
+
result.startTime = new Date(params.startWallTime);
|
237
|
+
this._reporter.onTestBegin?.(test, result);
|
238
|
+
this._currentlyRunning = { test, result };
|
239
|
+
}
|
240
|
+
_onTestEnd(params) {
|
241
|
+
if (this._failureTracker.hasReachedMaxFailures()) {
|
242
|
+
params.status = "interrupted";
|
243
|
+
params.errors = [];
|
244
|
+
}
|
245
|
+
const data = this._dataByTestId.get(params.testId);
|
246
|
+
if (!data) {
|
247
|
+
return;
|
248
|
+
}
|
249
|
+
this._dataByTestId.delete(params.testId);
|
250
|
+
this._remainingByTestId.delete(params.testId);
|
251
|
+
const { result, test } = data;
|
252
|
+
result.duration = params.duration;
|
253
|
+
result.errors = params.errors;
|
254
|
+
result.error = result.errors[0];
|
255
|
+
result.status = params.status;
|
256
|
+
result.annotations = params.annotations;
|
257
|
+
test.annotations = [...params.annotations];
|
258
|
+
test.expectedStatus = params.expectedStatus;
|
259
|
+
test.timeout = params.timeout;
|
260
|
+
const isFailure = result.status !== "skipped" && result.status !== test.expectedStatus;
|
261
|
+
if (isFailure)
|
262
|
+
this._failedTests.add(test);
|
263
|
+
if (params.hasNonRetriableError)
|
264
|
+
this._addNonretriableTestAndSerialModeParents(test);
|
265
|
+
this._reportTestEnd(test, result);
|
266
|
+
this._currentlyRunning = void 0;
|
267
|
+
}
|
268
|
+
_addNonretriableTestAndSerialModeParents(test) {
|
269
|
+
this._failedWithNonRetriableError.add(test);
|
270
|
+
for (let parent = test.parent; parent; parent = parent.parent) {
|
271
|
+
if (parent._parallelMode === "serial")
|
272
|
+
this._failedWithNonRetriableError.add(parent);
|
273
|
+
}
|
274
|
+
}
|
275
|
+
_onStepBegin(params) {
|
276
|
+
const data = this._dataByTestId.get(params.testId);
|
277
|
+
if (!data) {
|
278
|
+
return;
|
279
|
+
}
|
280
|
+
const { result, steps, test } = data;
|
281
|
+
const parentStep = params.parentStepId ? steps.get(params.parentStepId) : void 0;
|
282
|
+
const step = {
|
283
|
+
title: params.title,
|
284
|
+
titlePath: () => {
|
285
|
+
const parentPath = parentStep?.titlePath() || [];
|
286
|
+
return [...parentPath, params.title];
|
287
|
+
},
|
288
|
+
parent: parentStep,
|
289
|
+
category: params.category,
|
290
|
+
startTime: new Date(params.wallTime),
|
291
|
+
duration: -1,
|
292
|
+
steps: [],
|
293
|
+
attachments: [],
|
294
|
+
annotations: [],
|
295
|
+
location: params.location
|
296
|
+
};
|
297
|
+
steps.set(params.stepId, step);
|
298
|
+
(parentStep || result).steps.push(step);
|
299
|
+
this._reporter.onStepBegin?.(test, result, step);
|
300
|
+
}
|
301
|
+
_onStepEnd(params) {
|
302
|
+
const data = this._dataByTestId.get(params.testId);
|
303
|
+
if (!data) {
|
304
|
+
return;
|
305
|
+
}
|
306
|
+
const { result, steps, test } = data;
|
307
|
+
const step = steps.get(params.stepId);
|
308
|
+
if (!step) {
|
309
|
+
this._reporter.onStdErr?.("Internal error: step end without step begin: " + params.stepId, test, result);
|
310
|
+
return;
|
311
|
+
}
|
312
|
+
step.duration = params.wallTime - step.startTime.getTime();
|
313
|
+
if (params.error)
|
314
|
+
step.error = params.error;
|
315
|
+
if (params.suggestedRebaseline)
|
316
|
+
(0, import_rebase.addSuggestedRebaseline)(step.location, params.suggestedRebaseline);
|
317
|
+
step.annotations = params.annotations;
|
318
|
+
steps.delete(params.stepId);
|
319
|
+
this._reporter.onStepEnd?.(test, result, step);
|
320
|
+
}
|
321
|
+
_onAttach(params) {
|
322
|
+
const data = this._dataByTestId.get(params.testId);
|
323
|
+
if (!data) {
|
324
|
+
return;
|
325
|
+
}
|
326
|
+
const attachment = {
|
327
|
+
name: params.name,
|
328
|
+
path: params.path,
|
329
|
+
contentType: params.contentType,
|
330
|
+
body: params.body !== void 0 ? Buffer.from(params.body, "base64") : void 0
|
331
|
+
};
|
332
|
+
data.result.attachments.push(attachment);
|
333
|
+
if (params.stepId) {
|
334
|
+
const step = data.steps.get(params.stepId);
|
335
|
+
if (step)
|
336
|
+
step.attachments.push(attachment);
|
337
|
+
else
|
338
|
+
this._reporter.onStdErr?.("Internal error: step id not found: " + params.stepId);
|
339
|
+
}
|
340
|
+
}
|
341
|
+
_failTestWithErrors(test, errors) {
|
342
|
+
const runData = this._dataByTestId.get(test.id);
|
343
|
+
let result;
|
344
|
+
if (runData) {
|
345
|
+
result = runData.result;
|
346
|
+
} else {
|
347
|
+
result = test._appendTestResult();
|
348
|
+
this._reporter.onTestBegin?.(test, result);
|
349
|
+
}
|
350
|
+
result.errors = [...errors];
|
351
|
+
result.error = result.errors[0];
|
352
|
+
result.status = errors.length ? "failed" : "skipped";
|
353
|
+
this._reportTestEnd(test, result);
|
354
|
+
this._failedTests.add(test);
|
355
|
+
}
|
356
|
+
_massSkipTestsFromRemaining(testIds, errors) {
|
357
|
+
for (const test of this._remainingByTestId.values()) {
|
358
|
+
if (!testIds.has(test.id))
|
359
|
+
continue;
|
360
|
+
if (!this._failureTracker.hasReachedMaxFailures()) {
|
361
|
+
this._failTestWithErrors(test, errors);
|
362
|
+
errors = [];
|
363
|
+
}
|
364
|
+
this._remainingByTestId.delete(test.id);
|
365
|
+
}
|
366
|
+
if (errors.length) {
|
367
|
+
this._failureTracker.onWorkerError();
|
368
|
+
for (const error of errors)
|
369
|
+
this._reporter.onError?.(error);
|
370
|
+
}
|
371
|
+
}
|
372
|
+
_onDone(params) {
|
373
|
+
if (!this._remainingByTestId.size && !this._failedTests.size && !params.fatalErrors.length && !params.skipTestsDueToSetupFailure.length && !params.fatalUnknownTestIds && !params.unexpectedExitError && !params.stoppedDueToUnhandledErrorInTestFail) {
|
374
|
+
this._finished({ didFail: false });
|
375
|
+
return;
|
376
|
+
}
|
377
|
+
for (const testId of params.fatalUnknownTestIds || []) {
|
378
|
+
const test = this._remainingByTestId.get(testId);
|
379
|
+
if (test) {
|
380
|
+
this._remainingByTestId.delete(testId);
|
381
|
+
this._failTestWithErrors(test, [{ message: `Test not found in the worker process. Make sure test title does not change.` }]);
|
382
|
+
}
|
383
|
+
}
|
384
|
+
if (params.fatalErrors.length) {
|
385
|
+
this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), params.fatalErrors);
|
386
|
+
}
|
387
|
+
this._massSkipTestsFromRemaining(new Set(params.skipTestsDueToSetupFailure), []);
|
388
|
+
if (params.unexpectedExitError) {
|
389
|
+
if (this._currentlyRunning)
|
390
|
+
this._massSkipTestsFromRemaining(/* @__PURE__ */ new Set([this._currentlyRunning.test.id]), [params.unexpectedExitError]);
|
391
|
+
else
|
392
|
+
this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), [params.unexpectedExitError]);
|
393
|
+
}
|
394
|
+
const retryCandidates = /* @__PURE__ */ new Set();
|
395
|
+
const serialSuitesWithFailures = /* @__PURE__ */ new Set();
|
396
|
+
for (const failedTest of this._failedTests) {
|
397
|
+
if (this._failedWithNonRetriableError.has(failedTest))
|
398
|
+
continue;
|
399
|
+
retryCandidates.add(failedTest);
|
400
|
+
let outermostSerialSuite;
|
401
|
+
for (let parent = failedTest.parent; parent; parent = parent.parent) {
|
402
|
+
if (parent._parallelMode === "serial")
|
403
|
+
outermostSerialSuite = parent;
|
404
|
+
}
|
405
|
+
if (outermostSerialSuite && !this._failedWithNonRetriableError.has(outermostSerialSuite))
|
406
|
+
serialSuitesWithFailures.add(outermostSerialSuite);
|
407
|
+
}
|
408
|
+
const testsBelongingToSomeSerialSuiteWithFailures = [...this._remainingByTestId.values()].filter((test) => {
|
409
|
+
let parent = test.parent;
|
410
|
+
while (parent && !serialSuitesWithFailures.has(parent))
|
411
|
+
parent = parent.parent;
|
412
|
+
return !!parent;
|
413
|
+
});
|
414
|
+
this._massSkipTestsFromRemaining(new Set(testsBelongingToSomeSerialSuiteWithFailures.map((test) => test.id)), []);
|
415
|
+
for (const serialSuite of serialSuitesWithFailures) {
|
416
|
+
serialSuite.allTests().forEach((test) => retryCandidates.add(test));
|
417
|
+
}
|
418
|
+
const remaining = [...this._remainingByTestId.values()];
|
419
|
+
for (const test of retryCandidates) {
|
420
|
+
if (test.results.length < test.retries + 1)
|
421
|
+
remaining.push(test);
|
422
|
+
}
|
423
|
+
const newJob = remaining.length ? { ...this.job, tests: remaining } : void 0;
|
424
|
+
this._finished({ didFail: true, newJob });
|
425
|
+
}
|
426
|
+
onExit(data) {
|
427
|
+
const unexpectedExitError = data.unexpectedly ? {
|
428
|
+
message: `Error: worker process exited unexpectedly (code=${data.code}, signal=${data.signal})`
|
429
|
+
} : void 0;
|
430
|
+
this._onDone({ skipTestsDueToSetupFailure: [], fatalErrors: [], unexpectedExitError });
|
431
|
+
}
|
432
|
+
_finished(result) {
|
433
|
+
import_utils.eventsHelper.removeEventListeners(this._listeners);
|
434
|
+
this.jobResult.resolve(result);
|
435
|
+
}
|
436
|
+
runInWorker(worker) {
|
437
|
+
this._parallelIndex = worker.parallelIndex;
|
438
|
+
this._workerIndex = worker.workerIndex;
|
439
|
+
const runPayload = {
|
440
|
+
file: this.job.requireFile,
|
441
|
+
entries: this.job.tests.map((test) => {
|
442
|
+
return { testId: test.id, retry: test.results.length };
|
443
|
+
})
|
444
|
+
};
|
445
|
+
worker.runTestGroup(runPayload);
|
446
|
+
this._listeners = [
|
447
|
+
import_utils.eventsHelper.addEventListener(worker, "testBegin", this._onTestBegin.bind(this)),
|
448
|
+
import_utils.eventsHelper.addEventListener(worker, "testEnd", this._onTestEnd.bind(this)),
|
449
|
+
import_utils.eventsHelper.addEventListener(worker, "stepBegin", this._onStepBegin.bind(this)),
|
450
|
+
import_utils.eventsHelper.addEventListener(worker, "stepEnd", this._onStepEnd.bind(this)),
|
451
|
+
import_utils.eventsHelper.addEventListener(worker, "attach", this._onAttach.bind(this)),
|
452
|
+
import_utils.eventsHelper.addEventListener(worker, "done", this._onDone.bind(this)),
|
453
|
+
import_utils.eventsHelper.addEventListener(worker, "exit", this.onExit.bind(this))
|
454
|
+
];
|
455
|
+
}
|
456
|
+
skipWholeJob() {
|
457
|
+
const allTestsSkipped = this.job.tests.every((test) => test.expectedStatus === "skipped");
|
458
|
+
if (allTestsSkipped && !this._failureTracker.hasReachedMaxFailures()) {
|
459
|
+
for (const test of this.job.tests) {
|
460
|
+
const result = test._appendTestResult();
|
461
|
+
this._reporter.onTestBegin?.(test, result);
|
462
|
+
result.status = "skipped";
|
463
|
+
this._reportTestEnd(test, result);
|
464
|
+
}
|
465
|
+
return true;
|
466
|
+
}
|
467
|
+
return false;
|
468
|
+
}
|
469
|
+
currentlyRunning() {
|
470
|
+
return this._currentlyRunning;
|
471
|
+
}
|
472
|
+
_reportTestEnd(test, result) {
|
473
|
+
this._reporter.onTestEnd?.(test, result);
|
474
|
+
const hadMaxFailures = this._failureTracker.hasReachedMaxFailures();
|
475
|
+
this._failureTracker.onTestEnd(test, result);
|
476
|
+
if (this._failureTracker.hasReachedMaxFailures()) {
|
477
|
+
this._stopCallback();
|
478
|
+
if (!hadMaxFailures)
|
479
|
+
this._reporter.onError?.({ message: import_utils2.colors.red(`Testing stopped early after ${this._failureTracker.maxFailures()} maximum allowed failures.`) });
|
480
|
+
}
|
481
|
+
}
|
482
|
+
}
|
483
|
+
function chunkFromParams(params) {
|
484
|
+
if (typeof params.text === "string")
|
485
|
+
return params.text;
|
486
|
+
return Buffer.from(params.buffer, "base64");
|
487
|
+
}
|
488
|
+
// Annotate the CommonJS export names for ESM import in node:
|
489
|
+
0 && (module.exports = {
|
490
|
+
Dispatcher
|
491
|
+
});
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../../src/runner/dispatcher.ts"],
|
4
|
+
"sourcesContent": ["/**\n * Copyright Microsoft Corporation. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ManualPromise, eventsHelper } from 'playwright-core/lib/utils';\nimport { colors } from 'playwright-core/lib/utils';\n\nimport { addSuggestedRebaseline } from './rebase';\nimport { WorkerHost } from './workerHost';\nimport { serializeConfig } from '../common/ipc';\n\nimport type { FailureTracker } from './failureTracker';\nimport type { ProcessExitData } from './processHost';\nimport type { TestGroup } from './testGroups';\nimport type { TestError, TestResult, TestStep } from '../../types/testReporter';\nimport type { FullConfigInternal } from '../common/config';\nimport type { AttachmentPayload, DonePayload, RunPayload, SerializedConfig, StepBeginPayload, StepEndPayload, TeardownErrorsPayload, TestBeginPayload, TestEndPayload, TestOutputPayload } from '../common/ipc';\nimport type { Suite } from '../common/test';\nimport type { TestCase } from '../common/test';\nimport type { ReporterV2 } from '../reporters/reporterV2';\nimport type { RegisteredListener } from 'playwright-core/lib/utils';\n\n\nexport type EnvByProjectId = Map<string, Record<string, string | undefined>>;\n\nexport class Dispatcher {\n private _workerSlots: { busy: boolean, worker?: WorkerHost, jobDispatcher?: JobDispatcher }[] = [];\n private _queue: TestGroup[] = [];\n private _workerLimitPerProjectId = new Map<string, number>();\n private _queuedOrRunningHashCount = new Map<string, number>();\n private _finished = new ManualPromise<void>();\n private _isStopped = true;\n\n private _config: FullConfigInternal;\n private _reporter: ReporterV2;\n private _failureTracker: FailureTracker;\n\n private _extraEnvByProjectId: EnvByProjectId = new Map();\n private _producedEnvByProjectId: EnvByProjectId = new Map();\n\n constructor(config: FullConfigInternal, reporter: ReporterV2, failureTracker: FailureTracker) {\n this._config = config;\n this._reporter = reporter;\n this._failureTracker = failureTracker;\n for (const project of config.projects) {\n if (project.workers)\n this._workerLimitPerProjectId.set(project.id, project.workers);\n }\n }\n\n private _findFirstJobToRun() {\n // Always pick the first job that can be run while respecting the project worker limit.\n for (let index = 0; index < this._queue.length; index++) {\n const job = this._queue[index];\n const projectIdWorkerLimit = this._workerLimitPerProjectId.get(job.projectId);\n if (!projectIdWorkerLimit)\n return index;\n const runningWorkersWithSameProjectId = this._workerSlots.filter(w => w.busy && w.worker && w.worker.projectId() === job.projectId).length;\n if (runningWorkersWithSameProjectId < projectIdWorkerLimit)\n return index;\n }\n return -1;\n }\n\n private _scheduleJob() {\n // NOTE: keep this method synchronous for easier reasoning.\n\n // 0. No more running jobs after stop.\n if (this._isStopped)\n return;\n\n // 1. Find a job to run.\n const jobIndex = this._findFirstJobToRun();\n if (jobIndex === -1)\n return;\n const job = this._queue[jobIndex];\n\n // 2. Find a worker with the same hash, or just some free worker.\n let workerIndex = this._workerSlots.findIndex(w => !w.busy && w.worker && w.worker.hash() === job.workerHash && !w.worker.didSendStop());\n if (workerIndex === -1)\n workerIndex = this._workerSlots.findIndex(w => !w.busy);\n if (workerIndex === -1) {\n // No workers available, bail out.\n return;\n }\n\n // 3. Claim both the job and the worker slot.\n this._queue.splice(jobIndex, 1);\n const jobDispatcher = new JobDispatcher(job, this._reporter, this._failureTracker, () => this.stop().catch(() => {}));\n this._workerSlots[workerIndex].busy = true;\n this._workerSlots[workerIndex].jobDispatcher = jobDispatcher;\n\n // 4. Run the job. This is the only async operation.\n void this._runJobInWorker(workerIndex, jobDispatcher).then(() => {\n\n // 5. Release the worker slot.\n this._workerSlots[workerIndex].jobDispatcher = undefined;\n this._workerSlots[workerIndex].busy = false;\n\n // 6. Check whether we are done or should schedule another job.\n this._checkFinished();\n this._scheduleJob();\n });\n }\n\n private async _runJobInWorker(index: number, jobDispatcher: JobDispatcher) {\n const job = jobDispatcher.job;\n\n // 0. Perhaps skip the whole job?\n if (jobDispatcher.skipWholeJob())\n return;\n\n let worker = this._workerSlots[index].worker;\n\n // 1. Restart the worker if it has the wrong hash or is being stopped already.\n if (worker && (worker.hash() !== job.workerHash || worker.didSendStop())) {\n await worker.stop();\n worker = undefined;\n if (this._isStopped) // Check stopped signal after async hop.\n return;\n }\n\n // 2. Start the worker if it is down.\n let startError;\n if (!worker) {\n worker = this._createWorker(job, index, serializeConfig(this._config, true));\n this._workerSlots[index].worker = worker;\n worker.on('exit', () => this._workerSlots[index].worker = undefined);\n startError = await worker.start();\n if (this._isStopped) // Check stopped signal after async hop.\n return;\n }\n\n // 3. Finally, run some tests in the worker! Or fail all of them because of startup error...\n if (startError)\n jobDispatcher.onExit(startError);\n else\n jobDispatcher.runInWorker(worker);\n const result = await jobDispatcher.jobResult;\n this._updateCounterForWorkerHash(job.workerHash, -1);\n\n // 4. When worker encounters error, we stop it and create a new one.\n // We also do not keep the worker alive if it cannot serve any more jobs.\n if (result.didFail)\n void worker.stop(true /* didFail */);\n else if (this._isWorkerRedundant(worker))\n void worker.stop();\n\n // 5. Possibly queue a new job with leftover tests and/or retries.\n if (!this._isStopped && result.newJob) {\n this._queue.unshift(result.newJob);\n this._updateCounterForWorkerHash(result.newJob.workerHash, +1);\n }\n }\n\n private _checkFinished() {\n if (this._finished.isDone())\n return;\n\n // Check that we have no more work to do.\n if (this._queue.length && !this._isStopped)\n return;\n\n // Make sure all workers have finished the current job.\n if (this._workerSlots.some(w => w.busy))\n return;\n\n this._finished.resolve();\n }\n\n private _isWorkerRedundant(worker: WorkerHost) {\n let workersWithSameHash = 0;\n for (const slot of this._workerSlots) {\n if (slot.worker && !slot.worker.didSendStop() && slot.worker.hash() === worker.hash())\n workersWithSameHash++;\n }\n return workersWithSameHash > this._queuedOrRunningHashCount.get(worker.hash())!;\n }\n\n private _updateCounterForWorkerHash(hash: string, delta: number) {\n this._queuedOrRunningHashCount.set(hash, delta + (this._queuedOrRunningHashCount.get(hash) || 0));\n }\n\n async run(testGroups: TestGroup[], extraEnvByProjectId: EnvByProjectId) {\n this._extraEnvByProjectId = extraEnvByProjectId;\n this._queue = testGroups;\n for (const group of testGroups)\n this._updateCounterForWorkerHash(group.workerHash, +1);\n this._isStopped = false;\n this._workerSlots = [];\n // 0. Stop right away if we have reached max failures.\n if (this._failureTracker.hasReachedMaxFailures())\n void this.stop();\n // 1. Allocate workers.\n for (let i = 0; i < this._config.config.workers; i++)\n this._workerSlots.push({ busy: false });\n // 2. Schedule enough jobs.\n for (let i = 0; i < this._workerSlots.length; i++)\n this._scheduleJob();\n this._checkFinished();\n // 3. More jobs are scheduled when the worker becomes free.\n // 4. Wait for all jobs to finish.\n await this._finished;\n }\n\n _createWorker(testGroup: TestGroup, parallelIndex: number, loaderData: SerializedConfig) {\n const projectConfig = this._config.projects.find(p => p.id === testGroup.projectId)!;\n const outputDir = projectConfig.project.outputDir;\n const worker = new WorkerHost(testGroup, parallelIndex, loaderData, this._extraEnvByProjectId.get(testGroup.projectId) || {}, outputDir);\n const handleOutput = (params: TestOutputPayload) => {\n const chunk = chunkFromParams(params);\n if (worker.didFail()) {\n // Note: we keep reading stdio from workers that are currently stopping after failure,\n // to debug teardown issues. However, we avoid spoiling the test result from\n // the next retry.\n return { chunk };\n }\n const currentlyRunning = this._workerSlots[parallelIndex].jobDispatcher?.currentlyRunning();\n if (!currentlyRunning)\n return { chunk };\n return { chunk, test: currentlyRunning.test, result: currentlyRunning.result };\n };\n worker.on('stdOut', (params: TestOutputPayload) => {\n const { chunk, test, result } = handleOutput(params);\n result?.stdout.push(chunk);\n this._reporter.onStdOut?.(chunk, test, result);\n });\n worker.on('stdErr', (params: TestOutputPayload) => {\n const { chunk, test, result } = handleOutput(params);\n result?.stderr.push(chunk);\n this._reporter.onStdErr?.(chunk, test, result);\n });\n worker.on('teardownErrors', (params: TeardownErrorsPayload) => {\n this._failureTracker.onWorkerError();\n for (const error of params.fatalErrors)\n this._reporter.onError?.(error);\n });\n worker.on('exit', () => {\n const producedEnv = this._producedEnvByProjectId.get(testGroup.projectId) || {};\n this._producedEnvByProjectId.set(testGroup.projectId, { ...producedEnv, ...worker.producedEnv() });\n });\n return worker;\n }\n\n producedEnvByProjectId() {\n return this._producedEnvByProjectId;\n }\n\n async stop() {\n if (this._isStopped)\n return;\n this._isStopped = true;\n await Promise.all(this._workerSlots.map(({ worker }) => worker?.stop()));\n this._checkFinished();\n }\n}\n\nclass JobDispatcher {\n jobResult = new ManualPromise<{ newJob?: TestGroup, didFail: boolean }>();\n\n readonly job: TestGroup;\n private _reporter: ReporterV2;\n private _failureTracker: FailureTracker;\n private _stopCallback: () => void;\n private _listeners: RegisteredListener[] = [];\n private _failedTests = new Set<TestCase>();\n private _failedWithNonRetriableError = new Set<TestCase|Suite>();\n private _remainingByTestId = new Map<string, TestCase>();\n private _dataByTestId = new Map<string, { test: TestCase, result: TestResult, steps: Map<string, TestStep> }>();\n private _parallelIndex = 0;\n private _workerIndex = 0;\n private _currentlyRunning: { test: TestCase, result: TestResult } | undefined;\n\n constructor(job: TestGroup, reporter: ReporterV2, failureTracker: FailureTracker, stopCallback: () => void) {\n this.job = job;\n this._reporter = reporter;\n this._failureTracker = failureTracker;\n this._stopCallback = stopCallback;\n this._remainingByTestId = new Map(this.job.tests.map(e => [e.id, e]));\n }\n\n private _onTestBegin(params: TestBeginPayload) {\n const test = this._remainingByTestId.get(params.testId);\n if (!test) {\n // TODO: this should never be the case, report an internal error?\n return;\n }\n const result = test._appendTestResult();\n this._dataByTestId.set(test.id, { test, result, steps: new Map() });\n result.parallelIndex = this._parallelIndex;\n result.workerIndex = this._workerIndex;\n result.startTime = new Date(params.startWallTime);\n this._reporter.onTestBegin?.(test, result);\n this._currentlyRunning = { test, result };\n }\n\n private _onTestEnd(params: TestEndPayload) {\n if (this._failureTracker.hasReachedMaxFailures()) {\n // Do not show more than one error to avoid confusion, but report\n // as interrupted to indicate that we did actually start the test.\n params.status = 'interrupted';\n params.errors = [];\n }\n const data = this._dataByTestId.get(params.testId);\n if (!data) {\n // TODO: this should never be the case, report an internal error?\n return;\n }\n this._dataByTestId.delete(params.testId);\n this._remainingByTestId.delete(params.testId);\n const { result, test } = data;\n result.duration = params.duration;\n result.errors = params.errors;\n result.error = result.errors[0];\n result.status = params.status;\n result.annotations = params.annotations;\n test.annotations = [...params.annotations]; // last test result wins\n test.expectedStatus = params.expectedStatus;\n test.timeout = params.timeout;\n const isFailure = result.status !== 'skipped' && result.status !== test.expectedStatus;\n if (isFailure)\n this._failedTests.add(test);\n if (params.hasNonRetriableError)\n this._addNonretriableTestAndSerialModeParents(test);\n this._reportTestEnd(test, result);\n this._currentlyRunning = undefined;\n }\n\n private _addNonretriableTestAndSerialModeParents(test: TestCase) {\n this._failedWithNonRetriableError.add(test);\n for (let parent: Suite | undefined = test.parent; parent; parent = parent.parent) {\n if (parent._parallelMode === 'serial')\n this._failedWithNonRetriableError.add(parent);\n }\n }\n\n private _onStepBegin(params: StepBeginPayload) {\n const data = this._dataByTestId.get(params.testId);\n if (!data) {\n // The test has finished, but steps are still coming. Just ignore them.\n return;\n }\n const { result, steps, test } = data;\n const parentStep = params.parentStepId ? steps.get(params.parentStepId) : undefined;\n const step: TestStep = {\n title: params.title,\n titlePath: () => {\n const parentPath = parentStep?.titlePath() || [];\n return [...parentPath, params.title];\n },\n parent: parentStep,\n category: params.category,\n startTime: new Date(params.wallTime),\n duration: -1,\n steps: [],\n attachments: [],\n annotations: [],\n location: params.location,\n };\n steps.set(params.stepId, step);\n (parentStep || result).steps.push(step);\n this._reporter.onStepBegin?.(test, result, step);\n }\n\n private _onStepEnd(params: StepEndPayload) {\n const data = this._dataByTestId.get(params.testId);\n if (!data) {\n // The test has finished, but steps are still coming. Just ignore them.\n return;\n }\n const { result, steps, test } = data;\n const step = steps.get(params.stepId);\n if (!step) {\n this._reporter.onStdErr?.('Internal error: step end without step begin: ' + params.stepId, test, result);\n return;\n }\n step.duration = params.wallTime - step.startTime.getTime();\n if (params.error)\n step.error = params.error;\n if (params.suggestedRebaseline)\n addSuggestedRebaseline(step.location!, params.suggestedRebaseline);\n step.annotations = params.annotations;\n steps.delete(params.stepId);\n this._reporter.onStepEnd?.(test, result, step);\n }\n\n private _onAttach(params: AttachmentPayload) {\n const data = this._dataByTestId.get(params.testId)!;\n if (!data) {\n // The test has finished, but attachments are still coming. Just ignore them.\n return;\n }\n const attachment = {\n name: params.name,\n path: params.path,\n contentType: params.contentType,\n body: params.body !== undefined ? Buffer.from(params.body, 'base64') : undefined\n };\n data.result.attachments.push(attachment);\n if (params.stepId) {\n const step = data.steps.get(params.stepId);\n if (step)\n step.attachments.push(attachment);\n else\n this._reporter.onStdErr?.('Internal error: step id not found: ' + params.stepId);\n }\n }\n\n private _failTestWithErrors(test: TestCase, errors: TestError[]) {\n const runData = this._dataByTestId.get(test.id);\n // There might be a single test that has started but has not finished yet.\n let result: TestResult;\n if (runData) {\n result = runData.result;\n } else {\n result = test._appendTestResult();\n this._reporter.onTestBegin?.(test, result);\n }\n result.errors = [...errors];\n result.error = result.errors[0];\n result.status = errors.length ? 'failed' : 'skipped';\n this._reportTestEnd(test, result);\n this._failedTests.add(test);\n }\n\n private _massSkipTestsFromRemaining(testIds: Set<string>, errors: TestError[]) {\n for (const test of this._remainingByTestId.values()) {\n if (!testIds.has(test.id))\n continue;\n if (!this._failureTracker.hasReachedMaxFailures()) {\n this._failTestWithErrors(test, errors);\n errors = []; // Only report errors for the first test.\n }\n this._remainingByTestId.delete(test.id);\n }\n if (errors.length) {\n // We had fatal errors after all tests have passed - most likely in some teardown.\n // Let's just fail the test run.\n this._failureTracker.onWorkerError();\n for (const error of errors)\n this._reporter.onError?.(error);\n }\n }\n\n private _onDone(params: DonePayload & { unexpectedExitError?: TestError }) {\n // We won't file remaining if:\n // - there are no remaining\n // - we are here not because something failed\n // - no unrecoverable worker error\n if (!this._remainingByTestId.size && !this._failedTests.size && !params.fatalErrors.length && !params.skipTestsDueToSetupFailure.length && !params.fatalUnknownTestIds && !params.unexpectedExitError) {\n this._finished({ didFail: false });\n return;\n }\n\n for (const testId of params.fatalUnknownTestIds || []) {\n const test = this._remainingByTestId.get(testId);\n if (test) {\n this._remainingByTestId.delete(testId);\n this._failTestWithErrors(test, [{ message: `Test not found in the worker process. Make sure test title does not change.` }]);\n }\n }\n\n if (params.fatalErrors.length) {\n // In case of fatal errors, report first remaining test as failing with these errors,\n // and all others as skipped.\n this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), params.fatalErrors);\n }\n // Handle tests that should be skipped because of the setup failure.\n this._massSkipTestsFromRemaining(new Set(params.skipTestsDueToSetupFailure), []);\n\n if (params.unexpectedExitError) {\n // When worker exits during a test, we blame the test itself.\n //\n // The most common situation when worker exits while not running a test is:\n // worker failed to require the test file (at the start) because of an exception in one of imports.\n // In this case, \"skip\" all remaining tests, to avoid running into the same exception over and over.\n if (this._currentlyRunning)\n this._massSkipTestsFromRemaining(new Set([this._currentlyRunning.test.id]), [params.unexpectedExitError]);\n else\n this._massSkipTestsFromRemaining(new Set(this._remainingByTestId.keys()), [params.unexpectedExitError]);\n }\n\n const retryCandidates = new Set<TestCase>();\n const serialSuitesWithFailures = new Set<Suite>();\n\n for (const failedTest of this._failedTests) {\n if (this._failedWithNonRetriableError.has(failedTest))\n continue;\n retryCandidates.add(failedTest);\n\n let outermostSerialSuite: Suite | undefined;\n for (let parent: Suite | undefined = failedTest.parent; parent; parent = parent.parent) {\n if (parent._parallelMode === 'serial')\n outermostSerialSuite = parent;\n }\n if (outermostSerialSuite && !this._failedWithNonRetriableError.has(outermostSerialSuite))\n serialSuitesWithFailures.add(outermostSerialSuite);\n }\n\n // If we have failed tests that belong to a serial suite,\n // we should skip all future tests from the same serial suite.\n const testsBelongingToSomeSerialSuiteWithFailures = [...this._remainingByTestId.values()].filter(test => {\n let parent: Suite | undefined = test.parent;\n while (parent && !serialSuitesWithFailures.has(parent))\n parent = parent.parent;\n return !!parent;\n });\n this._massSkipTestsFromRemaining(new Set(testsBelongingToSomeSerialSuiteWithFailures.map(test => test.id)), []);\n\n for (const serialSuite of serialSuitesWithFailures) {\n // Add all tests from failed serial suites for possible retry.\n // These will only be retried together, because they have the same\n // \"retries\" setting and the same number of previous runs.\n serialSuite.allTests().forEach(test => retryCandidates.add(test));\n }\n\n const remaining = [...this._remainingByTestId.values()];\n for (const test of retryCandidates) {\n if (test.results.length < test.retries + 1)\n remaining.push(test);\n }\n\n // This job is over, we will schedule another one.\n const newJob = remaining.length ? { ...this.job, tests: remaining } : undefined;\n this._finished({ didFail: true, newJob });\n }\n\n onExit(data: ProcessExitData) {\n const unexpectedExitError: TestError | undefined = data.unexpectedly ? {\n message: `Error: worker process exited unexpectedly (code=${data.code}, signal=${data.signal})`\n } : undefined;\n this._onDone({ skipTestsDueToSetupFailure: [], fatalErrors: [], unexpectedExitError });\n }\n\n private _finished(result: { newJob?: TestGroup, didFail: boolean }) {\n eventsHelper.removeEventListeners(this._listeners);\n this.jobResult.resolve(result);\n }\n\n runInWorker(worker: WorkerHost) {\n this._parallelIndex = worker.parallelIndex;\n this._workerIndex = worker.workerIndex;\n\n const runPayload: RunPayload = {\n file: this.job.requireFile,\n entries: this.job.tests.map(test => {\n return { testId: test.id, retry: test.results.length };\n }),\n };\n worker.runTestGroup(runPayload);\n\n this._listeners = [\n eventsHelper.addEventListener(worker, 'testBegin', this._onTestBegin.bind(this)),\n eventsHelper.addEventListener(worker, 'testEnd', this._onTestEnd.bind(this)),\n eventsHelper.addEventListener(worker, 'stepBegin', this._onStepBegin.bind(this)),\n eventsHelper.addEventListener(worker, 'stepEnd', this._onStepEnd.bind(this)),\n eventsHelper.addEventListener(worker, 'attach', this._onAttach.bind(this)),\n eventsHelper.addEventListener(worker, 'done', this._onDone.bind(this)),\n eventsHelper.addEventListener(worker, 'exit', this.onExit.bind(this)),\n ];\n }\n\n skipWholeJob(): boolean {\n // If all the tests in a group are skipped, we report them immediately\n // without sending anything to a worker. This avoids creating unnecessary worker processes.\n //\n // However, if there is at least one non-skipped test in a group, we'll send\n // the whole group to the worker process and report tests in the natural order,\n // with skipped tests mixed in-between non-skipped. This makes\n // for a better reporter experience.\n const allTestsSkipped = this.job.tests.every(test => test.expectedStatus === 'skipped');\n if (allTestsSkipped && !this._failureTracker.hasReachedMaxFailures()) {\n for (const test of this.job.tests) {\n const result = test._appendTestResult();\n this._reporter.onTestBegin?.(test, result);\n result.status = 'skipped';\n this._reportTestEnd(test, result);\n }\n return true;\n }\n return false;\n }\n\n currentlyRunning() {\n return this._currentlyRunning;\n }\n\n private _reportTestEnd(test: TestCase, result: TestResult) {\n this._reporter.onTestEnd?.(test, result);\n const hadMaxFailures = this._failureTracker.hasReachedMaxFailures();\n this._failureTracker.onTestEnd(test, result);\n if (this._failureTracker.hasReachedMaxFailures()) {\n this._stopCallback();\n if (!hadMaxFailures)\n this._reporter.onError?.({ message: colors.red(`Testing stopped early after ${this._failureTracker.maxFailures()} maximum allowed failures.`) });\n }\n }\n}\n\nfunction chunkFromParams(params: TestOutputPayload): string | Buffer {\n if (typeof params.text === 'string')\n return params.text;\n return Buffer.from(params.buffer!, 'base64');\n}\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["import_utils"]
|
7
|
+
}
|
@@ -0,0 +1,72 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __defProp = Object.defineProperty;
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
6
|
+
var __export = (target, all) => {
|
7
|
+
for (var name in all)
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
9
|
+
};
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
12
|
+
for (let key of __getOwnPropNames(from))
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
15
|
+
}
|
16
|
+
return to;
|
17
|
+
};
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
19
|
+
var failureTracker_exports = {};
|
20
|
+
__export(failureTracker_exports, {
|
21
|
+
FailureTracker: () => FailureTracker
|
22
|
+
});
|
23
|
+
module.exports = __toCommonJS(failureTracker_exports);
|
24
|
+
class FailureTracker {
|
25
|
+
constructor(_config, options) {
|
26
|
+
this._config = _config;
|
27
|
+
this._failureCount = 0;
|
28
|
+
this._hasWorkerErrors = false;
|
29
|
+
this._topLevelProjects = [];
|
30
|
+
this._pauseOnError = options?.pauseOnError ?? false;
|
31
|
+
this._pauseAtEnd = options?.pauseAtEnd ?? false;
|
32
|
+
}
|
33
|
+
onRootSuite(rootSuite, topLevelProjects) {
|
34
|
+
this._rootSuite = rootSuite;
|
35
|
+
this._topLevelProjects = topLevelProjects;
|
36
|
+
}
|
37
|
+
onTestEnd(test, result) {
|
38
|
+
if (test.outcome() === "unexpected" && test.results.length > test.retries)
|
39
|
+
++this._failureCount;
|
40
|
+
}
|
41
|
+
onWorkerError() {
|
42
|
+
this._hasWorkerErrors = true;
|
43
|
+
}
|
44
|
+
pauseOnError() {
|
45
|
+
return this._pauseOnError;
|
46
|
+
}
|
47
|
+
pauseAtEnd(inProject) {
|
48
|
+
return this._pauseAtEnd && this._topLevelProjects.includes(inProject);
|
49
|
+
}
|
50
|
+
hasReachedMaxFailures() {
|
51
|
+
return this.maxFailures() > 0 && this._failureCount >= this.maxFailures();
|
52
|
+
}
|
53
|
+
hasWorkerErrors() {
|
54
|
+
return this._hasWorkerErrors;
|
55
|
+
}
|
56
|
+
result() {
|
57
|
+
return this._hasWorkerErrors || this.hasReachedMaxFailures() || this.hasFailedTests() || this._config.failOnFlakyTests && this.hasFlakyTests() ? "failed" : "passed";
|
58
|
+
}
|
59
|
+
hasFailedTests() {
|
60
|
+
return this._rootSuite?.allTests().some((test) => !test.ok());
|
61
|
+
}
|
62
|
+
hasFlakyTests() {
|
63
|
+
return this._rootSuite?.allTests().some((test) => test.outcome() === "flaky");
|
64
|
+
}
|
65
|
+
maxFailures() {
|
66
|
+
return this._config.config.maxFailures;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
// Annotate the CommonJS export names for ESM import in node:
|
70
|
+
0 && (module.exports = {
|
71
|
+
FailureTracker
|
72
|
+
});
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../../src/runner/failureTracker.ts"],
|
4
|
+
"sourcesContent": ["/**\n * Copyright Microsoft Corporation. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { TestResult } from '../../types/testReporter';\nimport type { FullConfigInternal } from '../common/config';\nimport type { Suite, TestCase } from '../common/test';\n\nexport class FailureTracker {\n private _failureCount = 0;\n private _hasWorkerErrors = false;\n private _rootSuite: Suite | undefined;\n\n constructor(private _config: FullConfigInternal) {\n }\n\n onRootSuite(rootSuite: Suite) {\n this._rootSuite = rootSuite;\n }\n\n onTestEnd(test: TestCase, result: TestResult) {\n // Test is considered failing after the last retry.\n if (test.outcome() === 'unexpected' && test.results.length > test.retries)\n ++this._failureCount;\n }\n\n onWorkerError() {\n this._hasWorkerErrors = true;\n }\n\n hasReachedMaxFailures() {\n return this.maxFailures() > 0 && this._failureCount >= this.maxFailures();\n }\n\n hasWorkerErrors() {\n return this._hasWorkerErrors;\n }\n\n result(): 'failed' | 'passed' {\n return this._hasWorkerErrors || this.hasReachedMaxFailures() || this.hasFailedTests() || (this._config.failOnFlakyTests && this.hasFlakyTests()) ? 'failed' : 'passed';\n }\n\n hasFailedTests() {\n return this._rootSuite?.allTests().some(test => !test.ok());\n }\n\n hasFlakyTests() {\n return this._rootSuite?.allTests().some(test => (test.outcome() === 'flaky'));\n }\n\n maxFailures() {\n return this._config.config.maxFailures;\n }\n\n}\n"],
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBO,MAAM,eAAe;AAAA,EAK1B,YAAoB,SAA6B;AAA7B;AAJpB,SAAQ,gBAAgB;AACxB,SAAQ,mBAAmB;AAAA,EAI3B;AAAA,EAEA,YAAY,WAAkB;AAC5B,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,UAAU,MAAgB,QAAoB;AAE5C,QAAI,KAAK,QAAQ,MAAM,gBAAgB,KAAK,QAAQ,SAAS,KAAK;AAChE,QAAE,KAAK;AAAA,EACX;AAAA,EAEA,gBAAgB;AACd,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,wBAAwB;AACtB,WAAO,KAAK,YAAY,IAAI,KAAK,KAAK,iBAAiB,KAAK,YAAY;AAAA,EAC1E;AAAA,EAEA,kBAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAA8B;AAC5B,WAAO,KAAK,oBAAoB,KAAK,sBAAsB,KAAK,KAAK,eAAe,KAAM,KAAK,QAAQ,oBAAoB,KAAK,cAAc,IAAK,WAAW;AAAA,EAChK;AAAA,EAEA,iBAAiB;AACf,WAAO,KAAK,YAAY,SAAS,EAAE,KAAK,UAAQ,CAAC,KAAK,GAAG,CAAC;AAAA,EAC5D;AAAA,EAEA,gBAAgB;AACd,WAAO,KAAK,YAAY,SAAS,EAAE,KAAK,UAAS,KAAK,QAAQ,MAAM,OAAQ;AAAA,EAC9E;AAAA,EAEA,cAAc;AACZ,WAAO,KAAK,QAAQ,OAAO;AAAA,EAC7B;AAEF;",
|
6
|
+
"names": []
|
7
|
+
}
|