|
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 testTree_exports = {}; |
|
20
|
__export(testTree_exports, { |
|
21
|
TestTree: () => TestTree, |
|
22
|
sortAndPropagateStatus: () => sortAndPropagateStatus, |
|
23
|
statusEx: () => statusEx |
|
24
|
}); |
|
25
|
module.exports = __toCommonJS(testTree_exports); |
|
26
|
class TestTree { |
|
27
|
constructor(rootFolder, rootSuite, loadErrors, projectFilters, pathSeparator, hideFiles) { |
|
28
|
this._treeItemById = /* @__PURE__ */ new Map(); |
|
29
|
this._treeItemByTestId = /* @__PURE__ */ new Map(); |
|
30
|
const filterProjects = projectFilters && [...projectFilters.values()].some(Boolean); |
|
31
|
this.pathSeparator = pathSeparator; |
|
32
|
this.rootItem = { |
|
33
|
kind: "group", |
|
34
|
subKind: "folder", |
|
35
|
id: rootFolder, |
|
36
|
title: "", |
|
37
|
location: { file: "", line: 0, column: 0 }, |
|
38
|
duration: 0, |
|
39
|
parent: void 0, |
|
40
|
children: [], |
|
41
|
status: "none", |
|
42
|
hasLoadErrors: false |
|
43
|
}; |
|
44
|
this._treeItemById.set(rootFolder, this.rootItem); |
|
45
|
const visitSuite = (project, parentSuite, parentGroup, mode) => { |
|
46
|
for (const suite of mode === "tests" ? [] : parentSuite.suites) { |
|
47
|
if (!suite.title) { |
|
48
|
visitSuite(project, suite, parentGroup, "all"); |
|
49
|
continue; |
|
50
|
} |
|
51
|
let group = parentGroup.children.find((item) => item.kind === "group" && item.title === suite.title); |
|
52
|
if (!group) { |
|
53
|
group = { |
|
54
|
kind: "group", |
|
55
|
subKind: "describe", |
|
56
|
id: "suite:" + parentSuite.titlePath().join("") + "" + suite.title, |
|
57
|
// account for anonymous suites |
|
58
|
title: suite.title, |
|
59
|
location: suite.location, |
|
60
|
duration: 0, |
|
61
|
parent: parentGroup, |
|
62
|
children: [], |
|
63
|
status: "none", |
|
64
|
hasLoadErrors: false |
|
65
|
}; |
|
66
|
this._addChild(parentGroup, group); |
|
67
|
} |
|
68
|
visitSuite(project, suite, group, "all"); |
|
69
|
} |
|
70
|
for (const test of mode === "suites" ? [] : parentSuite.tests) { |
|
71
|
const title = test.title; |
|
72
|
let testCaseItem = parentGroup.children.find((t) => t.kind !== "group" && t.title === title); |
|
73
|
if (!testCaseItem) { |
|
74
|
testCaseItem = { |
|
75
|
kind: "case", |
|
76
|
id: "test:" + test.titlePath().join(""), |
|
77
|
title, |
|
78
|
parent: parentGroup, |
|
79
|
children: [], |
|
80
|
tests: [], |
|
81
|
location: test.location, |
|
82
|
duration: 0, |
|
83
|
status: "none", |
|
84
|
project: void 0, |
|
85
|
test: void 0, |
|
86
|
tags: test.tags |
|
87
|
}; |
|
88
|
this._addChild(parentGroup, testCaseItem); |
|
89
|
} |
|
90
|
const result = test.results[0]; |
|
91
|
let status = "none"; |
|
92
|
if (result?.[statusEx] === "scheduled") |
|
93
|
status = "scheduled"; |
|
94
|
else if (result?.[statusEx] === "running") |
|
95
|
status = "running"; |
|
96
|
else if (result?.status === "skipped") |
|
97
|
status = "skipped"; |
|
98
|
else if (result?.status === "interrupted") |
|
99
|
status = "none"; |
|
100
|
else if (result && test.outcome() !== "expected") |
|
101
|
status = "failed"; |
|
102
|
else if (result && test.outcome() === "expected") |
|
103
|
status = "passed"; |
|
104
|
testCaseItem.tests.push(test); |
|
105
|
const testItem = { |
|
106
|
kind: "test", |
|
107
|
id: test.id, |
|
108
|
title: project.name, |
|
109
|
location: test.location, |
|
110
|
test, |
|
111
|
parent: testCaseItem, |
|
112
|
children: [], |
|
113
|
status, |
|
114
|
duration: test.results.length ? Math.max(0, test.results[0].duration) : 0, |
|
115
|
project |
|
116
|
}; |
|
117
|
this._addChild(testCaseItem, testItem); |
|
118
|
this._treeItemByTestId.set(test.id, testItem); |
|
119
|
testCaseItem.duration = testCaseItem.children.reduce((a, b) => a + b.duration, 0); |
|
120
|
} |
|
121
|
}; |
|
122
|
for (const projectSuite of rootSuite?.suites || []) { |
|
123
|
if (filterProjects && !projectFilters.get(projectSuite.title)) |
|
124
|
continue; |
|
125
|
for (const fileSuite of projectSuite.suites) { |
|
126
|
if (hideFiles) { |
|
127
|
visitSuite(projectSuite.project(), fileSuite, this.rootItem, "suites"); |
|
128
|
if (fileSuite.tests.length) { |
|
129
|
const defaultDescribeItem = this._defaultDescribeItem(); |
|
130
|
visitSuite(projectSuite.project(), fileSuite, defaultDescribeItem, "tests"); |
|
131
|
} |
|
132
|
} else { |
|
133
|
const fileItem = this._fileItem(fileSuite.location.file.split(pathSeparator), true); |
|
134
|
visitSuite(projectSuite.project(), fileSuite, fileItem, "all"); |
|
135
|
} |
|
136
|
} |
|
137
|
} |
|
138
|
for (const loadError of loadErrors) { |
|
139
|
if (!loadError.location) |
|
140
|
continue; |
|
141
|
const fileItem = this._fileItem(loadError.location.file.split(pathSeparator), true); |
|
142
|
fileItem.hasLoadErrors = true; |
|
143
|
} |
|
144
|
} |
|
145
|
_addChild(parent, child) { |
|
146
|
parent.children.push(child); |
|
147
|
child.parent = parent; |
|
148
|
this._treeItemById.set(child.id, child); |
|
149
|
} |
|
150
|
filterTree(filterText, statusFilters, runningTestIds) { |
|
151
|
const tokens = filterText.trim().toLowerCase().split(" "); |
|
152
|
const filtersStatuses = [...statusFilters.values()].some(Boolean); |
|
153
|
const filter = (testCase) => { |
|
154
|
const titleWithTags = [...testCase.tests[0].titlePath(), ...testCase.tests[0].tags].join(" ").toLowerCase(); |
|
155
|
if (!tokens.every((token) => titleWithTags.includes(token)) && !testCase.tests.some((t) => runningTestIds?.has(t.id))) |
|
156
|
return false; |
|
157
|
testCase.children = testCase.children.filter((test) => { |
|
158
|
return !filtersStatuses || runningTestIds?.has(test.test.id) || statusFilters.get(test.status); |
|
159
|
}); |
|
160
|
testCase.tests = testCase.children.map((c) => c.test); |
|
161
|
return !!testCase.children.length; |
|
162
|
}; |
|
163
|
const visit = (treeItem) => { |
|
164
|
const newChildren = []; |
|
165
|
for (const child of treeItem.children) { |
|
166
|
if (child.kind === "case") { |
|
167
|
if (filter(child)) |
|
168
|
newChildren.push(child); |
|
169
|
} else { |
|
170
|
visit(child); |
|
171
|
if (child.children.length || child.hasLoadErrors) |
|
172
|
newChildren.push(child); |
|
173
|
} |
|
174
|
} |
|
175
|
treeItem.children = newChildren; |
|
176
|
}; |
|
177
|
visit(this.rootItem); |
|
178
|
} |
|
179
|
_fileItem(filePath, isFile) { |
|
180
|
if (filePath.length === 0) |
|
181
|
return this.rootItem; |
|
182
|
const fileName = filePath.join(this.pathSeparator); |
|
183
|
const existingFileItem = this._treeItemById.get(fileName); |
|
184
|
if (existingFileItem) |
|
185
|
return existingFileItem; |
|
186
|
const parentFileItem = this._fileItem(filePath.slice(0, filePath.length - 1), false); |
|
187
|
const fileItem = { |
|
188
|
kind: "group", |
|
189
|
subKind: isFile ? "file" : "folder", |
|
190
|
id: fileName, |
|
191
|
title: filePath[filePath.length - 1], |
|
192
|
location: { file: fileName, line: 0, column: 0 }, |
|
193
|
duration: 0, |
|
194
|
parent: parentFileItem, |
|
195
|
children: [], |
|
196
|
status: "none", |
|
197
|
hasLoadErrors: false |
|
198
|
}; |
|
199
|
this._addChild(parentFileItem, fileItem); |
|
200
|
return fileItem; |
|
201
|
} |
|
202
|
_defaultDescribeItem() { |
|
203
|
let defaultDescribeItem = this._treeItemById.get("<anonymous>"); |
|
204
|
if (!defaultDescribeItem) { |
|
205
|
defaultDescribeItem = { |
|
206
|
kind: "group", |
|
207
|
subKind: "describe", |
|
208
|
id: "<anonymous>", |
|
209
|
title: "<anonymous>", |
|
210
|
location: { file: "", line: 0, column: 0 }, |
|
211
|
duration: 0, |
|
212
|
parent: this.rootItem, |
|
213
|
children: [], |
|
214
|
status: "none", |
|
215
|
hasLoadErrors: false |
|
216
|
}; |
|
217
|
this._addChild(this.rootItem, defaultDescribeItem); |
|
218
|
} |
|
219
|
return defaultDescribeItem; |
|
220
|
} |
|
221
|
sortAndPropagateStatus() { |
|
222
|
sortAndPropagateStatus(this.rootItem); |
|
223
|
} |
|
224
|
flattenForSingleProject() { |
|
225
|
const visit = (treeItem) => { |
|
226
|
if (treeItem.kind === "case" && treeItem.children.length === 1) { |
|
227
|
treeItem.project = treeItem.children[0].project; |
|
228
|
treeItem.test = treeItem.children[0].test; |
|
229
|
treeItem.children = []; |
|
230
|
this._treeItemByTestId.set(treeItem.test.id, treeItem); |
|
231
|
} else { |
|
232
|
treeItem.children.forEach(visit); |
|
233
|
} |
|
234
|
}; |
|
235
|
visit(this.rootItem); |
|
236
|
} |
|
237
|
shortenRoot() { |
|
238
|
let shortRoot = this.rootItem; |
|
239
|
while (shortRoot.children.length === 1 && shortRoot.children[0].kind === "group" && shortRoot.children[0].subKind === "folder") |
|
240
|
shortRoot = shortRoot.children[0]; |
|
241
|
shortRoot.location = this.rootItem.location; |
|
242
|
this.rootItem = shortRoot; |
|
243
|
} |
|
244
|
fileNames() { |
|
245
|
const result = /* @__PURE__ */ new Set(); |
|
246
|
const visit = (treeItem) => { |
|
247
|
if (treeItem.kind === "group" && treeItem.subKind === "file") |
|
248
|
result.add(treeItem.id); |
|
249
|
else |
|
250
|
treeItem.children.forEach(visit); |
|
251
|
}; |
|
252
|
visit(this.rootItem); |
|
253
|
return [...result]; |
|
254
|
} |
|
255
|
flatTreeItems() { |
|
256
|
const result = []; |
|
257
|
const visit = (treeItem) => { |
|
258
|
result.push(treeItem); |
|
259
|
treeItem.children.forEach(visit); |
|
260
|
}; |
|
261
|
visit(this.rootItem); |
|
262
|
return result; |
|
263
|
} |
|
264
|
treeItemById(id) { |
|
265
|
return this._treeItemById.get(id); |
|
266
|
} |
|
267
|
collectTestIds(treeItem) { |
|
268
|
return collectTestIds(treeItem); |
|
269
|
} |
|
270
|
} |
|
271
|
function sortAndPropagateStatus(treeItem) { |
|
272
|
for (const child of treeItem.children) |
|
273
|
sortAndPropagateStatus(child); |
|
274
|
if (treeItem.kind === "group") { |
|
275
|
treeItem.children.sort((a, b) => { |
|
276
|
const fc = a.location.file.localeCompare(b.location.file); |
|
277
|
return fc || a.location.line - b.location.line; |
|
278
|
}); |
|
279
|
} |
|
280
|
let allPassed = treeItem.children.length > 0; |
|
281
|
let allSkipped = treeItem.children.length > 0; |
|
282
|
let hasFailed = false; |
|
283
|
let hasRunning = false; |
|
284
|
let hasScheduled = false; |
|
285
|
for (const child of treeItem.children) { |
|
286
|
allSkipped = allSkipped && child.status === "skipped"; |
|
287
|
allPassed = allPassed && (child.status === "passed" || child.status === "skipped"); |
|
288
|
hasFailed = hasFailed || child.status === "failed"; |
|
289
|
hasRunning = hasRunning || child.status === "running"; |
|
290
|
hasScheduled = hasScheduled || child.status === "scheduled"; |
|
291
|
} |
|
292
|
if (hasRunning) |
|
293
|
treeItem.status = "running"; |
|
294
|
else if (hasScheduled) |
|
295
|
treeItem.status = "scheduled"; |
|
296
|
else if (hasFailed) |
|
297
|
treeItem.status = "failed"; |
|
298
|
else if (allSkipped) |
|
299
|
treeItem.status = "skipped"; |
|
300
|
else if (allPassed) |
|
301
|
treeItem.status = "passed"; |
|
302
|
} |
|
303
|
function collectTestIds(treeItem) { |
|
304
|
const testIds = /* @__PURE__ */ new Set(); |
|
305
|
const locations = /* @__PURE__ */ new Set(); |
|
306
|
const visit = (treeItem2) => { |
|
307
|
if (treeItem2.kind !== "test" && treeItem2.kind !== "case") { |
|
308
|
treeItem2.children.forEach(visit); |
|
309
|
return; |
|
310
|
} |
|
311
|
let fileItem = treeItem2; |
|
312
|
while (fileItem && fileItem.parent && !(fileItem.kind === "group" && fileItem.subKind === "file")) |
|
313
|
fileItem = fileItem.parent; |
|
314
|
locations.add(fileItem.location.file); |
|
315
|
if (treeItem2.kind === "case") |
|
316
|
treeItem2.tests.forEach((test) => testIds.add(test.id)); |
|
317
|
else |
|
318
|
testIds.add(treeItem2.id); |
|
319
|
}; |
|
320
|
visit(treeItem); |
|
321
|
return { testIds, locations }; |
|
322
|
} |
|
323
|
const statusEx = Symbol("statusEx"); |
|
324
|
// Annotate the CommonJS export names for ESM import in node: |
|
325
|
0 && (module.exports = { |
|
326
|
TestTree, |
|
327
|
sortAndPropagateStatus, |
|
328
|
statusEx |
|
329
|
}); |
|
330
|
|