diff --git a/smart_tests/test_runners/smart_tests.py b/smart_tests/test_runners/smart_tests.py
index 6d4b72e88..8b639e264 100644
--- a/smart_tests/test_runners/smart_tests.py
+++ b/smart_tests/test_runners/smart_tests.py
@@ -169,16 +169,20 @@ def record_tests(client: RecordTests,
source_roots: Annotated[list[str], typer.Argument(
multiple=True,
help="Source directories containing test report files"
- )]):
+ )],
+ file_path_attribute: Annotated[list[str], typer.Option(
+ "--file-path-attribute",
+ multiple=True,
+ help="Attributes to look for file paths in test reports (e.g., name, classname, file, filepath)"
+ )] = ["file", "filepath"]):
def path_builder(
case: TestCase, suite: TestSuite, report_file: str
) -> TestPath:
def find_filename():
"""look for what looks like file names from test reports"""
for e in [case, suite]:
- for a in ["file", "filepath"]:
- filepath = e._elem.attrib.get(a)
- if filepath:
+ for a in file_path_attribute:
+ if filepath := e._elem.attrib.get(a):
return filepath
return None # failing to find a test name
@@ -188,9 +192,9 @@ def find_filename():
# default test path in `subset` expects to have this file name
test_path = [client.make_file_path_component(filepath)]
- if suite.name:
+ if suite.name and suite.name != filepath:
test_path.append({"type": "testsuite", "name": suite.name})
- if case.name:
+ if case.name and case.name != filepath:
test_path.append({"type": "testcase", "name": case.name})
return test_path
diff --git a/tests/data/file/record_test_result.json b/tests/data/file/record_test_result.json
new file mode 100644
index 000000000..f3d9cb4df
--- /dev/null
+++ b/tests/data/file/record_test_result.json
@@ -0,0 +1,53 @@
+{
+ "events": [
+ {
+ "type": "case",
+ "testPath": [
+ {
+ "type": "file",
+ "name": "tests/test_example.py"
+ },
+ {
+ "type": "testsuite",
+ "name": "Suite 1"
+ },
+ {
+ "type": "testcase",
+ "name": "test_case_1"
+ }
+ ],
+ "duration": 0.5,
+ "status": 1,
+ "stdout": "",
+ "stderr": "",
+ "data": null
+ },
+ {
+ "type": "case",
+ "testPath": [
+ {
+ "type": "file",
+ "name": "tests/test_example.py"
+ },
+ {
+ "type": "testsuite",
+ "name": "Suite 1"
+ },
+ {
+ "type": "testcase",
+ "name": "test_case_2"
+ }
+ ],
+ "duration": 0.734,
+ "status": 1,
+ "stdout": "",
+ "stderr": "",
+ "data": null
+ }
+ ],
+ "testRunner": "file",
+ "group": "",
+ "noBuild": false,
+ "flavors": [],
+ "testSuite": ""
+}
diff --git a/tests/data/file/record_test_result_custom_attribute.json b/tests/data/file/record_test_result_custom_attribute.json
new file mode 100644
index 000000000..9f76a8673
--- /dev/null
+++ b/tests/data/file/record_test_result_custom_attribute.json
@@ -0,0 +1,45 @@
+{
+ "events": [
+ {
+ "type": "case",
+ "testPath": [
+ {
+ "type": "file",
+ "name": "tests/test_custom.py"
+ },
+ {
+ "type": "testsuite",
+ "name": "Suite 1"
+ }
+ ],
+ "duration": 0.5,
+ "status": 1,
+ "stdout": "",
+ "stderr": "",
+ "data": null
+ },
+ {
+ "type": "case",
+ "testPath": [
+ {
+ "type": "file",
+ "name": "tests/test_custom2.py"
+ },
+ {
+ "type": "testsuite",
+ "name": "Suite 1"
+ }
+ ],
+ "duration": 0.734,
+ "status": 1,
+ "stdout": "",
+ "stderr": "",
+ "data": null
+ }
+ ],
+ "testRunner": "file",
+ "group": "",
+ "noBuild": false,
+ "flavors": [],
+ "testSuite": ""
+}
diff --git a/tests/data/file/result.xml b/tests/data/file/result.xml
new file mode 100644
index 000000000..107083979
--- /dev/null
+++ b/tests/data/file/result.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/file/result_custom_attribute.xml b/tests/data/file/result_custom_attribute.xml
new file mode 100644
index 000000000..cd39eb461
--- /dev/null
+++ b/tests/data/file/result_custom_attribute.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/test_runners/test_file.py b/tests/test_runners/test_file.py
new file mode 100644
index 000000000..49896a09d
--- /dev/null
+++ b/tests/test_runners/test_file.py
@@ -0,0 +1,41 @@
+import os
+from unittest import mock
+
+import responses # type: ignore
+
+from tests.cli_test_case import CliTestCase
+
+
+class FileTest(CliTestCase):
+ @responses.activate
+ @mock.patch.dict(os.environ, {"LAUNCHABLE_TOKEN": CliTestCase.smart_tests_token})
+ def test_record_test_file(self):
+ result = self.cli(
+ "record",
+ "tests",
+ "--session",
+ self.session,
+ "file",
+ str(self.test_files_dir.joinpath("result.xml")),
+ )
+
+ self.assert_success(result)
+ self.assert_record_tests_payload("record_test_result.json")
+
+ @responses.activate
+ @mock.patch.dict(os.environ, {"LAUNCHABLE_TOKEN": CliTestCase.smart_tests_token})
+ def test_record_test_file_with_custom_file_path_attribute(self):
+ """Test that --file-path-attribute option allows specifying custom attributes"""
+ result = self.cli(
+ "record",
+ "tests",
+ "--session",
+ self.session,
+ "file",
+ "--file-path-attribute",
+ "name",
+ str(self.test_files_dir.joinpath("result_custom_attribute.xml")),
+ )
+
+ self.assert_success(result)
+ self.assert_record_tests_payload("record_test_result_custom_attribute.json")