public async refreshTestData()

in src/client/testing/testController/pytest/pytestController.ts [166:284]


    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) {
                        // We found the node to update
                        await this.resolveChildren(testController, testNode, token);
                    } else {
                        // update the entire workspace tree
                        await this.resolveChildren(testController, workspaceNode, token);
                    }
                }
            } else if (rawTestData.length > 0) {
                // This is a new workspace with tests.
                const newItem = createWorkspaceRootTestItem(testController, this.idToRawData, {
                    id: root,
                    label: path.basename(root),
                    uri: Uri.file(root),
                    runId: root,
                });
                testController.items.add(newItem);

                await this.resolveChildren(testController, newItem, token);
            }
        }
        sendTelemetryEvent(EventName.UNITTEST_DISCOVERY_DONE, undefined, { tool: 'pytest', failed: false });
        return Promise.resolve();
    }