Skip to content

Commit 0bdaaa7

Browse files
fix: discovering last test in identical-named suites only
1 parent 7ad1de5 commit 0bdaaa7

File tree

2 files changed

+64
-11
lines changed

2 files changed

+64
-11
lines changed

src/controller.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import picomatch from "picomatch";
55
import * as vscode from "vscode";
66
import { coverageContext } from "./coverage";
77
import { DisposableStore, MutableDisposable } from "./disposable";
8+
import { ExtensionConfig } from './extension-config';
89
import { last } from "./iterable";
910
import { ICreateOpts, ItemType, getContainingItemsForFile, testMetadata } from "./metadata";
1011
import { IParsedNode, parseSource } from "./parsing";
1112
import { RunHandler, TestRunner } from "./runner";
1213
import { ISourceMapMaintainer, SourceMapStore } from "./source-map-store";
13-
import { ExtensionConfig } from './extension-config';
1414

1515
const diagnosticCollection = vscode.languages.createDiagnosticCollection("nodejs-testing-dupes");
1616

@@ -185,20 +185,31 @@ export class Controller {
185185
const add = (
186186
parent: vscode.TestItem,
187187
node: IParsedNode,
188+
id: string,
188189
start: vscode.Location,
189190
end: vscode.Location,
190191
): vscode.TestItem => {
191-
let item = parent.children.get(node.name);
192+
let item = parent.children.get(id);
192193
if (!item) {
193-
item = this.ctrl.createTestItem(node.name, node.name, start.uri);
194+
item = this.ctrl.createTestItem(id, node.name, start.uri);
194195
testMetadata.set(item, { type: ItemType.Test });
195196
parent.children.add(item);
196197
}
197198
item.range = new vscode.Range(start.range.start, end.range.end);
198199

199200
const seen = new Map<string, vscode.TestItem>();
201+
const level2Dupes = new Map<string, vscode.TestItem>();
202+
for (const [, sibling] of parent.children) {
203+
if (sibling.id == item.id || sibling.label !== node.name) {
204+
continue;
205+
}
206+
207+
for (const [, cousin] of sibling.children) {
208+
level2Dupes.set(cousin.label, cousin);
209+
}
210+
}
200211
for (const child of node.children) {
201-
const existing = seen.get(child.name);
212+
const existing = seen.get(child.name) || level2Dupes.get(child.name);
202213
const start = sourceMap.originalPositionFor(
203214
child.location.start.line,
204215
child.location.start.column,
@@ -212,7 +223,7 @@ export class Controller {
212223
continue;
213224
}
214225

215-
seen.set(child.name, add(item, child, start, end));
226+
seen.set(child.name, add(item, child, child.name, start, end));
216227
}
217228

218229
for (const [id] of item.children) {
@@ -228,6 +239,7 @@ export class Controller {
228239
// source file. This is probably a good assumption. Likewise we assume that a single
229240
// a single describe/test is not split between different files.
230241
const newTestsInFile = new Map<string, vscode.TestItem>();
242+
let nId: number = 0;
231243
for (const node of tree) {
232244
const start = sourceMap.originalPositionFor(
233245
node.location.start.line,
@@ -236,7 +248,14 @@ export class Controller {
236248
const end = sourceMap.originalPositionFor(node.location.end.line, node.location.end.column);
237249
const file = last(this.getContainingItemsForFile(start.uri, { compiledFile: uri }))!.item!;
238250
diagnosticCollection.delete(start.uri);
239-
newTestsInFile.set(node.name, add(file, node, start, end));
251+
if (newTestsInFile.has(node.name) && ["describe", "suite"].includes(node.fn)) {
252+
const id = `${node.name}#${nId++}`;
253+
newTestsInFile.set(id, add(file, node, id, start, end));
254+
}
255+
else {
256+
nId = 0;
257+
newTestsInFile.set(node.name, add(file, node, node.name, start, end));
258+
}
240259
}
241260

242261
if (previous) {

src/runner.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,33 @@ export class TestRunner implements vscode.Disposable {
9999
const concurrency = this.concurrency.value || cpus().length;
100100
const getTestByPath = (path: string[]): vscode.TestItem | undefined => {
101101
const uri = vscode.Uri.parse(path[0]);
102-
let item = last(getContainingItemsForFile(wf, ctrl, uri))!.item;
103-
if (!item) {
102+
let fileItem = last(getContainingItemsForFile(wf, ctrl, uri))!.item;
103+
if (!fileItem) {
104104
return undefined;
105105
}
106106

107-
for (let i = 1; item && i < path.length; i++) {
108-
item = item.children.get(path[i]);
107+
let item: vscode.TestItem;
108+
const searchPath = (test: vscode.TestItem, pathIndex: number) => {
109+
let id = path[pathIndex];
110+
let nId = 0;
111+
let child;
112+
do {
113+
child = test.children.get(id);
114+
if (child && path[pathIndex + 1] === undefined) {
115+
item = child;
116+
}
117+
else {
118+
child && searchPath(child, pathIndex + 1);
119+
}
120+
121+
id = `${path[pathIndex]}#${nId++}`;
122+
}
123+
while (child)
109124
}
110125

111-
return item;
126+
searchPath(fileItem, 1);
127+
128+
return item!;
112129
};
113130

114131
// inline source maps read from the runtime. These will both be definitive
@@ -422,6 +439,23 @@ export class TestRunner implements vscode.Disposable {
422439
const modernNamePatterns = nodeMajorVersion >= 22;
423440

424441
const addTestsToFileRecord = (record: IIncludeFile, queue: vscode.TestItem[]) => {
442+
//merge queue-items with the same (extended) id
443+
for (let i = 0; i < queue.length; i++) {
444+
let nId = 0;
445+
for (let j = 0; j < queue.length; j++) {
446+
if (i == j) continue;
447+
448+
if (`${queue[i].id}#${nId++}` === queue[j].id) {
449+
for (const [, child] of queue[j].children) {
450+
queue[i].children.add(child);
451+
}
452+
queue.splice(j, 1);
453+
j--;
454+
if (i > j) i--;
455+
}
456+
}
457+
}
458+
425459
record.include ??= new Set();
426460

427461
while (queue.length) {

0 commit comments

Comments
 (0)