in src/client/testing/testController/pytest/pytestController.ts [146:261]
await updateTestItemFromRawData(
item,
testController,
this.idToRawData,
workspaceNode.id,
rawTestData,
token,
);
}
}
} else {
const workspaceNode = getWorkspaceNode(item, this.idToRawData);
if (workspaceNode) {
testController.items.delete(workspaceNode.id);
}
}
}
return Promise.resolve();
}
public async refreshTestData(testController: TestController, uri: Uri, token?: CancellationToken): Promise<void> {
sendTelemetryEvent(EventName.UNITTEST_DISCOVERING, undefined, { tool: 'pytest' });
const workspace = this.workspaceService.getWorkspaceFolder(uri);
if (workspace) {
// Discovery is expensive. So if it is already running then use the promise
// from the last run
const previous = this.discovering.get(workspace.uri.fsPath);
if (previous) {
return previous.promise;
}
const settings = this.configService.getSettings(workspace.uri);
const options: TestDiscoveryOptions = {
workspaceFolder: workspace.uri,
cwd:
settings.testing.cwd && settings.testing.cwd.length > 0
? settings.testing.cwd
: workspace.uri.fsPath,
args: settings.testing.pytestArgs,
ignoreCache: true,
token,
};
// Get individual test directories selected by the user.
const testDirectories = pytestGetTestFolders(options.args);
// Set arguments to use with pytest discovery script.
const args = runAdapter(['discover', 'pytest', '--', ...preparePytestArgumentsForDiscovery(options)]);
// Build options for each directory selected by the user.
let discoveryRunOptions: TestDiscoveryOptions[];
if (testDirectories.length === 0) {
// User did not provide any directory. So we don't need to tweak arguments.
discoveryRunOptions = [
{
...options,
args,
},
];
} else {
discoveryRunOptions = testDirectories.map((testDir) => ({
...options,
args: [...args, testDir],
}));
}
const deferred = createDeferred<void>();
this.discovering.set(workspace.uri.fsPath, deferred);
let rawTestData: RawDiscoveredTests[] = [];
try {
// This is where we execute pytest discovery via a common helper.
rawTestData = flatten(
await Promise.all(discoveryRunOptions.map((o) => this.discoveryHelper.runTestDiscovery(o))),
);
this.testData.set(workspace.uri.fsPath, rawTestData);
// Remove error node
testController.items.delete(`DiscoveryError:${workspace.uri.fsPath}`);
deferred.resolve();
} catch (ex) {
sendTelemetryEvent(EventName.UNITTEST_DISCOVERY_DONE, undefined, { tool: 'pytest', failed: true });
const cancel = options.token?.isCancellationRequested ? 'Cancelled' : 'Error';
traceError(`${cancel} discovering pytest tests:\r\n`, ex);
const message = getTestDiscoveryExceptions((ex as Error).message);
// Report also on the test view. Getting root node is more complicated due to fact
// that in pytest project can be organized in many ways
testController.items.add(
createErrorTestItem(testController, {
id: `DiscoveryError:${workspace.uri.fsPath}`,
label: `Pytest Discovery Error [${path.basename(workspace.uri.fsPath)}]`,
error: util.format(
`${cancel} discovering pytest tests (see Output > Python):\r\n`,
message.length > 0 ? message : ex,
),
}),
);
deferred.reject(ex as Error);
} finally {
// Discovery has finished running we have the raw test data at this point.
this.discovering.delete(workspace.uri.fsPath);
}
const root = rawTestData.length === 1 ? rawTestData[0].root : workspace.uri.fsPath;
const workspaceNode = testController.items.get(root);
if (workspaceNode) {
if (uri.fsPath === workspace.uri.fsPath) {
// this is a workspace level refresh
// This is an existing workspace test node. Just update the children
await this.resolveChildren(testController, workspaceNode, token);
} else {
// This is a child node refresh
const testNode = getNodeByUri(workspaceNode, uri);
if (testNode) {