codeflash/tests/test_languages/test_javascript_integration.py
Kevin Turcios eceac13fc3 Merge remote-tracking branch 'origin/main' into omni-java
# Conflicts:
#	.claude/rules/architecture.md
#	.claude/rules/code-style.md
#	.github/workflows/claude.yml
#	.github/workflows/duplicate-code-detector.yml
#	codeflash/api/aiservice.py
#	codeflash/cli_cmds/console.py
#	codeflash/cli_cmds/logging_config.py
#	codeflash/code_utils/deduplicate_code.py
#	codeflash/discovery/discover_unit_tests.py
#	codeflash/languages/base.py
#	codeflash/languages/code_replacer.py
#	codeflash/languages/javascript/mocha_runner.py
#	codeflash/languages/javascript/support.py
#	codeflash/languages/python/support.py
#	codeflash/optimization/function_optimizer.py
#	codeflash/verification/parse_test_output.py
#	codeflash/verification/verification_utils.py
#	codeflash/verification/verifier.py
#	packages/codeflash/package-lock.json
#	packages/codeflash/package.json
#	tests/languages/javascript/test_support_dispatch.py
#	tests/test_codeflash_capture.py
#	tests/test_languages/test_javascript_test_runner.py
#	tests/test_multi_file_code_replacement.py
2026-03-04 01:52:32 -05:00

315 lines
12 KiB
Python

"""E2E tests for JavaScript/TypeScript optimization flow with backend.
These tests call the actual backend /testgen API endpoint and verify:
1. Language parameter is correctly passed to backend
2. Backend validates generated code with correct parser (JS vs TS)
3. CLI receives and processes tests correctly
Similar to test_validate_python_code.py but for JavaScript/TypeScript.
"""
from unittest.mock import patch
import pytest
from codeflash.api.aiservice import AiServiceClient
from codeflash.languages.base import Language
from codeflash.models.models import CodeString, OptimizedCandidateSource
def skip_if_js_not_supported():
"""Skip test if JavaScript/TypeScript languages are not supported."""
try:
from codeflash.languages import get_language_support
get_language_support(Language.JAVASCRIPT)
except Exception as e:
pytest.skip(f"JavaScript/TypeScript language support not available: {e}")
class TestJavaScriptCodeStringValidation:
"""Tests for JavaScript CodeString validation - mirrors test_validate_python_code.py."""
def test_javascript_string(self):
"""Test valid JavaScript code string."""
skip_if_js_not_supported()
code = CodeString(code="console.log('Hello, World!');", language="javascript")
assert code.code == "console.log('Hello, World!');"
def test_valid_javascript_code(self):
"""Test that valid JavaScript code passes validation."""
skip_if_js_not_supported()
valid_code = "const x = 1;\nconst y = x + 2;\nconsole.log(y);"
cs = CodeString(code=valid_code, language="javascript")
assert cs.code == valid_code
def test_invalid_javascript_code_syntax(self):
"""Test that invalid JavaScript code fails validation."""
skip_if_js_not_supported()
from pydantic import ValidationError
invalid_code = "const x = 1;\nconsole.log(x" # Missing parenthesis
with pytest.raises(ValidationError) as exc_info:
CodeString(code=invalid_code, language="javascript")
assert "Invalid Javascript code" in str(exc_info.value)
def test_empty_javascript_code(self):
"""Test that empty code passes validation."""
skip_if_js_not_supported()
empty_code = ""
cs = CodeString(code=empty_code, language="javascript")
assert cs.code == empty_code
class TestTypeScriptCodeStringValidation:
"""Tests for TypeScript CodeString validation."""
def test_typescript_string(self):
"""Test valid TypeScript code string."""
skip_if_js_not_supported()
code = CodeString(code="const x: number = 1;", language="typescript")
assert code.code == "const x: number = 1;"
def test_valid_typescript_code(self):
"""Test that valid TypeScript code passes validation."""
skip_if_js_not_supported()
valid_code = "function add(a: number, b: number): number { return a + b; }"
cs = CodeString(code=valid_code, language="typescript")
assert cs.code == valid_code
def test_typescript_type_assertion_valid(self):
"""TypeScript type assertions should pass TypeScript validation."""
skip_if_js_not_supported()
ts_code = "const value = 4.9 as unknown as number;"
cs = CodeString(code=ts_code, language="typescript")
assert cs.code == ts_code
def test_typescript_type_assertion_invalid_in_javascript(self):
"""TypeScript type assertions should FAIL JavaScript validation.
This is the critical test - TypeScript syntax like 'as unknown as number'
should fail when validated as JavaScript.
"""
skip_if_js_not_supported()
from pydantic import ValidationError
ts_code = "const value = 4.9 as unknown as number;"
with pytest.raises(ValidationError) as exc_info:
CodeString(code=ts_code, language="javascript")
assert "Invalid Javascript code" in str(exc_info.value)
def test_typescript_interface_valid(self):
"""TypeScript interfaces should pass TypeScript validation."""
skip_if_js_not_supported()
ts_code = "interface User { name: string; age: number; }"
cs = CodeString(code=ts_code, language="typescript")
assert cs.code == ts_code
def test_typescript_interface_invalid_in_javascript(self):
"""TypeScript interfaces should FAIL JavaScript validation."""
skip_if_js_not_supported()
from pydantic import ValidationError
ts_code = "interface User { name: string; age: number; }"
with pytest.raises(ValidationError) as exc_info:
CodeString(code=ts_code, language="javascript")
assert "Invalid Javascript code" in str(exc_info.value)
def test_typescript_generics_valid(self):
"""TypeScript generics should pass TypeScript validation."""
skip_if_js_not_supported()
ts_code = "function identity<T>(arg: T): T { return arg; }"
cs = CodeString(code=ts_code, language="typescript")
assert cs.code == ts_code
def test_typescript_generics_invalid_in_javascript(self):
"""TypeScript generics should FAIL JavaScript validation."""
skip_if_js_not_supported()
from pydantic import ValidationError
ts_code = "function identity<T>(arg: T): T { return arg; }"
with pytest.raises(ValidationError) as exc_info:
CodeString(code=ts_code, language="javascript")
assert "Invalid Javascript code" in str(exc_info.value)
class TestAiServiceClientJavaScript:
"""Tests for AiServiceClient with JavaScript/TypeScript - mirrors test_validate_python_code.py."""
def test_javascript_generated_candidates_validation(self):
"""Test that JavaScript candidates are validated correctly."""
skip_if_js_not_supported()
ai_service = AiServiceClient()
# Invalid JavaScript (missing closing parenthesis)
code = """```javascript:file.js
console.log(name
```"""
mock_candidates = [{"source_code": code, "explanation": "", "optimization_id": ""}]
candidates = ai_service._get_valid_candidates(mock_candidates, OptimizedCandidateSource.OPTIMIZE)
assert len(candidates) == 0
# Valid JavaScript
code = """```javascript:file.js
console.log('Hello, World!');
```"""
mock_candidates = [{"source_code": code, "explanation": "", "optimization_id": ""}]
candidates = ai_service._get_valid_candidates(mock_candidates, OptimizedCandidateSource.OPTIMIZE)
assert len(candidates) == 1
assert candidates[0].source_code.code_strings[0].code == "console.log('Hello, World!');"
def test_typescript_generated_candidates_validation(self):
"""Test that TypeScript candidates are validated correctly."""
skip_if_js_not_supported()
ai_service = AiServiceClient()
# Valid TypeScript with type annotations
code = """```typescript:file.ts
function add(a: number, b: number): number {
return a + b;
}
```"""
mock_candidates = [{"source_code": code, "explanation": "", "optimization_id": ""}]
candidates = ai_service._get_valid_candidates(mock_candidates, OptimizedCandidateSource.OPTIMIZE)
assert len(candidates) == 1
def test_typescript_type_assertion_in_candidate(self):
"""Test that TypeScript type assertions are valid in TS candidates."""
skip_if_js_not_supported()
ai_service = AiServiceClient()
# TypeScript-specific syntax should be valid
code = """```typescript:file.ts
const value = 4.9 as unknown as number;
```"""
mock_candidates = [{"source_code": code, "explanation": "", "optimization_id": ""}]
candidates = ai_service._get_valid_candidates(mock_candidates, OptimizedCandidateSource.OPTIMIZE)
assert len(candidates) == 1
class TestBackendLanguageParameter:
"""Tests verifying language parameter flows correctly to backend."""
def test_testgen_request_includes_typescript_language(self, tmp_path):
"""Verify the language parameter is sent as 'typescript' for .ts files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages import current as lang_current
# Set current language to TypeScript
lang_current._current_language = Language.TYPESCRIPT
ts_file = tmp_path / "utils.ts"
ts_file.write_text("""
export function add(a: number, b: number): number {
return a + b;
}
""")
functions = find_all_functions_in_file(ts_file)
func = functions[ts_file][0]
# Verify function has correct language
assert func.language == "typescript"
ai_client = AiServiceClient()
captured_payload = None
def capture_request(*args, **kwargs):
nonlocal captured_payload
if "payload" in kwargs:
captured_payload = kwargs["payload"]
elif len(args) > 1:
captured_payload = args[1]
# Return a mock response to avoid actual API call
from unittest.mock import MagicMock
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"generated_tests": "// test",
"instrumented_behavior_tests": "// test",
"instrumented_perf_tests": "// test",
}
return mock_response
with patch.object(ai_client, "make_ai_service_request", side_effect=capture_request):
ai_client.generate_regression_tests(
source_code_being_tested=ts_file.read_text(),
function_to_optimize=func,
helper_function_names=[],
module_path=ts_file,
test_module_path=tmp_path / "tests" / "utils.test.ts",
test_framework="vitest",
test_timeout=30,
trace_id="test-language-param-ts",
test_index=0,
language="typescript",
)
assert captured_payload is not None
assert captured_payload.get("language") == "typescript", (
f"Expected language='typescript', got: {captured_payload.get('language')}"
)
def test_testgen_request_includes_javascript_language(self, tmp_path):
"""Verify the language parameter is sent as 'javascript' for .js files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages import current as lang_current
# Set current language to JavaScript
lang_current._current_language = Language.JAVASCRIPT
js_file = tmp_path / "utils.js"
js_file.write_text("""
function add(a, b) {
return a + b;
}
module.exports = { add };
""")
functions = find_all_functions_in_file(js_file)
func = functions[js_file][0]
# Verify function has correct language
assert func.language == "javascript"
ai_client = AiServiceClient()
captured_payload = None
def capture_request(*args, **kwargs):
nonlocal captured_payload
if "payload" in kwargs:
captured_payload = kwargs["payload"]
elif len(args) > 1:
captured_payload = args[1]
from unittest.mock import MagicMock
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"generated_tests": "// test",
"instrumented_behavior_tests": "// test",
"instrumented_perf_tests": "// test",
}
return mock_response
with patch.object(ai_client, "make_ai_service_request", side_effect=capture_request):
ai_client.generate_regression_tests(
source_code_being_tested=js_file.read_text(),
function_to_optimize=func,
helper_function_names=[],
module_path=js_file,
test_module_path=tmp_path / "tests" / "utils.test.js",
test_framework="jest",
test_timeout=30,
trace_id="test-language-param-js",
test_index=0,
language="javascript",
)
assert captured_payload is not None
assert captured_payload.get("language") == "javascript", (
f"Expected language='javascript', got: {captured_payload.get('language')}"
)