mirror of
https://github.com/codeflash-ai/codeflash-internal.git
synced 2026-05-04 18:25:18 +00:00
327 lines
9.9 KiB
Python
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
|