codeflash/tests/test_languages/test_javascript_optimization_flow.py

536 lines
19 KiB
Python
Raw Permalink Normal View History

2026-02-04 23:01:48 +00:00
"""End-to-end tests for JavaScript/TypeScript optimization flow.
These tests verify the full optimization pipeline including:
- Test generation (with mocked backend)
- Language parameter propagation
- Syntax validation with correct parser
- Running and parsing tests
This is the JavaScript equivalent of test_instrument_tests.py for Python.
"""
from unittest.mock import MagicMock, patch
import pytest
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
from codeflash.languages.base import Language
from codeflash.models.models import CodeString, FunctionParent
from codeflash.verification.verification_utils import TestConfig
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 TestLanguageParameterPropagation:
"""Tests verifying language parameter is correctly passed through all layers."""
def test_function_to_optimize_has_correct_language_for_typescript(self, tmp_path):
"""Verify FunctionToOptimize has language='typescript' for .ts files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
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)
assert ts_file in functions
assert len(functions[ts_file]) == 1
assert functions[ts_file][0].language == "typescript"
def test_function_to_optimize_has_correct_language_for_javascript(self, tmp_path):
"""Verify FunctionToOptimize has language='javascript' for .js files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
js_file = tmp_path / "utils.js"
js_file.write_text("""
function add(a, b) {
2026-02-04 23:01:48 +00:00
return a + b;
}
module.exports = { add };
2026-02-04 23:01:48 +00:00
""")
functions = find_all_functions_in_file(js_file)
assert js_file in functions
assert len(functions[js_file]) == 1
assert functions[js_file][0].language == "javascript"
def test_code_context_preserves_language(self, tmp_path):
"""Verify language is preserved in code context extraction."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages import get_language_support
from codeflash.languages.javascript.function_optimizer import JavaScriptFunctionOptimizer
2026-02-04 23:01:48 +00:00
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]
ts_support = get_language_support(Language.TYPESCRIPT)
code_context = ts_support.extract_code_context(func, tmp_path, tmp_path)
context = JavaScriptFunctionOptimizer._build_optimization_context(code_context, ts_file, "typescript", tmp_path)
2026-02-04 23:01:48 +00:00
assert context.read_writable_code is not None
assert context.read_writable_code.language == "typescript"
class TestCodeStringSyntaxValidation:
"""Tests verifying CodeString validates with correct parser based on language."""
def test_typescript_code_valid_with_typescript_language(self):
"""TypeScript code should pass validation when language='typescript'."""
skip_if_js_not_supported()
ts_code = "const value = 4.9 as unknown as number;"
code_string = CodeString(code=ts_code, language="typescript")
assert code_string.code == ts_code
def test_typescript_code_invalid_with_javascript_language(self):
"""TypeScript code should FAIL validation when language='javascript'.
This is the exact bug that was in production - TypeScript code being
validated with JavaScript parser.
"""
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_with_typescript_language(self):
"""TypeScript interface should pass validation when language='typescript'."""
skip_if_js_not_supported()
ts_code = "interface User { name: string; age: number; }"
code_string = CodeString(code=ts_code, language="typescript")
assert code_string.code == ts_code
def test_typescript_interface_invalid_with_javascript_language(self):
"""TypeScript interface should FAIL validation when language='javascript'."""
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)
class TestBackendAPIResponseValidation:
"""Tests verifying backend API responses are validated with correct parser."""
def test_testgen_request_includes_correct_language(self, tmp_path):
"""Verify test generation request includes the correct language parameter."""
skip_if_js_not_supported()
from codeflash.api.aiservice import AiServiceClient
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages import current as lang_current
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"
# Mock the AI service request
ai_client = AiServiceClient()
with patch.object(ai_client, "make_ai_service_request") as mock_request:
2026-02-04 23:01:48 +00:00
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
"generated_tests": "// test code",
"instrumented_behavior_tests": "// behavior code",
"instrumented_perf_tests": "// perf code",
}
mock_request.return_value = mock_response
# Call generate_regression_tests with correct parameters
ai_client.generate_regression_tests(
source_code_being_tested="export function add(a: number, b: number): number { return a + b; }",
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-trace-id",
test_index=0,
language=func.language, # This is the key - language should be "typescript"
)
# Verify the request was made with correct language
assert mock_request.called, "API request should have been made"
call_args = mock_request.call_args
payload = call_args[1].get("payload", call_args[0][1] if len(call_args[0]) > 1 else {})
assert payload.get("language") == "typescript", (
2026-02-04 23:01:48 +00:00
f"Expected language='typescript', got language='{payload.get('language')}'"
)
2026-02-04 23:01:48 +00:00
class TestFunctionOptimizerForJavaScript:
"""Tests for FunctionOptimizer with JavaScript/TypeScript functions.
This is the JavaScript equivalent of test_instrument_tests.py tests.
"""
@pytest.fixture
def js_project(self, tmp_path):
"""Create a minimal JavaScript project for testing."""
project = tmp_path / "js_project"
project.mkdir()
# Create source file
src_file = project / "utils.js"
src_file.write_text("""
function fibonacci(n) {
2026-02-04 23:01:48 +00:00
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
module.exports = { fibonacci };
2026-02-04 23:01:48 +00:00
""")
# Create test file
tests_dir = project / "tests"
tests_dir.mkdir()
test_file = tests_dir / "utils.test.js"
test_file.write_text("""
const { fibonacci } = require('../utils');
describe('fibonacci', () => {
test('returns 0 for n=0', () => {
expect(fibonacci(0)).toBe(0);
});
test('returns 1 for n=1', () => {
expect(fibonacci(1)).toBe(1);
});
test('returns 5 for n=5', () => {
expect(fibonacci(5)).toBe(5);
});
});
""")
# Create package.json
package_json = project / "package.json"
package_json.write_text("""
{
"name": "test-project",
"devDependencies": {
"jest": "^29.0.0"
}
}
""")
return project
@pytest.fixture
def ts_project(self, tmp_path):
"""Create a minimal TypeScript project for testing."""
project = tmp_path / "ts_project"
project.mkdir()
# Create source file
src_file = project / "utils.ts"
src_file.write_text("""
export function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
""")
# Create test file
tests_dir = project / "tests"
tests_dir.mkdir()
test_file = tests_dir / "utils.test.ts"
test_file.write_text("""
import { fibonacci } from '../utils';
describe('fibonacci', () => {
test('returns 0 for n=0', () => {
expect(fibonacci(0)).toBe(0);
});
test('returns 1 for n=1', () => {
expect(fibonacci(1)).toBe(1);
});
});
""")
# Create package.json
package_json = project / "package.json"
package_json.write_text("""
{
"name": "test-project",
"devDependencies": {
"vitest": "^1.0.0"
}
}
""")
return project
def test_function_optimizer_instantiation_javascript(self, js_project):
"""Test FunctionOptimizer can be instantiated for JavaScript."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.function_optimizer import FunctionOptimizer
2026-02-04 23:01:48 +00:00
src_file = js_project / "utils.js"
functions = find_all_functions_in_file(src_file)
func = functions[src_file][0]
func_to_optimize = FunctionToOptimize(
function_name=func.function_name,
file_path=func.file_path,
parents=[FunctionParent(name=p.name, type=p.type) for p in func.parents],
starting_line=func.starting_line,
ending_line=func.ending_line,
language=func.language,
)
test_config = TestConfig(
tests_root=js_project / "tests",
tests_project_rootdir=js_project,
project_root_path=js_project,
pytest_cmd="jest",
)
optimizer = FunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
assert optimizer is not None
assert optimizer.function_to_optimize.language == "javascript"
def test_function_optimizer_instantiation_typescript(self, ts_project):
"""Test FunctionOptimizer can be instantiated for TypeScript."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.function_optimizer import FunctionOptimizer
2026-02-04 23:01:48 +00:00
src_file = ts_project / "utils.ts"
functions = find_all_functions_in_file(src_file)
func = functions[src_file][0]
func_to_optimize = FunctionToOptimize(
function_name=func.function_name,
file_path=func.file_path,
parents=[FunctionParent(name=p.name, type=p.type) for p in func.parents],
starting_line=func.starting_line,
ending_line=func.ending_line,
language=func.language,
)
test_config = TestConfig(
tests_root=ts_project / "tests",
tests_project_rootdir=ts_project,
project_root_path=ts_project,
pytest_cmd="vitest",
)
optimizer = FunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
assert optimizer is not None
assert optimizer.function_to_optimize.language == "typescript"
def test_get_code_optimization_context_javascript(self, js_project):
"""Test get_code_optimization_context for JavaScript."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.javascript.function_optimizer import JavaScriptFunctionOptimizer
2026-02-04 23:01:48 +00:00
src_file = js_project / "utils.js"
functions = find_all_functions_in_file(src_file)
func = functions[src_file][0]
func_to_optimize = FunctionToOptimize(
function_name=func.function_name,
file_path=func.file_path,
parents=[FunctionParent(name=p.name, type=p.type) for p in func.parents],
starting_line=func.starting_line,
ending_line=func.ending_line,
language=func.language,
)
test_config = TestConfig(
tests_root=js_project / "tests",
tests_project_rootdir=js_project,
project_root_path=js_project,
pytest_cmd="jest",
)
optimizer = JavaScriptFunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
result = optimizer.get_code_optimization_context()
context = result.unwrap()
assert context is not None
assert context.read_writable_code is not None
assert context.read_writable_code.language == "javascript"
def test_get_code_optimization_context_typescript(self, ts_project):
"""Test get_code_optimization_context for TypeScript."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.javascript.function_optimizer import JavaScriptFunctionOptimizer
2026-02-04 23:01:48 +00:00
src_file = ts_project / "utils.ts"
functions = find_all_functions_in_file(src_file)
func = functions[src_file][0]
func_to_optimize = FunctionToOptimize(
function_name=func.function_name,
file_path=func.file_path,
parents=[FunctionParent(name=p.name, type=p.type) for p in func.parents],
starting_line=func.starting_line,
ending_line=func.ending_line,
language=func.language,
)
test_config = TestConfig(
tests_root=ts_project / "tests",
tests_project_rootdir=ts_project,
project_root_path=ts_project,
pytest_cmd="vitest",
)
optimizer = JavaScriptFunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
result = optimizer.get_code_optimization_context()
context = result.unwrap()
assert context is not None
assert context.read_writable_code is not None
assert context.read_writable_code.language == "typescript"
class TestHelperFunctionLanguageAttribute:
"""Tests for helper function language attribute (import_resolver.py fix)."""
def test_helper_functions_have_correct_language_javascript(self, tmp_path):
"""Verify helper functions have language='javascript' for .js files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.javascript.function_optimizer import JavaScriptFunctionOptimizer
2026-02-04 23:01:48 +00:00
# Create a file with helper functions
src_file = tmp_path / "main.js"
src_file.write_text("""
function helper() {
return 42;
}
function main() {
2026-02-04 23:01:48 +00:00
return helper() * 2;
}
module.exports = { main };
2026-02-04 23:01:48 +00:00
""")
functions = find_all_functions_in_file(src_file)
main_func = next(f for f in functions[src_file] if f.function_name == "main")
func_to_optimize = FunctionToOptimize(
function_name=main_func.function_name,
file_path=main_func.file_path,
parents=[],
starting_line=main_func.starting_line,
ending_line=main_func.ending_line,
language=main_func.language,
)
test_config = TestConfig(
tests_root=tmp_path, tests_project_rootdir=tmp_path, project_root_path=tmp_path, pytest_cmd="jest"
2026-02-04 23:01:48 +00:00
)
optimizer = JavaScriptFunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
result = optimizer.get_code_optimization_context()
context = result.unwrap()
# Verify main function has correct language
assert context.read_writable_code.language == "javascript"
def test_helper_functions_have_correct_language_typescript(self, tmp_path):
"""Verify helper functions have language='typescript' for .ts files."""
skip_if_js_not_supported()
from codeflash.discovery.functions_to_optimize import find_all_functions_in_file
from codeflash.languages.javascript.function_optimizer import JavaScriptFunctionOptimizer
2026-02-04 23:01:48 +00:00
# Create a file with helper functions
src_file = tmp_path / "main.ts"
src_file.write_text("""
function helper(): number {
return 42;
}
export function main(): number {
return helper() * 2;
}
""")
functions = find_all_functions_in_file(src_file)
main_func = next(f for f in functions[src_file] if f.function_name == "main")
func_to_optimize = FunctionToOptimize(
function_name=main_func.function_name,
file_path=main_func.file_path,
parents=[],
starting_line=main_func.starting_line,
ending_line=main_func.ending_line,
language=main_func.language,
)
test_config = TestConfig(
tests_root=tmp_path, tests_project_rootdir=tmp_path, project_root_path=tmp_path, pytest_cmd="vitest"
2026-02-04 23:01:48 +00:00
)
optimizer = JavaScriptFunctionOptimizer(
function_to_optimize=func_to_optimize, test_cfg=test_config, aiservice_client=MagicMock()
2026-02-04 23:01:48 +00:00
)
result = optimizer.get_code_optimization_context()
context = result.unwrap()
# Verify main function has correct language
assert context.read_writable_code.language == "typescript"