Skip to content

Commit d4fa6e4

Browse files
committed
playwright: add support for test file prefixes in JSON reports
1 parent 7b46a7b commit d4fa6e4

3 files changed

Lines changed: 125 additions & 1 deletion

File tree

launchable/test_runners/playwright.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
# https://playwright.dev/
44
#
55
import json
6+
import os
67
from typing import Dict, Generator, List
8+
from pathlib import Path
79

810
import click
911
from junitparser import TestCase, TestSuite # type: ignore
@@ -173,13 +175,54 @@ def parse_func(self, report_file: str) -> Generator[CaseEvent, None, None]:
173175
click.echo("Can't find test results from {}. Make sure to confirm report file.".format(
174176
report_file), err=True)
175177

178+
test_prefix = self._compute_test_prefix(data)
176179
for s in suites:
177180
# The title of the root suite object contains the file name.
178-
test_file = str(s.get("title", ""))
181+
test_file = self._resolve_test_file(str(s.get("title", "")), test_prefix)
179182

180183
for event in self._parse_suites(test_file, s, []):
181184
yield event
182185

186+
def _compute_test_prefix(self, report: Dict) -> str:
187+
"""
188+
Playwright JSON stores test `file` paths relative to `config.rootDir`.
189+
Our CLI wants paths relative to the Playwright config directory
190+
(usually the project/repo root), so we compute:
191+
relpath(root_dir, base_dir)
192+
where base_dir = dirname(configFile).
193+
194+
Example:
195+
configFile = /repo/playwright.config.ts
196+
rootDir = /repo/tests
197+
relpath(...) -> "tests"
198+
"""
199+
config: Dict = report.get("config", {})
200+
config_file = str(config.get("configFile", ""))
201+
root_dir = str(config.get("rootDir", ""))
202+
if not config_file or not root_dir:
203+
return ""
204+
205+
base_dir = Path(config_file).parent
206+
try:
207+
test_prefix = Path(root_dir).relative_to(base_dir).as_posix()
208+
except ValueError:
209+
return ""
210+
211+
if test_prefix == ".":
212+
return ""
213+
214+
return test_prefix
215+
216+
def _resolve_test_file(self, test_file: str, test_prefix: str) -> str:
217+
if not test_prefix or not test_file:
218+
return test_file
219+
220+
# Guard against duplicate paths when report data is already prefixed.
221+
if test_file.startswith(test_prefix):
222+
return test_file
223+
224+
return Path(test_prefix, test_file).as_posix()
225+
183226
def _parse_suites(self, test_file: str, suite: Dict[str, Dict], test_case_names: List[str] = []) -> List:
184227
events = []
185228

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"config": {
3+
"configFile": "/repo/playwright.config.ts",
4+
"rootDir": "/repo/packages/e2e"
5+
},
6+
"suites": [
7+
{
8+
"title": "tests/a.spec.ts",
9+
"specs": [],
10+
"suites": [
11+
{
12+
"title": "smoke",
13+
"specs": [
14+
{
15+
"title": "passes",
16+
"line": 10,
17+
"tests": [
18+
{
19+
"results": [
20+
{
21+
"status": "passed",
22+
"duration": 12,
23+
"stdout": [],
24+
"errors": []
25+
}
26+
]
27+
}
28+
]
29+
}
30+
],
31+
"suites": []
32+
}
33+
]
34+
},
35+
{
36+
"title": "packages/e2e/tests/b.spec.ts",
37+
"specs": [],
38+
"suites": [
39+
{
40+
"title": "smoke",
41+
"specs": [
42+
{
43+
"title": "already prefixed",
44+
"line": 20,
45+
"tests": [
46+
{
47+
"results": [
48+
{
49+
"status": "passed",
50+
"duration": 15,
51+
"stdout": [],
52+
"errors": []
53+
}
54+
]
55+
}
56+
]
57+
}
58+
],
59+
"suites": []
60+
}
61+
]
62+
}
63+
]
64+
}

tests/test_runners/test_playwright.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,20 @@ def _test_test_path_status(payload, test_path: str, status: CaseEvent) -> bool:
6464
'playwright', '--json', str(self.test_files_dir.joinpath("report.json")))
6565
json_payload = json.loads(gzip.decompress(self.find_request('/events', 1).request.body).decode())
6666
self.assertEqual(_test_test_path_status(json_payload, target_test_path, CaseEvent.TEST_FAILED), True)
67+
68+
@responses.activate
69+
@mock.patch.dict(os.environ,
70+
{"LAUNCHABLE_TOKEN": CliTestCase.launchable_token})
71+
def test_record_test_with_json_option_adds_prefix_from_config(self):
72+
report_file = str(self.test_files_dir.joinpath("report_with_prefix.json"))
73+
74+
result = self.cli('record', 'tests', '--session', self.session,
75+
'playwright', '--json', report_file)
76+
77+
print(result.output)
78+
self.assert_success(result)
79+
80+
payload = json.loads(gzip.decompress(self.find_request('/events').request.body).decode())
81+
test_paths = [unparse_test_path(event.get("testPath")) for event in payload.get("events")]
82+
self.assertIn("file=packages/e2e/tests/a.spec.ts#testcase=smoke › passes", test_paths)
83+
self.assertIn("file=packages/e2e/tests/b.spec.ts#testcase=smoke › already prefixed", test_paths)

0 commit comments

Comments
 (0)