@checkly/playwright-core 1.51.15 → 1.51.17-beta.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.
Files changed (57) hide show
  1. package/lib/checkly/secretsFilter.js +9 -2
  2. package/lib/generated/clockSource.js +2 -1
  3. package/lib/generated/consoleApiSource.js +2 -1
  4. package/lib/generated/injectedScriptSource.js +2 -1
  5. package/lib/generated/pollingRecorderSource.js +2 -1
  6. package/lib/generated/utilityScriptSource.js +2 -1
  7. package/lib/generated/webSocketMockSource.js +2 -1
  8. package/lib/vite/recorder/assets/codeMirrorModule-DrMbgOIo.js +16684 -0
  9. package/lib/vite/recorder/assets/codeMirrorModule-DuST8d_k.css +344 -0
  10. package/lib/vite/recorder/assets/index-5NM3V7eb.css +2524 -0
  11. package/lib/vite/recorder/assets/index-CT-scFHn.js +16848 -0
  12. package/lib/vite/recorder/index.html +2 -2
  13. package/lib/vite/traceViewer/assets/codeMirrorModule-CB-2okZ8.js +16684 -0
  14. package/lib/vite/traceViewer/assets/defaultSettingsView-CBiB4avC.js +217 -0
  15. package/lib/vite/traceViewer/assets/inspectorTab-CwgfffWb.js +25143 -0
  16. package/lib/vite/traceViewer/assets/workbench-CWZselvp.js +2470 -0
  17. package/lib/vite/traceViewer/assets/xtermModule-Es_gt_u7.js +5994 -0
  18. package/lib/vite/traceViewer/codeMirrorModule.DuST8d_k.css +344 -0
  19. package/lib/vite/traceViewer/defaultSettingsView.Dp3b_92q.css +41 -0
  20. package/lib/vite/traceViewer/embedded.BeldSa2G.css +68 -0
  21. package/lib/vite/traceViewer/embedded.gzudoghF.js +106 -0
  22. package/lib/vite/traceViewer/embedded.html +6 -6
  23. package/lib/vite/traceViewer/index.DilotR1h.js +314 -0
  24. package/lib/vite/traceViewer/index.QewjJ85u.css +131 -0
  25. package/lib/vite/traceViewer/index.html +8 -8
  26. package/lib/vite/traceViewer/inspectorTab.DnGm18kV.css +3178 -0
  27. package/lib/vite/traceViewer/recorder.DLgqV9db.css +15 -0
  28. package/lib/vite/traceViewer/recorder.DVrkq3Um.js +551 -0
  29. package/lib/vite/traceViewer/recorder.html +4 -4
  30. package/lib/vite/traceViewer/uiMode.C9_OcpPU.js +1756 -0
  31. package/lib/vite/traceViewer/uiMode.c5ORgcrX.css +1424 -0
  32. package/lib/vite/traceViewer/uiMode.html +8 -8
  33. package/lib/vite/traceViewer/workbench.xUZSA8PY.css +787 -0
  34. package/lib/vite/traceViewer/xtermModule.EsaqrrTX.css +209 -0
  35. package/package.json +1 -1
  36. package/lib/vite/recorder/assets/codeMirrorModule-B9YMkrwa.js +0 -24
  37. package/lib/vite/recorder/assets/codeMirrorModule-C3UTv-Ge.css +0 -1
  38. package/lib/vite/recorder/assets/index-ELPgmkwA.js +0 -184
  39. package/lib/vite/recorder/assets/index-eHBmevrY.css +0 -1
  40. package/lib/vite/traceViewer/assets/codeMirrorModule-gU1OOCQO.js +0 -24
  41. package/lib/vite/traceViewer/assets/defaultSettingsView-B5n_FjMx.js +0 -1
  42. package/lib/vite/traceViewer/assets/inspectorTab-6Tru8Mn_.js +0 -235
  43. package/lib/vite/traceViewer/assets/workbench-B_Nj4NA2.js +0 -25
  44. package/lib/vite/traceViewer/assets/xtermModule-BoAIEibi.js +0 -9
  45. package/lib/vite/traceViewer/codeMirrorModule.C3UTv-Ge.css +0 -1
  46. package/lib/vite/traceViewer/defaultSettingsView.CO3FR0CX.css +0 -1
  47. package/lib/vite/traceViewer/embedded.DpNPH6mk.js +0 -2
  48. package/lib/vite/traceViewer/embedded.mLhjB5IF.css +0 -1
  49. package/lib/vite/traceViewer/index.CFOW-Ezb.css +0 -1
  50. package/lib/vite/traceViewer/index.CuE3SYGw.js +0 -2
  51. package/lib/vite/traceViewer/inspectorTab.CXDulcFG.css +0 -1
  52. package/lib/vite/traceViewer/recorder.BD-uZJs7.js +0 -2
  53. package/lib/vite/traceViewer/recorder.tn0RQdqM.css +0 -0
  54. package/lib/vite/traceViewer/uiMode.BatfzHMG.css +0 -1
  55. package/lib/vite/traceViewer/uiMode.DHrNgddz.js +0 -5
  56. package/lib/vite/traceViewer/workbench.B9vIAzH9.css +0 -1
  57. package/lib/vite/traceViewer/xtermModule.Beg8tuEN.css +0 -32
@@ -0,0 +1,1756 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./assets/xtermModule-Es_gt_u7.js","./xtermModule.EsaqrrTX.css"])))=>i.map(i=>d[i]);
2
+ import { u as useMeasure, r as reactExports, b as currentTheme, _ as __vitePreload, d as addThemeListener, e as removeThemeListener, j as jsxRuntimeExports, R as React, s as settings, f as clsx, m as msToString, g as Toolbar, T as ToolbarButton, M as MultiTraceModel, h as useSetting, S as SplitView, a as applyTheme, c as clientExports } from "./assets/inspectorTab-CwgfffWb.js";
3
+ import { T as TestServerConnection, W as WebSocketTestServerTransport, D as DefaultSettingsView } from "./assets/defaultSettingsView-CBiB4avC.js";
4
+ import { E as Expandable, T as TreeView, t as testStatusIcon, W as Workbench, L as LLMProvider } from "./assets/workbench-CWZselvp.js";
5
+ var define_process_env_default = {};
6
+ class TeleReporterReceiver {
7
+ constructor(reporter, options = {}) {
8
+ this.isListing = false;
9
+ this._tests = /* @__PURE__ */ new Map();
10
+ this._rootSuite = new TeleSuite("", "root");
11
+ this._options = options;
12
+ this._reporter = reporter;
13
+ }
14
+ reset() {
15
+ this._rootSuite._entries = [];
16
+ this._tests.clear();
17
+ }
18
+ dispatch(message) {
19
+ const { method, params } = message;
20
+ if (method === "onConfigure") {
21
+ this._onConfigure(params.config);
22
+ return;
23
+ }
24
+ if (method === "onProject") {
25
+ this._onProject(params.project);
26
+ return;
27
+ }
28
+ if (method === "onBegin") {
29
+ this._onBegin();
30
+ return;
31
+ }
32
+ if (method === "onTestBegin") {
33
+ this._onTestBegin(params.testId, params.result);
34
+ return;
35
+ }
36
+ if (method === "onTestEnd") {
37
+ this._onTestEnd(params.test, params.result);
38
+ return;
39
+ }
40
+ if (method === "onStepBegin") {
41
+ this._onStepBegin(params.testId, params.resultId, params.step);
42
+ return;
43
+ }
44
+ if (method === "onStepEnd") {
45
+ this._onStepEnd(params.testId, params.resultId, params.step);
46
+ return;
47
+ }
48
+ if (method === "onError") {
49
+ this._onError(params.error);
50
+ return;
51
+ }
52
+ if (method === "onStdIO") {
53
+ this._onStdIO(params.type, params.testId, params.resultId, params.data, params.isBase64);
54
+ return;
55
+ }
56
+ if (method === "onEnd")
57
+ return this._onEnd(params.result);
58
+ if (method === "onExit")
59
+ return this._onExit();
60
+ }
61
+ _onConfigure(config) {
62
+ var _a, _b;
63
+ this._rootDir = config.rootDir;
64
+ this._config = this._parseConfig(config);
65
+ (_b = (_a = this._reporter).onConfigure) == null ? void 0 : _b.call(_a, this._config);
66
+ }
67
+ _onProject(project) {
68
+ let projectSuite = this._options.mergeProjects ? this._rootSuite.suites.find((suite) => suite.project().name === project.name) : void 0;
69
+ if (!projectSuite) {
70
+ projectSuite = new TeleSuite(project.name, "project");
71
+ this._rootSuite._addSuite(projectSuite);
72
+ }
73
+ projectSuite._project = this._parseProject(project);
74
+ for (const suite of project.suites)
75
+ this._mergeSuiteInto(suite, projectSuite);
76
+ }
77
+ _onBegin() {
78
+ var _a, _b;
79
+ (_b = (_a = this._reporter).onBegin) == null ? void 0 : _b.call(_a, this._rootSuite);
80
+ }
81
+ _onTestBegin(testId, payload) {
82
+ var _a, _b;
83
+ const test = this._tests.get(testId);
84
+ if (this._options.clearPreviousResultsWhenTestBegins)
85
+ test.results = [];
86
+ const testResult = test._createTestResult(payload.id);
87
+ testResult.retry = payload.retry;
88
+ testResult.workerIndex = payload.workerIndex;
89
+ testResult.parallelIndex = payload.parallelIndex;
90
+ testResult.setStartTimeNumber(payload.startTime);
91
+ (_b = (_a = this._reporter).onTestBegin) == null ? void 0 : _b.call(_a, test, testResult);
92
+ }
93
+ _onTestEnd(testEndPayload, payload) {
94
+ var _a, _b, _c;
95
+ const test = this._tests.get(testEndPayload.testId);
96
+ test.timeout = testEndPayload.timeout;
97
+ test.expectedStatus = testEndPayload.expectedStatus;
98
+ test.annotations = testEndPayload.annotations;
99
+ const result = test.results.find((r) => r._id === payload.id);
100
+ result.duration = payload.duration;
101
+ result.status = payload.status;
102
+ result.errors = payload.errors;
103
+ result.error = (_a = result.errors) == null ? void 0 : _a[0];
104
+ result.attachments = this._parseAttachments(payload.attachments);
105
+ (_c = (_b = this._reporter).onTestEnd) == null ? void 0 : _c.call(_b, test, result);
106
+ result._stepMap = /* @__PURE__ */ new Map();
107
+ }
108
+ _onStepBegin(testId, resultId, payload) {
109
+ var _a, _b;
110
+ const test = this._tests.get(testId);
111
+ const result = test.results.find((r) => r._id === resultId);
112
+ const parentStep = payload.parentStepId ? result._stepMap.get(payload.parentStepId) : void 0;
113
+ const location = this._absoluteLocation(payload.location);
114
+ const step = new TeleTestStep(payload, parentStep, location, result);
115
+ if (parentStep)
116
+ parentStep.steps.push(step);
117
+ else
118
+ result.steps.push(step);
119
+ result._stepMap.set(payload.id, step);
120
+ (_b = (_a = this._reporter).onStepBegin) == null ? void 0 : _b.call(_a, test, result, step);
121
+ }
122
+ _onStepEnd(testId, resultId, payload) {
123
+ var _a, _b;
124
+ const test = this._tests.get(testId);
125
+ const result = test.results.find((r) => r._id === resultId);
126
+ const step = result._stepMap.get(payload.id);
127
+ step._endPayload = payload;
128
+ step.duration = payload.duration;
129
+ step.error = payload.error;
130
+ (_b = (_a = this._reporter).onStepEnd) == null ? void 0 : _b.call(_a, test, result, step);
131
+ }
132
+ _onError(error) {
133
+ var _a, _b;
134
+ (_b = (_a = this._reporter).onError) == null ? void 0 : _b.call(_a, error);
135
+ }
136
+ _onStdIO(type, testId, resultId, data, isBase64) {
137
+ var _a, _b, _c, _d;
138
+ const chunk = isBase64 ? globalThis.Buffer ? Buffer.from(data, "base64") : atob(data) : data;
139
+ const test = testId ? this._tests.get(testId) : void 0;
140
+ const result = test && resultId ? test.results.find((r) => r._id === resultId) : void 0;
141
+ if (type === "stdout") {
142
+ result == null ? void 0 : result.stdout.push(chunk);
143
+ (_b = (_a = this._reporter).onStdOut) == null ? void 0 : _b.call(_a, chunk, test, result);
144
+ } else {
145
+ result == null ? void 0 : result.stderr.push(chunk);
146
+ (_d = (_c = this._reporter).onStdErr) == null ? void 0 : _d.call(_c, chunk, test, result);
147
+ }
148
+ }
149
+ async _onEnd(result) {
150
+ var _a, _b;
151
+ await ((_b = (_a = this._reporter).onEnd) == null ? void 0 : _b.call(_a, {
152
+ status: result.status,
153
+ startTime: new Date(result.startTime),
154
+ duration: result.duration
155
+ }));
156
+ }
157
+ _onExit() {
158
+ var _a, _b;
159
+ return (_b = (_a = this._reporter).onExit) == null ? void 0 : _b.call(_a);
160
+ }
161
+ _parseConfig(config) {
162
+ const result = { ...baseFullConfig, ...config };
163
+ if (this._options.configOverrides) {
164
+ result.configFile = this._options.configOverrides.configFile;
165
+ result.reportSlowTests = this._options.configOverrides.reportSlowTests;
166
+ result.quiet = this._options.configOverrides.quiet;
167
+ result.reporter = [...this._options.configOverrides.reporter];
168
+ }
169
+ return result;
170
+ }
171
+ _parseProject(project) {
172
+ return {
173
+ metadata: project.metadata,
174
+ name: project.name,
175
+ outputDir: this._absolutePath(project.outputDir),
176
+ repeatEach: project.repeatEach,
177
+ retries: project.retries,
178
+ testDir: this._absolutePath(project.testDir),
179
+ testIgnore: parseRegexPatterns(project.testIgnore),
180
+ testMatch: parseRegexPatterns(project.testMatch),
181
+ timeout: project.timeout,
182
+ grep: parseRegexPatterns(project.grep),
183
+ grepInvert: parseRegexPatterns(project.grepInvert),
184
+ dependencies: project.dependencies,
185
+ teardown: project.teardown,
186
+ snapshotDir: this._absolutePath(project.snapshotDir),
187
+ use: project.use
188
+ };
189
+ }
190
+ _parseAttachments(attachments) {
191
+ return attachments.map((a) => {
192
+ return {
193
+ ...a,
194
+ body: a.base64 && globalThis.Buffer ? Buffer.from(a.base64, "base64") : void 0
195
+ };
196
+ });
197
+ }
198
+ _mergeSuiteInto(jsonSuite, parent) {
199
+ let targetSuite = parent.suites.find((s) => s.title === jsonSuite.title);
200
+ if (!targetSuite) {
201
+ targetSuite = new TeleSuite(jsonSuite.title, parent.type === "project" ? "file" : "describe");
202
+ parent._addSuite(targetSuite);
203
+ }
204
+ targetSuite.location = this._absoluteLocation(jsonSuite.location);
205
+ jsonSuite.entries.forEach((e) => {
206
+ if ("testId" in e)
207
+ this._mergeTestInto(e, targetSuite);
208
+ else
209
+ this._mergeSuiteInto(e, targetSuite);
210
+ });
211
+ }
212
+ _mergeTestInto(jsonTest, parent) {
213
+ let targetTest = this._options.mergeTestCases ? parent.tests.find((s) => s.title === jsonTest.title && s.repeatEachIndex === jsonTest.repeatEachIndex) : void 0;
214
+ if (!targetTest) {
215
+ targetTest = new TeleTestCase(jsonTest.testId, jsonTest.title, this._absoluteLocation(jsonTest.location), jsonTest.repeatEachIndex);
216
+ parent._addTest(targetTest);
217
+ this._tests.set(targetTest.id, targetTest);
218
+ }
219
+ this._updateTest(jsonTest, targetTest);
220
+ }
221
+ _updateTest(payload, test) {
222
+ test.id = payload.testId;
223
+ test.location = this._absoluteLocation(payload.location);
224
+ test.retries = payload.retries;
225
+ test.tags = payload.tags ?? [];
226
+ test.annotations = payload.annotations ?? [];
227
+ return test;
228
+ }
229
+ _absoluteLocation(location) {
230
+ if (!location)
231
+ return location;
232
+ return {
233
+ ...location,
234
+ file: this._absolutePath(location.file)
235
+ };
236
+ }
237
+ _absolutePath(relativePath) {
238
+ if (relativePath === void 0)
239
+ return;
240
+ return this._options.resolvePath ? this._options.resolvePath(this._rootDir, relativePath) : this._rootDir + "/" + relativePath;
241
+ }
242
+ }
243
+ class TeleSuite {
244
+ constructor(title, type) {
245
+ this._entries = [];
246
+ this._requireFile = "";
247
+ this._parallelMode = "none";
248
+ this.title = title;
249
+ this._type = type;
250
+ }
251
+ get type() {
252
+ return this._type;
253
+ }
254
+ get suites() {
255
+ return this._entries.filter((e) => e.type !== "test");
256
+ }
257
+ get tests() {
258
+ return this._entries.filter((e) => e.type === "test");
259
+ }
260
+ entries() {
261
+ return this._entries;
262
+ }
263
+ allTests() {
264
+ const result = [];
265
+ const visit = (suite) => {
266
+ for (const entry of suite.entries()) {
267
+ if (entry.type === "test")
268
+ result.push(entry);
269
+ else
270
+ visit(entry);
271
+ }
272
+ };
273
+ visit(this);
274
+ return result;
275
+ }
276
+ titlePath() {
277
+ const titlePath = this.parent ? this.parent.titlePath() : [];
278
+ if (this.title || this._type !== "describe")
279
+ titlePath.push(this.title);
280
+ return titlePath;
281
+ }
282
+ project() {
283
+ var _a;
284
+ return this._project ?? ((_a = this.parent) == null ? void 0 : _a.project());
285
+ }
286
+ _addTest(test) {
287
+ test.parent = this;
288
+ this._entries.push(test);
289
+ }
290
+ _addSuite(suite) {
291
+ suite.parent = this;
292
+ this._entries.push(suite);
293
+ }
294
+ }
295
+ class TeleTestCase {
296
+ constructor(id, title, location, repeatEachIndex) {
297
+ this.fn = () => {
298
+ };
299
+ this.results = [];
300
+ this.type = "test";
301
+ this.expectedStatus = "passed";
302
+ this.timeout = 0;
303
+ this.annotations = [];
304
+ this.retries = 0;
305
+ this.tags = [];
306
+ this.repeatEachIndex = 0;
307
+ this.id = id;
308
+ this.title = title;
309
+ this.location = location;
310
+ this.repeatEachIndex = repeatEachIndex;
311
+ }
312
+ titlePath() {
313
+ const titlePath = this.parent ? this.parent.titlePath() : [];
314
+ titlePath.push(this.title);
315
+ return titlePath;
316
+ }
317
+ outcome() {
318
+ return computeTestCaseOutcome(this);
319
+ }
320
+ ok() {
321
+ const status = this.outcome();
322
+ return status === "expected" || status === "flaky" || status === "skipped";
323
+ }
324
+ _createTestResult(id) {
325
+ const result = new TeleTestResult(this.results.length, id);
326
+ this.results.push(result);
327
+ return result;
328
+ }
329
+ }
330
+ class TeleTestStep {
331
+ constructor(payload, parentStep, location, result) {
332
+ this.duration = -1;
333
+ this.steps = [];
334
+ this._startTime = 0;
335
+ this.title = payload.title;
336
+ this.category = payload.category;
337
+ this.location = location;
338
+ this.parent = parentStep;
339
+ this._startTime = payload.startTime;
340
+ this._result = result;
341
+ }
342
+ titlePath() {
343
+ var _a;
344
+ const parentPath = ((_a = this.parent) == null ? void 0 : _a.titlePath()) || [];
345
+ return [...parentPath, this.title];
346
+ }
347
+ get startTime() {
348
+ return new Date(this._startTime);
349
+ }
350
+ set startTime(value) {
351
+ this._startTime = +value;
352
+ }
353
+ get attachments() {
354
+ var _a, _b;
355
+ return ((_b = (_a = this._endPayload) == null ? void 0 : _a.attachments) == null ? void 0 : _b.map((index) => this._result.attachments[index])) ?? [];
356
+ }
357
+ get annotations() {
358
+ var _a;
359
+ return ((_a = this._endPayload) == null ? void 0 : _a.annotations) ?? [];
360
+ }
361
+ }
362
+ class TeleTestResult {
363
+ constructor(retry, id) {
364
+ this.parallelIndex = -1;
365
+ this.workerIndex = -1;
366
+ this.duration = -1;
367
+ this.stdout = [];
368
+ this.stderr = [];
369
+ this.attachments = [];
370
+ this.status = "skipped";
371
+ this.steps = [];
372
+ this.errors = [];
373
+ this._stepMap = /* @__PURE__ */ new Map();
374
+ this._startTime = 0;
375
+ this.retry = retry;
376
+ this._id = id;
377
+ }
378
+ setStartTimeNumber(startTime) {
379
+ this._startTime = startTime;
380
+ }
381
+ get startTime() {
382
+ return new Date(this._startTime);
383
+ }
384
+ set startTime(value) {
385
+ this._startTime = +value;
386
+ }
387
+ }
388
+ const baseFullConfig = {
389
+ forbidOnly: false,
390
+ fullyParallel: false,
391
+ globalSetup: null,
392
+ globalTeardown: null,
393
+ globalTimeout: 0,
394
+ grep: /.*/,
395
+ grepInvert: null,
396
+ maxFailures: 0,
397
+ metadata: {},
398
+ preserveOutput: "always",
399
+ projects: [],
400
+ reporter: [[define_process_env_default.CI ? "dot" : "list"]],
401
+ reportSlowTests: {
402
+ max: 5,
403
+ threshold: 3e5
404
+ /* 5 minutes */
405
+ },
406
+ configFile: "",
407
+ rootDir: "",
408
+ quiet: false,
409
+ shard: null,
410
+ updateSnapshots: "missing",
411
+ updateSourceMethod: "patch",
412
+ version: "",
413
+ workers: 0,
414
+ webServer: null
415
+ };
416
+ function parseRegexPatterns(patterns) {
417
+ return patterns.map((p) => {
418
+ if (p.s !== void 0)
419
+ return p.s;
420
+ return new RegExp(p.r.source, p.r.flags);
421
+ });
422
+ }
423
+ function computeTestCaseOutcome(test) {
424
+ let skipped = 0;
425
+ let expected = 0;
426
+ let unexpected = 0;
427
+ for (const result of test.results) {
428
+ if (result.status === "interrupted") ;
429
+ else if (result.status === "skipped" && test.expectedStatus === "skipped") {
430
+ ++skipped;
431
+ } else if (result.status === "skipped") ;
432
+ else if (result.status === test.expectedStatus) {
433
+ ++expected;
434
+ } else {
435
+ ++unexpected;
436
+ }
437
+ }
438
+ if (expected === 0 && unexpected === 0)
439
+ return "skipped";
440
+ if (unexpected === 0)
441
+ return "expected";
442
+ if (expected === 0 && skipped === 0)
443
+ return "unexpected";
444
+ return "flaky";
445
+ }
446
+ class TestTree {
447
+ constructor(rootFolder, rootSuite, loadErrors, projectFilters, pathSeparator) {
448
+ this._treeItemById = /* @__PURE__ */ new Map();
449
+ this._treeItemByTestId = /* @__PURE__ */ new Map();
450
+ const filterProjects = projectFilters && [...projectFilters.values()].some(Boolean);
451
+ this.pathSeparator = pathSeparator;
452
+ this.rootItem = {
453
+ kind: "group",
454
+ subKind: "folder",
455
+ id: rootFolder,
456
+ title: "",
457
+ location: { file: "", line: 0, column: 0 },
458
+ duration: 0,
459
+ parent: void 0,
460
+ children: [],
461
+ status: "none",
462
+ hasLoadErrors: false
463
+ };
464
+ this._treeItemById.set(rootFolder, this.rootItem);
465
+ const visitSuite = (project, parentSuite, parentGroup) => {
466
+ for (const suite of parentSuite.suites) {
467
+ if (!suite.title) {
468
+ visitSuite(project, suite, parentGroup);
469
+ continue;
470
+ }
471
+ let group = parentGroup.children.find((item) => item.kind === "group" && item.title === suite.title);
472
+ if (!group) {
473
+ group = {
474
+ kind: "group",
475
+ subKind: "describe",
476
+ id: "suite:" + parentSuite.titlePath().join("") + "" + suite.title,
477
+ // account for anonymous suites
478
+ title: suite.title,
479
+ location: suite.location,
480
+ duration: 0,
481
+ parent: parentGroup,
482
+ children: [],
483
+ status: "none",
484
+ hasLoadErrors: false
485
+ };
486
+ this._addChild(parentGroup, group);
487
+ }
488
+ visitSuite(project, suite, group);
489
+ }
490
+ for (const test of parentSuite.tests) {
491
+ const title = test.title;
492
+ let testCaseItem = parentGroup.children.find((t) => t.kind !== "group" && t.title === title);
493
+ if (!testCaseItem) {
494
+ testCaseItem = {
495
+ kind: "case",
496
+ id: "test:" + test.titlePath().join(""),
497
+ title,
498
+ parent: parentGroup,
499
+ children: [],
500
+ tests: [],
501
+ location: test.location,
502
+ duration: 0,
503
+ status: "none",
504
+ project: void 0,
505
+ test: void 0,
506
+ tags: test.tags
507
+ };
508
+ this._addChild(parentGroup, testCaseItem);
509
+ }
510
+ const result = test.results[0];
511
+ let status = "none";
512
+ if ((result == null ? void 0 : result[statusEx]) === "scheduled")
513
+ status = "scheduled";
514
+ else if ((result == null ? void 0 : result[statusEx]) === "running")
515
+ status = "running";
516
+ else if ((result == null ? void 0 : result.status) === "skipped")
517
+ status = "skipped";
518
+ else if ((result == null ? void 0 : result.status) === "interrupted")
519
+ status = "none";
520
+ else if (result && test.outcome() !== "expected")
521
+ status = "failed";
522
+ else if (result && test.outcome() === "expected")
523
+ status = "passed";
524
+ testCaseItem.tests.push(test);
525
+ const testItem = {
526
+ kind: "test",
527
+ id: test.id,
528
+ title: project.name,
529
+ location: test.location,
530
+ test,
531
+ parent: testCaseItem,
532
+ children: [],
533
+ status,
534
+ duration: test.results.length ? Math.max(0, test.results[0].duration) : 0,
535
+ project
536
+ };
537
+ this._addChild(testCaseItem, testItem);
538
+ this._treeItemByTestId.set(test.id, testItem);
539
+ testCaseItem.duration = testCaseItem.children.reduce((a, b) => a + b.duration, 0);
540
+ }
541
+ };
542
+ for (const projectSuite of (rootSuite == null ? void 0 : rootSuite.suites) || []) {
543
+ if (filterProjects && !projectFilters.get(projectSuite.title))
544
+ continue;
545
+ for (const fileSuite of projectSuite.suites) {
546
+ const fileItem = this._fileItem(fileSuite.location.file.split(pathSeparator), true);
547
+ visitSuite(projectSuite.project(), fileSuite, fileItem);
548
+ }
549
+ }
550
+ for (const loadError of loadErrors) {
551
+ if (!loadError.location)
552
+ continue;
553
+ const fileItem = this._fileItem(loadError.location.file.split(pathSeparator), true);
554
+ fileItem.hasLoadErrors = true;
555
+ }
556
+ }
557
+ _addChild(parent, child) {
558
+ parent.children.push(child);
559
+ child.parent = parent;
560
+ this._treeItemById.set(child.id, child);
561
+ }
562
+ filterTree(filterText, statusFilters, runningTestIds) {
563
+ const tokens = filterText.trim().toLowerCase().split(" ");
564
+ const filtersStatuses = [...statusFilters.values()].some(Boolean);
565
+ const filter = (testCase) => {
566
+ const titleWithTags = [...testCase.tests[0].titlePath(), ...testCase.tests[0].tags].join(" ").toLowerCase();
567
+ if (!tokens.every((token) => titleWithTags.includes(token)) && !testCase.tests.some((t) => runningTestIds == null ? void 0 : runningTestIds.has(t.id)))
568
+ return false;
569
+ testCase.children = testCase.children.filter((test) => {
570
+ return !filtersStatuses || (runningTestIds == null ? void 0 : runningTestIds.has(test.test.id)) || statusFilters.get(test.status);
571
+ });
572
+ testCase.tests = testCase.children.map((c) => c.test);
573
+ return !!testCase.children.length;
574
+ };
575
+ const visit = (treeItem) => {
576
+ const newChildren = [];
577
+ for (const child of treeItem.children) {
578
+ if (child.kind === "case") {
579
+ if (filter(child))
580
+ newChildren.push(child);
581
+ } else {
582
+ visit(child);
583
+ if (child.children.length || child.hasLoadErrors)
584
+ newChildren.push(child);
585
+ }
586
+ }
587
+ treeItem.children = newChildren;
588
+ };
589
+ visit(this.rootItem);
590
+ }
591
+ _fileItem(filePath, isFile) {
592
+ if (filePath.length === 0)
593
+ return this.rootItem;
594
+ const fileName = filePath.join(this.pathSeparator);
595
+ const existingFileItem = this._treeItemById.get(fileName);
596
+ if (existingFileItem)
597
+ return existingFileItem;
598
+ const parentFileItem = this._fileItem(filePath.slice(0, filePath.length - 1), false);
599
+ const fileItem = {
600
+ kind: "group",
601
+ subKind: isFile ? "file" : "folder",
602
+ id: fileName,
603
+ title: filePath[filePath.length - 1],
604
+ location: { file: fileName, line: 0, column: 0 },
605
+ duration: 0,
606
+ parent: parentFileItem,
607
+ children: [],
608
+ status: "none",
609
+ hasLoadErrors: false
610
+ };
611
+ this._addChild(parentFileItem, fileItem);
612
+ return fileItem;
613
+ }
614
+ sortAndPropagateStatus() {
615
+ sortAndPropagateStatus(this.rootItem);
616
+ }
617
+ flattenForSingleProject() {
618
+ const visit = (treeItem) => {
619
+ if (treeItem.kind === "case" && treeItem.children.length === 1) {
620
+ treeItem.project = treeItem.children[0].project;
621
+ treeItem.test = treeItem.children[0].test;
622
+ treeItem.children = [];
623
+ this._treeItemByTestId.set(treeItem.test.id, treeItem);
624
+ } else {
625
+ treeItem.children.forEach(visit);
626
+ }
627
+ };
628
+ visit(this.rootItem);
629
+ }
630
+ shortenRoot() {
631
+ let shortRoot = this.rootItem;
632
+ while (shortRoot.children.length === 1 && shortRoot.children[0].kind === "group" && shortRoot.children[0].subKind === "folder")
633
+ shortRoot = shortRoot.children[0];
634
+ shortRoot.location = this.rootItem.location;
635
+ this.rootItem = shortRoot;
636
+ }
637
+ testIds() {
638
+ const result = /* @__PURE__ */ new Set();
639
+ const visit = (treeItem) => {
640
+ if (treeItem.kind === "case")
641
+ treeItem.tests.forEach((t) => result.add(t.id));
642
+ treeItem.children.forEach(visit);
643
+ };
644
+ visit(this.rootItem);
645
+ return result;
646
+ }
647
+ fileNames() {
648
+ const result = /* @__PURE__ */ new Set();
649
+ const visit = (treeItem) => {
650
+ if (treeItem.kind === "group" && treeItem.subKind === "file")
651
+ result.add(treeItem.id);
652
+ else
653
+ treeItem.children.forEach(visit);
654
+ };
655
+ visit(this.rootItem);
656
+ return [...result];
657
+ }
658
+ flatTreeItems() {
659
+ const result = [];
660
+ const visit = (treeItem) => {
661
+ result.push(treeItem);
662
+ treeItem.children.forEach(visit);
663
+ };
664
+ visit(this.rootItem);
665
+ return result;
666
+ }
667
+ treeItemById(id) {
668
+ return this._treeItemById.get(id);
669
+ }
670
+ collectTestIds(treeItem) {
671
+ return treeItem ? collectTestIds(treeItem) : /* @__PURE__ */ new Set();
672
+ }
673
+ }
674
+ function sortAndPropagateStatus(treeItem) {
675
+ for (const child of treeItem.children)
676
+ sortAndPropagateStatus(child);
677
+ if (treeItem.kind === "group") {
678
+ treeItem.children.sort((a, b) => {
679
+ const fc = a.location.file.localeCompare(b.location.file);
680
+ return fc || a.location.line - b.location.line;
681
+ });
682
+ }
683
+ let allPassed = treeItem.children.length > 0;
684
+ let allSkipped = treeItem.children.length > 0;
685
+ let hasFailed = false;
686
+ let hasRunning = false;
687
+ let hasScheduled = false;
688
+ for (const child of treeItem.children) {
689
+ allSkipped = allSkipped && child.status === "skipped";
690
+ allPassed = allPassed && (child.status === "passed" || child.status === "skipped");
691
+ hasFailed = hasFailed || child.status === "failed";
692
+ hasRunning = hasRunning || child.status === "running";
693
+ hasScheduled = hasScheduled || child.status === "scheduled";
694
+ }
695
+ if (hasRunning)
696
+ treeItem.status = "running";
697
+ else if (hasScheduled)
698
+ treeItem.status = "scheduled";
699
+ else if (hasFailed)
700
+ treeItem.status = "failed";
701
+ else if (allSkipped)
702
+ treeItem.status = "skipped";
703
+ else if (allPassed)
704
+ treeItem.status = "passed";
705
+ }
706
+ function collectTestIds(treeItem) {
707
+ const testIds = /* @__PURE__ */ new Set();
708
+ const visit = (treeItem2) => {
709
+ var _a;
710
+ if (treeItem2.kind === "case")
711
+ treeItem2.tests.map((t) => t.id).forEach((id) => testIds.add(id));
712
+ else if (treeItem2.kind === "test")
713
+ testIds.add(treeItem2.id);
714
+ else
715
+ (_a = treeItem2.children) == null ? void 0 : _a.forEach(visit);
716
+ };
717
+ visit(treeItem);
718
+ return testIds;
719
+ }
720
+ const statusEx = Symbol("statusEx");
721
+ class TeleSuiteUpdater {
722
+ constructor(options) {
723
+ this.loadErrors = [];
724
+ this.progress = {
725
+ total: 0,
726
+ passed: 0,
727
+ failed: 0,
728
+ skipped: 0
729
+ };
730
+ this._lastRunTestCount = 0;
731
+ this._receiver = new TeleReporterReceiver(this._createReporter(), {
732
+ mergeProjects: true,
733
+ mergeTestCases: true,
734
+ resolvePath: (rootDir, relativePath) => rootDir + options.pathSeparator + relativePath,
735
+ clearPreviousResultsWhenTestBegins: true
736
+ });
737
+ this._options = options;
738
+ }
739
+ _createReporter() {
740
+ return {
741
+ version: () => "v2",
742
+ onConfigure: (c) => {
743
+ this.config = c;
744
+ this._lastRunReceiver = new TeleReporterReceiver({
745
+ version: () => "v2",
746
+ onBegin: (suite) => {
747
+ this._lastRunTestCount = suite.allTests().length;
748
+ this._lastRunReceiver = void 0;
749
+ }
750
+ }, {
751
+ mergeProjects: true,
752
+ mergeTestCases: false,
753
+ resolvePath: (rootDir, relativePath) => rootDir + this._options.pathSeparator + relativePath
754
+ });
755
+ },
756
+ onBegin: (suite) => {
757
+ var _a;
758
+ if (!this.rootSuite)
759
+ this.rootSuite = suite;
760
+ if (this._testResultsSnapshot) {
761
+ for (const test of this.rootSuite.allTests())
762
+ test.results = ((_a = this._testResultsSnapshot) == null ? void 0 : _a.get(test.id)) || test.results;
763
+ this._testResultsSnapshot = void 0;
764
+ }
765
+ this.progress.total = this._lastRunTestCount;
766
+ this.progress.passed = 0;
767
+ this.progress.failed = 0;
768
+ this.progress.skipped = 0;
769
+ this._options.onUpdate(true);
770
+ },
771
+ onEnd: () => {
772
+ this._options.onUpdate(true);
773
+ },
774
+ onTestBegin: (test, testResult) => {
775
+ testResult[statusEx] = "running";
776
+ this._options.onUpdate();
777
+ },
778
+ onTestEnd: (test, testResult) => {
779
+ if (test.outcome() === "skipped")
780
+ ++this.progress.skipped;
781
+ else if (test.outcome() === "unexpected")
782
+ ++this.progress.failed;
783
+ else
784
+ ++this.progress.passed;
785
+ testResult[statusEx] = testResult.status;
786
+ this._options.onUpdate();
787
+ },
788
+ onError: (error) => this._handleOnError(error),
789
+ printsToStdio: () => false
790
+ };
791
+ }
792
+ processGlobalReport(report) {
793
+ const receiver = new TeleReporterReceiver({
794
+ version: () => "v2",
795
+ onConfigure: (c) => {
796
+ this.config = c;
797
+ },
798
+ onError: (error) => this._handleOnError(error)
799
+ });
800
+ for (const message of report)
801
+ void receiver.dispatch(message);
802
+ }
803
+ processListReport(report) {
804
+ var _a;
805
+ const tests = ((_a = this.rootSuite) == null ? void 0 : _a.allTests()) || [];
806
+ this._testResultsSnapshot = new Map(tests.map((test) => [test.id, test.results]));
807
+ this._receiver.reset();
808
+ for (const message of report)
809
+ void this._receiver.dispatch(message);
810
+ }
811
+ processTestReportEvent(message) {
812
+ var _a, _b, _c;
813
+ (_b = (_a = this._lastRunReceiver) == null ? void 0 : _a.dispatch(message)) == null ? void 0 : _b.catch(() => {
814
+ });
815
+ (_c = this._receiver.dispatch(message)) == null ? void 0 : _c.catch(() => {
816
+ });
817
+ }
818
+ _handleOnError(error) {
819
+ var _a, _b;
820
+ this.loadErrors.push(error);
821
+ (_b = (_a = this._options).onError) == null ? void 0 : _b.call(_a, error);
822
+ this._options.onUpdate();
823
+ }
824
+ asModel() {
825
+ return {
826
+ rootSuite: this.rootSuite || new TeleSuite("", "root"),
827
+ config: this.config,
828
+ loadErrors: this.loadErrors,
829
+ progress: this.progress
830
+ };
831
+ }
832
+ }
833
+ const XtermWrapper = ({
834
+ source
835
+ }) => {
836
+ const [measure, xtermElement] = useMeasure();
837
+ const [theme, setTheme] = reactExports.useState(currentTheme());
838
+ const [modulePromise] = reactExports.useState(__vitePreload(() => import("./assets/xtermModule-Es_gt_u7.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url).then((m) => m.default));
839
+ const terminal = reactExports.useRef(null);
840
+ reactExports.useEffect(() => {
841
+ addThemeListener(setTheme);
842
+ return () => removeThemeListener(setTheme);
843
+ }, []);
844
+ reactExports.useEffect(() => {
845
+ const oldSourceWrite = source.write;
846
+ const oldSourceClear = source.clear;
847
+ (async () => {
848
+ const { Terminal, FitAddon } = await modulePromise;
849
+ const element = xtermElement.current;
850
+ if (!element)
851
+ return;
852
+ const terminalTheme = theme === "dark-mode" ? darkTheme : lightTheme;
853
+ if (terminal.current && terminal.current.terminal.options.theme === terminalTheme)
854
+ return;
855
+ if (terminal.current)
856
+ element.textContent = "";
857
+ const newTerminal = new Terminal({
858
+ convertEol: true,
859
+ fontSize: 13,
860
+ scrollback: 1e4,
861
+ fontFamily: "var(--vscode-editor-font-family)",
862
+ theme: terminalTheme
863
+ });
864
+ const fitAddon = new FitAddon();
865
+ newTerminal.loadAddon(fitAddon);
866
+ for (const p of source.pending)
867
+ newTerminal.write(p);
868
+ source.write = (data) => {
869
+ source.pending.push(data);
870
+ newTerminal.write(data);
871
+ };
872
+ source.clear = () => {
873
+ source.pending = [];
874
+ newTerminal.clear();
875
+ };
876
+ newTerminal.open(element);
877
+ fitAddon.fit();
878
+ terminal.current = { terminal: newTerminal, fitAddon };
879
+ })();
880
+ return () => {
881
+ source.clear = oldSourceClear;
882
+ source.write = oldSourceWrite;
883
+ };
884
+ }, [modulePromise, terminal, xtermElement, source, theme]);
885
+ reactExports.useEffect(() => {
886
+ setTimeout(() => {
887
+ if (!terminal.current)
888
+ return;
889
+ terminal.current.fitAddon.fit();
890
+ source.resize(terminal.current.terminal.cols, terminal.current.terminal.rows);
891
+ }, 250);
892
+ }, [measure, source]);
893
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { "data-testid": "output", className: "xterm-wrapper", style: { flex: "auto" }, ref: xtermElement });
894
+ };
895
+ const lightTheme = {
896
+ foreground: "#383a42",
897
+ background: "#fafafa",
898
+ cursor: "#383a42",
899
+ black: "#000000",
900
+ red: "#e45649",
901
+ green: "#50a14f",
902
+ yellow: "#c18401",
903
+ blue: "#4078f2",
904
+ magenta: "#a626a4",
905
+ cyan: "#0184bc",
906
+ white: "#a0a0a0",
907
+ brightBlack: "#000000",
908
+ brightRed: "#e06c75",
909
+ brightGreen: "#98c379",
910
+ brightYellow: "#d19a66",
911
+ brightBlue: "#4078f2",
912
+ brightMagenta: "#a626a4",
913
+ brightCyan: "#0184bc",
914
+ brightWhite: "#383a42",
915
+ selectionBackground: "#d7d7d7",
916
+ selectionForeground: "#383a42"
917
+ };
918
+ const darkTheme = {
919
+ foreground: "#f8f8f2",
920
+ background: "#1e1e1e",
921
+ cursor: "#f8f8f0",
922
+ black: "#000000",
923
+ red: "#ff5555",
924
+ green: "#50fa7b",
925
+ yellow: "#f1fa8c",
926
+ blue: "#bd93f9",
927
+ magenta: "#ff79c6",
928
+ cyan: "#8be9fd",
929
+ white: "#bfbfbf",
930
+ brightBlack: "#4d4d4d",
931
+ brightRed: "#ff6e6e",
932
+ brightGreen: "#69ff94",
933
+ brightYellow: "#ffffa5",
934
+ brightBlue: "#d6acff",
935
+ brightMagenta: "#ff92df",
936
+ brightCyan: "#a4ffff",
937
+ brightWhite: "#e6e6e6",
938
+ selectionBackground: "#44475a",
939
+ selectionForeground: "#f8f8f2"
940
+ };
941
+ const FiltersView = ({ filterText, setFilterText, statusFilters, setStatusFilters, projectFilters, setProjectFilters, testModel, runTests }) => {
942
+ const [expanded, setExpanded] = React.useState(false);
943
+ const inputRef = React.useRef(null);
944
+ React.useEffect(() => {
945
+ var _a;
946
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
947
+ }, []);
948
+ const statusLine = [...statusFilters.entries()].filter(([_, v]) => v).map(([s]) => s).join(" ") || "all";
949
+ const projectsLine = [...projectFilters.entries()].filter(([_, v]) => v).map(([p]) => p).join(" ") || "all";
950
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "filters", children: [
951
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
952
+ Expandable,
953
+ {
954
+ expanded,
955
+ setExpanded,
956
+ title: /* @__PURE__ */ jsxRuntimeExports.jsx(
957
+ "input",
958
+ {
959
+ ref: inputRef,
960
+ type: "search",
961
+ placeholder: "Filter (e.g. text, @tag)",
962
+ spellCheck: false,
963
+ value: filterText,
964
+ onChange: (e) => {
965
+ setFilterText(e.target.value);
966
+ },
967
+ onKeyDown: (e) => {
968
+ if (e.key === "Enter")
969
+ runTests();
970
+ }
971
+ }
972
+ )
973
+ }
974
+ ),
975
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "filter-summary", title: "Status: " + statusLine + "\nProjects: " + projectsLine, onClick: () => setExpanded(!expanded), children: [
976
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "filter-label", children: "Status:" }),
977
+ " ",
978
+ statusLine,
979
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "filter-label", children: "Projects:" }),
980
+ " ",
981
+ projectsLine
982
+ ] }),
983
+ expanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "hbox", style: { marginLeft: 14, maxHeight: 200, overflowY: "auto" }, children: [
984
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "filter-list", role: "list", "data-testid": "status-filters", children: [...statusFilters.entries()].map(([status, value]) => {
985
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "filter-entry", role: "listitem", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { children: [
986
+ /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: value, onChange: () => {
987
+ const copy = new Map(statusFilters);
988
+ copy.set(status, !copy.get(status));
989
+ setStatusFilters(copy);
990
+ } }),
991
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: status })
992
+ ] }) }, status);
993
+ }) }),
994
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "filter-list", role: "list", "data-testid": "project-filters", children: [...projectFilters.entries()].map(([projectName, value]) => {
995
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "filter-entry", role: "listitem", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { children: [
996
+ /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: value, onChange: () => {
997
+ var _a;
998
+ const copy = new Map(projectFilters);
999
+ copy.set(projectName, !copy.get(projectName));
1000
+ setProjectFilters(copy);
1001
+ const configFile = (_a = testModel == null ? void 0 : testModel.config) == null ? void 0 : _a.configFile;
1002
+ if (configFile)
1003
+ settings.setObject(configFile + ":projects", [...copy.entries()].filter(([_, v]) => v).map(([k]) => k));
1004
+ } }),
1005
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: projectName || "untitled" })
1006
+ ] }) }, projectName);
1007
+ }) })
1008
+ ] })
1009
+ ] });
1010
+ };
1011
+ const TagView = ({ tag, style, onClick }) => {
1012
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1013
+ "span",
1014
+ {
1015
+ className: clsx("tag", `tag-color-${tagNameToColor(tag)}`),
1016
+ onClick,
1017
+ style: { margin: "6px 0 0 6px", ...style },
1018
+ title: `Click to filter by tag: ${tag}`,
1019
+ children: tag
1020
+ }
1021
+ );
1022
+ };
1023
+ function tagNameToColor(str) {
1024
+ let hash = 0;
1025
+ for (let i = 0; i < str.length; i++)
1026
+ hash = str.charCodeAt(i) + ((hash << 8) - hash);
1027
+ return Math.abs(hash % 6);
1028
+ }
1029
+ const TestTreeView = TreeView;
1030
+ const TestListView = ({ filterText, testModel, testServerConnection, testTree, runTests, runningState, watchAll, watchedTreeIds, setWatchedTreeIds, isLoading, onItemSelected, requestedCollapseAllCount, requestedExpandAllCount, setFilterText, onRevealSource }) => {
1031
+ const [treeState, setTreeState] = React.useState({ expandedItems: /* @__PURE__ */ new Map() });
1032
+ const [selectedTreeItemId, setSelectedTreeItemId] = React.useState();
1033
+ const [collapseAllCount, setCollapseAllCount] = React.useState(requestedCollapseAllCount);
1034
+ const [expandAllCount, setExpandAllCount] = React.useState(requestedExpandAllCount);
1035
+ React.useEffect(() => {
1036
+ if (collapseAllCount !== requestedCollapseAllCount) {
1037
+ treeState.expandedItems.clear();
1038
+ for (const item of testTree.flatTreeItems())
1039
+ treeState.expandedItems.set(item.id, false);
1040
+ setCollapseAllCount(requestedCollapseAllCount);
1041
+ setSelectedTreeItemId(void 0);
1042
+ setTreeState({ ...treeState });
1043
+ return;
1044
+ }
1045
+ if (expandAllCount !== requestedExpandAllCount) {
1046
+ treeState.expandedItems.clear();
1047
+ for (const item of testTree.flatTreeItems())
1048
+ treeState.expandedItems.set(item.id, true);
1049
+ setExpandAllCount(requestedExpandAllCount);
1050
+ setSelectedTreeItemId(void 0);
1051
+ setTreeState({ ...treeState });
1052
+ return;
1053
+ }
1054
+ if (!runningState || runningState.itemSelectedByUser)
1055
+ return;
1056
+ let selectedTreeItem2;
1057
+ const visit = (treeItem) => {
1058
+ var _a;
1059
+ treeItem.children.forEach(visit);
1060
+ if (selectedTreeItem2)
1061
+ return;
1062
+ if (treeItem.status === "failed") {
1063
+ if (treeItem.kind === "test" && runningState.testIds.has(treeItem.test.id))
1064
+ selectedTreeItem2 = treeItem;
1065
+ else if (treeItem.kind === "case" && runningState.testIds.has((_a = treeItem.tests[0]) == null ? void 0 : _a.id))
1066
+ selectedTreeItem2 = treeItem;
1067
+ }
1068
+ };
1069
+ visit(testTree.rootItem);
1070
+ if (selectedTreeItem2)
1071
+ setSelectedTreeItemId(selectedTreeItem2.id);
1072
+ }, [runningState, setSelectedTreeItemId, testTree, collapseAllCount, setCollapseAllCount, requestedCollapseAllCount, expandAllCount, setExpandAllCount, requestedExpandAllCount, treeState, setTreeState]);
1073
+ const selectedTreeItem = React.useMemo(() => {
1074
+ if (!selectedTreeItemId)
1075
+ return void 0;
1076
+ return testTree.treeItemById(selectedTreeItemId);
1077
+ }, [selectedTreeItemId, testTree]);
1078
+ React.useEffect(() => {
1079
+ if (!testModel)
1080
+ return;
1081
+ const testFile = itemLocation(selectedTreeItem, testModel);
1082
+ let selectedTest;
1083
+ if ((selectedTreeItem == null ? void 0 : selectedTreeItem.kind) === "test")
1084
+ selectedTest = selectedTreeItem.test;
1085
+ else if ((selectedTreeItem == null ? void 0 : selectedTreeItem.kind) === "case" && selectedTreeItem.tests.length === 1)
1086
+ selectedTest = selectedTreeItem.tests[0];
1087
+ onItemSelected({ treeItem: selectedTreeItem, testCase: selectedTest, testFile });
1088
+ }, [testModel, selectedTreeItem, onItemSelected]);
1089
+ React.useEffect(() => {
1090
+ if (isLoading)
1091
+ return;
1092
+ if (watchAll) {
1093
+ testServerConnection == null ? void 0 : testServerConnection.watchNoReply({ fileNames: testTree.fileNames() });
1094
+ } else {
1095
+ const fileNames = /* @__PURE__ */ new Set();
1096
+ for (const itemId of watchedTreeIds.value) {
1097
+ const treeItem = testTree.treeItemById(itemId);
1098
+ const fileName = treeItem == null ? void 0 : treeItem.location.file;
1099
+ if (fileName)
1100
+ fileNames.add(fileName);
1101
+ }
1102
+ testServerConnection == null ? void 0 : testServerConnection.watchNoReply({ fileNames: [...fileNames] });
1103
+ }
1104
+ }, [isLoading, testTree, watchAll, watchedTreeIds, testServerConnection]);
1105
+ const runTreeItem = (treeItem) => {
1106
+ setSelectedTreeItemId(treeItem.id);
1107
+ runTests("bounce-if-busy", testTree.collectTestIds(treeItem));
1108
+ };
1109
+ const handleTagClick = (e, tag) => {
1110
+ e.preventDefault();
1111
+ e.stopPropagation();
1112
+ if (e.metaKey || e.ctrlKey) {
1113
+ const parts = filterText.split(" ");
1114
+ if (parts.includes(tag))
1115
+ setFilterText(parts.filter((t) => t !== tag).join(" ").trim());
1116
+ else
1117
+ setFilterText((filterText + " " + tag).trim());
1118
+ } else {
1119
+ setFilterText((filterText.split(" ").filter((t) => !t.startsWith("@")).join(" ") + " " + tag).trim());
1120
+ }
1121
+ };
1122
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1123
+ TestTreeView,
1124
+ {
1125
+ name: "tests",
1126
+ treeState,
1127
+ setTreeState,
1128
+ rootItem: testTree.rootItem,
1129
+ dataTestId: "test-tree",
1130
+ render: (treeItem) => {
1131
+ const prefixId = treeItem.id.replace(/[^\w\d-_]/g, "-");
1132
+ const labelId = prefixId + "-label";
1133
+ const timeId = prefixId + "-time";
1134
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "hbox ui-mode-tree-item", "aria-labelledby": `${labelId} ${timeId}`, children: [
1135
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { id: labelId, className: "ui-mode-tree-item-title", children: [
1136
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: treeItem.title }),
1137
+ treeItem.kind === "case" ? treeItem.tags.map((tag) => /* @__PURE__ */ jsxRuntimeExports.jsx(TagView, { tag: tag.slice(1), onClick: (e) => handleTagClick(e, tag) }, tag)) : null
1138
+ ] }),
1139
+ !!treeItem.duration && treeItem.status !== "skipped" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: timeId, className: "ui-mode-tree-item-time", children: msToString(treeItem.duration) }),
1140
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Toolbar, { noMinHeight: true, noShadow: true, children: [
1141
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "play", title: "Run", onClick: () => runTreeItem(treeItem), disabled: !!runningState && !runningState.completed }),
1142
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "go-to-file", title: "Show source", onClick: onRevealSource, style: treeItem.kind === "group" && treeItem.subKind === "folder" ? { visibility: "hidden" } : {} }),
1143
+ !watchAll && /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "eye", title: "Watch", onClick: () => {
1144
+ if (watchedTreeIds.value.has(treeItem.id))
1145
+ watchedTreeIds.value.delete(treeItem.id);
1146
+ else
1147
+ watchedTreeIds.value.add(treeItem.id);
1148
+ setWatchedTreeIds({ ...watchedTreeIds });
1149
+ }, toggled: watchedTreeIds.value.has(treeItem.id) })
1150
+ ] })
1151
+ ] });
1152
+ },
1153
+ icon: (treeItem) => testStatusIcon(treeItem.status),
1154
+ title: (treeItem) => treeItem.title,
1155
+ selectedItem: selectedTreeItem,
1156
+ onAccepted: runTreeItem,
1157
+ onSelected: (treeItem) => {
1158
+ if (runningState)
1159
+ runningState.itemSelectedByUser = true;
1160
+ setSelectedTreeItemId(treeItem.id);
1161
+ },
1162
+ isError: (treeItem) => treeItem.kind === "group" ? treeItem.hasLoadErrors : false,
1163
+ autoExpandDepth: filterText ? 5 : 1,
1164
+ noItemsMessage: isLoading ? "Loading…" : "No tests"
1165
+ }
1166
+ );
1167
+ };
1168
+ function itemLocation(item, model) {
1169
+ if (!item || !model)
1170
+ return;
1171
+ return {
1172
+ file: item.location.file,
1173
+ line: item.location.line,
1174
+ column: item.location.column,
1175
+ source: {
1176
+ errors: model.loadErrors.filter((e) => {
1177
+ var _a;
1178
+ return ((_a = e.location) == null ? void 0 : _a.file) === item.location.file;
1179
+ }).map((e) => ({ line: e.location.line, message: e.message })),
1180
+ content: void 0
1181
+ }
1182
+ };
1183
+ }
1184
+ function artifactsFolderName(workerIndex) {
1185
+ return `.playwright-artifacts-${workerIndex}`;
1186
+ }
1187
+ const TraceView = ({ item, rootDir, onOpenExternally, revealSource, pathSeparator }) => {
1188
+ var _a, _b;
1189
+ const [model, setModel] = React.useState();
1190
+ const [counter, setCounter] = React.useState(0);
1191
+ const pollTimer = React.useRef(null);
1192
+ const { outputDir } = React.useMemo(() => {
1193
+ const outputDir2 = item.testCase ? outputDirForTestCase(item.testCase) : void 0;
1194
+ return { outputDir: outputDir2 };
1195
+ }, [item]);
1196
+ React.useEffect(() => {
1197
+ var _a2, _b2;
1198
+ if (pollTimer.current)
1199
+ clearTimeout(pollTimer.current);
1200
+ const result = (_a2 = item.testCase) == null ? void 0 : _a2.results[0];
1201
+ if (!result) {
1202
+ setModel(void 0);
1203
+ return;
1204
+ }
1205
+ const attachment = result && result.duration >= 0 && result.attachments.find((a) => a.name === "trace");
1206
+ if (attachment && attachment.path) {
1207
+ loadSingleTraceFile(attachment.path).then((model2) => setModel({ model: model2, isLive: false }));
1208
+ return;
1209
+ }
1210
+ if (!outputDir) {
1211
+ setModel(void 0);
1212
+ return;
1213
+ }
1214
+ const traceLocation = [
1215
+ outputDir,
1216
+ artifactsFolderName(result.workerIndex),
1217
+ "traces",
1218
+ `${(_b2 = item.testCase) == null ? void 0 : _b2.id}.json`
1219
+ ].join(pathSeparator);
1220
+ pollTimer.current = setTimeout(async () => {
1221
+ try {
1222
+ const model2 = await loadSingleTraceFile(traceLocation);
1223
+ setModel({ model: model2, isLive: true });
1224
+ } catch {
1225
+ setModel(void 0);
1226
+ } finally {
1227
+ setCounter(counter + 1);
1228
+ }
1229
+ }, 500);
1230
+ return () => {
1231
+ if (pollTimer.current)
1232
+ clearTimeout(pollTimer.current);
1233
+ };
1234
+ }, [outputDir, item, setModel, counter, setCounter, pathSeparator]);
1235
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
1236
+ Workbench,
1237
+ {
1238
+ model: model == null ? void 0 : model.model,
1239
+ showSourcesFirst: true,
1240
+ rootDir,
1241
+ fallbackLocation: item.testFile,
1242
+ isLive: model == null ? void 0 : model.isLive,
1243
+ status: (_a = item.treeItem) == null ? void 0 : _a.status,
1244
+ annotations: ((_b = item.testCase) == null ? void 0 : _b.annotations) || [],
1245
+ onOpenExternally,
1246
+ revealSource
1247
+ },
1248
+ "workbench"
1249
+ );
1250
+ };
1251
+ const outputDirForTestCase = (testCase) => {
1252
+ var _a;
1253
+ for (let suite = testCase.parent; suite; suite = suite.parent) {
1254
+ if (suite.project())
1255
+ return (_a = suite.project()) == null ? void 0 : _a.outputDir;
1256
+ }
1257
+ return void 0;
1258
+ };
1259
+ async function loadSingleTraceFile(url) {
1260
+ const params = new URLSearchParams();
1261
+ params.set("trace", url);
1262
+ params.set("limit", "1");
1263
+ const response = await fetch(`contexts?${params.toString()}`);
1264
+ const contextEntries = await response.json();
1265
+ return new MultiTraceModel(contextEntries);
1266
+ }
1267
+ let xtermSize = { cols: 80 };
1268
+ const xtermDataSource = {
1269
+ pending: [],
1270
+ clear: () => {
1271
+ },
1272
+ write: (data) => xtermDataSource.pending.push(data),
1273
+ resize: () => {
1274
+ }
1275
+ };
1276
+ const searchParams = new URLSearchParams(window.location.search);
1277
+ const testServerBaseUrl = new URL(searchParams.get("server") ?? "../", window.location.href);
1278
+ const wsURL = new URL(searchParams.get("ws"), testServerBaseUrl);
1279
+ wsURL.protocol = wsURL.protocol === "https:" ? "wss:" : "ws:";
1280
+ const queryParams = {
1281
+ args: searchParams.getAll("arg"),
1282
+ grep: searchParams.get("grep") || void 0,
1283
+ grepInvert: searchParams.get("grepInvert") || void 0,
1284
+ projects: searchParams.getAll("project"),
1285
+ workers: searchParams.get("workers") || void 0,
1286
+ headed: searchParams.has("headed"),
1287
+ updateSnapshots: searchParams.get("updateSnapshots") || void 0,
1288
+ reporters: searchParams.has("reporter") ? searchParams.getAll("reporter") : void 0,
1289
+ pathSeparator: searchParams.get("pathSeparator") || "/"
1290
+ };
1291
+ if (queryParams.updateSnapshots && !["all", "none", "missing"].includes(queryParams.updateSnapshots))
1292
+ queryParams.updateSnapshots = void 0;
1293
+ const isMac = navigator.platform === "MacIntel";
1294
+ const UIModeView = ({}) => {
1295
+ var _a;
1296
+ const [filterText, setFilterText] = React.useState("");
1297
+ const [isShowingOutput, setIsShowingOutput] = React.useState(false);
1298
+ const [outputContainsError, setOutputContainsError] = React.useState(false);
1299
+ const [statusFilters, setStatusFilters] = React.useState(/* @__PURE__ */ new Map([
1300
+ ["passed", false],
1301
+ ["failed", false],
1302
+ ["skipped", false]
1303
+ ]));
1304
+ const [projectFilters, setProjectFilters] = React.useState(/* @__PURE__ */ new Map());
1305
+ const [testModel, setTestModel] = React.useState();
1306
+ const [progress, setProgress] = React.useState();
1307
+ const [selectedItem, setSelectedItem] = React.useState({});
1308
+ const [visibleTestIds, setVisibleTestIds] = React.useState(/* @__PURE__ */ new Set());
1309
+ const [isLoading, setIsLoading] = React.useState(false);
1310
+ const [runningState, setRunningState] = React.useState();
1311
+ const isRunningTest = runningState && !runningState.completed;
1312
+ const [watchAll, setWatchAll] = useSetting("watch-all", false);
1313
+ const [watchedTreeIds, setWatchedTreeIds] = React.useState({ value: /* @__PURE__ */ new Set() });
1314
+ const commandQueue = React.useRef(Promise.resolve());
1315
+ const runTestBacklog = React.useRef(/* @__PURE__ */ new Set());
1316
+ const [collapseAllCount, setCollapseAllCount] = React.useState(0);
1317
+ const [expandAllCount, setExpandAllCount] = React.useState(0);
1318
+ const [isDisconnected, setIsDisconnected] = React.useState(false);
1319
+ const [hasBrowsers, setHasBrowsers] = React.useState(true);
1320
+ const [testServerConnection, setTestServerConnection] = React.useState();
1321
+ const [teleSuiteUpdater, setTeleSuiteUpdater] = React.useState();
1322
+ const [settingsVisible, setSettingsVisible] = React.useState(false);
1323
+ const [testingOptionsVisible, setTestingOptionsVisible] = React.useState(false);
1324
+ const [revealSource, setRevealSource] = React.useState(false);
1325
+ const onRevealSource = React.useCallback(() => setRevealSource(true), [setRevealSource]);
1326
+ const showTestingOptions = false;
1327
+ const [singleWorker, setSingleWorker] = React.useState(false);
1328
+ const [showBrowser, setShowBrowser] = React.useState(false);
1329
+ const [updateSnapshots, setUpdateSnapshots] = React.useState(false);
1330
+ const inputRef = React.useRef(null);
1331
+ const reloadTests = React.useCallback(() => {
1332
+ setTestServerConnection((prevConnection) => {
1333
+ prevConnection == null ? void 0 : prevConnection.close();
1334
+ return new TestServerConnection(new WebSocketTestServerTransport(wsURL));
1335
+ });
1336
+ }, []);
1337
+ React.useEffect(() => {
1338
+ var _a2;
1339
+ (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
1340
+ setIsLoading(true);
1341
+ reloadTests();
1342
+ }, [reloadTests]);
1343
+ React.useEffect(() => {
1344
+ if (!testServerConnection)
1345
+ return;
1346
+ const disposables = [
1347
+ testServerConnection.onStdio((params) => {
1348
+ if (params.buffer) {
1349
+ const data = atob(params.buffer);
1350
+ xtermDataSource.write(data);
1351
+ } else {
1352
+ xtermDataSource.write(params.text);
1353
+ }
1354
+ if (params.type === "stderr")
1355
+ setOutputContainsError(true);
1356
+ }),
1357
+ testServerConnection.onClose(() => setIsDisconnected(true))
1358
+ ];
1359
+ xtermDataSource.resize = (cols, rows) => {
1360
+ xtermSize = { cols, rows };
1361
+ testServerConnection.resizeTerminalNoReply({ cols, rows });
1362
+ };
1363
+ return () => {
1364
+ for (const disposable of disposables)
1365
+ disposable.dispose();
1366
+ };
1367
+ }, [testServerConnection]);
1368
+ React.useEffect(() => {
1369
+ if (!testServerConnection)
1370
+ return;
1371
+ let throttleTimer;
1372
+ const teleSuiteUpdater2 = new TeleSuiteUpdater({
1373
+ onUpdate: (immediate) => {
1374
+ clearTimeout(throttleTimer);
1375
+ throttleTimer = void 0;
1376
+ if (immediate) {
1377
+ setTestModel(teleSuiteUpdater2.asModel());
1378
+ } else if (!throttleTimer) {
1379
+ throttleTimer = setTimeout(() => {
1380
+ setTestModel(teleSuiteUpdater2.asModel());
1381
+ }, 250);
1382
+ }
1383
+ },
1384
+ onError: (error) => {
1385
+ xtermDataSource.write((error.stack || error.value || "") + "\n");
1386
+ setOutputContainsError(true);
1387
+ },
1388
+ pathSeparator: queryParams.pathSeparator
1389
+ });
1390
+ setTeleSuiteUpdater(teleSuiteUpdater2);
1391
+ setTestModel(void 0);
1392
+ setIsLoading(true);
1393
+ setWatchedTreeIds({ value: /* @__PURE__ */ new Set() });
1394
+ (async () => {
1395
+ try {
1396
+ await testServerConnection.initialize({
1397
+ interceptStdio: true,
1398
+ watchTestDirs: true
1399
+ });
1400
+ const { status, report } = await testServerConnection.runGlobalSetup({});
1401
+ teleSuiteUpdater2.processGlobalReport(report);
1402
+ if (status !== "passed")
1403
+ return;
1404
+ const result = await testServerConnection.listTests({ projects: queryParams.projects, locations: queryParams.args, grep: queryParams.grep, grepInvert: queryParams.grepInvert });
1405
+ teleSuiteUpdater2.processListReport(result.report);
1406
+ testServerConnection.onReport((params) => {
1407
+ teleSuiteUpdater2.processTestReportEvent(params);
1408
+ });
1409
+ const { hasBrowsers: hasBrowsers2 } = await testServerConnection.checkBrowsers({});
1410
+ setHasBrowsers(hasBrowsers2);
1411
+ } finally {
1412
+ setIsLoading(false);
1413
+ }
1414
+ })();
1415
+ return () => {
1416
+ clearTimeout(throttleTimer);
1417
+ };
1418
+ }, [testServerConnection]);
1419
+ React.useEffect(() => {
1420
+ if (!testModel)
1421
+ return;
1422
+ const { config, rootSuite } = testModel;
1423
+ const selectedProjects = config.configFile ? settings.getObject(config.configFile + ":projects", void 0) : void 0;
1424
+ const newFilter = new Map(projectFilters);
1425
+ for (const projectName of newFilter.keys()) {
1426
+ if (!rootSuite.suites.find((s) => s.title === projectName))
1427
+ newFilter.delete(projectName);
1428
+ }
1429
+ for (const projectSuite of rootSuite.suites) {
1430
+ if (!newFilter.has(projectSuite.title))
1431
+ newFilter.set(projectSuite.title, !!(selectedProjects == null ? void 0 : selectedProjects.includes(projectSuite.title)));
1432
+ }
1433
+ if (!selectedProjects && newFilter.size && ![...newFilter.values()].includes(true))
1434
+ newFilter.set(newFilter.entries().next().value[0], true);
1435
+ if (projectFilters.size !== newFilter.size || [...projectFilters].some(([k, v]) => newFilter.get(k) !== v))
1436
+ setProjectFilters(newFilter);
1437
+ }, [projectFilters, testModel]);
1438
+ React.useEffect(() => {
1439
+ if (isRunningTest && (testModel == null ? void 0 : testModel.progress))
1440
+ setProgress(testModel.progress);
1441
+ else if (!testModel)
1442
+ setProgress(void 0);
1443
+ }, [testModel, isRunningTest]);
1444
+ const { testTree } = React.useMemo(() => {
1445
+ if (!testModel)
1446
+ return { testTree: new TestTree("", new TeleSuite("", "root"), [], projectFilters, queryParams.pathSeparator) };
1447
+ const testTree2 = new TestTree("", testModel.rootSuite, testModel.loadErrors, projectFilters, queryParams.pathSeparator);
1448
+ testTree2.filterTree(filterText, statusFilters, isRunningTest ? runningState == null ? void 0 : runningState.testIds : void 0);
1449
+ testTree2.sortAndPropagateStatus();
1450
+ testTree2.shortenRoot();
1451
+ testTree2.flattenForSingleProject();
1452
+ setVisibleTestIds(testTree2.testIds());
1453
+ return { testTree: testTree2 };
1454
+ }, [filterText, testModel, statusFilters, projectFilters, setVisibleTestIds, runningState, isRunningTest]);
1455
+ const runTests = React.useCallback((mode, testIds) => {
1456
+ if (!testServerConnection || !testModel)
1457
+ return;
1458
+ if (mode === "bounce-if-busy" && isRunningTest)
1459
+ return;
1460
+ runTestBacklog.current = /* @__PURE__ */ new Set([...runTestBacklog.current, ...testIds]);
1461
+ commandQueue.current = commandQueue.current.then(async () => {
1462
+ var _a2, _b, _c;
1463
+ const testIds2 = runTestBacklog.current;
1464
+ runTestBacklog.current = /* @__PURE__ */ new Set();
1465
+ if (!testIds2.size)
1466
+ return;
1467
+ {
1468
+ for (const test of ((_a2 = testModel.rootSuite) == null ? void 0 : _a2.allTests()) || []) {
1469
+ if (testIds2.has(test.id)) {
1470
+ test.results = [];
1471
+ const result = test._createTestResult("pending");
1472
+ result[statusEx] = "scheduled";
1473
+ }
1474
+ }
1475
+ setTestModel({ ...testModel });
1476
+ }
1477
+ const time = " [" + (/* @__PURE__ */ new Date()).toLocaleTimeString() + "]";
1478
+ xtermDataSource.write("\x1B[2m—".repeat(Math.max(0, xtermSize.cols - time.length)) + time + "\x1B[22m");
1479
+ setProgress({ total: 0, passed: 0, failed: 0, skipped: 0 });
1480
+ setRunningState({ testIds: testIds2 });
1481
+ await testServerConnection.runTests({
1482
+ locations: queryParams.args,
1483
+ grep: queryParams.grep,
1484
+ grepInvert: queryParams.grepInvert,
1485
+ testIds: [...testIds2],
1486
+ projects: [...projectFilters].filter(([_, v]) => v).map(([p]) => p),
1487
+ ...singleWorker ? { workers: "1" } : {},
1488
+ ...showBrowser ? { headed: true } : {},
1489
+ ...updateSnapshots ? { updateSnapshots: "all" } : {},
1490
+ reporters: queryParams.reporters,
1491
+ trace: "on"
1492
+ });
1493
+ for (const test of ((_b = testModel.rootSuite) == null ? void 0 : _b.allTests()) || []) {
1494
+ if (((_c = test.results[0]) == null ? void 0 : _c.duration) === -1)
1495
+ test.results = [];
1496
+ }
1497
+ setTestModel({ ...testModel });
1498
+ setRunningState((oldState) => oldState ? { ...oldState, completed: true } : void 0);
1499
+ });
1500
+ }, [projectFilters, isRunningTest, testModel, testServerConnection, singleWorker, showBrowser, updateSnapshots]);
1501
+ React.useEffect(() => {
1502
+ if (!testServerConnection || !teleSuiteUpdater)
1503
+ return;
1504
+ const disposable = testServerConnection.onTestFilesChanged(async (params) => {
1505
+ commandQueue.current = commandQueue.current.then(async () => {
1506
+ setIsLoading(true);
1507
+ try {
1508
+ const result = await testServerConnection.listTests({ projects: queryParams.projects, locations: queryParams.args, grep: queryParams.grep, grepInvert: queryParams.grepInvert });
1509
+ teleSuiteUpdater.processListReport(result.report);
1510
+ } catch (e) {
1511
+ console.log(e);
1512
+ } finally {
1513
+ setIsLoading(false);
1514
+ }
1515
+ });
1516
+ await commandQueue.current;
1517
+ if (params.testFiles.length === 0)
1518
+ return;
1519
+ const testModel2 = teleSuiteUpdater.asModel();
1520
+ const testTree2 = new TestTree("", testModel2.rootSuite, testModel2.loadErrors, projectFilters, queryParams.pathSeparator);
1521
+ const testIds = [];
1522
+ const set = new Set(params.testFiles);
1523
+ if (watchAll) {
1524
+ const visit = (treeItem) => {
1525
+ const fileName = treeItem.location.file;
1526
+ if (fileName && set.has(fileName))
1527
+ testIds.push(...testTree2.collectTestIds(treeItem));
1528
+ if (treeItem.kind === "group" && treeItem.subKind === "folder")
1529
+ treeItem.children.forEach(visit);
1530
+ };
1531
+ visit(testTree2.rootItem);
1532
+ } else {
1533
+ for (const treeId of watchedTreeIds.value) {
1534
+ const treeItem = testTree2.treeItemById(treeId);
1535
+ const fileName = treeItem == null ? void 0 : treeItem.location.file;
1536
+ if (fileName && set.has(fileName))
1537
+ testIds.push(...testTree2.collectTestIds(treeItem));
1538
+ }
1539
+ }
1540
+ runTests("queue-if-busy", new Set(testIds));
1541
+ });
1542
+ return () => disposable.dispose();
1543
+ }, [runTests, testServerConnection, watchAll, watchedTreeIds, teleSuiteUpdater, projectFilters]);
1544
+ React.useEffect(() => {
1545
+ if (!testServerConnection)
1546
+ return;
1547
+ const onShortcutEvent = (e) => {
1548
+ if (e.code === "Backquote" && e.ctrlKey) {
1549
+ e.preventDefault();
1550
+ setIsShowingOutput(!isShowingOutput);
1551
+ } else if (e.code === "F5" && e.shiftKey) {
1552
+ e.preventDefault();
1553
+ testServerConnection == null ? void 0 : testServerConnection.stopTestsNoReply({});
1554
+ } else if (e.code === "F5") {
1555
+ e.preventDefault();
1556
+ runTests("bounce-if-busy", visibleTestIds);
1557
+ }
1558
+ };
1559
+ addEventListener("keydown", onShortcutEvent);
1560
+ return () => {
1561
+ removeEventListener("keydown", onShortcutEvent);
1562
+ };
1563
+ }, [runTests, reloadTests, testServerConnection, visibleTestIds, isShowingOutput]);
1564
+ const dialogRef = React.useRef(null);
1565
+ const openInstallDialog = React.useCallback((e) => {
1566
+ var _a2;
1567
+ e.preventDefault();
1568
+ e.stopPropagation();
1569
+ (_a2 = dialogRef.current) == null ? void 0 : _a2.showModal();
1570
+ }, []);
1571
+ const closeInstallDialog = React.useCallback((e) => {
1572
+ var _a2;
1573
+ e.preventDefault();
1574
+ e.stopPropagation();
1575
+ (_a2 = dialogRef.current) == null ? void 0 : _a2.close();
1576
+ }, []);
1577
+ const installBrowsers = React.useCallback((e) => {
1578
+ closeInstallDialog(e);
1579
+ setIsShowingOutput(true);
1580
+ testServerConnection == null ? void 0 : testServerConnection.installBrowsers({}).then(async () => {
1581
+ setIsShowingOutput(false);
1582
+ const { hasBrowsers: hasBrowsers2 } = await (testServerConnection == null ? void 0 : testServerConnection.checkBrowsers({}));
1583
+ setHasBrowsers(hasBrowsers2);
1584
+ });
1585
+ }, [closeInstallDialog, testServerConnection]);
1586
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(LLMProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "vbox ui-mode", children: [
1587
+ !hasBrowsers && /* @__PURE__ */ jsxRuntimeExports.jsxs("dialog", { ref: dialogRef, children: [
1588
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "title", children: [
1589
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "codicon codicon-lightbulb" }),
1590
+ "Install browsers"
1591
+ ] }),
1592
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "body", children: [
1593
+ "Playwright did not find installed browsers.",
1594
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
1595
+ "Would you like to run `playwright install`?",
1596
+ /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}),
1597
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "button", onClick: installBrowsers, children: "Install" }),
1598
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "button secondary", onClick: closeInstallDialog, children: "Dismiss" })
1599
+ ] })
1600
+ ] }),
1601
+ isDisconnected && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "disconnected", children: [
1602
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "title", children: "UI Mode disconnected" }),
1603
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1604
+ /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href: "#", onClick: () => window.location.href = "/", children: "Reload the page" }),
1605
+ " to reconnect"
1606
+ ] })
1607
+ ] }),
1608
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1609
+ SplitView,
1610
+ {
1611
+ sidebarSize: 250,
1612
+ minSidebarSize: 150,
1613
+ orientation: "horizontal",
1614
+ sidebarIsFirst: true,
1615
+ settingName: "testListSidebar",
1616
+ main: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "vbox", children: [
1617
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: clsx("vbox", !isShowingOutput && "hidden"), children: [
1618
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Toolbar, { children: [
1619
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "section-title", style: { flex: "none" }, children: "Output" }),
1620
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "circle-slash", title: "Clear output", onClick: () => {
1621
+ xtermDataSource.clear();
1622
+ setOutputContainsError(false);
1623
+ } }),
1624
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "spacer" }),
1625
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "close", title: "Close", onClick: () => setIsShowingOutput(false) })
1626
+ ] }),
1627
+ /* @__PURE__ */ jsxRuntimeExports.jsx(XtermWrapper, { source: xtermDataSource })
1628
+ ] }),
1629
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: clsx("vbox", isShowingOutput && "hidden"), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1630
+ TraceView,
1631
+ {
1632
+ pathSeparator: queryParams.pathSeparator,
1633
+ item: selectedItem,
1634
+ rootDir: (_a = testModel == null ? void 0 : testModel.config) == null ? void 0 : _a.rootDir,
1635
+ revealSource,
1636
+ onOpenExternally: (location) => testServerConnection == null ? void 0 : testServerConnection.openNoReply({ location: { file: location.file, line: location.line, column: location.column } })
1637
+ }
1638
+ ) })
1639
+ ] }),
1640
+ sidebar: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "vbox ui-mode-sidebar", children: [
1641
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Toolbar, { noShadow: true, noMinHeight: true, children: [
1642
+ /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: "playwright-logo.svg", alt: "Playwright logo" }),
1643
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "section-title", children: "Playwright" }),
1644
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "refresh", title: "Reload", onClick: () => reloadTests(), disabled: isRunningTest || isLoading }),
1645
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { position: "relative" }, children: [
1646
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "terminal", title: "Toggle output — " + (isMac ? "⌃`" : "Ctrl + `"), toggled: isShowingOutput, onClick: () => {
1647
+ setIsShowingOutput(!isShowingOutput);
1648
+ } }),
1649
+ outputContainsError && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { title: "Output contains error", style: { position: "absolute", top: 2, right: 2, width: 7, height: 7, borderRadius: "50%", backgroundColor: "var(--vscode-notificationsErrorIcon-foreground)" } })
1650
+ ] }),
1651
+ !hasBrowsers && /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "lightbulb-autofix", style: { color: "var(--vscode-list-warningForeground)" }, title: "Playwright browsers are missing", onClick: openInstallDialog })
1652
+ ] }),
1653
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1654
+ FiltersView,
1655
+ {
1656
+ filterText,
1657
+ setFilterText,
1658
+ statusFilters,
1659
+ setStatusFilters,
1660
+ projectFilters,
1661
+ setProjectFilters,
1662
+ testModel,
1663
+ runTests: () => runTests("bounce-if-busy", visibleTestIds)
1664
+ }
1665
+ ),
1666
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Toolbar, { noMinHeight: true, children: [
1667
+ !isRunningTest && !progress && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "section-title", children: "Tests" }),
1668
+ !isRunningTest && progress && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { "data-testid": "status-line", className: "status-line", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1669
+ progress.passed,
1670
+ "/",
1671
+ progress.total,
1672
+ " passed (",
1673
+ progress.passed / progress.total * 100 | 0,
1674
+ "%)"
1675
+ ] }) }),
1676
+ isRunningTest && progress && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { "data-testid": "status-line", className: "status-line", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1677
+ "Running ",
1678
+ progress.passed,
1679
+ "/",
1680
+ runningState.testIds.size,
1681
+ " passed (",
1682
+ progress.passed / runningState.testIds.size * 100 | 0,
1683
+ "%)"
1684
+ ] }) }),
1685
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "play", title: "Run all — F5", onClick: () => runTests("bounce-if-busy", visibleTestIds), disabled: isRunningTest || isLoading }),
1686
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "debug-stop", title: "Stop — " + (isMac ? "⇧F5" : "Shift + F5"), onClick: () => testServerConnection == null ? void 0 : testServerConnection.stopTests({}), disabled: !isRunningTest || isLoading }),
1687
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "eye", title: "Watch all", toggled: watchAll, onClick: () => {
1688
+ setWatchedTreeIds({ value: /* @__PURE__ */ new Set() });
1689
+ setWatchAll(!watchAll);
1690
+ } }),
1691
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "collapse-all", title: "Collapse all", onClick: () => {
1692
+ setCollapseAllCount(collapseAllCount + 1);
1693
+ } }),
1694
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ToolbarButton, { icon: "expand-all", title: "Expand all", onClick: () => {
1695
+ setExpandAllCount(expandAllCount + 1);
1696
+ } })
1697
+ ] }),
1698
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1699
+ TestListView,
1700
+ {
1701
+ filterText,
1702
+ testModel,
1703
+ testTree,
1704
+ testServerConnection,
1705
+ runningState,
1706
+ runTests,
1707
+ onItemSelected: setSelectedItem,
1708
+ watchAll,
1709
+ watchedTreeIds,
1710
+ setWatchedTreeIds,
1711
+ isLoading,
1712
+ requestedCollapseAllCount: collapseAllCount,
1713
+ requestedExpandAllCount: expandAllCount,
1714
+ setFilterText,
1715
+ onRevealSource
1716
+ }
1717
+ ),
1718
+ showTestingOptions,
1719
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Toolbar, { noShadow: true, noMinHeight: true, className: "settings-toolbar", onClick: () => setSettingsVisible(!settingsVisible), children: [
1720
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
1721
+ "span",
1722
+ {
1723
+ className: `codicon codicon-${settingsVisible ? "chevron-down" : "chevron-right"}`,
1724
+ style: { marginLeft: 5 },
1725
+ title: settingsVisible ? "Hide Settings" : "Show Settings"
1726
+ }
1727
+ ),
1728
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "section-title", children: "Settings" })
1729
+ ] }),
1730
+ settingsVisible && /* @__PURE__ */ jsxRuntimeExports.jsx(DefaultSettingsView, {})
1731
+ ] })
1732
+ }
1733
+ )
1734
+ ] }) });
1735
+ };
1736
+ (async () => {
1737
+ applyTheme();
1738
+ if (window.location.protocol !== "file:") {
1739
+ if (window.location.href.includes("isUnderTest=true"))
1740
+ await new Promise((f) => setTimeout(f, 1e3));
1741
+ if (!navigator.serviceWorker)
1742
+ throw new Error(`Service workers are not supported.
1743
+ Make sure to serve the website (${window.location}) via HTTPS or localhost.`);
1744
+ navigator.serviceWorker.register("sw.bundle.js");
1745
+ if (!navigator.serviceWorker.controller) {
1746
+ await new Promise((f) => {
1747
+ navigator.serviceWorker.oncontrollerchange = () => f();
1748
+ });
1749
+ }
1750
+ setInterval(function() {
1751
+ fetch("ping");
1752
+ }, 1e4);
1753
+ }
1754
+ clientExports.createRoot(document.querySelector("#root")).render(/* @__PURE__ */ jsxRuntimeExports.jsx(UIModeView, {}));
1755
+ })();
1756
+ //# sourceMappingURL=uiMode.C9_OcpPU.js.map