diff --git a/fusion_plating/fusion_plating_quality/tests/test_dashboard_snapshot.py b/fusion_plating/fusion_plating_quality/tests/test_dashboard_snapshot.py index 41ea9855..5adbfc77 100644 --- a/fusion_plating/fusion_plating_quality/tests/test_dashboard_snapshot.py +++ b/fusion_plating/fusion_plating_quality/tests/test_dashboard_snapshot.py @@ -170,3 +170,38 @@ class TestDashboardSnapshotBanner(TransactionCase): # Empty DB — no overdue, no critical self.assertTrue(snap['banner']['all_clear']) self.assertEqual(snap['banner']['items'], []) + + +class TestDashboardSnapshotDefensive(TransactionCase): + """Module-not-installed + missing-field guards.""" + + def _build(self): + from odoo.addons.fusion_plating_quality.controllers.fp_quality_dashboard \ + import FpQualityDashboardSnapshot + return FpQualityDashboardSnapshot(self.env).build() + + def test_missing_partner_field_falls_through(self): + # Empty DB + helper must not raise even when x_fc_rush absent. + # (In this codebase x_fc_rush isn't a registered field — only + # read defensively via the `in partner._fields` check. The + # snapshot must build cleanly.) + snap = self._build() + self.assertIn('banner', snap) + self.assertTrue(snap['banner']['all_clear']) + + def test_computed_at_is_iso_string(self): + from datetime import datetime + snap = self._build() + self.assertIsInstance(snap['computed_at'], str) + # Must be parseable as ISO timestamp + datetime.fromisoformat(snap['computed_at']) + + def test_all_sections_have_open_kanban_xmlid(self): + snap = self._build() + for section in snap['sections']: + self.assertTrue( + section['open_kanban_xmlid'], + f"section {section['type']} missing open_kanban_xmlid", + ) + # Should contain a dot (module.xmlid format) + self.assertIn('.', section['open_kanban_xmlid'])