6Regression Tests — id_instrumentation
7=======================================
11Verify the full behaviour of ``id_instrumentation``: structural-ID protection,
12dict-ID passthrough, depth-limit guarding, recursive children traversal, and
13project-defined custom structural ID extensions.
17- Confirm ``is_structural_id()`` correctly classifies built-in structural and
19- Confirm ``instrument_ids()`` rewrites non-structural string IDs to
20 ``{"event": "<id>"}``.
21- Confirm dict IDs are never rewritten.
22- Confirm components without an ``id`` attribute are returned unchanged.
23- Confirm recursion stops at ``MAX_INSTRUMENT_DEPTH`` without raising.
24- Confirm nested children are instrumented recursively.
25- Confirm ``ADDITIONAL_STRUCTURAL_PREFIXES`` prevents instrumentation.
26- Confirm ``ADDITIONAL_STRUCTURAL_EXACT`` prevents instrumentation.
38- All Dash-dependent tests are skipped automatically when Dash is not installed.
39- Must not permanently modify oc_diagnostics global state.
40- Must restore all patched globals in finally blocks.
41- Must not start servers or require network access.
42- Must run deterministically across repeated invocations.
52_REPO_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__),
".."))
53if _REPO_ROOT
not in sys.path:
54 sys.path.insert(0, _REPO_ROOT)
59dash_html = pytest.importorskip(
"dash.html", reason=
"Dash not installed")
75 """is_structural_id() correctly classifies structural and non-structural IDs."""
85 for cid
in structural_ids:
86 assert is_structural_id(cid), f
"Expected structural: {cid!r}"
88 non_structural_ids = [
94 for cid
in non_structural_ids:
95 assert not is_structural_id(cid), f
"Expected non-structural: {cid!r}"
103 """instrument_ids() rewrites a non-structural string ID to {"event": "<id>"}."""
104 old_enabled = _ud.INSTRUMENTATION_ENABLED
105 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
106 _ud.INSTRUMENTATION_ENABLED =
True
107 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
109 comp = html.Button(
"Click me", id=
"btn-test")
110 result = instrument_ids(comp)
111 assert result.id == {
"event":
"btn-test"}, (
112 f
"Expected {{'event': 'btn-test'}}, got: {result.id!r}"
115 _ud.INSTRUMENTATION_ENABLED = old_enabled
116 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
124 """Components with dict IDs are returned unchanged — no double-wrapping."""
125 old_enabled = _ud.INSTRUMENTATION_ENABLED
126 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
127 _ud.INSTRUMENTATION_ENABLED =
True
128 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
130 original_id = {
"event":
"already-instrumented"}
131 comp = html.Button(
"X", id=original_id)
132 result = instrument_ids(comp)
133 assert result.id == original_id, (
134 f
"Dict ID must not be rewritten, got: {result.id!r}"
137 _ud.INSTRUMENTATION_ENABLED = old_enabled
138 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
146 """Components without an id attribute have their ID left as None."""
147 old_enabled = _ud.INSTRUMENTATION_ENABLED
148 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
149 _ud.INSTRUMENTATION_ENABLED =
True
150 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
152 comp = html.Div(
"no id")
153 result = instrument_ids(comp)
155 cid = getattr(result,
"id",
None)
156 assert not isinstance(cid, dict), (
157 f
"Component without id must not receive a dict ID, got: {cid!r}"
160 _ud.INSTRUMENTATION_ENABLED = old_enabled
161 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
169 """instrument_ids() stops recursion at MAX_INSTRUMENT_DEPTH without RecursionError."""
170 old_enabled = _ud.INSTRUMENTATION_ENABLED
171 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
172 _ud.INSTRUMENTATION_ENABLED =
True
173 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
175 comp = html.Div(
"deep-component", id=
"deep-comp")
177 result = instrument_ids(comp, _depth=MAX_INSTRUMENT_DEPTH + 1)
179 assert result
is comp, (
180 "instrument_ids must return the component unchanged at MAX_INSTRUMENT_DEPTH"
182 assert result.id ==
"deep-comp", (
183 f
"ID must not be rewritten at depth limit, got: {result.id!r}"
186 _ud.INSTRUMENTATION_ENABLED = old_enabled
187 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
195 """instrument_ids() recursively instruments children of a component."""
196 old_enabled = _ud.INSTRUMENTATION_ENABLED
197 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
198 _ud.INSTRUMENTATION_ENABLED =
True
199 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
201 inner = html.Button(
"Click", id=
"inner-btn")
202 outer = html.Div(inner, id=
"outer-div")
203 result = instrument_ids(outer)
204 assert result.id == {
"event":
"outer-div"}, (
205 f
"Outer ID must be instrumented, got: {result.id!r}"
207 assert result.children.id == {
"event":
"inner-btn"}, (
208 f
"Inner child ID must be instrumented, got: {result.children.id!r}"
211 _ud.INSTRUMENTATION_ENABLED = old_enabled
212 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
220 """ADDITIONAL_STRUCTURAL_PREFIXES prevents ID rewriting for matching components."""
221 old_enabled = _ud.INSTRUMENTATION_ENABLED
222 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
223 old_prefixes = _ud.ADDITIONAL_STRUCTURAL_PREFIXES
224 _ud.INSTRUMENTATION_ENABLED =
True
225 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
226 _ud.ADDITIONAL_STRUCTURAL_PREFIXES = (
"custom-struct-",)
228 comp = html.Div(
"protected", id=
"custom-struct-main")
229 result = instrument_ids(comp)
230 assert result.id ==
"custom-struct-main", (
231 f
"Custom structural prefix must prevent ID rewriting, got: {result.id!r}"
234 _ud.INSTRUMENTATION_ENABLED = old_enabled
235 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
236 _ud.ADDITIONAL_STRUCTURAL_PREFIXES = old_prefixes
244 """ADDITIONAL_STRUCTURAL_EXACT prevents ID rewriting for exact-match IDs."""
245 old_enabled = _ud.INSTRUMENTATION_ENABLED
246 old_level = _ud.DEBUG_LEVELS.get(
"INSTRUMENTATION", 0)
247 old_exact = _ud.ADDITIONAL_STRUCTURAL_EXACT
248 _ud.INSTRUMENTATION_ENABLED =
True
249 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = 9
250 _ud.ADDITIONAL_STRUCTURAL_EXACT = frozenset([
"my-special-store"])
252 comp = html.Div(
"protected-exact", id=
"my-special-store")
253 result = instrument_ids(comp)
254 assert result.id ==
"my-special-store", (
255 f
"Custom structural exact ID must prevent rewriting, got: {result.id!r}"
258 _ud.INSTRUMENTATION_ENABLED = old_enabled
259 _ud.DEBUG_LEVELS[
"INSTRUMENTATION"] = old_level
260 _ud.ADDITIONAL_STRUCTURAL_EXACT = old_exact
test_instrument_ids_basic()
test_dict_id_not_rewritten()
test_no_id_component_unchanged()
test_nested_children_traversal()
test_additional_structural_exact()
test_additional_structural_prefixes()
test_structural_id_protection()