@@ -54,11 +54,11 @@ def test_unknown_specific_model_logs_warning_no_exception(self, caplog):
5454
5555
5656class TestRegisterTabs :
57- def test_dispatches_combined_and_typed_tabs (self ):
57+ def test_dispatches_combined_tabs_immediately_and_defers_typed (self ):
58+ """register_tabs() registers combined tabs in ready() and defers typed tabs."""
5859 from netbox_custom_objects_tab import views
5960
6061 combined_models = [MagicMock ()]
61- typed_models = [MagicMock ()]
6262
6363 config_map = {
6464 "combined_models" : ["dcim.device" ],
@@ -70,14 +70,52 @@ def test_dispatches_combined_and_typed_tabs(self):
7070
7171 with (
7272 patch .object (views , "get_plugin_config" , side_effect = lambda _plugin , key : config_map [key ]),
73- patch .object (views , "_resolve_model_labels" , side_effect = [ combined_models , typed_models ] ),
73+ patch .object (views , "_resolve_model_labels" , return_value = combined_models ),
7474 patch .object (views , "register_combined_tabs" ) as register_combined ,
7575 patch .object (views , "register_typed_tabs" ) as register_typed ,
76+ patch ("django.core.signals.request_started" ) as mock_signal ,
7677 ):
7778 views .register_tabs ()
7879
80+ # Combined tabs registered immediately
7981 register_combined .assert_called_once_with (combined_models , "Custom Objects" , 2000 )
80- register_typed .assert_called_once_with (typed_models , 2100 )
82+ # Typed tabs NOT called during register_tabs() — deferred to first request
83+ register_typed .assert_not_called ()
84+ # Signal handler connected for deferred init
85+ mock_signal .connect .assert_called_once ()
86+
87+ def test_deferred_init_dispatches_typed_tabs (self ):
88+ """_deferred_typed_init() resolves labels and registers typed tabs."""
89+ from netbox_custom_objects_tab import views
90+
91+ typed_models = [MagicMock ()]
92+ typed_models [0 ]._meta .app_label = "ipam"
93+
94+ # Reset the deferred state so the handler can run
95+ views ._deferred_init_done = False
96+ views ._deferred_config .update (
97+ {
98+ "combined_models" : [],
99+ "typed_labels" : ["ipam.prefix" ],
100+ "typed_weight" : 2100 ,
101+ }
102+ )
103+
104+ try :
105+ with (
106+ patch .object (views , "_resolve_model_labels" , return_value = typed_models ),
107+ patch .object (views , "register_typed_tabs" ) as register_typed ,
108+ patch .object (views , "_inject_co_urls" ),
109+ patch .object (views , "_deduplicate_registry" ),
110+ patch ("django.core.signals.request_started" ),
111+ ):
112+ views ._deferred_typed_init ()
113+
114+ register_typed .assert_called_once_with (typed_models , 2100 )
115+ finally :
116+ # Clean up global state
117+ views ._deferred_init_done = False
118+ views ._deferred_config .clear ()
81119
82120 def test_skips_dispatch_when_configured_model_lists_are_empty (self ):
83121 from netbox_custom_objects_tab import views
@@ -94,25 +132,22 @@ def test_skips_dispatch_when_configured_model_lists_are_empty(self):
94132 patch .object (views , "get_plugin_config" , side_effect = lambda _plugin , key : config_map [key ]),
95133 patch .object (views , "_resolve_model_labels" ) as resolve_labels ,
96134 patch .object (views , "register_combined_tabs" ) as register_combined ,
97- patch . object ( views , "register_typed_tabs" ) as register_typed ,
135+ patch ( "django.core.signals.request_started" ) ,
98136 ):
99137 views .register_tabs ()
100138
101139 resolve_labels .assert_not_called ()
102140 register_combined .assert_not_called ()
103- register_typed .assert_not_called ()
104141
105142 def test_config_exception_is_handled (self , caplog ):
106143 from netbox_custom_objects_tab import views
107144
108145 with (
109146 patch .object (views , "get_plugin_config" , side_effect = RuntimeError ("boom" )),
110147 patch .object (views , "register_combined_tabs" ) as register_combined ,
111- patch .object (views , "register_typed_tabs" ) as register_typed ,
112148 ):
113149 with caplog .at_level (logging .ERROR , logger = "netbox_custom_objects_tab" ):
114150 views .register_tabs ()
115151
116152 register_combined .assert_not_called ()
117- register_typed .assert_not_called ()
118153 assert any ("Could not read netbox_custom_objects_tab plugin config" in r .message for r in caplog .records )
0 commit comments