Skip to content

Commit

Permalink
feat: Add JSX test targets and make them targetable
Browse files Browse the repository at this point in the history
  • Loading branch information
tobni committed Jul 31, 2024
1 parent 6676f7c commit 9502b7c
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 22 deletions.
11 changes: 9 additions & 2 deletions src/python/pants/backend/experimental/javascript/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
JSTestsGeneratorTarget,
JSTestTarget,
)
from pants.backend.jsx.target_types import JSXSourceTarget, JSXSourcesGeneratorTarget
from pants.backend.jsx.goals import tailor as jsx_tailor
from pants.backend.jsx.target_types import (
JSXSourcesGeneratorTarget,
JSXSourceTarget,
JSXTestsGeneratorTarget,
JSXTestTarget,
)
from pants.build_graph.build_file_aliases import BuildFileAliases
from pants.engine.rules import Rule
from pants.engine.target import Target
Expand All @@ -33,7 +38,7 @@ def rules() -> Iterable[Rule | UnionRule]:
*run_rules(),
*test.rules(),
*export.rules(),
*jsx_tailor.rules()
*jsx_tailor.rules(),
)


Expand All @@ -45,6 +50,8 @@ def target_types() -> Iterable[type[Target]]:
JSTestsGeneratorTarget,
JSXSourceTarget,
JSXSourcesGeneratorTarget,
JSXTestTarget,
JSXTestsGeneratorTarget,
*package_json.target_types(),
)

Expand Down
21 changes: 9 additions & 12 deletions src/python/pants/backend/javascript/goals/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@
OwningNodePackageRequest,
)
from pants.backend.javascript.subsystems.nodejstest import NodeJSTest
from pants.backend.javascript.target_types import (
JSRuntimeSourceField,
JSTestBatchCompatibilityTagField,
JSTestExtraEnvVarsField,
JSTestSourceField,
JSTestTimeoutField,
)
from pants.backend.javascript.target_types import JSRuntimeSourceField, JSTestRuntimeSourceField
from pants.base.glob_match_error_behavior import GlobMatchErrorBehavior
from pants.build_graph.address import Address
from pants.core.goals.test import (
Expand All @@ -37,10 +31,13 @@
CoverageReports,
FilesystemCoverageReport,
TestExtraEnv,
TestExtraEnvVarsField,
TestFieldSet,
TestRequest,
TestResult,
TestsBatchCompatibilityTagField,
TestSubsystem,
TestTimeoutField,
)
from pants.core.target_types import AssetSourceField
from pants.core.util_rules import source_files
Expand Down Expand Up @@ -88,13 +85,13 @@ class JSCoverageDataCollection(CoverageDataCollection[JSCoverageData]):

@dataclass(frozen=True)
class JSTestFieldSet(TestFieldSet):
required_fields = (JSTestSourceField,)
required_fields = (JSTestRuntimeSourceField,)

batch_compatibility_tag: JSTestBatchCompatibilityTagField
source: JSTestSourceField
batch_compatibility_tag: TestsBatchCompatibilityTagField
source: JSTestRuntimeSourceField
dependencies: Dependencies
timeout: JSTestTimeoutField
extra_env_vars: JSTestExtraEnvVarsField
timeout: TestTimeoutField
extra_env_vars: TestExtraEnvVarsField


class JSTestRequest(TestRequest):
Expand Down
6 changes: 5 additions & 1 deletion src/python/pants/backend/javascript/target_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class JSRuntimeSourceField(SingleSourceField):
"""A source that is javascript at runtime."""


class JSTestRuntimeSourceField(SingleSourceField):
"""A source that is runnable by javascript test-runners at runtime."""


class JSSourceField(JSRuntimeSourceField):
expected_file_extensions = JS_FILE_EXTENSIONS

Expand Down Expand Up @@ -94,7 +98,7 @@ class JSTestDependenciesField(JSDependenciesField):
pass


class JSTestSourceField(JSSourceField):
class JSTestSourceField(JSSourceField, JSTestRuntimeSourceField):
expected_file_extensions = JS_FILE_EXTENSIONS


Expand Down
20 changes: 17 additions & 3 deletions src/python/pants/backend/jsx/goals/tailor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@

from __future__ import annotations

import dataclasses
from dataclasses import dataclass
from typing import Iterable

from pants.backend.jsx.target_types import JSX_FILE_EXTENSIONS, JSXSourcesGeneratorTarget
from pants.backend.jsx.target_types import (
JSX_FILE_EXTENSIONS,
JSXSourcesGeneratorTarget,
JSXTestsGeneratorSourcesField,
JSXTestsGeneratorTarget,
)
from pants.core.goals.tailor import (
AllOwnedSources,
PutativeTarget,
PutativeTargets,
PutativeTargetsRequest,
)
from pants.core.util_rules.ownership import get_unowned_files_for_globs
from pants.core.util_rules.source_files import classify_files_for_sources_and_tests
from pants.engine.rules import Rule, collect_rules, rule
from pants.engine.unions import UnionRule
from pants.util.dirutil import group_by_dir
Expand All @@ -32,12 +39,19 @@ async def find_putative_jsx_targets(
unowned_jsx_files = await get_unowned_files_for_globs(
req, all_owned_sources, (f"*{ext}" for ext in JSX_FILE_EXTENSIONS)
)
classified_unowned_js_files = classify_files_for_sources_and_tests(
paths=unowned_jsx_files,
test_file_glob=JSXTestsGeneratorSourcesField.default,
sources_generator=JSXSourcesGeneratorTarget,
tests_generator=JSXTestsGeneratorTarget,
)

return PutativeTargets(
PutativeTarget.for_target_type(
JSXSourcesGeneratorTarget, path=dirname, name=None, triggering_sources=sorted(filenames)
tgt_type, path=dirname, name=name, triggering_sources=sorted(filenames)
)
for dirname, filenames in group_by_dir(unowned_jsx_files).items()
for tgt_type, paths, name in (dataclasses.astuple(f) for f in classified_unowned_js_files)
for dirname, filenames in group_by_dir(paths).items()
)


Expand Down
36 changes: 33 additions & 3 deletions src/python/pants/backend/jsx/goals/tailor_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from pants.backend.jsx.goals import tailor
from pants.backend.jsx.goals.tailor import PutativeJSXTargetsRequest
from pants.backend.jsx.target_types import JSXSourcesGeneratorTarget
from pants.backend.jsx.target_types import JSXSourcesGeneratorTarget, JSXTestsGeneratorTarget
from pants.core.goals.tailor import AllOwnedSources, PutativeTarget, PutativeTargets
from pants.core.util_rules.source_files import ClassifiedSources
from pants.engine.rules import QueryRule
Expand All @@ -20,7 +20,7 @@ def rule_runner() -> RuleRunner:
*tailor.rules(),
QueryRule(PutativeTargets, (PutativeJSXTargetsRequest, AllOwnedSources)),
],
target_types=[JSXSourcesGeneratorTarget],
target_types=[JSXTestsGeneratorTarget, JSXSourcesGeneratorTarget],
)


Expand All @@ -42,7 +42,37 @@ def rule_runner() -> RuleRunner:
)
],
id="only_jsx_sources",
)
),
pytest.param(
{
"src/owned/BUILD": "jsx_sources()\n",
"src/owned/OwnedFile.jsx": "",
"src/unowned/UnownedFile1.test.jsx": "",
"src/unowned/UnownedFile2.test.mjsx": "",
"src/unowned/UnownedFile3.test.cjsx": "",
},
[
ClassifiedSources(
JSXTestsGeneratorTarget,
["UnownedFile1.test.jsx", "UnownedFile2.test.mjsx", "UnownedFile3.test.cjsx"],
"tests",
)
],
id="only_jsx_tests",
),
pytest.param(
{
"src/owned/BUILD": "jsx_sources()\n",
"src/owned/OwnedFile.jsx": "",
"src/unowned/UnownedFile1.jsx": "",
"src/unowned/UnownedFile1.test.jsx": "",
},
[
ClassifiedSources(JSXTestsGeneratorTarget, ["UnownedFile1.test.jsx"], "tests"),
ClassifiedSources(JSXSourcesGeneratorTarget, ["UnownedFile1.jsx"]),
],
id="both_tests_and_source",
),
],
)
def test_find_putative_jsx_targets(
Expand Down
78 changes: 78 additions & 0 deletions src/python/pants/backend/jsx/target_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
JS_FILE_EXTENSIONS,
JSRuntimeDependenciesField,
JSRuntimeSourceField,
JSTestRuntimeSourceField,
)
from pants.core.goals.test import (
TestExtraEnvVarsField,
TestsBatchCompatibilityTagField,
TestTimeoutField,
)
from pants.engine.target import (
COMMON_TARGET_FIELDS,
Expand All @@ -17,6 +23,7 @@
generate_file_based_overrides_field_help_message,
generate_multiple_sources_field_help_message,
)
from pants.util.strutil import help_text

JSX_FILE_EXTENSIONS = tuple(f"{ext}x" for ext in JS_FILE_EXTENSIONS)

Expand Down Expand Up @@ -74,3 +81,74 @@ class JSXSourcesGeneratorTarget(TargetFilesGenerator):
copied_fields = COMMON_TARGET_FIELDS
moved_fields = (JSXDependenciesField,)
help = "Generate a `jsx_source` target for each file in the `sources` field."


class JSXTestDependenciesField(JSXDependenciesField):
pass


class JSXTestSourceField(JSXSourceField, JSTestRuntimeSourceField):
expected_file_extensions = JSX_FILE_EXTENSIONS


class JSXTestTimeoutField(TestTimeoutField):
pass


class JSXTestExtraEnvVarsField(TestExtraEnvVarsField):
pass


class JSXTestBatchCompatibilityTagField(TestsBatchCompatibilityTagField):
help = help_text(TestsBatchCompatibilityTagField.format_help("jsx_test", "nodejs test runner"))


class JSXTestTarget(Target):
alias = "jsx_test"
core_fields = (
*COMMON_TARGET_FIELDS,
JSXTestDependenciesField,
JSXTestSourceField,
JSXTestTimeoutField,
JSXTestExtraEnvVarsField,
JSXTestBatchCompatibilityTagField,
)
help = "A single JSX test file."


class JSXTestsOverridesField(OverridesField):
help = generate_file_based_overrides_field_help_message(
JSXTestTarget.alias,
"""
overrides={
"foo.test.jsx": {"timeout": 120},
"bar.test.jsx": {"timeout": 200},
("foo.test.jsx", "bar.test.jsx"): {"tags": ["slow_tests"]},
}
""",
)


class JSXTestsGeneratorSourcesField(JSXGeneratorSourcesField):
default = tuple(f"*.test{ext}" for ext in JSX_FILE_EXTENSIONS)
help = generate_multiple_sources_field_help_message(
"Example: `sources=['utils.test.jsx', 'subdir/*.test.jsx', '!ignore_me.test.jsx']`"
)


class JSXTestsGeneratorTarget(TargetFilesGenerator):
alias = "jsx_tests"
core_fields = (
*COMMON_TARGET_FIELDS,
JSXTestsGeneratorSourcesField,
JSXTestsOverridesField,
)
generated_target_cls = JSXTestTarget
copied_fields = COMMON_TARGET_FIELDS
moved_fields = (
JSXTestDependenciesField,
JSXTestTimeoutField,
JSXTestExtraEnvVarsField,
JSXTestBatchCompatibilityTagField,
)
help = "Generate a `jsx_test` target for each file in the `sources` field."
2 changes: 1 addition & 1 deletion testprojects/src/js/hello_react/src/test/BUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).

javascript_tests(
jsx_tests(
name="tests",
)

0 comments on commit 9502b7c

Please sign in to comment.