@@ -56,6 +56,32 @@ def test_element_relocation(self):
5656 assert relocated [0 ].has_class ("new-class" )
5757 assert relocated [0 ].css (".new-description" )[0 ].text == "Description 1"
5858
59+ def test_relocation_auto_save_no_match_above_threshold (self ):
60+ """Adaptive relocation with `auto_save=True` must not crash when no element
61+ clears the `percentage` threshold (relocate() returns an empty list)."""
62+ original_html = """
63+ <div class="container">
64+ <article class="product" id="target">
65+ <h3>Widget</h3>
66+ <p class="desc">A widget</p>
67+ </article>
68+ </div>
69+ """
70+ # Unrelated structure so nothing can match a high threshold
71+ changed_html = "<html><body><span>totally unrelated content</span></body></html>"
72+
73+ old_page = Selector (original_html , url = "example.com" , adaptive = True )
74+ new_page = Selector (changed_html , url = "example.com" , adaptive = True )
75+
76+ old_page .css ("#target" , identifier = "target" , auto_save = True )
77+
78+ # Before the fix this raised `IndexError: list index out of range` because the
79+ # guard checked `elements is not None` but relocate() returns [] (never None).
80+ result = new_page .css (
81+ "#target" , identifier = "target" , adaptive = True , auto_save = True , percentage = 95
82+ )
83+ assert list (result ) == []
84+
5985 @pytest .mark .asyncio
6086 async def test_element_relocation_async (self ):
6187 """Test relocating element after structure change in async mode"""
0 commit comments