Keep evidence artifacts out of the cherry-pick path
This commit is contained in:
1 parent
e032cbb222
commit
11a3abeca1
5 files changed
-294
No files matched your search
@@ -1,111 +0,0 @@
|
||||
# Test Evidence Summary — DOM Node Recycling PR
|
||||
|
||||
## Test counts
|
||||
|
||||
| Suite | Count | Status |
|
||||
|-------|-------|--------|
|
||||
| Recycling + scrollbar drag (pytest) | 48 | 48/48 pass |
|
||||
| Existing virtualization regression (pytest) | 29 | 29/29 pass |
|
||||
| CDP behavioral (live browser) | 8 | 8/8 pass |
|
||||
| Native scrollbar drag (SendInput + CDP) | 4 | 4/4 pass |
|
||||
| **Total** | **89** | **89 pass, 0 skip** |
|
||||
|
||||
## Maintainer must-fix items (PR #4474 CHANGES_REQUESTED)
|
||||
|
||||
### MF-1: data-msg-idx on .assistant-turn corrupts measurement
|
||||
|
||||
**Finding:** `querySelector('[data-msg-idx="N"]')` returns the `.assistant-turn` container (height 560px) instead of the `.assistant-segment` child (height 120px), inflating virtual window padding by 440px per turn.
|
||||
|
||||
**Fix:** Use `data-recycle-key` on `.assistant-turn`, leaving `data-msg-idx` exclusively on `.assistant-segment`.
|
||||
|
||||
**Evidence (test_mf1_multi_segment_turn_raw_heights):**
|
||||
- 3-segment turn: segments at 120px, 90px, 150px with tool cards at 60px, 80+60px
|
||||
- Measured heights: seg5=180px (120+60), seg6=230px (90+80+60), seg7=150px
|
||||
- Total measured: 560px (correct sum of segments + tools)
|
||||
- Buggy path would return: 560px for the FIRST SEGMENT ALONE (4.67x inflation)
|
||||
|
||||
**Evidence (test_mf1_buggy_path_inflates_height):**
|
||||
- Buggy (container match): 560px
|
||||
- Fixed (segment match): 120px
|
||||
- Inflation: 440px per turn, 4.67x factor
|
||||
|
||||
### MF-2: un-typed stash lookups allow cross-type recycling
|
||||
|
||||
**Finding:** Without type guards, index shift between renders could hand a user row to the assistant branch or vice versa, causing blank-chat via null dereference.
|
||||
|
||||
**Fix:** `classList.contains('msg-row')` guard on user branch, `classList.contains('assistant-turn')` guard on assistant branch.
|
||||
|
||||
**Evidence (test_mf2_user_row_in_assistant_slot_without_guard):**
|
||||
- Without guard: accepts user row (3 mismatched fields: className, dataset.role, id)
|
||||
- With guard: rejects → falls back to fresh build
|
||||
|
||||
**Evidence (test_mf2_assistant_turn_in_user_slot_without_guard):**
|
||||
- Without guard: accepts assistant turn (3 mismatched fields: className, dataset.role, dataset.msgIdx)
|
||||
- With guard: rejects → falls back to fresh build
|
||||
|
||||
**Evidence (test_mf2_stash_collision_rate_in_shifted_indices):**
|
||||
- 5 nodes stashed, indices shift by +2 (prepend scenario)
|
||||
- Without guards: cross-type collisions occur at shifted boundary
|
||||
- With guards: all collisions rejected, fresh nodes built instead
|
||||
|
||||
### MF-3: source-text greps pass on broken code
|
||||
|
||||
**Finding:** Original tests were `assertIn(pattern, source_text)` which pass regardless of whether the code path works.
|
||||
|
||||
**Fix:** Replaced with behavioral tests that extract and execute functions against mock DOM, producing concrete pixel values and node counts.
|
||||
|
||||
**Evidence (test_mf3_measurement_test_fails_on_buggy_layout):**
|
||||
- Buggy layout: returns 560px (test would FAIL the 120px assertion)
|
||||
- Fixed layout: returns 120px (test PASSES)
|
||||
- Test sensitivity confirmed: different outputs on buggy vs fixed
|
||||
|
||||
**Evidence (test_mf3_type_check_test_fails_on_unguarded_code):**
|
||||
- Guarded: rejects wrong-type node (null)
|
||||
- Unguarded: accepts wrong-type node (non-null)
|
||||
- Test sensitivity confirmed: opposite results with/without guard
|
||||
|
||||
## Scrollbar drag handling
|
||||
|
||||
**Problem:** Virtual scroll re-renders during native scrollbar drag need to keep `scrollHeight` stable, otherwise the thumb jumps on release.
|
||||
|
||||
**Approach:** Detect scrollbar pointerdown via `offsetX >= clientWidth`. During drag, run full renders (with DOM recycling) using `_compensateScrollForMeasurementDelta` instead of the normal path. This keeps the rendered DOM in sync with the scroll position throughout the drag, so `scrollHeight` stays stable and the thumb doesn't jump when the user releases.
|
||||
|
||||
**Why not spacer-only updates:** An earlier iteration used spacer-only updates during drag (updating spacer heights without rebuilding DOM). This caused `scrollHeight` to drift by 10,000+ px because the stale rendered content didn't match the new spacer heights. On release, the full render would correct the content, but the `scrollHeight` change shifted the thumb position by ~40% of the viewport.
|
||||
|
||||
**Why full renders work:** The scroll container (`#messages`) is never destroyed; only its inner container (`#msgInner`) gets `innerHTML = ''`. The browser maintains the native pointer grab on the scrollbar because the scrollbar belongs to `#messages`, not `#msgInner`. DOM recycling further reduces the churn by reattaching surviving nodes after the wipe.
|
||||
|
||||
**Evidence (native scrollbar drag, Windows SendInput + CDP):**
|
||||
- 12-step drag from near-top to near-bottom of scrollbar track
|
||||
- Total scroll delta: 13,522px
|
||||
- All 12 steps monotonically increasing, 0 reversals
|
||||
- `_scrollbarDragActive` flag: `true` during drag, `false` after release
|
||||
- 53 content nodes, 0 blanks after release
|
||||
- `scrollHeight` delta on release: 49px (0.06% of total, vs 10,710px / 14.8% with spacer-only)
|
||||
|
||||
**Evidence (CDP behavioral, synthetic PointerEvents):**
|
||||
- Scrollbar click (offsetX >= clientWidth): flag activates
|
||||
- Content click (offsetX < clientWidth): flag does NOT activate
|
||||
- pointerup: flag clears
|
||||
- pointercancel: flag clears
|
||||
- DOM children count preserved during drag (65 → 65)
|
||||
|
||||
## Research-informed design
|
||||
|
||||
Virtual scroll libraries surveyed: react-virtuoso, TanStack Virtual, react-window, react-virtualized.
|
||||
|
||||
**Key finding:** None implement DOM node recycling. This pattern is novel to this codebase.
|
||||
|
||||
**Adopted from research:**
|
||||
- TanStack Virtual's spatial threshold (1.5px) vs temporal (150ms) for programmatic scroll detection — we use a 150ms safety valve
|
||||
- Debounced clear pattern from react-virtuoso's scroll-to-index implementation — our `_deferClearProgrammaticScroll`
|
||||
- No library tests scrollbar drag interaction; our SendInput-based test is novel
|
||||
|
||||
**Test architecture:**
|
||||
- Tier 1: Structural (flag/stash existence, lifecycle) — 6 tests
|
||||
- Tier 2: Bug-specific behavioral (measurement corruption, type guards, stuck flag) — 9 tests
|
||||
- Tier 3: Integration (full stash→wipe→lookup cycles) — 8 tests
|
||||
- Tier 4: Optimization correctness (content-skip, key coercion) — 3 tests
|
||||
- Tier 5: Scrollbar drag (detection, full-render-during-drag, release) — 13 tests
|
||||
- Tier 6: Maintainer regression tests (raw numerical evidence for each must-fix) — 9 tests
|
||||
- CDP behavioral: live browser flag lifecycle and render suppression — 8 tests
|
||||
- Native scrollbar: real OS mouse events via Windows SendInput + CDP — 4 tests
|
||||
@@ -1,30 +0,0 @@
|
||||
Connecting to ws://localhost:9222/devtools/page/3CC47AC2E288A6FE8670B6C1EAD90117
|
||||
|
||||
=== T1: Flag initial state ===
|
||||
PASS: flag starts as false
|
||||
|
||||
=== T2: Pointerdown on scrollbar area ===
|
||||
PASS: scrollbar click activates flag
|
||||
|
||||
=== T3: Pointerdown on content area ===
|
||||
PASS: content click does not activate flag
|
||||
|
||||
=== T4: Pointerup clears flag ===
|
||||
PASS: pointerup clears flag
|
||||
|
||||
=== T5: Pointercancel clears flag ===
|
||||
PASS: pointercancel clears flag
|
||||
|
||||
=== T6: Spacer-only path ===
|
||||
PASS: spacers present (before=315848px, after=13747px)
|
||||
|
||||
=== T7: DOM stability during drag (render suppression) ===
|
||||
PASS: children preserved (65 -> 65)
|
||||
|
||||
=== T8: Full render after drag release ===
|
||||
PASS: content rendered after drag release
|
||||
|
||||
==================================================
|
||||
RESULTS: 8 passed, 0 failed, 8 total
|
||||
==================================================
|
||||
ALL CDP BEHAVIORAL TESTS PASSED
|
||||
@@ -1,42 +0,0 @@
|
||||
Connected to ws://localhost:9222/devtools/page/3CC47AC2E288A6FE8670B6C1EAD90117
|
||||
Window bounds: {'left': -6, 'top': -6, 'width': 1720, 'height': 926, 'windowState': 'maximized'}
|
||||
Messages element: {'left': 348, 'top': 38.88888931274414, 'right': 1706.2222900390625, 'bottom': 674.9375343322754, 'width': 1358.2222900390625, 'height': 636.0486450195312, 'clientWidth': 1348, 'scrollHeight': 358441, 'scrollTop': 317723.5625, 'scrollbarWidth': 10, 'dpr': 2.25, 'innerWidth': 1707, 'innerHeight': 791}
|
||||
DPR=2.25, chrome header: 135px CSS
|
||||
Viewport origin CSS: (7, 129)
|
||||
Scrollbar screen X: 3837, track Y: 423-1764
|
||||
|
||||
Pre-drag scrollTop: 0
|
||||
|
||||
=== Native Scrollbar Drag via SendInput ===
|
||||
Mouse down at (3837, 453)
|
||||
_scrollbarDragActive after native pointerdown: True
|
||||
Step 1/12: screen_y=562, scrollTop=556.4444580078125
|
||||
Step 2/12: screen_y=671, scrollTop=1670.6666259765625
|
||||
Step 3/12: screen_y=781, scrollTop=3339.5556640625
|
||||
Step 4/12: screen_y=890, scrollTop=4521.77783203125
|
||||
Step 5/12: screen_y=999, scrollTop=5158.22216796875
|
||||
Step 6/12: screen_y=1108, scrollTop=6757.77783203125
|
||||
Step 7/12: screen_y=1218, scrollTop=7540
|
||||
Step 8/12: screen_y=1327, scrollTop=9349.3330078125
|
||||
Step 9/12: screen_y=1436, scrollTop=10461.77734375
|
||||
Step 10/12: screen_y=1545, scrollTop=11644.888671875
|
||||
Step 11/12: screen_y=1655, scrollTop=12757.3330078125
|
||||
Step 12/12: screen_y=1764, scrollTop=13522.6669921875
|
||||
_scrollbarDragActive after release: False
|
||||
|
||||
=== RESULTS ===
|
||||
Total scroll delta: 13522.6669921875px
|
||||
Monotonic steps: 11/11
|
||||
Reversals: 0
|
||||
Flag set during drag: True
|
||||
Flag cleared after release: True
|
||||
Content nodes: 53, blanks: 0
|
||||
|
||||
==================================================
|
||||
PASS: T1 Native drag moved scroll
|
||||
PASS: T2 Monotonic scrolling
|
||||
PASS: T3 No blank content after release
|
||||
PASS: T4 Flag lifecycle (set during, cleared after)
|
||||
|
||||
ALL PASS: True
|
||||
==================================================
|
||||
@@ -1,46 +0,0 @@
|
||||
============================= test session starts =============================
|
||||
platform win32 -- Python 3.11.15, pytest-9.0.3, pluggy-1.6.0 -- C:\Apps\hermes\hermes-agent\venv\Scripts\python.exe
|
||||
cachedir: .pytest_cache
|
||||
rootdir: D:\Repos\hermes-webui-pr-4346-vscroll-footer-jitter
|
||||
configfile: pytest.ini
|
||||
plugins: anyio-4.12.1, langsmith-0.8.14, shard-0.1.2, timeout-2.4.0
|
||||
collecting ... collected 29 items
|
||||
Running 29 items in this shard: tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_virtualizes_older_history_but_keeps_recent_tail, tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_collapses_to_tail_only_near_bottom, tests/test_issue500_message_list_virtualization.py::test_render_messages_uses_virtual_window_and_spacer_measurement_path, tests/test_issue500_message_list_virtualization.py::test_measurement_uses_one_primary_row_and_adjacent_activity_siblings_only, tests/test_issue500_message_list_virtualization.py::test_virtual_keep_tail_count_stays_bounded_after_history_expands_render_window, tests/test_issue500_message_list_virtualization.py::test_virtual_prepended_height_delta_uses_prefix_cache_only_when_virtualized, tests/test_issue500_message_list_virtualization.py::test_virtual_question_jump_scroll_target_uses_visible_index_height_prefix, tests/test_issue500_message_list_virtualization.py::test_height_cache_preserves_measured_prefix_across_append_only_growth, tests/test_issue500_message_list_virtualization.py::test_height_cache_preserves_measured_suffix_across_prepended_history, tests/test_issue500_message_list_virtualization.py::test_measurement_refresh_budget_is_keyed_to_window_shape_not_pad_height, tests/test_issue500_message_list_virtualization.py::test_tool_rows_do_not_carry_message_measurement_hook, tests/test_issue500_message_list_virtualization.py::test_viewport_intersection_helper_detects_visible_rendered_rows_only, tests/test_issue500_message_list_virtualization.py::test_render_messages_has_one_shot_virtual_blank_viewport_fallback, tests/test_issue500_message_list_virtualization.py::test_virtual_blank_viewport_recovery_evicts_stale_cache_before_fallback, tests/test_issue500_message_list_virtualization.py::test_same_frame_restore_nudges_virtual_window_when_anchor_row_is_missing, tests/test_issue500_message_list_virtualization.py::test_virtualize_transcript_opt_out_forces_full_render_window, tests/test_issue500_message_list_virtualization.py::test_virtualize_transcript_gate_present_in_current_window_fn, tests/test_issue500_message_list_virtualization.py::test_message_virtual_default_height_for_role_returns_correct_heights, tests/test_issue500_message_list_virtualization.py::test_message_virtual_role_for_entry_classifies_tool_calls, tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_with_role_for_idx_uses_role_defaults, tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_cached_heights_override_role_defaults, tests/test_issue500_message_list_virtualization.py::test_offset_helpers_use_per_role_defaults_for_uncached_rows, tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_no_anchor_does_not_throw, tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_shifts_scroll_when_anchor_moves, tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_skips_small_delta, tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_sets_programmatic_scroll_flag, tests/test_issue500_message_list_virtualization.py::test_virtualized_render_uses_compensation_helper, tests/test_issue500_message_list_virtualization.py::test_scroll_listener_guards_programmatic_scroll_before_marking_active, tests/test_issue500_message_list_virtualization.py::test_clear_height_cache_resets_scroll_settle_globals
|
||||
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_virtualizes_older_history_but_keeps_recent_tail PASSED [ 3%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_collapses_to_tail_only_near_bottom PASSED [ 6%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_render_messages_uses_virtual_window_and_spacer_measurement_path PASSED [ 10%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_measurement_uses_one_primary_row_and_adjacent_activity_siblings_only PASSED [ 13%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtual_keep_tail_count_stays_bounded_after_history_expands_render_window PASSED [ 17%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtual_prepended_height_delta_uses_prefix_cache_only_when_virtualized PASSED [ 20%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtual_question_jump_scroll_target_uses_visible_index_height_prefix PASSED [ 24%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_height_cache_preserves_measured_prefix_across_append_only_growth PASSED [ 27%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_height_cache_preserves_measured_suffix_across_prepended_history PASSED [ 31%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_measurement_refresh_budget_is_keyed_to_window_shape_not_pad_height PASSED [ 34%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_tool_rows_do_not_carry_message_measurement_hook PASSED [ 37%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_viewport_intersection_helper_detects_visible_rendered_rows_only PASSED [ 41%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_render_messages_has_one_shot_virtual_blank_viewport_fallback PASSED [ 44%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtual_blank_viewport_recovery_evicts_stale_cache_before_fallback PASSED [ 48%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_same_frame_restore_nudges_virtual_window_when_anchor_row_is_missing PASSED [ 51%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtualize_transcript_opt_out_forces_full_render_window PASSED [ 55%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtualize_transcript_gate_present_in_current_window_fn PASSED [ 58%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_default_height_for_role_returns_correct_heights PASSED [ 62%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_role_for_entry_classifies_tool_calls PASSED [ 65%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_with_role_for_idx_uses_role_defaults PASSED [ 68%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_cached_heights_override_role_defaults PASSED [ 72%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_offset_helpers_use_per_role_defaults_for_uncached_rows PASSED [ 75%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_no_anchor_does_not_throw PASSED [ 79%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_shifts_scroll_when_anchor_moves PASSED [ 82%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_skips_small_delta PASSED [ 86%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_compensate_scroll_for_measurement_delta_sets_programmatic_scroll_flag PASSED [ 89%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_virtualized_render_uses_compensation_helper PASSED [ 93%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_scroll_listener_guards_programmatic_scroll_before_marking_active PASSED [ 96%]
|
||||
tests/test_issue500_message_list_virtualization.py::test_clear_height_cache_resets_scroll_settle_globals PASSED [100%]
|
||||
|
||||
============================== warnings summary ===============================
|
||||
tests/test_issue500_message_list_virtualization.py::test_message_virtual_window_virtualizes_older_history_but_keeps_recent_tail
|
||||
C:\Apps\hermes\hermes-agent\venv\Lib\site-packages\discord\player.py:30: DeprecationWarning: 'audioop' is deprecated and slated for removal in Python 3.13
|
||||
import audioop
|
||||
|
||||
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
||||
======================== 29 passed, 1 warning in 5.74s ========================
|
||||
@@ -1,65 +0,0 @@
|
||||
============================= test session starts =============================
|
||||
platform win32 -- Python 3.11.15, pytest-9.0.3, pluggy-1.6.0 -- C:\Apps\hermes\hermes-agent\venv\Scripts\python.exe
|
||||
cachedir: .pytest_cache
|
||||
rootdir: D:\Repos\hermes-webui-pr-4346-vscroll-footer-jitter
|
||||
configfile: pytest.ini
|
||||
plugins: anyio-4.12.1, langsmith-0.8.14, shard-0.1.2, timeout-2.4.0
|
||||
collecting ... collected 48 items
|
||||
Running 48 items in this shard: tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_flag_exists, tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_stash_exists, tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_flag_lifecycle, tests/test_issue4346_vscroll_footer_jitter.py::test_js_stash_populated_before_wipe, tests/test_issue4346_vscroll_footer_jitter.py::test_assistant_turn_uses_recycle_key_not_msg_idx, tests/test_issue4346_vscroll_footer_jitter.py::test_no_stale_raf_settimeout_clear_pattern, tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_returns_segment_height_not_turn_height, tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_accumulates_tool_siblings, tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_on_buggy_turn_container_returns_wrong_height, tests/test_issue4346_vscroll_footer_jitter.py::TestBug2TypeCheckRecycling::test_user_branch_rejects_assistant_turn_node, tests/test_issue4346_vscroll_footer_jitter.py::TestBug2TypeCheckRecycling::test_assistant_branch_rejects_user_row_node, tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_defer_clear_debounces_and_clears_flag, tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_defer_clear_second_call_cancels_first, tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_scroll_handler_safety_valve_in_source, tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_safety_valve_clears_stale_flag, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_populates_from_recycle_key_and_msg_idx, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_excludes_live_assistant_turn, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_excludes_nested_live_assistant_turn, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_full_recycle_cycle_user_row, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_full_recycle_cycle_assistant_turn, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_cross_type_stash_collision_rejected, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_recycling_disabled_when_flag_false, tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_recycle_key_does_not_pollute_measurement_selector, tests/test_issue4346_vscroll_footer_jitter.py::TestContentSkipOptimization::test_unchanged_content_skips_innerhtml_update, tests/test_issue4346_vscroll_footer_jitter.py::TestContentSkipOptimization::test_changed_content_updates_innerhtml, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_scrollbar_drag_flag_declared, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerdown_sets_flag_when_on_scrollbar, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerdown_guard_exists_in_source, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerup_clears_flag_and_triggers_render, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointercancel_clears_flag, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_guard_exists_in_render_scheduler, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_path_uses_full_render, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_path_sets_programmatic_scroll, tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_release_uses_same_render_path, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_multi_segment_turn_raw_heights, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_buggy_path_inflates_height, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_queryselector_returns_segment_not_container, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_user_row_in_assistant_slot_without_guard, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_assistant_turn_in_user_slot_without_guard, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_stash_collision_rate_in_shifted_indices, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF3TestSensitivity::test_mf3_measurement_test_fails_on_buggy_layout, tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF3TestSensitivity::test_mf3_type_check_test_failsLine truncated
|
||||
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_flag_exists PASSED [ 2%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_stash_exists PASSED [ 4%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_flag_lifecycle PASSED [ 6%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_js_stash_populated_before_wipe PASSED [ 8%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_assistant_turn_uses_recycle_key_not_msg_idx PASSED [ 10%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_no_stale_raf_settimeout_clear_pattern PASSED [ 12%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_returns_segment_height_not_turn_height PASSED [ 14%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_accumulates_tool_siblings PASSED [ 16%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug1MeasurementSelectorCollision::test_measurement_on_buggy_turn_container_returns_wrong_height PASSED [ 18%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug2TypeCheckRecycling::test_user_branch_rejects_assistant_turn_node PASSED [ 20%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug2TypeCheckRecycling::test_assistant_branch_rejects_user_row_node PASSED [ 22%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_defer_clear_debounces_and_clears_flag PASSED [ 25%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_defer_clear_second_call_cancels_first PASSED [ 27%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_scroll_handler_safety_valve_in_source PASSED [ 29%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestBug3ProgrammaticScrollStuckFlag::test_safety_valve_clears_stale_flag PASSED [ 31%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_populates_from_recycle_key_and_msg_idx PASSED [ 33%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_excludes_live_assistant_turn PASSED [ 35%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_stash_excludes_nested_live_assistant_turn PASSED [ 37%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_full_recycle_cycle_user_row PASSED [ 39%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_full_recycle_cycle_assistant_turn PASSED [ 41%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_cross_type_stash_collision_rejected PASSED [ 43%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_recycling_disabled_when_flag_false PASSED [ 45%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestRecycleStashIntegration::test_recycle_key_does_not_pollute_measurement_selector PASSED [ 47%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestContentSkipOptimization::test_unchanged_content_skips_innerhtml_update PASSED [ 50%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestContentSkipOptimization::test_changed_content_updates_innerhtml PASSED [ 52%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_scrollbar_drag_flag_declared PASSED [ 54%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerdown_sets_flag_when_on_scrollbar PASSED [ 56%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerdown_guard_exists_in_source PASSED [ 58%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointerup_clears_flag_and_triggers_render PASSED [ 60%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragDetection::test_pointercancel_clears_flag PASSED [ 62%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_guard_exists_in_render_scheduler PASSED [ 64%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_path_uses_full_render PASSED [ 66%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_drag_path_sets_programmatic_scroll PASSED [ 68%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragRenderDuringDrag::test_release_uses_same_render_path PASSED [ 70%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_multi_segment_turn_raw_heights PASSED [ 72%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_buggy_path_inflates_height PASSED [ 75%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF1MeasurementCorruption::test_mf1_queryselector_returns_segment_not_container PASSED [ 77%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_user_row_in_assistant_slot_without_guard PASSED [ 79%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_assistant_turn_in_user_slot_without_guard PASSED [ 81%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF2CrossTypeCollision::test_mf2_stash_collision_rate_in_shifted_indices PASSED [ 83%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF3TestSensitivity::test_mf3_measurement_test_fails_on_buggy_layout PASSED [ 85%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF3TestSensitivity::test_mf3_type_check_test_fails_on_unguarded_code PASSED [ 87%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestMaintainerMF3TestSensitivity::test_mf3_recycle_key_separation_prevents_selector_collision PASSED [ 89%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragFullRender::test_drag_path_calls_compensate_scroll PASSED [ 91%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragFullRender::test_drag_path_sets_programmatic_scroll PASSED [ 93%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragFullRender::test_drag_path_no_spacer_only_update PASSED [ 95%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestScrollbarDragFullRender::test_drag_path_updates_window_key PASSED [ 97%]
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::TestStashKeyCoercion::test_string_dataset_matches_numeric_lookup PASSED [100%]
|
||||
|
||||
============================== warnings summary ===============================
|
||||
tests/test_issue4346_vscroll_footer_jitter.py::test_js_recycle_flag_exists
|
||||
C:\Apps\hermes\hermes-agent\venv\Lib\site-packages\discord\player.py:30: DeprecationWarning: 'audioop' is deprecated and slated for removal in Python 3.13
|
||||
import audioop
|
||||
|
||||
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
|
||||
======================== 48 passed, 1 warning in 6.45s ========================
|
||||
Reference in new issue
Block a user