codeflash-internal/django/aiservice/tests/testgen_instrumentation/test_instrument_javascript.py
2026-01-14 22:15:27 -08:00

327 lines
9.9 KiB
Python

"""Tests for JavaScript test instrumentation."""
from pathlib import Path
import pytest
from testgen.instrumentation.javascript.instrument_javascript import (
get_jest_helper_path,
get_jest_setup_code,
instrument_javascript_tests,
)
class TestJestHelperPath:
"""Tests for Jest helper path resolution."""
def test_helper_path_exists(self) -> None:
"""Test that the Jest helper file exists."""
helper_path = get_jest_helper_path()
assert helper_path.exists()
assert helper_path.is_file()
assert helper_path.name == "codeflash-jest-helper.js"
def test_helper_path_is_javascript(self) -> None:
"""Test that the helper file has .js extension."""
helper_path = get_jest_helper_path()
assert helper_path.suffix == ".js"
def test_helper_contains_capture_function(self) -> None:
"""Test that the helper contains the capture function."""
helper_path = get_jest_helper_path()
content = helper_path.read_text()
assert "function capture" in content
assert "module.exports" in content
class TestJestSetupCode:
"""Tests for Jest setup code generation."""
def test_generates_environment_variables(self) -> None:
"""Test that setup code sets environment variables."""
setup = get_jest_setup_code("/tmp/results.bin", "behavior", 0)
assert "CODEFLASH_OUTPUT_FILE" in setup
assert "/tmp/results.bin" in setup
assert "CODEFLASH_MODE" in setup
assert "behavior" in setup
assert "CODEFLASH_LOOP_INDEX" in setup
def test_performance_mode(self) -> None:
"""Test setup code for performance mode."""
setup = get_jest_setup_code("/tmp/results.bin", "performance", 5)
assert "performance" in setup
assert "'5'" in setup or "5" in setup
class TestInstrumentJavaScriptTests:
"""Tests for the main instrumentation function."""
def test_adds_helper_import(self) -> None:
"""Test that the codeflash helper import is added."""
test_source = """
const { fibonacci } = require('./fibonacci');
describe('fibonacci', () => {
test('should return 0 for n=0', () => {
expect(fibonacci(0)).toBe(0);
});
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="fibonacci",
module_path="./fibonacci",
)
assert "codeflash-jest-helper" in result
assert "const codeflash = require" in result
def test_does_not_duplicate_import(self) -> None:
"""Test that import is not duplicated if already present."""
test_source = """
const codeflash = require('codeflash-jest-helper');
const { fibonacci } = require('./fibonacci');
describe('fibonacci', () => {
test('should return 0 for n=0', () => {
expect(codeflash.capture('fibonacci', fibonacci, 0)).toBe(0);
});
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="fibonacci",
module_path="./fibonacci",
)
# Should only have one import
assert result.count("codeflash-jest-helper") == 1
def test_wraps_function_calls(self) -> None:
"""Test that function calls are wrapped with codeflash.capture."""
test_source = """
const { add } = require('./math');
describe('add', () => {
test('should add two numbers', () => {
const result = add(1, 2);
expect(result).toBe(3);
});
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="add",
module_path="./math",
)
assert "codeflash.capture('add', add, 1, 2)" in result
def test_wraps_function_without_args(self) -> None:
"""Test wrapping function calls without arguments."""
test_source = """
const { getVersion } = require('./utils');
test('should return version', () => {
expect(getVersion()).toBe('1.0.0');
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="getVersion",
module_path="./utils",
)
assert "codeflash.capture('getVersion', getVersion)" in result
def test_preserves_test_structure(self) -> None:
"""Test that the overall test structure is preserved."""
test_source = """
const { sort } = require('./sort');
describe('sort', () => {
describe('basic cases', () => {
test('should sort empty array', () => {
expect(sort([])).toEqual([]);
});
test('should sort single element', () => {
expect(sort([1])).toEqual([1]);
});
});
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="sort",
module_path="./sort",
)
# Test structure should be preserved
assert "describe('sort'" in result
assert "describe('basic cases'" in result
assert "test('should sort empty array'" in result
assert "test('should sort single element'" in result
def test_handles_es6_imports(self) -> None:
"""Test that ES6 imports are handled correctly."""
test_source = """
import { fibonacci } from './fibonacci';
describe('fibonacci', () => {
test('base case', () => {
expect(fibonacci(0)).toBe(0);
});
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="fibonacci",
module_path="./fibonacci",
)
# Helper should be added
assert "codeflash-jest-helper" in result
# Original import should be preserved
assert "import { fibonacci }" in result
def test_does_not_wrap_method_calls(self) -> None:
"""Test that method calls on objects are not wrapped."""
test_source = """
const { Calculator } = require('./calc');
test('should add', () => {
const calc = new Calculator();
expect(calc.add(1, 2)).toBe(3);
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="add",
module_path="./calc",
)
# Method calls should NOT be wrapped (they have a dot before them)
# Only standalone function calls should be wrapped
assert "calc.add" in result # Method call preserved
# But not wrapped (no codeflash.capture around method call)
def test_handles_multiple_calls_same_test(self) -> None:
"""Test handling multiple function calls in the same test."""
test_source = """
const { process } = require('./processor');
test('should process multiple inputs', () => {
const result1 = process('a');
const result2 = process('b');
const result3 = process('c');
expect([result1, result2, result3]).toEqual(['A', 'B', 'C']);
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="process",
module_path="./processor",
)
# All three calls should be wrapped
assert result.count("codeflash.capture('process'") == 3
def test_handles_async_functions(self) -> None:
"""Test instrumentation of async function calls."""
test_source = """
const { fetchData } = require('./api');
test('should fetch data', async () => {
const data = await fetchData('http://example.com');
expect(data).toBeDefined();
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="fetchData",
module_path="./api",
)
# Should wrap the async function call
assert "codeflash.capture('fetchData'" in result
class TestInstrumentationEdgeCases:
"""Tests for edge cases in instrumentation."""
def test_function_name_in_string_not_wrapped(self) -> None:
"""Test that function names in strings are not wrapped."""
test_source = """
const { add } = require('./math');
test('should call add function', () => {
console.log('Calling add function');
expect(add(1, 2)).toBe(3);
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="add",
module_path="./math",
)
# The string should remain unchanged
assert "'Calling add function'" in result
# But the actual call should be wrapped
assert "codeflash.capture('add', add, 1, 2)" in result
def test_function_name_in_comment_not_wrapped(self) -> None:
"""Test that function names in comments are not wrapped."""
test_source = """
const { multiply } = require('./math');
test('should multiply', () => {
// multiply is the function we're testing
const result = multiply(2, 3);
expect(result).toBe(6);
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="multiply",
module_path="./math",
)
# The actual call should be wrapped
assert "codeflash.capture('multiply', multiply, 2, 3)" in result
def test_empty_test_file(self) -> None:
"""Test handling of empty test file."""
result = instrument_javascript_tests(
test_source="",
function_name="test",
module_path="./test",
)
# Should add the helper import even to empty file
assert "codeflash-jest-helper" in result
def test_complex_arguments(self) -> None:
"""Test handling of complex function arguments."""
test_source = """
const { process } = require('./processor');
test('should process', () => {
const result = process({ key: 'value' }, [1, 2, 3], () => true);
expect(result).toBeDefined();
});
"""
result = instrument_javascript_tests(
test_source=test_source,
function_name="process",
module_path="./processor",
)
# Should handle complex arguments
assert "codeflash.capture('process'" in result