generated from coulomb/repo-seed
Complete integration of refactored testdrive-jsui capability: ## Refactored Architecture - js/ - All JavaScript source (controls, components, core) - static/ - CSS, images, templates - src/testdrive_jsui/ - Python package - tests/ - Python tests ## Plugin Self-Declaration - get_plugin_source_dir() - plugin declares own location - get_asset_paths() - organized asset paths - No hardcoded discovery logic ## Merged Content - Baseline UI scaffold (tutorials, LICENSE, INTRODUCTION.md) - Refactored capability implementation - Comprehensive documentation Ready for standalone use or integration with markitect. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
187 lines
6.1 KiB
Python
187 lines
6.1 KiB
Python
"""
|
|
Python-JavaScript Integration Bridge
|
|
|
|
Provides seamless integration between Python test suite and JavaScript tests.
|
|
Enables pytest to discover and run JavaScript tests as if they were Python tests.
|
|
"""
|
|
|
|
import pytest
|
|
from pathlib import Path
|
|
from typing import List, Optional, Generator
|
|
from .js_test_runner import JavaScriptTestRunner, JSTestResult
|
|
|
|
|
|
class PythonJSBridge:
|
|
"""
|
|
Bridge between Python and JavaScript testing environments.
|
|
Enables JavaScript tests to be run from Python test suite.
|
|
"""
|
|
|
|
def __init__(self, capability_root: Optional[Path] = None):
|
|
"""
|
|
Initialize the bridge.
|
|
|
|
Args:
|
|
capability_root: Root directory of the testdrive-jsui capability
|
|
"""
|
|
self.js_runner = JavaScriptTestRunner(capability_root)
|
|
|
|
def pytest_collect_file(self, path: Path, parent) -> Optional["JSTestFile"]:
|
|
"""
|
|
Pytest hook to collect JavaScript test files.
|
|
"""
|
|
if path.suffix == ".js" and "test" in path.name:
|
|
if self._is_js_test_file(path):
|
|
return JSTestFile.from_parent(parent, fspath=path)
|
|
return None
|
|
|
|
def _is_js_test_file(self, path: Path) -> bool:
|
|
"""Check if a file is a JavaScript test file."""
|
|
return (
|
|
path.name.startswith("test-") or
|
|
path.name.endswith(".test.js") or
|
|
"test" in path.parts
|
|
)
|
|
|
|
def run_all_js_tests(self) -> JSTestResult:
|
|
"""Run all JavaScript tests."""
|
|
return self.js_runner.run_js_tests()
|
|
|
|
def run_js_test_by_name(self, test_name: str) -> JSTestResult:
|
|
"""Run a specific JavaScript test by name."""
|
|
return self.js_runner.run_specific_test(test_name)
|
|
|
|
|
|
class JSTestFile(pytest.File):
|
|
"""
|
|
Represents a JavaScript test file in pytest.
|
|
"""
|
|
|
|
def collect(self) -> Generator["JSTestItem", None, None]:
|
|
"""Collect test items from this JavaScript file."""
|
|
# For now, treat each JS file as a single test item
|
|
# In the future, this could be enhanced to parse individual test functions
|
|
yield JSTestItem.from_parent(self, name=self.fspath.basename)
|
|
|
|
|
|
class JSTestItem(pytest.Item):
|
|
"""
|
|
Represents a JavaScript test item in pytest.
|
|
"""
|
|
|
|
def __init__(self, name: str, parent: JSTestFile):
|
|
super().__init__(name, parent)
|
|
self.js_runner = JavaScriptTestRunner()
|
|
|
|
def runtest(self) -> None:
|
|
"""Run the JavaScript test."""
|
|
test_file = str(self.fspath.relative_to(self.js_runner.js_dir))
|
|
result = self.js_runner.run_specific_test(test_file)
|
|
|
|
if not result.success:
|
|
failure_messages = []
|
|
for failure in result.failures:
|
|
failure_messages.append(f"{failure.get('title', 'Unknown')}: {failure.get('message', 'Unknown error')}")
|
|
|
|
failure_msg = "\n".join(failure_messages) if failure_messages else result.stderr
|
|
raise JSTestFailure(failure_msg, result)
|
|
|
|
def repr_failure(self, excinfo) -> str:
|
|
"""Represent test failure."""
|
|
if isinstance(excinfo.value, JSTestFailure):
|
|
return f"JavaScript test failed:\n{excinfo.value.message}"
|
|
return super().repr_failure(excinfo)
|
|
|
|
def reportinfo(self):
|
|
"""Report information about this test item."""
|
|
return self.fspath, 0, f"JavaScript test: {self.name}"
|
|
|
|
|
|
class JSTestFailure(Exception):
|
|
"""Exception raised when a JavaScript test fails."""
|
|
|
|
def __init__(self, message: str, result: JSTestResult):
|
|
super().__init__(message)
|
|
self.message = message
|
|
self.result = result
|
|
|
|
|
|
# Pytest fixtures for JavaScript testing
|
|
@pytest.fixture
|
|
def js_test_runner() -> JavaScriptTestRunner:
|
|
"""Provide a JavaScript test runner instance."""
|
|
return JavaScriptTestRunner()
|
|
|
|
|
|
@pytest.fixture
|
|
def js_bridge() -> PythonJSBridge:
|
|
"""Provide a Python-JavaScript bridge instance."""
|
|
return PythonJSBridge()
|
|
|
|
|
|
# Pytest markers
|
|
def pytest_configure(config):
|
|
"""Configure pytest markers for JavaScript tests."""
|
|
config.addinivalue_line(
|
|
"markers", "javascript: mark test as JavaScript integration test"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "js_component: mark test as JavaScript component test"
|
|
)
|
|
config.addinivalue_line(
|
|
"markers", "js_integration: mark test as JavaScript integration test"
|
|
)
|
|
|
|
|
|
# Test discovery function for manual use
|
|
def discover_js_tests(capability_root: Optional[Path] = None) -> List[str]:
|
|
"""
|
|
Discover all JavaScript test files.
|
|
|
|
Args:
|
|
capability_root: Root directory of the testdrive-jsui capability
|
|
|
|
Returns:
|
|
List of JavaScript test file paths
|
|
"""
|
|
runner = JavaScriptTestRunner(capability_root)
|
|
return runner.list_available_tests()
|
|
|
|
|
|
# Main test execution functions
|
|
def test_javascript_components(js_test_runner: JavaScriptTestRunner) -> None:
|
|
"""
|
|
Main test function that runs all JavaScript component tests.
|
|
This can be called from Python test suite.
|
|
"""
|
|
result = js_test_runner.run_js_tests(verbose=True)
|
|
|
|
assert result.success, f"JavaScript tests failed: {result.failures}"
|
|
assert result.tests_total > 0, "No JavaScript tests were found or executed"
|
|
assert result.tests_passed > 0, "No JavaScript tests passed"
|
|
|
|
|
|
def test_javascript_integration(js_test_runner: JavaScriptTestRunner) -> None:
|
|
"""
|
|
Test JavaScript integration components.
|
|
"""
|
|
integration_tests = [
|
|
test for test in js_test_runner.list_available_tests()
|
|
if "integration" in test.lower()
|
|
]
|
|
|
|
if integration_tests:
|
|
result = js_test_runner.run_js_tests(test_patterns=integration_tests)
|
|
assert result.success, f"JavaScript integration tests failed: {result.failures}"
|
|
|
|
|
|
def test_javascript_environment(js_test_runner: JavaScriptTestRunner) -> None:
|
|
"""
|
|
Test that JavaScript testing environment is properly set up.
|
|
"""
|
|
assert js_test_runner.check_node_environment(), "Node.js environment not available"
|
|
|
|
info = js_test_runner.get_test_info()
|
|
assert info["node_available"], "Node.js not available"
|
|
assert info["package_json_exists"], "package.json not found"
|
|
assert len(info["available_tests"]) > 0, "No JavaScript tests found" |