Navegador

navegador / tests / test_enrichment_react_native.py
Source Blame History 261 lines
96b97a1… lmata 1 """Tests for navegador.enrichment.react_native — ReactNativeEnricher."""
96b97a1… lmata 2
96b97a1… lmata 3 from unittest.mock import MagicMock
96b97a1… lmata 4
96b97a1… lmata 5 import pytest
96b97a1… lmata 6
96b97a1… lmata 7 from navegador.enrichment import EnrichmentResult
96b97a1… lmata 8 from navegador.enrichment.react_native import ReactNativeEnricher
96b97a1… lmata 9 from navegador.graph.store import GraphStore
96b97a1… lmata 10
96b97a1… lmata 11
96b97a1… lmata 12 # ── Helpers ───────────────────────────────────────────────────────────────────
96b97a1… lmata 13
96b97a1… lmata 14
96b97a1… lmata 15 def _mock_store(result_set=None):
96b97a1… lmata 16 client = MagicMock()
96b97a1… lmata 17 graph = MagicMock()
96b97a1… lmata 18 graph.query.return_value = MagicMock(result_set=result_set)
96b97a1… lmata 19 client.select_graph.return_value = graph
96b97a1… lmata 20 return GraphStore(client)
96b97a1… lmata 21
96b97a1… lmata 22
96b97a1… lmata 23 def _mock_store_with_responses(responses):
96b97a1… lmata 24 """Return a GraphStore whose graph.query returns the given result sets in order.
96b97a1… lmata 25
96b97a1… lmata 26 Any calls beyond the provided list (e.g. _promote_node SET queries) receive
96b97a1… lmata 27 a MagicMock with result_set=None, which is harmless.
96b97a1… lmata 28 """
96b97a1… lmata 29 client = MagicMock()
96b97a1… lmata 30 graph = MagicMock()
96b97a1… lmata 31 response_iter = iter(responses)
96b97a1… lmata 32
96b97a1… lmata 33 def _side_effect(cypher, params):
96b97a1… lmata 34 try:
96b97a1… lmata 35 rs = next(response_iter)
96b97a1… lmata 36 except StopIteration:
96b97a1… lmata 37 rs = None
96b97a1… lmata 38 return MagicMock(result_set=rs)
96b97a1… lmata 39
96b97a1… lmata 40 graph.query.side_effect = _side_effect
96b97a1… lmata 41 client.select_graph.return_value = graph
96b97a1… lmata 42 return GraphStore(client)
96b97a1… lmata 43
96b97a1… lmata 44
96b97a1… lmata 45 # ── framework_name ────────────────────────────────────────────────────────────
96b97a1… lmata 46
96b97a1… lmata 47
96b97a1… lmata 48 class TestFrameworkName:
96b97a1… lmata 49 def test_framework_name_is_react_native(self):
96b97a1… lmata 50 enricher = ReactNativeEnricher(_mock_store())
96b97a1… lmata 51 assert enricher.framework_name == "react-native"
96b97a1… lmata 52
96b97a1… lmata 53
96b97a1… lmata 54 # ── detection_patterns ────────────────────────────────────────────────────────
96b97a1… lmata 55
96b97a1… lmata 56
96b97a1… lmata 57 class TestDetectionPatterns:
96b97a1… lmata 58 def test_contains_react_native_hyphenated(self):
96b97a1… lmata 59 enricher = ReactNativeEnricher(_mock_store())
96b97a1… lmata 60 assert "react-native" in enricher.detection_patterns
96b97a1… lmata 61
96b97a1… lmata 62 def test_contains_expo(self):
96b97a1… lmata 63 enricher = ReactNativeEnricher(_mock_store())
96b97a1… lmata 64 assert "expo" in enricher.detection_patterns
96b97a1… lmata 65
96b97a1… lmata 66 def test_returns_list(self):
96b97a1… lmata 67 enricher = ReactNativeEnricher(_mock_store())
96b97a1… lmata 68 assert isinstance(enricher.detection_patterns, list)
2c266d2… lmata 69
2c266d2… lmata 70 def test_has_at_least_two_patterns(self):
2c266d2… lmata 71 enricher = ReactNativeEnricher(_mock_store())
2c266d2… lmata 72 assert len(enricher.detection_patterns) >= 2
96b97a1… lmata 73
96b97a1… lmata 74
96b97a1… lmata 75 # ── detect() ─────────────────────────────────────────────────────────────────
96b97a1… lmata 76
96b97a1… lmata 77
96b97a1… lmata 78 class TestDetect:
96b97a1… lmata 79 def test_returns_true_when_pattern_found(self):
96b97a1… lmata 80 store = _mock_store(result_set=[[1]])
96b97a1… lmata 81 enricher = ReactNativeEnricher(store)
96b97a1… lmata 82 assert enricher.detect() is True
96b97a1… lmata 83
96b97a1… lmata 84 def test_returns_false_when_no_match(self):
96b97a1… lmata 85 store = _mock_store(result_set=[[0]])
96b97a1… lmata 86 enricher = ReactNativeEnricher(store)
96b97a1… lmata 87 assert enricher.detect() is False
96b97a1… lmata 88
96b97a1… lmata 89 def test_returns_false_on_empty_result_set(self):
96b97a1… lmata 90 store = _mock_store(result_set=[])
96b97a1… lmata 91 enricher = ReactNativeEnricher(store)
96b97a1… lmata 92 assert enricher.detect() is False
96b97a1… lmata 93
96b97a1… lmata 94 def test_short_circuits_on_first_match(self):
96b97a1… lmata 95 store = _mock_store(result_set=[[1]])
96b97a1… lmata 96 enricher = ReactNativeEnricher(store)
96b97a1… lmata 97 assert enricher.detect() is True
96b97a1… lmata 98 assert store._graph.query.call_count == 1
96b97a1… lmata 99
96b97a1… lmata 100
96b97a1… lmata 101 # ── enrich() ─────────────────────────────────────────────────────────────────
96b97a1… lmata 102
96b97a1… lmata 103
96b97a1… lmata 104 class TestEnrich:
96b97a1… lmata 105 def _empty_enricher(self):
96b97a1… lmata 106 # 4 pattern queries: components, screens, hooks, navigation
96b97a1… lmata 107 store = _mock_store_with_responses([[], [], [], []])
96b97a1… lmata 108 return ReactNativeEnricher(store)
96b97a1… lmata 109
96b97a1… lmata 110 def test_returns_enrichment_result(self):
96b97a1… lmata 111 assert isinstance(self._empty_enricher().enrich(), EnrichmentResult)
96b97a1… lmata 112
96b97a1… lmata 113 def test_zero_promoted_when_no_matches(self):
96b97a1… lmata 114 result = self._empty_enricher().enrich()
96b97a1… lmata 115 assert result.promoted == 0
96b97a1… lmata 116
96b97a1… lmata 117 def test_patterns_found_keys_present(self):
96b97a1… lmata 118 result = self._empty_enricher().enrich()
96b97a1… lmata 119 assert "components" in result.patterns_found
96b97a1… lmata 120 assert "screens" in result.patterns_found
96b97a1… lmata 121 assert "hooks" in result.patterns_found
96b97a1… lmata 122 assert "navigation" in result.patterns_found
96b97a1… lmata 123
96b97a1… lmata 124 def test_promotes_component_nodes(self):
96b97a1… lmata 125 """JSX/TSX nodes should become RNComponent."""
96b97a1… lmata 126 store = _mock_store_with_responses(
96b97a1… lmata 127 [
96b97a1… lmata 128 [["Button", "src/components/Button.tsx"]], # components
96b97a1… lmata 129 [], # screens
96b97a1… lmata 130 [], # hooks
96b97a1… lmata 131 [], # navigation
96b97a1… lmata 132 ]
96b97a1… lmata 133 )
96b97a1… lmata 134 enricher = ReactNativeEnricher(store)
96b97a1… lmata 135 result = enricher.enrich()
96b97a1… lmata 136 assert result.promoted == 1
96b97a1… lmata 137 assert result.patterns_found["components"] == 1
96b97a1… lmata 138
96b97a1… lmata 139 calls = store._graph.query.call_args_list
96b97a1… lmata 140 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 141 assert len(promote_calls) == 1
96b97a1… lmata 142 assert promote_calls[0][0][1]["semantic_type"] == "RNComponent"
96b97a1… lmata 143
96b97a1… lmata 144 def test_promotes_screen_nodes_by_path(self):
96b97a1… lmata 145 """Nodes under /screens/ should become RNScreen."""
96b97a1… lmata 146 store = _mock_store_with_responses(
96b97a1… lmata 147 [
96b97a1… lmata 148 [], # components
96b97a1… lmata 149 [["HomeScreen", "src/screens/HomeScreen.tsx"]], # screens
96b97a1… lmata 150 [], # hooks
96b97a1… lmata 151 [], # navigation
96b97a1… lmata 152 ]
96b97a1… lmata 153 )
96b97a1… lmata 154 enricher = ReactNativeEnricher(store)
96b97a1… lmata 155 result = enricher.enrich()
96b97a1… lmata 156 assert result.promoted == 1
96b97a1… lmata 157 assert result.patterns_found["screens"] == 1
96b97a1… lmata 158
96b97a1… lmata 159 calls = store._graph.query.call_args_list
96b97a1… lmata 160 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 161 assert promote_calls[0][0][1]["semantic_type"] == "RNScreen"
96b97a1… lmata 162
96b97a1… lmata 163 def test_promotes_screen_nodes_by_name_suffix(self):
96b97a1… lmata 164 """Nodes whose name ends with 'Screen' should become RNScreen."""
96b97a1… lmata 165 store = _mock_store_with_responses(
96b97a1… lmata 166 [
96b97a1… lmata 167 [], # components
96b97a1… lmata 168 [["ProfileScreen", "src/ProfileScreen.tsx"]], # screens
96b97a1… lmata 169 [], # hooks
96b97a1… lmata 170 [], # navigation
96b97a1… lmata 171 ]
96b97a1… lmata 172 )
96b97a1… lmata 173 enricher = ReactNativeEnricher(store)
96b97a1… lmata 174 result = enricher.enrich()
96b97a1… lmata 175 assert result.promoted == 1
96b97a1… lmata 176
96b97a1… lmata 177 calls = store._graph.query.call_args_list
96b97a1… lmata 178 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 179 assert promote_calls[0][0][1]["semantic_type"] == "RNScreen"
96b97a1… lmata 180
96b97a1… lmata 181 def test_promotes_hook_nodes(self):
96b97a1… lmata 182 """use* functions should become RNHook."""
96b97a1… lmata 183 store = _mock_store_with_responses(
96b97a1… lmata 184 [
96b97a1… lmata 185 [], # components
96b97a1… lmata 186 [], # screens
96b97a1… lmata 187 [["useTheme", "src/hooks/useTheme.ts"]], # hooks
96b97a1… lmata 188 [], # navigation
96b97a1… lmata 189 ]
96b97a1… lmata 190 )
96b97a1… lmata 191 enricher = ReactNativeEnricher(store)
96b97a1… lmata 192 result = enricher.enrich()
96b97a1… lmata 193 assert result.promoted == 1
96b97a1… lmata 194 assert result.patterns_found["hooks"] == 1
96b97a1… lmata 195
96b97a1… lmata 196 calls = store._graph.query.call_args_list
96b97a1… lmata 197 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 198 assert promote_calls[0][0][1]["semantic_type"] == "RNHook"
96b97a1… lmata 199
96b97a1… lmata 200 def test_promotes_navigation_nodes(self):
96b97a1… lmata 201 """createStackNavigator etc. should become RNNavigation."""
96b97a1… lmata 202 store = _mock_store_with_responses(
96b97a1… lmata 203 [
96b97a1… lmata 204 [], # components
96b97a1… lmata 205 [], # screens
96b97a1… lmata 206 [], # hooks
96b97a1… lmata 207 [["createStackNavigator", "src/navigation/AppNavigator.ts"]], # navigation
96b97a1… lmata 208 ]
96b97a1… lmata 209 )
96b97a1… lmata 210 enricher = ReactNativeEnricher(store)
96b97a1… lmata 211 result = enricher.enrich()
96b97a1… lmata 212 assert result.promoted == 1
96b97a1… lmata 213 assert result.patterns_found["navigation"] == 1
96b97a1… lmata 214
96b97a1… lmata 215 calls = store._graph.query.call_args_list
96b97a1… lmata 216 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 217 assert promote_calls[0][0][1]["semantic_type"] == "RNNavigation"
96b97a1… lmata 218
96b97a1… lmata 219 def test_promoted_accumulates_across_patterns(self):
96b97a1… lmata 220 # Each matched node triggers a _promote_node SET query after its pattern query.
96b97a1… lmata 221 store = _mock_store_with_responses(
96b97a1… lmata 222 [
96b97a1… lmata 223 [["View", "a.tsx"], ["Text", "b.tsx"]], # components query (2 rows)
96b97a1… lmata 224 None, # _promote_node for View
96b97a1… lmata 225 None, # _promote_node for Text
96b97a1… lmata 226 [["HomeScreen", "screens/Home.tsx"]], # screens query (1 row)
96b97a1… lmata 227 None, # _promote_node for HomeScreen
96b97a1… lmata 228 [["useAuth", "hooks/useAuth.ts"]], # hooks query (1 row)
96b97a1… lmata 229 None, # _promote_node for useAuth
96b97a1… lmata 230 [["NavigationContainer", "nav/App.ts"],
96b97a1… lmata 231 ["createStackNavigator", "nav/App.ts"]], # navigation query (2 rows)
96b97a1… lmata 232 None, # _promote_node for NavigationContainer
96b97a1… lmata 233 None, # _promote_node for createStackNavigator
96b97a1… lmata 234 ]
96b97a1… lmata 235 )
96b97a1… lmata 236 enricher = ReactNativeEnricher(store)
96b97a1… lmata 237 result = enricher.enrich()
96b97a1… lmata 238 assert result.promoted == 6
96b97a1… lmata 239 assert result.patterns_found["components"] == 2
96b97a1… lmata 240 assert result.patterns_found["screens"] == 1
96b97a1… lmata 241 assert result.patterns_found["hooks"] == 1
96b97a1… lmata 242 assert result.patterns_found["navigation"] == 2
96b97a1… lmata 243
96b97a1… lmata 244 def test_promote_node_called_with_correct_semantic_type_for_navigation(self):
96b97a1… lmata 245 store = _mock_store_with_responses(
96b97a1… lmata 246 [
96b97a1… lmata 247 [],
96b97a1… lmata 248 [],
96b97a1… lmata 249 [],
96b97a1… lmata 250 [["createBottomTabNavigator", "src/nav/Tabs.ts"]],
96b97a1… lmata 251 ]
96b97a1… lmata 252 )
96b97a1… lmata 253 enricher = ReactNativeEnricher(store)
96b97a1… lmata 254 enricher.enrich()
96b97a1… lmata 255
96b97a1… lmata 256 calls = store._graph.query.call_args_list
96b97a1… lmata 257 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 258 params = promote_calls[0][0][1]
96b97a1… lmata 259 assert params["name"] == "createBottomTabNavigator"
96b97a1… lmata 260 assert params["file_path"] == "src/nav/Tabs.ts"
96b97a1… lmata 261 assert params["semantic_type"] == "RNNavigation"

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button