Skip to content

Commit 01191b8

Browse files
authored
address test suite error didn't get propagated correctly issue (#1165)
1 parent 8cec4c9 commit 01191b8

File tree

2 files changed

+132
-3
lines changed

2 files changed

+132
-3
lines changed

src/test-provider/test-item-data.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export class WorkspaceRoot extends TestItemDataBase {
160160
coverage: options?.profile?.kind === vscode.TestRunProfileKind.Coverage,
161161
};
162162
}
163+
163164
discoverTest(run: JestTestRun): void {
164165
const testList = this.context.ext.testResultProvider.getTestList();
165166
// only trigger update when testList is not empty because it's possible test-list is not available yet,
@@ -294,7 +295,9 @@ export class WorkspaceRoot extends TestItemDataBase {
294295
if (event.files.length === 0) {
295296
run.write(`No tests were run.`, `new-line`);
296297
} else {
297-
event.files.forEach((f) => this.addTestFile(f, (testRoot) => testRoot.discoverTest(run)));
298+
event.files.forEach((f) =>
299+
this.addTestFile(f, (testRoot) => testRoot.onAssertionUpdate(run))
300+
);
298301
}
299302
run.end({ process: event.process, delay: 1000, reason: 'assertions-updated' });
300303
this.preventZombieProcess(event.process);
@@ -540,6 +543,15 @@ abstract class TestResultData extends TestItemDataBase {
540543
super(context, name);
541544
}
542545

546+
// TODO - we should use "unknown" state when vscode supports it
547+
// (see https://github.com/microsoft/vscode/issues/206139).
548+
resetChildrenState(run: JestTestRun, result: TestSuiteResult): void {
549+
this.forEachChild((child) => {
550+
child.updateItemState(run, result);
551+
child.resetChildrenState(run, result);
552+
});
553+
}
554+
543555
updateItemState(
544556
run: JestTestRun,
545557
result?: TestSuiteResult | TestAssertionStatus,
@@ -625,6 +637,7 @@ abstract class TestResultData extends TestItemDataBase {
625637
}
626638

627639
forEachChild(onTestData: (child: TestData) => void): void {
640+
console.log(`${this.item.id} has ${this.item.children.size} children`);
628641
this.item.children.forEach((childItem) => {
629642
const child = this.context.getData<TestData>(childItem);
630643
if (child) {
@@ -655,6 +668,20 @@ export class TestDocumentRoot extends TestResultData {
655668
return item;
656669
}
657670

671+
onAssertionUpdate(run: JestTestRun): void {
672+
// handle special case when the test results contains no assertions
673+
// (usually due to syntax error), we will need to mark the item's children
674+
// explicitly failed instead of just removing them. Due to vscode's current
675+
// implementation - removing the test item will not reset the item's status,
676+
// when they get added back again later (by the parsed source nodes), they
677+
// will inherit the previous status, which might not be correct.
678+
const suiteResult = this.context.ext.testResultProvider.getTestSuiteResult(this.item.id);
679+
if (suiteResult && isContainerEmpty(suiteResult.assertionContainer)) {
680+
this.resetChildrenState(run, suiteResult);
681+
}
682+
this.discoverTest(run);
683+
}
684+
658685
discoverTest = (run?: JestTestRun, parsedRoot?: ContainerNode<ItBlock>): void => {
659686
this.createChildItems(parsedRoot);
660687
if (run) {

tests/test-provider/test-item-data.test.ts

+104-2
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,22 @@ describe('test-item-data', () => {
156156

157157
const createAllTestItems = () => {
158158
const wsRoot = new WorkspaceRoot(context);
159-
const folder = new FolderData(context, 'dir', wsRoot.item);
160-
const uri: any = { fsPath: 'whatever' };
159+
const folder = new FolderData(context, 'tests', wsRoot.item);
160+
const uri: any = { fsPath: '/ws-1/tests/a.test.ts' };
161161
const doc = new TestDocumentRoot(context, uri, folder.item);
162162
const node: any = { fullName: 'a test', attrs: {}, data: {} };
163163
const testItem = new TestData(context, uri, node, doc.item);
164164
return { wsRoot, folder, doc, testItem };
165165
};
166+
// like createAllTestItems but with added a describe block
167+
const createTestDataTree = () => {
168+
const { wsRoot, folder, doc, testItem } = createAllTestItems();
169+
const node1: any = { fullName: 'describe', attrs: {}, data: {} };
170+
const desc = new TestData(context, doc.uri, node1, doc.item);
171+
const node2: any = { fullName: 'describe test 2', attrs: {}, data: {} };
172+
const test2 = new TestData(context, doc.uri, node2, desc.item);
173+
return { wsRoot, folder, doc, testItem, desc, test2 };
174+
};
166175

167176
beforeEach(() => {
168177
controllerMock = mockController();
@@ -1834,4 +1843,97 @@ describe('test-item-data', () => {
18341843
);
18351844
});
18361845
});
1846+
describe('onAssertionUpdate', () => {
1847+
let folder, doc, desc, testItem, test2;
1848+
beforeEach(() => {
1849+
({ folder, doc, desc, testItem, test2 } = createTestDataTree());
1850+
});
1851+
describe('when test suite failed without assertions', () => {
1852+
it("all child items should inherit the test suite's status", () => {
1853+
// address https://github.com/jest-community/vscode-jest/issues/1098
1854+
const file = '/ws-1/tests/a.test.ts';
1855+
// context.ext.testResultProvider.getTestList.mockReturnValueOnce([]);
1856+
const runMode = new RunMode({ type: 'watch' });
1857+
context.ext.settings = { runMode };
1858+
1859+
// test suite failed and there is no assertions
1860+
const testSuiteResult: any = {
1861+
status: 'KnownFail',
1862+
message: 'test file failed',
1863+
};
1864+
context.ext.testResultProvider.getTestSuiteResult.mockReturnValue(testSuiteResult);
1865+
1866+
// doc has 2 children before the test suite event
1867+
expect(doc.item.children.size).toBe(2);
1868+
1869+
// triggers testSuiteChanged event listener
1870+
contextCreateTestRunSpy.mockClear();
1871+
mockedJestTestRun.mockClear();
1872+
1873+
// mock a non-watch process that is still running
1874+
const process = {
1875+
id: 'whatever',
1876+
request: { type: 'watch-tests' },
1877+
};
1878+
context.ext.testResultProvider.events.testSuiteChanged.event.mock.calls[0][0]({
1879+
type: 'assertions-updated',
1880+
process,
1881+
files: [file],
1882+
});
1883+
1884+
// all child items should have been removed
1885+
expect(doc.item.children.size).toBe(0);
1886+
1887+
// checking item status update...
1888+
const run = mockedJestTestRun.mock.results[0].value;
1889+
1890+
// all child items should be updated regardless before being removed
1891+
expect(run.failed).toHaveBeenCalledTimes(4);
1892+
[doc.item, testItem.item, desc.item, test2.item].forEach((item) => {
1893+
expect(run.failed).toHaveBeenCalledWith(item, expect.anything());
1894+
});
1895+
1896+
expect(run.end).toHaveBeenCalledTimes(1);
1897+
});
1898+
});
1899+
it('when no test suite result found, the doc and its child items should be removed without any status update', () => {
1900+
const file = '/ws-1/tests/a.test.ts';
1901+
const runMode = new RunMode({ type: 'watch' });
1902+
context.ext.settings = { runMode };
1903+
1904+
// test suite failed and there is no assertions
1905+
context.ext.testResultProvider.getTestSuiteResult.mockReturnValue(undefined);
1906+
1907+
// doc has 2 children before the test suite event
1908+
expect(folder.item.children.size).toBe(1);
1909+
expect(doc.item.children.size).toBe(2);
1910+
1911+
// triggers testSuiteChanged event listener
1912+
contextCreateTestRunSpy.mockClear();
1913+
mockedJestTestRun.mockClear();
1914+
1915+
// mock a non-watch process that is still running
1916+
const process = {
1917+
id: 'whatever',
1918+
request: { type: 'watch-tests' },
1919+
};
1920+
context.ext.testResultProvider.events.testSuiteChanged.event.mock.calls[0][0]({
1921+
type: 'assertions-updated',
1922+
process,
1923+
files: [file],
1924+
});
1925+
1926+
// all doc's child items should have been removed but the doc itself would remain
1927+
expect(folder.item.children.size).toBe(1);
1928+
expect(doc.item.children.size).toBe(0);
1929+
1930+
// checking item status update...
1931+
const run = mockedJestTestRun.mock.results[0].value;
1932+
1933+
// no update should occur
1934+
expect(run.failed).not.toHaveBeenCalled();
1935+
1936+
expect(run.end).toHaveBeenCalledTimes(1);
1937+
});
1938+
});
18371939
});

0 commit comments

Comments
 (0)