Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions src/client/testing/testController/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,27 +175,36 @@ export async function startDiscoveryNamedPipe(
}

/**
* Detects if an error message indicates that pytest is not installed.
* @param message The error message to check
* @returns True if the error indicates pytest is not installed
* Extracts the missing module name from a ModuleNotFoundError or ImportError message.
* @param message The error message to parse
* @returns The module name if found, undefined otherwise
*/
function isPytestNotInstalledError(message: string): boolean {
return (
(message.includes('ModuleNotFoundError') && message.includes('pytest')) ||
(message.includes('No module named') && message.includes('pytest')) ||
(message.includes('ImportError') && message.includes('pytest'))
);
function extractMissingModuleName(message: string): string | undefined {
// Match patterns like:
// - No module named 'requests'
// - No module named "requests"
// - ModuleNotFoundError: No module named 'requests'
// - ImportError: No module named requests
const patterns = [/No module named ['"]([^'"]+)['"]/, /No module named (\S+)/];

for (const pattern of patterns) {
const match = message.match(pattern);
if (match) {
return match[1];
}
}
return undefined;
}

export function buildErrorNodeOptions(uri: Uri, message: string, testType: string): ErrorTestItemOptions {
let labelText = testType === 'pytest' ? 'pytest Discovery Error' : 'Unittest Discovery Error';
let errorMessage = message;

// Provide more specific error message if pytest is not installed
if (testType === 'pytest' && isPytestNotInstalledError(message)) {
labelText = 'pytest Not Installed';
errorMessage =
'pytest is not installed in the selected Python environment. Please install pytest to enable test discovery and execution.';
// Check for missing module errors and provide specific messaging
const missingModule = extractMissingModuleName(message);
if (missingModule) {
labelText = `Missing Module: ${missingModule}`;
errorMessage = `The module '${missingModule}' is not installed in the selected Python environment. Please install it to enable test discovery.`;
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,56 @@ import { expect } from 'chai';
import { Uri } from 'vscode';
import { buildErrorNodeOptions } from '../../../../client/testing/testController/common/utils';

suite('buildErrorNodeOptions - pytest not installed detection', () => {
suite('buildErrorNodeOptions - missing module detection', () => {
const workspaceUri = Uri.file('/test/workspace');

test('Should detect pytest ModuleNotFoundError and provide specific message', () => {
test('Should detect pytest ModuleNotFoundError and show missing module label', () => {
const errorMessage =
'Traceback (most recent call last):\n File "<string>", line 1, in <module>\n import pytest\nModuleNotFoundError: No module named \'pytest\'';

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'pytest');

expect(result.label).to.equal('pytest Not Installed [workspace]');
expect(result.label).to.equal('Missing Module: pytest [workspace]');
expect(result.error).to.equal(
'pytest is not installed in the selected Python environment. Please install pytest to enable test discovery and execution.',
"The module 'pytest' is not installed in the selected Python environment. Please install it to enable test discovery.",
);
});

test('Should detect pytest ImportError and provide specific message', () => {
test('Should detect pytest ImportError and show missing module label', () => {
const errorMessage = 'ImportError: No module named pytest';

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'pytest');

expect(result.label).to.equal('pytest Not Installed [workspace]');
expect(result.label).to.equal('Missing Module: pytest [workspace]');
expect(result.error).to.equal(
'pytest is not installed in the selected Python environment. Please install pytest to enable test discovery and execution.',
"The module 'pytest' is not installed in the selected Python environment. Please install it to enable test discovery.",
);
});

test('Should use generic error for non-pytest-related errors', () => {
test('Should detect other missing modules and show module name in label', () => {
const errorMessage =
"bob\\test_bob.py:3: in <module>\n import requests\nE ModuleNotFoundError: No module named 'requests'\n=========================== short test summary info";

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'pytest');

expect(result.label).to.equal('Missing Module: requests [workspace]');
expect(result.error).to.equal(
"The module 'requests' is not installed in the selected Python environment. Please install it to enable test discovery.",
);
});

test('Should detect missing module with double quotes', () => {
const errorMessage = 'ModuleNotFoundError: No module named "numpy"';

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'pytest');

expect(result.label).to.equal('Missing Module: numpy [workspace]');
expect(result.error).to.equal(
"The module 'numpy' is not installed in the selected Python environment. Please install it to enable test discovery.",
);
});

test('Should use generic error for non-module-related errors', () => {
const errorMessage = 'Some other error occurred';

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'pytest');
Expand All @@ -40,12 +63,23 @@ suite('buildErrorNodeOptions - pytest not installed detection', () => {
expect(result.error).to.equal('Some other error occurred');
});

test('Should use generic error for unittest errors', () => {
const errorMessage = "ModuleNotFoundError: No module named 'pytest'";
test('Should detect missing module for unittest errors', () => {
const errorMessage = "ModuleNotFoundError: No module named 'pandas'";

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'unittest');

expect(result.label).to.equal('Missing Module: pandas [workspace]');
expect(result.error).to.equal(
"The module 'pandas' is not installed in the selected Python environment. Please install it to enable test discovery.",
);
});

test('Should use generic error for unittest non-module errors', () => {
const errorMessage = 'Some other error occurred';

const result = buildErrorNodeOptions(workspaceUri, errorMessage, 'unittest');

expect(result.label).to.equal('Unittest Discovery Error [workspace]');
expect(result.error).to.equal("ModuleNotFoundError: No module named 'pytest'");
expect(result.error).to.equal('Some other error occurred');
});
});