"""Unit tests for HTML renderer.""" from datetime import datetime import pytest from py_dvt_ate.data.models import TestResult, TestRun, TestStatus from py_dvt_ate.reporting.exceptions import TemplateRenderError from py_dvt_ate.reporting.models import ReportConfig, ReportData from py_dvt_ate.reporting.renderers.html import HTMLRenderer class TestHTMLRenderer: """Tests for HTMLRenderer class.""" @pytest.fixture def renderer(self) -> HTMLRenderer: """Create an HTML renderer instance.""" return HTMLRenderer() @pytest.fixture def sample_run(self) -> TestRun: """Create a sample test run.""" return TestRun( id="12345678-1234-1234-1234-123456789abc", test_name="tempco", started_at=datetime(2024, 1, 15, 10, 30, 0), completed_at=datetime(2024, 1, 15, 10, 35, 0), status=TestStatus.PASSED, config_json='{"temperatures": [-40, 25, 85], "input_voltage": 5.0}', operator="test_user", description="Temperature coefficient characterisation test", ) @pytest.fixture def sample_results(self) -> list[TestResult]: """Create sample test results.""" return [ TestResult( id="result-1", test_run_id="12345678-1234-1234-1234-123456789abc", parameter="tempco", value=45.0, unit="ppm/C", measured_at=datetime(2024, 1, 15, 10, 35, 0), lower_limit=None, upper_limit=100.0, ), TestResult( id="result-2", test_run_id="12345678-1234-1234-1234-123456789abc", parameter="output_voltage_25c", value=3.3001, unit="V", measured_at=datetime(2024, 1, 15, 10, 33, 0), lower_limit=3.2, upper_limit=3.4, ), ] @pytest.fixture def sample_report_data( self, sample_run: TestRun, sample_results: list[TestResult] ) -> ReportData: """Create sample report data.""" return ReportData( run=sample_run, results=sample_results, config=ReportConfig(company_name="Test Company"), ) def test_render_produces_html( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render produces valid HTML output.""" html = renderer.render(sample_report_data) assert isinstance(html, str) assert html.startswith("") assert "" in html def test_render_includes_title( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes the test name in title.""" html = renderer.render(sample_report_data) assert "" in html assert "tempco" in html def test_render_includes_company_name( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes the company name.""" html = renderer.render(sample_report_data) assert "Test Company" in html def test_render_includes_results_table( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes results in a table.""" html = renderer.render(sample_report_data) # Check for parameter names in output assert "tempco" in html assert "output_voltage_25c" in html # Check for values assert "45.000000" in html assert "3.300100" in html def test_render_includes_pass_status( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render shows pass status badges.""" html = renderer.render(sample_report_data) # Check for PASS badge (results should pass) assert "PASS" in html def test_render_includes_run_metadata( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes run metadata.""" html = renderer.render(sample_report_data) assert "12345678-1234-1234-1234-123456789abc" in html assert "test_user" in html assert "Temperature coefficient characterisation test" in html def test_render_includes_css( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes CSS styles.""" html = renderer.render(sample_report_data) # Check for some CSS from styles.css assert "<style>" in html assert "@page" in html or "font-family" in html def test_render_includes_configuration( self, renderer: HTMLRenderer, sample_report_data: ReportData ) -> None: """Test that render includes test configuration.""" html = renderer.render(sample_report_data) # Check for config values (formatted JSON) assert "temperatures" in html assert "input_voltage" in html def test_render_with_charts( self, renderer: HTMLRenderer, sample_run: TestRun, sample_results: list[TestResult] ) -> None: """Test that render includes chart images.""" # Create sample base64 chart data charts = { "Test Chart": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" } data = ReportData( run=sample_run, results=sample_results, charts=charts, config=ReportConfig(), ) html = renderer.render(data) # Check for chart section and base64 image assert "Charts" in html assert "data:image/png;base64," in html def test_render_empty_results( self, renderer: HTMLRenderer, sample_run: TestRun ) -> None: """Test rendering with no results.""" data = ReportData( run=sample_run, results=[], config=ReportConfig(), ) html = renderer.render(data) # Should still produce valid HTML assert "<!DOCTYPE html>" in html assert "No results recorded" in html def test_css_is_cached(self, renderer: HTMLRenderer) -> None: """Test that CSS content is cached after first load.""" # Access CSS twice css1 = renderer._load_css() css2 = renderer._load_css() # Should be the same object (cached) assert css1 is css2 assert len(css1) > 0 def test_render_formats_limits( self, renderer: HTMLRenderer, sample_run: TestRun ) -> None: """Test that limits are properly formatted.""" results = [ TestResult( id="result-1", test_run_id="12345678-1234-1234-1234-123456789abc", parameter="test_param", value=50.0, unit="units", measured_at=datetime(2024, 1, 15, 10, 35, 0), lower_limit=10.0, upper_limit=100.0, ), ] data = ReportData(run=sample_run, results=results, config=ReportConfig()) html = renderer.render(data) # Check limits are formatted assert "10.000000" in html assert "100.000000" in html