diff --git a/src/client/testing/testController/common/resultResolver.ts b/src/client/testing/testController/common/resultResolver.ts index 8e08ffbeedf5..65969ed81c9a 100644 --- a/src/client/testing/testController/common/resultResolver.ts +++ b/src/client/testing/testController/common/resultResolver.ts @@ -65,18 +65,19 @@ export class PythonResultResolver implements ITestResultResolver { } errorNode.error = message; } else { - // Remove the error node if necessary, - // then parse and insert test data. + // remove error node only if no errors exist. this.testController.items.delete(`DiscoveryError:${workspacePath}`); + } + if (rawTestData.tests) { + // if any tests exist, they should be populated in the test tree, regardless of whether there were errors or not. + // parse and insert test data. - if (rawTestData.tests) { - // If the test root for this folder exists: Workspace refresh, update its children. - // Otherwise, it is a freshly discovered workspace, and we need to create a new test root and populate the test tree. - populateTestTree(this.testController, rawTestData.tests, undefined, this, token); - } else { - // Delete everything from the test controller. - this.testController.items.replace([]); - } + // If the test root for this folder exists: Workspace refresh, update its children. + // Otherwise, it is a freshly discovered workspace, and we need to create a new test root and populate the test tree. + populateTestTree(this.testController, rawTestData.tests, undefined, this, token); + } else { + // Delete everything from the test controller. + this.testController.items.replace([]); } sendTelemetryEvent(EventName.UNITTEST_DISCOVERY_DONE, undefined, { diff --git a/src/test/testing/testController/resultResolver.unit.test.ts b/src/test/testing/testController/resultResolver.unit.test.ts index 0fc7eb3ab353..30b2ccecf513 100644 --- a/src/test/testing/testController/resultResolver.unit.test.ts +++ b/src/test/testing/testController/resultResolver.unit.test.ts @@ -101,8 +101,7 @@ suite('Result Resolver tests', () => { cancelationToken, // token ); }); - // what about if the error node already exists: this.testController.items.get(`DiscoveryError:${workspacePath}`); - test('resolveDiscovery should create error node on error with correct params', async () => { + test('resolveDiscovery should create error node on error with correct params and no root node with tests in payload', async () => { // test specific constants used expected values testProvider = 'pytest'; workspaceUri = Uri.file('/foo/bar'); @@ -136,6 +135,61 @@ suite('Result Resolver tests', () => { // header of createErrorTestItem is (options: ErrorTestItemOptions, testController: TestController, uri: Uri) sinon.assert.calledWithMatch(createErrorTestItemStub, sinon.match.any, sinon.match.any); }); + test('resolveDiscovery should create error and root node when error and tests exist on payload', async () => { + // test specific constants used expected values + testProvider = 'pytest'; + workspaceUri = Uri.file('/foo/bar'); + resultResolver = new ResultResolver.PythonResultResolver(testController, testProvider, workspaceUri); + const errorMessage = 'error msg A'; + const expectedErrorMessage = `${defaultErrorMessage}\r\n ${errorMessage}`; + + // create test result node + const tests: DiscoveredTestNode = { + path: 'path', + name: 'name', + type_: 'folder', + id_: 'id', + children: [], + }; + // stub out return values of functions called in resolveDiscovery + const payload: DiscoveredTestPayload = { + cwd: workspaceUri.fsPath, + status: 'error', + error: [errorMessage], + tests, + }; + const errorTestItemOptions: testItemUtilities.ErrorTestItemOptions = { + id: 'id', + label: 'label', + error: 'error', + }; + + // stub out functionality of buildErrorNodeOptions and createErrorTestItem which are called in resolveDiscovery + const buildErrorNodeOptionsStub = sinon.stub(util, 'buildErrorNodeOptions').returns(errorTestItemOptions); + const createErrorTestItemStub = sinon.stub(testItemUtilities, 'createErrorTestItem').returns(blankTestItem); + + // stub out functionality of populateTestTreeStub which is called in resolveDiscovery + const populateTestTreeStub = sinon.stub(util, 'populateTestTree').returns(); + // call resolve discovery + resultResolver.resolveDiscovery(payload, cancelationToken); + + // assert the stub functions were called with the correct parameters + + // builds an error node root + sinon.assert.calledWithMatch(buildErrorNodeOptionsStub, workspaceUri, expectedErrorMessage, testProvider); + // builds an error item + sinon.assert.calledWithMatch(createErrorTestItemStub, sinon.match.any, sinon.match.any); + + // also calls populateTestTree with the discovery test results + sinon.assert.calledWithMatch( + populateTestTreeStub, + testController, // testController + tests, // testTreeData + undefined, // testRoot + resultResolver, // resultResolver + cancelationToken, // token + ); + }); }); suite('Test execution result resolver', () => { let resultResolver: ResultResolver.PythonResultResolver;