Skip to content

Commit 1a9ae7e

Browse files
committed
feat: add --group filter support for ClassFilterStrategy
- Add getGroupFilter() to FilterStrategy base class; ClassFilterStrategy includes --group flag when class has group annotations/attributes - Add #[Group('integration')] attribute to AssertionsTest.php and AttributeTest.php fixtures for parser and integration test coverage - Add extension tests: run class with group, run method with group, run at cursor with group - Update line numbers across test files for fixture changes
1 parent ebe1f92 commit 1a9ae7e

File tree

20 files changed

+284
-236
lines changed

20 files changed

+284
-236
lines changed

__mocks__/vscode.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ const Uri = new Proxy(URI, {
4343
},
4444
});
4545

46+
class FakeTestTag {
47+
readonly id: string;
48+
constructor(id: string) {
49+
this.id = id;
50+
}
51+
}
52+
4653
class FakeTestItemCollection implements Iterable<[id: string, testItem: TestItem]> {
4754
private items = new Map<string, TestItem>();
4855
private readonly parent: any;
@@ -369,4 +376,5 @@ export {
369376
StatementCoverage,
370377
DocumentLink,
371378
debug,
379+
FakeTestTag as TestTag,
372380
};

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@
6666
{
6767
"command": "phpunit.rerun",
6868
"title": "PHPUnit: Repeat the last test run"
69-
},
70-
{
71-
"command": "phpunit.run-by-group",
72-
"title": "PHPUnit: Run tests by group"
7369
}
7470
],
7571
"keybindings": [

src/Commands/TestCommandRegistry.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
TestRunRequest,
88
window,
99
} from 'vscode';
10-
import { GroupRegistry, TestCollection } from '../TestCollection';
10+
import { TestCollection } from '../TestCollection';
1111
import { TestFileDiscovery } from '../TestDiscovery';
1212
import { TestRunHandler } from '../TestExecution';
1313

@@ -76,28 +76,6 @@ export class TestCommandRegistry {
7676
});
7777
}
7878

79-
runByGroup() {
80-
return commands.registerCommand('phpunit.run-by-group', async () => {
81-
const groups = GroupRegistry.getInstance().getAll();
82-
if (groups.length === 0) {
83-
window.showInformationMessage('No PHPUnit groups found. Add @group annotations or #[Group] attributes to your tests.');
84-
return;
85-
}
86-
87-
const selectedGroup = await window.showQuickPick(groups, {
88-
placeHolder: 'Select a PHPUnit group to run',
89-
title: 'Run Tests by Group',
90-
});
91-
92-
if (!selectedGroup) {
93-
return;
94-
}
95-
96-
const cancellation = new CancellationTokenSource().token;
97-
await this.handler.startGroupTestRun(selectedGroup, cancellation);
98-
});
99-
}
100-
10179
private async run(include: readonly TestItem[] | undefined) {
10280
const cancellation = new CancellationTokenSource().token;
10381

src/Observers/OutputChannelObserver.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ describe.each(detectPhpUnitStubs())('OutputChannelObserver on $name (PHPUnit $ph
152152
` ┐ `,
153153
` ├ Failed asserting that false is true.`,
154154
` │ `,
155-
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`,
155+
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
156156
].join(EOL),
157157
),
158158
);
@@ -191,7 +191,7 @@ describe.each(detectPhpUnitStubs())('OutputChannelObserver on $name (PHPUnit $ph
191191
` ┊ 1 => 'h'${DOT}`,
192192
` ┊ ${ARRAY_CLOSE}`,
193193
` │ `,
194-
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
194+
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`,
195195
].join(EOL),
196196
),
197197
);

src/Observers/Printers/CollisionPrinter.test.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ describe('CollisionPrinter', () => {
7373
details: [
7474
{
7575
file: phpUnitProject('tests/AssertionsTest.php'),
76-
line: 22,
76+
line: 27,
7777
},
7878
],
7979
duration: 0,
@@ -87,19 +87,19 @@ describe('CollisionPrinter', () => {
8787
`❌ FAILED Recca0120\\VSCode\\Tests\\AssertionsTest > failed`,
8888
`Failed asserting that false is true.`,
8989
``,
90-
`at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`,
91-
` 18 ▕ * @depends test_passed`,
92-
` 19 ▕ */`,
93-
` 20 ▕ public function test_failed()`,
94-
` 21 ▕ {`,
95-
`➜ 22 ▕ $this->assertTrue(false);`,
96-
` 23 ▕ }`,
97-
` 24 ▕ `,
98-
` 25 ▕ public function test_is_not_same()`,
90+
`at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
91+
` 23 ▕ * @depends test_passed`,
92+
` 24 ▕ */`,
93+
` 25 ▕ public function test_failed()`,
9994
` 26 ▕ {`,
100-
` 27 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`,
95+
`➜ 27 ▕ $this->assertTrue(false);`,
96+
` 28 ▕ }`,
97+
` 29 ▕ `,
98+
` 30 ▕ public function test_is_not_same()`,
99+
` 31 ▕ {`,
100+
` 32 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`,
101101
``,
102-
`1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`,
102+
`1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
103103
``,
104104
].join(EOL),
105105
);
@@ -117,7 +117,7 @@ describe('CollisionPrinter', () => {
117117
details: [
118118
{
119119
file: phpUnitProject('tests/AssertionsTest.php'),
120-
line: 27,
120+
line: 32,
121121
},
122122
],
123123
duration: 29,
@@ -142,19 +142,19 @@ describe('CollisionPrinter', () => {
142142
` ]`,
143143
``,
144144
``,
145-
`at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
146-
` 23 ▕ }`,
147-
` 24 ▕ `,
148-
` 25 ▕ public function test_is_not_same()`,
149-
` 26 ▕ {`,
150-
`➜ 27 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`,
145+
`at ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`,
151146
` 28 ▕ }`,
152147
` 29 ▕ `,
153-
` 30 ▕ public function test_risky()`,
148+
` 30 ▕ public function test_is_not_same()`,
154149
` 31 ▕ {`,
155-
` 32 ▕ $a = 1;`,
150+
`➜ 32 ▕ $this->assertSame(['a' => 'b', 'c' => 'd'], ['e' => 'f', 'g', 'h']);`,
151+
` 33 ▕ }`,
152+
` 34 ▕ `,
153+
` 35 ▕ public function test_risky()`,
154+
` 36 ▕ {`,
155+
` 37 ▕ $a = 1;`,
156156
``,
157-
`1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
157+
`1. ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`,
158158
``,
159159
].join(EOL),
160160
);

src/Observers/Printers/PrettyPrinter.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('PrettyPrinter', () => {
6363
details: [
6464
{
6565
file: phpUnitProject('tests/AssertionsTest.php'),
66-
line: 22,
66+
line: 27,
6767
},
6868
],
6969
duration: 0,
@@ -75,7 +75,7 @@ describe('PrettyPrinter', () => {
7575
` ┐ `,
7676
` ├ Failed asserting that false is true.`,
7777
` │ `,
78-
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 22)}`,
78+
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
7979
` ┴ `,
8080
``,
8181
].join(EOL),
@@ -94,7 +94,7 @@ describe('PrettyPrinter', () => {
9494
details: [
9595
{
9696
file: phpUnitProject('tests/AssertionsTest.php'),
97-
line: 27,
97+
line: 32,
9898
},
9999
],
100100
duration: 29,
@@ -118,7 +118,7 @@ describe('PrettyPrinter', () => {
118118
` ┊ 1 => 'h',`,
119119
` ┊ ]`,
120120
` │ `,
121-
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 27)}`,
121+
` │ ${OutputFormatter.fileFormat(phpUnitProject('tests/AssertionsTest.php'), 32)}`,
122122
` ┴ `,
123123
``,
124124
].join(EOL),

src/PHPUnit/Element.test.ts

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ describe('Element Test', () => {
88
project: {
99
package: [
1010
{ file: { '@_name': 'file1.php' } },
11-
{ file: { '@_name': 'file2.php' } }
12-
]
13-
}
14-
}
11+
{ file: { '@_name': 'file2.php' } },
12+
],
13+
},
14+
},
1515
};
1616

1717
const element = new XmlElement(data);
@@ -28,17 +28,13 @@ describe('Element Test', () => {
2828
project: [
2929
{ file: { '@_name': 'file.php' } },
3030
{
31-
package: [
32-
{ file: { '@_name': 'file1.php' } },
33-
]
31+
package: [{ file: { '@_name': 'file1.php' } }],
3432
},
3533
{
36-
package: [
37-
{ file: { '@_name': 'file2.php' } }
38-
]
39-
}
40-
]
41-
}
34+
package: [{ file: { '@_name': 'file2.php' } }],
35+
},
36+
],
37+
},
4238
};
4339

4440
const element = new XmlElement(data);

src/PHPUnit/ProblemMatcher/PHPUnitProblemMatcher.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('PHPUnit ProblemMatcher Text', () => {
103103

104104
it('testFailed', () => {
105105
resultShouldBe(
106-
`##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests\\AssertionsTest.php')}:27|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`,
106+
`##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests\\AssertionsTest.php')}:32|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`,
107107
undefined,
108108
);
109109
});
@@ -118,7 +118,7 @@ describe('PHPUnit ProblemMatcher Text', () => {
118118
details: [
119119
{
120120
file: phpUnitProjectWin('tests/AssertionsTest.php'),
121-
line: 27,
121+
line: 32,
122122
},
123123
],
124124
duration: 0,
@@ -159,7 +159,7 @@ describe('PHPUnit ProblemMatcher Text', () => {
159159

160160
it('testFailed addition_provider with failed', () => {
161161
resultShouldBe(
162-
`##teamcity[testFailed name='addition_provider with data set #2' message='Failed asserting that 1 matches expected 2.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:60|n ' duration='0' type='comparisonFailure' actual='1' expected='2' flowId='8024']`,
162+
`##teamcity[testFailed name='addition_provider with data set #2' message='Failed asserting that 1 matches expected 2.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:66|n ' duration='0' type='comparisonFailure' actual='1' expected='2' flowId='8024']`,
163163
undefined,
164164
);
165165

@@ -175,7 +175,7 @@ describe('PHPUnit ProblemMatcher Text', () => {
175175
details: [
176176
{
177177
file: phpUnitProjectWin('tests/AssertionsTest.php'),
178-
line: 60,
178+
line: 66,
179179
},
180180
],
181181
type: 'comparisonFailure',

src/PHPUnit/ProblemMatcher/TestResultParser.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ describe('TestResultParser', () => {
128128
});
129129

130130
it('parse test_failed testFailed', () => {
131-
const text = `##teamcity[testFailed name='test_failed' message='Failed asserting that false is true.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:22|n ' duration='0' flowId='8024'] `;
131+
const text = `##teamcity[testFailed name='test_failed' message='Failed asserting that false is true.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:27|n ' duration='0' flowId='8024'] `;
132132

133133
expect(parse(text)).toEqual({
134134
event: TeamcityEvent.testFailed,
@@ -137,7 +137,7 @@ describe('TestResultParser', () => {
137137
details: [
138138
{
139139
file: phpUnitProjectWin('tests/AssertionsTest.php'),
140-
line: 22,
140+
line: 27,
141141
},
142142
],
143143
duration: 0,
@@ -146,7 +146,7 @@ describe('TestResultParser', () => {
146146
});
147147

148148
it('parse test_is_not_same testFailed', () => {
149-
const text = `##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:27|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`;
149+
const text = `##teamcity[testFailed name='test_is_not_same' message='Failed asserting that two arrays are identical.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:32|n ' duration='0' type='comparisonFailure' actual='Array &0 (|n |'e|' => |'f|'|n 0 => |'g|'|n 1 => |'h|'|n)' expected='Array &0 (|n |'a|' => |'b|'|n |'c|' => |'d|'|n)' flowId='8024']`;
150150

151151
expect(parse(text)).toEqual({
152152
event: TeamcityEvent.testFailed,
@@ -155,7 +155,7 @@ describe('TestResultParser', () => {
155155
details: [
156156
{
157157
file: phpUnitProjectWin('tests/AssertionsTest.php'),
158-
line: 27,
158+
line: 32,
159159
},
160160
],
161161
duration: 0,
@@ -230,7 +230,7 @@ describe('TestResultParser', () => {
230230
});
231231

232232
it('parse test_skipped testIgnored', () => {
233-
const text = `##teamcity[testIgnored name='test_skipped' message='The MySQLi extension is not available.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:45|n ' duration='0' flowId='8024']`;
233+
const text = `##teamcity[testIgnored name='test_skipped' message='The MySQLi extension is not available.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:51|n ' duration='0' flowId='8024']`;
234234

235235
expect(parse(text)).toEqual({
236236
event: TeamcityEvent.testIgnored,
@@ -239,7 +239,7 @@ describe('TestResultParser', () => {
239239
details: [
240240
{
241241
file: phpUnitProjectWin('tests/AssertionsTest.php'),
242-
line: 45,
242+
line: 51,
243243
},
244244
],
245245
duration: 0,
@@ -248,7 +248,7 @@ describe('TestResultParser', () => {
248248
});
249249

250250
it('parse test_incomplete testIgnored', () => {
251-
const text = `##teamcity[testIgnored name='test_incomplete' message='This test has not been implemented yet.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:50|n ' duration='0' flowId='8024']`;
251+
const text = `##teamcity[testIgnored name='test_incomplete' message='This test has not been implemented yet.' details=' ${phpUnitProjectWin('tests/AssertionsTest.php')}:56|n ' duration='0' flowId='8024']`;
252252

253253
expect(parse(text)).toEqual({
254254
event: TeamcityEvent.testIgnored,
@@ -257,7 +257,7 @@ describe('TestResultParser', () => {
257257
details: [
258258
{
259259
file: phpUnitProjectWin('tests/AssertionsTest.php'),
260-
line: 50,
260+
line: 56,
261261
},
262262
],
263263
duration: 0,
@@ -266,7 +266,7 @@ describe('TestResultParser', () => {
266266
});
267267

268268
it('parse test_risky testFailed', () => {
269-
const text = `##teamcity[testFailed name='test_risky' message='This test did not perform any assertions|n|n${phpUnitProjectWin('tests/AssertionsTest.php')}:30' details=' ' duration='0' flowId='8024']`;
269+
const text = `##teamcity[testFailed name='test_risky' message='This test did not perform any assertions|n|n${phpUnitProjectWin('tests/AssertionsTest.php')}:35' details=' ' duration='0' flowId='8024']`;
270270

271271
expect(parse(text)).toEqual({
272272
event: TeamcityEvent.testFailed,
@@ -275,7 +275,7 @@ describe('TestResultParser', () => {
275275
details: [
276276
{
277277
file: phpUnitProjectWin('tests/AssertionsTest.php'),
278-
line: 30,
278+
line: 35,
279279
},
280280
],
281281
duration: 0,

src/PHPUnit/ProcessBuilder/FilterStrategy.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ abstract class FilterStrategy {
66

77
abstract getFilter(): string;
88

9+
protected getGroupFilter(): string | undefined {
10+
const groups = (this.testDefinition.annotations?.group as string[]) ?? [];
11+
return groups.length > 0 ? `--group=${groups.join(',')}` : undefined;
12+
}
13+
914
protected parseFilter(filter: string) {
1015
return `--filter="${filter}(( with (data set )?.*)?)?$"`;
1116
}
@@ -19,7 +24,9 @@ class NamespaceFilterStrategy extends FilterStrategy {
1924

2025
class ClassFilterStrategy extends FilterStrategy {
2126
getFilter() {
22-
return this.testDefinition.file!;
27+
return [this.getGroupFilter(), this.testDefinition.file!]
28+
.filter((value) => !!value)
29+
.join(' ');
2330
}
2431
}
2532

0 commit comments

Comments
 (0)