Files
testdrive-jsui/src/testdrive_jsui/testing/integration.py
tegwick 9d7964f9e5 feat: add refactored testdrive-jsui capability with consolidated architecture
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>
2025-12-16 00:01:58 +01:00

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"