Skip to content

Commit 6220771

Browse files
authored
Merge pull request #1039 from launchableinc/vitest
Support Vitest
2 parents 2ec8f48 + fff3bab commit 6220771

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed

launchable/test_runners/vitest.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import xml.etree.ElementTree as ET
2+
3+
import click
4+
5+
from . import launchable
6+
7+
8+
@click.argument('reports', required=True, nargs=-1)
9+
@launchable.record.tests
10+
def record_tests(client, reports):
11+
def parse_func(report: str) -> ET.ElementTree:
12+
"""
13+
Vitest junit report doesn't set file/filepath attributes on test cases, and it's set as a classname attribute instead.
14+
So, set the classname value as the file name in this function.
15+
e.g.) <testcase classname="src/components/Hello.test.tsx" name="renders hello message" time="0.008676833">
16+
"""
17+
tree = ET.parse(report)
18+
root = tree.getroot()
19+
for test_suite in root.findall('testsuite'):
20+
for test_case in test_suite.findall('testcase'):
21+
classname = test_case.get('classname', '')
22+
test_case.set('file', classname)
23+
test_case.attrib.pop('classname', None)
24+
25+
return tree
26+
27+
client.junitxml_parse_func = parse_func
28+
launchable.CommonRecordTestImpls.load_report_files(client=client, source_roots=reports)
29+
30+
31+
@launchable.subset
32+
def subset(client):
33+
# read lines as test file names
34+
for t in client.stdin():
35+
client.test_path(t.rstrip("\n"))
36+
37+
client.run()
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"events": [
3+
{
4+
"type": "case",
5+
"testPath": [
6+
{
7+
"type": "file",
8+
"name": "__test__/add.test.tsx"
9+
},
10+
{
11+
"type": "testcase",
12+
"name": "add"
13+
}
14+
],
15+
"duration": 0.0005895,
16+
"status": 1,
17+
"stdout": "",
18+
"stderr": "",
19+
"data": null
20+
},
21+
{
22+
"type": "case",
23+
"testPath": [
24+
{
25+
"type": "file",
26+
"name": "__test__/sub.test.tsx"
27+
},
28+
{
29+
"type": "testcase",
30+
"name": "sub - 1"
31+
}
32+
],
33+
"duration": 0.000542459,
34+
"status": 1,
35+
"stdout": "",
36+
"stderr": "",
37+
"data": null
38+
},
39+
{
40+
"type": "case",
41+
"testPath": [
42+
{
43+
"type": "file",
44+
"name": "__test__/sub.test.tsx"
45+
},
46+
{
47+
"type": "testcase",
48+
"name": "sub - 2"
49+
}
50+
],
51+
"duration": 0.002866375,
52+
"status": 0,
53+
"stdout": "",
54+
"stderr": "\nAssertionError: expected 50 to be 5 // Object.is equality\n\n- Expected\n+ Received\n\n- 5\n+ 50\n\n \u276f __test__/sub.test.tsx:12:24\n ",
55+
"data": null
56+
},
57+
{
58+
"type": "case",
59+
"testPath": [
60+
{
61+
"type": "file",
62+
"name": "src/components/Hello.test.tsx"
63+
},
64+
{
65+
"type": "testcase",
66+
"name": "renders hello message"
67+
}
68+
],
69+
"duration": 0.009431167,
70+
"status": 1,
71+
"stdout": "",
72+
"stderr": "",
73+
"data": null
74+
},
75+
{
76+
"type": "case",
77+
"testPath": [
78+
{
79+
"type": "file",
80+
"name": "src/components/Hello.test.tsx"
81+
},
82+
{
83+
"type": "testcase",
84+
"name": "error: renders invalid message"
85+
}
86+
],
87+
"duration": 0.003817459,
88+
"status": 0,
89+
"stdout": "",
90+
"stderr": "\nTestingLibraryElementError: Unable to find an element with the text: Invalid!!. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.\n\nIgnored nodes: comments, script, style\n<body>\n <div>\n <h1>\n Hello, World!\n </h1>\n </div>\n</body>\n \u276f Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19\n \u276f node_modules/@testing-library/dom/dist/query-helpers.js:76:38\n \u276f node_modules/@testing-library/dom/dist/query-helpers.js:52:17\n \u276f node_modules/@testing-library/dom/dist/query-helpers.js:95:19\n ",
91+
"data": null
92+
}
93+
],
94+
"testRunner": "vitest",
95+
"group": "",
96+
"noBuild": false,
97+
"testSuite": "",
98+
"flavors": []
99+
}

tests/data/vitest/report.xml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<testsuites name="vitest tests" tests="5" failures="2" errors="0" time="0.018447583">
3+
<testsuite name="__test__/add.test.tsx" timestamp="2025-06-09T08:30:48.826Z" hostname="MAC-ryabuki" tests="1" failures="0" errors="0" skipped="0" time="0.000916833">
4+
<testcase classname="__test__/add.test.tsx" name="add" time="0.0005895">
5+
</testcase>
6+
</testsuite>
7+
<testsuite name="__test__/sub.test.tsx" timestamp="2025-06-09T08:30:48.827Z" hostname="MAC-ryabuki" tests="2" failures="1" errors="0" skipped="0" time="0.003741542">
8+
<testcase classname="__test__/sub.test.tsx" name="sub - 1" time="0.000542459">
9+
</testcase>
10+
<testcase classname="__test__/sub.test.tsx" name="sub - 2" time="0.002866375">
11+
<failure message="expected 50 to be 5 // Object.is equality" type="AssertionError">
12+
AssertionError: expected 50 to be 5 // Object.is equality
13+
14+
- Expected
15+
+ Received
16+
17+
- 5
18+
+ 50
19+
20+
❯ __test__/sub.test.tsx:12:24
21+
</failure>
22+
</testcase>
23+
</testsuite>
24+
<testsuite name="src/components/Hello.test.tsx" timestamp="2025-06-09T08:30:48.829Z" hostname="MAC-ryabuki" tests="2" failures="1" errors="0" skipped="0" time="0.013789208">
25+
<testcase classname="src/components/Hello.test.tsx" name="renders hello message" time="0.009431167">
26+
</testcase>
27+
<testcase classname="src/components/Hello.test.tsx" name="error: renders invalid message" time="0.003817459">
28+
<failure message="Unable to find an element with the text: Invalid!!. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
29+
30+
Ignored nodes: comments, script, style
31+
[36m&lt;body&gt;[39m
32+
[36m&lt;div&gt;[39m
33+
[36m&lt;h1&gt;[39m
34+
[0mHello, World![0m
35+
[36m&lt;/h1&gt;[39m
36+
[36m&lt;/div&gt;[39m
37+
[36m&lt;/body&gt;[39m" type="TestingLibraryElementError">
38+
TestingLibraryElementError: Unable to find an element with the text: Invalid!!. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
39+
40+
Ignored nodes: comments, script, style
41+
&lt;body&gt;
42+
&lt;div&gt;
43+
&lt;h1&gt;
44+
Hello, World!
45+
&lt;/h1&gt;
46+
&lt;/div&gt;
47+
&lt;/body&gt;
48+
❯ Object.getElementError node_modules/@testing-library/dom/dist/config.js:37:19
49+
❯ node_modules/@testing-library/dom/dist/query-helpers.js:76:38
50+
❯ node_modules/@testing-library/dom/dist/query-helpers.js:52:17
51+
❯ node_modules/@testing-library/dom/dist/query-helpers.js:95:19
52+
</failure>
53+
</testcase>
54+
</testsuite>
55+
</testsuites>

tests/test_runners/test_vitest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import os
2+
from unittest import mock
3+
4+
import responses
5+
6+
from tests.cli_test_case import CliTestCase
7+
8+
9+
class VitestTest(CliTestCase):
10+
@responses.activate
11+
@mock.patch.dict(os.environ, {"LAUNCHABLE_TOKEN": CliTestCase.launchable_token})
12+
def test_record_tests(self):
13+
result = self.cli('record', 'tests', '--session',
14+
self.session, 'vitest', str(self.test_files_dir.joinpath("report.xml")))
15+
self.assert_success(result)
16+
self.assert_record_tests_payload('record_test_result.json')

0 commit comments

Comments
 (0)