Skip to content

Commit 1523dd6

Browse files
phloosekarthiknadig
authored andcommitted
Add "Run All/Debug All" dropdown picker for parametrized tests (#8757)
* Register new command for running parametrized tests * Show "Run All" or "Debug All" in dropdown picker on parametrized tests * Use CommandSource as input to second call of getNamesAndValues In the picker unit tests two calls to getNamesAndValues are used to extract values from enums. The second call used a generic with type 'CommandSource' but as input a Type object. To be more meaningful this has been changed to 'CommandSource' so that the test checks different TestItem types against different command sources. Otherwise it would test TestItem types against TestItem types. Furthermore extracting name and value of CommandSource.commandpalette with getNamesAndValues was not successful and returned undefined. This has been fixed by assigning CommandSource.commandpalette directly to commandSource.value when this command source is evaluated. * Add test for Tests_Run_Parametrized command * Add news entry for #5608
1 parent 9449a2e commit 1523dd6

File tree

6 files changed

+56
-6
lines changed

6 files changed

+56
-6
lines changed

news/1 Enhancements/5608.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add QuickPick dropdown option _Run All/Debug All_ when clicking on a Code Lens for a parametrized test to be able to run/debug all belonging test variants at once. Thanks to [Philipp Loose](https://github.com/phloose)

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
9797
[Commands.Tests_Run]: [undefined | TestWorkspaceFolder, undefined | CommandSource, undefined | Uri, undefined | TestsToRun];
9898
// When command is invoked from a tree node, first argument is the node data.
9999
[Commands.Tests_Debug]: [undefined | TestWorkspaceFolder, undefined | CommandSource, undefined | Uri, undefined | TestsToRun];
100+
[Commands.Tests_Run_Parametrized]: [undefined, undefined | CommandSource, Uri, TestFunction[], boolean];
100101
// When command is invoked from a tree node, first argument is the node data.
101102
[Commands.Tests_Discover]: [undefined | TestWorkspaceFolder, undefined | CommandSource, undefined | Uri];
102103
[Commands.Tests_Run_Failed]: [undefined, CommandSource, Uri];

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export namespace Commands {
3232
export const Tests_Run_Failed = 'python.runFailedTests';
3333
export const Sort_Imports = 'python.sortImports';
3434
export const Tests_Run = 'python.runtests';
35+
export const Tests_Run_Parametrized = 'python.runParametrizedTests';
3536
export const Tests_Debug = 'python.debugtests';
3637
export const Tests_Ask_To_Stop_Test = 'python.askToStopTests';
3738
export const Tests_Ask_To_Stop_Discovery = 'python.askToStopTestDiscovery';

src/client/testing/display/picker.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export class TestDisplay implements ITestDisplay {
6565
return fn.parentTestFile.name === testFile.name &&
6666
testFunctions.some(testFunc => testFunc.nameToRun === fn.testFunction.nameToRun);
6767
});
68-
69-
this.appShell.showQuickPick(buildItemsForFunctions(rootDirectory, flattenedFunctions, undefined, undefined, debug),
70-
{ matchOnDescription: true, matchOnDetail: true })
68+
const runAllItem = buildRunAllParametrizedItem(flattenedFunctions, debug);
69+
const functionItems = buildItemsForFunctions(rootDirectory, flattenedFunctions, undefined, undefined, debug);
70+
this.appShell.showQuickPick(runAllItem.concat(...functionItems), { matchOnDescription: true, matchOnDetail: true })
7171
.then(testItem => testItem ? onItemSelected(this.commandManager, cmdSource, wkspace, testItem, debug) : Promise.resolve());
7272
}
7373
}
@@ -84,7 +84,8 @@ export enum Type {
8484
Null = 8,
8585
SelectAndRunMethod = 9,
8686
DebugMethod = 10,
87-
Configure = 11
87+
Configure = 11,
88+
RunParametrized = 12
8889
}
8990
const statusIconMapping = new Map<TestStatus, string>();
9091
statusIconMapping.set(TestStatus.Pass, constants.Octicons.Test_Pass);
@@ -95,6 +96,7 @@ statusIconMapping.set(TestStatus.Skipped, constants.Octicons.Test_Skip);
9596
type TestItem = QuickPickItem & {
9697
type: Type;
9798
fn?: FlattenedTestFunction;
99+
fns?: TestFunction[];
98100
};
99101

100102
type TestFileItem = QuickPickItem & {
@@ -150,6 +152,18 @@ const statusSortPrefix = {
150152
[TestStatus.Unknown]: undefined
151153
};
152154

155+
function buildRunAllParametrizedItem(tests: FlattenedTestFunction[], debug: boolean = false): TestItem[] {
156+
const testFunctions: TestFunction[] = [];
157+
tests.forEach(fn => {
158+
testFunctions.push(fn.testFunction);
159+
});
160+
return [{
161+
description: '',
162+
label: debug ? 'Debug All' : 'Run All',
163+
type: Type.RunParametrized,
164+
fns: testFunctions
165+
}];
166+
}
153167
function buildItemsForFunctions(rootDirectory: string, tests: FlattenedTestFunction[], sortBasedOnResults: boolean = false, displayStatusIcons: boolean = false, debug: boolean = false): TestItem[] {
154168
const functionItems: TestItem[] = [];
155169
tests.forEach(fn => {
@@ -218,6 +232,9 @@ export function onItemSelected(commandManager: ICommandManager, cmdSource: Comma
218232
case Type.RunAll: {
219233
return commandManager.executeCommand(constants.Commands.Tests_Run, undefined, cmdSource, wkspace, undefined);
220234
}
235+
case Type.RunParametrized: {
236+
return commandManager.executeCommand(constants.Commands.Tests_Run_Parametrized, undefined, cmdSource, wkspace, selection.fns!, debug!);
237+
}
221238
case Type.ReDiscover: {
222239
return commandManager.executeCommand(constants.Commands.Tests_Discover, undefined, cmdSource, wkspace);
223240
}

src/client/testing/main.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ export class UnitTestManagementService implements ITestManagementService, Dispos
225225
const testDisplay = this.serviceContainer.get<ITestDisplay>(ITestDisplay);
226226
testDisplay.displayFunctionTestPickerUI(cmdSource, testManager.workspaceFolder, testManager.workingDirectory, file, testFunctions, debug);
227227
}
228+
public async runParametrizedTests(cmdSource: CommandSource, resource: Uri, testFunctions: TestFunction[], debug?: boolean) {
229+
const testManager = await this.getTestManager(true, resource);
230+
if (!testManager) {
231+
return;
232+
}
233+
await this.runTestsImpl(cmdSource, resource, { testFunction: testFunctions }, undefined, debug);
234+
}
228235
public viewOutput(_cmdSource: CommandSource) {
229236
sendTelemetryEvent(EventName.UNITTEST_VIEW_OUTPUT);
230237
this.outputChannel.show();
@@ -398,6 +405,10 @@ export class UnitTestManagementService implements ITestManagementService, Dispos
398405
constants.Commands.Tests_Picker_UI_Debug,
399406
(_, cmdSource: CommandSource = CommandSource.commandPalette, file: Uri, testFunctions: TestFunction[]) => this.displayPickerUI(cmdSource, file, testFunctions, true)
400407
),
408+
commandManager.registerCommand(
409+
constants.Commands.Tests_Run_Parametrized,
410+
(_, cmdSource: CommandSource = CommandSource.commandPalette, resource: Uri, testFunctions: TestFunction[], debug: boolean) => this.runParametrizedTests(cmdSource, resource, testFunctions, debug)
411+
),
401412
commandManager.registerCommand(constants.Commands.Tests_Stop, (_, resource: Uri) => this.stopTests(resource)),
402413
commandManager.registerCommand(constants.Commands.Tests_ViewOutput, (_, cmdSource: CommandSource = CommandSource.commandPalette) => this.viewOutput(cmdSource)),
403414
commandManager.registerCommand(constants.Commands.Tests_Ask_To_Stop_Discovery, () => this.displayStopUI('Stop discovering tests')),

src/test/testing/display/picker.unit.test.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,29 @@ import { onItemSelected, Type } from '../../../client/testing/display/picker';
1616

1717
suite('Unit Tests - Picker (execution of commands)', () => {
1818
getNamesAndValues<Type>(Type).forEach(item => {
19-
getNamesAndValues<CommandSource>(Type).forEach(commandSource => {
19+
getNamesAndValues<CommandSource>(CommandSource).forEach(commandSource => {
2020
[true, false].forEach(debug => {
2121
test(`Invoking command for selection ${item.name} from ${commandSource.name} (${debug ? 'Debug' : 'No debug'})`, async () => {
2222
const commandManager = mock(CommandManager);
2323
const workspaceUri = Uri.file(__filename);
2424

2525
const testFunction = 'some test Function';
26-
const selection = { type: item.value, fn: { testFunction } };
26+
const testFunctions = [{
27+
name: 'some_name',
28+
nameToRun: 'some_name_to_run',
29+
time: 0,
30+
resource: workspaceUri
31+
}];
32+
const selection = { type: item.value, fn: { testFunction }, fns: testFunctions };
33+
34+
// Getting the value of CommandSource.commandPalette in getNamesAndValues(CommandSource)
35+
// fails because the names and values object is build by accessing the CommandSource enum
36+
// properties by value. In case of commandpalette the property is commandPalette and the
37+
// respective value is commandpalette which do not match and thus return undefined for value.
38+
if (commandSource.name === 'commandpalette') {
39+
commandSource.value = CommandSource.commandPalette;
40+
}
41+
2742
onItemSelected(instance(commandManager), commandSource.value, workspaceUri, selection as any, debug);
2843

2944
switch (selection.type) {
@@ -40,6 +55,10 @@ suite('Unit Tests - Picker (execution of commands)', () => {
4055
verify(commandManager.executeCommand(Commands.Tests_Run, undefined, commandSource.value, workspaceUri, undefined)).once();
4156
return;
4257
}
58+
case Type.RunParametrized: {
59+
verify(commandManager.executeCommand(Commands.Tests_Run_Parametrized, undefined, commandSource.value, workspaceUri, selection.fns, debug)).once();
60+
return;
61+
}
4362
case Type.ReDiscover: {
4463
verify(commandManager.executeCommand(Commands.Tests_Discover, undefined, commandSource.value, workspaceUri)).once();
4564
return;

0 commit comments

Comments
 (0)