Skip to content

Commit f20390e

Browse files
authored
fix: preserve namespace separators in Pest describe block names from locationHint (#407)
When Pest reports a test inside describe(SomeClass::class, ...), the locationHint contains backslashes as namespace separators in the method name (e.g. `Foo\Services\PlaylistService` → it test). The previous .replace(/\\/g, '/') converted ALL backslashes, so the runtime ID produced Foo/Services/PlaylistService which did not match the static analysis ID (Foo\Services\PlaylistService), causing Test Explorer icons to never update. Fix: only apply the backslash-to-slash normalisation on the file path portion (before ::), leaving the method name portion untouched. Closes #404
1 parent f4ff933 commit f20390e

2 files changed

Lines changed: 21 additions & 3 deletions

File tree

packages/phpunit/src/TestIdentifier/PestTestIdentifier.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ describe('PestTestIdentifier', () => {
4646
});
4747
});
4848

49+
describe('fromLocationHint with namespaced describe block (::class)', () => {
50+
it.each([
51+
[
52+
// describe(PlaylistService::class, ...) where PlaylistService is in Foo\\Services namespace
53+
'pest_qn://tests/Unit/PlaylistServiceTests.php::`Foo\\Services\\PlaylistService` → it does something',
54+
'it does something',
55+
'tests/Unit/PlaylistServiceTests.php::`Foo\\Services\\PlaylistService` → it does something',
56+
],
57+
])('fromLocationHint(%j, %j) → id: %s', (locationHint, name, expectedId) => {
58+
const result = transformer.fromLocationHint(locationHint, name);
59+
expect(result.id).toBe(expectedId);
60+
});
61+
});
62+
4963
describe('fromLocationHint v2 evaluable testSuiteStarted', () => {
5064
it.each([
5165
[

packages/phpunit/src/TestIdentifier/PestTestIdentifier.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ export class PestTestIdentifier extends PHPUnitTestIdentifier {
3535
/(pest_qn|file):\/\/(?<id>(?<prefix>[\w\s]+)\((?<classFQN>[\w\\]+)\)(::(?<method>.+))?)/,
3636
);
3737
if (!matched) {
38-
const location = PestV1Fixer.fixLocationHint(
39-
locationHint.replace(/(pest_qn|file):\/\//, '').replace(/\\/g, '/'),
40-
);
38+
const raw = locationHint.replace(/(pest_qn|file):\/\//, '');
39+
const sepIdx = raw.indexOf('::');
40+
const normalized =
41+
sepIdx === -1
42+
? raw.replace(/\\/g, '/')
43+
: raw.slice(0, sepIdx).replace(/\\/g, '/') + raw.slice(sepIdx);
44+
const location = PestV1Fixer.fixLocationHint(normalized);
4145
const id = this.normalizeMethodName(PestV2Fixer.fixId(location, name));
4246
const file = location.split('::')[0];
4347

0 commit comments

Comments
 (0)