diff --git a/launchable/test_runners/file.py b/launchable/test_runners/file.py index a9670d40a..daf725b4d 100644 --- a/launchable/test_runners/file.py +++ b/launchable/test_runners/file.py @@ -5,14 +5,7 @@ from . import launchable -@launchable.subset -def subset(client): - # read lines as test file names - for t in client.stdin(): - client.test_path(t.rstrip("\n")) - - client.run() - +subset = launchable.CommonSubsetImpls(__name__).scan_stdin() record_tests = launchable.CommonRecordTestImpls(__name__).file_profile_report_files() diff --git a/launchable/test_runners/jasmine.py b/launchable/test_runners/jasmine.py index 8a9e19f3c..daef2c6e3 100644 --- a/launchable/test_runners/jasmine.py +++ b/launchable/test_runners/jasmine.py @@ -19,14 +19,7 @@ def record_tests(client, reports): client.run() -@launchable.subset -def subset(client): - # read lines as test file names - for t in client.stdin(): - client.test_path(t.rstrip("\n")) - - client.run() - +subset = launchable.CommonSubsetImpls(__name__).scan_stdin() split_subset = launchable.CommonSplitSubsetImpls(__name__).split_subset() diff --git a/launchable/test_runners/karma.py b/launchable/test_runners/karma.py index ffd471208..12ed811eb 100644 --- a/launchable/test_runners/karma.py +++ b/launchable/test_runners/karma.py @@ -11,6 +11,18 @@ from . import launchable +@click.option('--with', '_with') +@launchable.subset +def subset(client, _with: str): + # TODO: implement the --with ng option + + # read lines as test file names + for t in client.stdin(): + client.test_path(t.rstrip("\n")) + + client.run() + + @click.argument('reports', required=True, nargs=-1) @launchable.record.tests def record_tests(client, reports): diff --git a/launchable/test_runners/launchable.py b/launchable/test_runners/launchable.py index df0907e36..250643c79 100644 --- a/launchable/test_runners/launchable.py +++ b/launchable/test_runners/launchable.py @@ -63,17 +63,35 @@ class CommonSubsetImpls: def __init__(self, module_name): self.cmdname = cmdname(module_name) - def scan_files(self, pattern): + def scan_stdin(self): + """ + Historical implementation of the files profile that's also used elsewhere. + Reads test one line at a time from stdin. Consider this implementation deprecated. + Newer test runners are advised to use scan_files() without the pattern argument. + """ + def subset(client): + # read lines as test file names + for t in client.stdin(): + client.test_path(t.rstrip("\n")) + client.run() + + return wrap(subset, subset_cmd, self.cmdname) + + def scan_files(self, pattern=None): """ Suitable for test runners that use files as unit of tests where file names follow a naming pattern. :param pattern: file masks that identify test files, such as '*_spec.rb' + for test runners that do not have natural file naming conventions, pass in None, + so that the implementation will refuse to accept directories. """ @click.argument('files', required=True, nargs=-1) def subset(client, files): # client type: Optimize in def lauchable.commands.subset.subset def parse(fname: str): if os.path.isdir(fname): + if pattern is None: + raise click.UsageError(f'{fname} is a directory, but expecting a file or GLOB') client.scan(fname, '**/' + pattern) elif fname == '@-': # read stdin diff --git a/launchable/test_runners/playwright.py b/launchable/test_runners/playwright.py index cd286e3a8..87e803213 100644 --- a/launchable/test_runners/playwright.py +++ b/launchable/test_runners/playwright.py @@ -51,14 +51,7 @@ def path_builder(case: TestCase, suite: TestSuite, client.run() -@launchable.subset -def subset(client): - # read lines as test file names - for t in client.stdin(): - client.test_path(t.rstrip("\n")) - - client.run() - +subset = launchable.CommonSubsetImpls(__name__).scan_stdin() split_subset = launchable.CommonSplitSubsetImpls(__name__).split_subset() diff --git a/launchable/test_runners/prove.py b/launchable/test_runners/prove.py index 67c83910a..f615034b9 100644 --- a/launchable/test_runners/prove.py +++ b/launchable/test_runners/prove.py @@ -14,13 +14,7 @@ def remove_leading_number_and_dash(input_string: str) -> str: return result -@launchable.subset -def subset(client): - # read lines as test file names - for t in client.stdin(): - client.test_path(t.rstrip("\n")) - - client.run() +subset = launchable.CommonSubsetImpls(__name__).scan_stdin() @click.argument('reports', required=True, nargs=-1) diff --git a/launchable/test_runners/vitest.py b/launchable/test_runners/vitest.py index d8731d5b5..523584300 100644 --- a/launchable/test_runners/vitest.py +++ b/launchable/test_runners/vitest.py @@ -28,10 +28,4 @@ def parse_func(report: str) -> ET.ElementTree: launchable.CommonRecordTestImpls.load_report_files(client=client, source_roots=reports) -@launchable.subset -def subset(client): - # read lines as test file names - for t in client.stdin(): - client.test_path(t.rstrip("\n")) - - client.run() +subset = launchable.CommonSubsetImpls(__name__).scan_stdin() diff --git a/tests/data/karma/subset_result.json b/tests/data/karma/subset_result.json new file mode 100644 index 000000000..d5642af31 --- /dev/null +++ b/tests/data/karma/subset_result.json @@ -0,0 +1,22 @@ +{ + "testPaths": [ + [ + { + "type": "file", + "name": "a.ts" + } + ], + [ + { + "type": "file", + "name": "b.ts" + } + ] + ], + "testRunner": "karma", + "session": { "id": "16" }, + "goal": {"type": "subset-by-percentage", "percentage": 0.1}, + "ignoreNewTests": false, + "getTestsFromGuess": false, + "getTestsFromPreviousSessions": false +} diff --git a/tests/test_runners/test_karma.py b/tests/test_runners/test_karma.py index 907904788..c8163cb86 100644 --- a/tests/test_runners/test_karma.py +++ b/tests/test_runners/test_karma.py @@ -3,6 +3,7 @@ import responses # type: ignore +from launchable.utils.session import write_build from tests.cli_test_case import CliTestCase @@ -16,3 +17,14 @@ def test_record_tests_json(self): self.assert_success(result) self.assert_record_tests_payload('record_test_result.json') + + @responses.activate + @mock.patch.dict(os.environ, {"LAUNCHABLE_TOKEN": CliTestCase.launchable_token}) + def test_subset(self): + # emulate launchable record build + write_build(self.build_name) + + result = self.cli('subset', '--target', '10%', '--base', + os.getcwd(), 'karma', '--with', 'ng', input="a.ts\nb.ts") + self.assert_success(result) + self.assert_subset_payload('subset_result.json')