@@ -314,6 +314,130 @@ async def test_type_text_default_interval(self, input_element):
314314 mock_sleep .assert_called_with (0.1 ) # Default interval
315315 assert input_element .click .call_count == 1
316316
317+ @pytest .mark .asyncio
318+ async def test_get_parent_element_success (self , web_element ):
319+ """Test successful parent element retrieval."""
320+ script_response = {
321+ 'result' : {
322+ 'result' : {
323+ 'objectId' : 'parent-object-id'
324+ }
325+ }
326+ }
327+ describe_response = {
328+ 'result' : {
329+ 'node' : {
330+ 'nodeName' : 'DIV' ,
331+ 'attributes' : ['id' , 'parent-container' , 'class' , 'container' ]
332+ }
333+ }
334+ }
335+ web_element ._connection_handler .execute_command .side_effect = [
336+ script_response , # Script execution
337+ describe_response , # Describe node
338+ ]
339+
340+ parent_element = await web_element .get_parent_element ()
341+
342+ assert isinstance (parent_element , WebElement )
343+ assert parent_element ._object_id == 'parent-object-id'
344+ assert parent_element ._attributes == {
345+ 'id' : 'parent-container' ,
346+ 'class_name' : 'container' ,
347+ 'tag_name' : 'div'
348+ }
349+ web_element ._connection_handler .execute_command .assert_called ()
350+
351+ @pytest .mark .asyncio
352+ async def test_get_parent_element_not_found (self , web_element ):
353+ """Test parent element not found raises ElementNotFound."""
354+ script_response = {
355+ 'result' : {
356+ 'result' : {} # No objectId
357+ }
358+ }
359+
360+ web_element ._connection_handler .execute_command .return_value = script_response
361+
362+ with pytest .raises (ElementNotFound , match = 'Parent element not found for element:' ):
363+ await web_element .get_parent_element ()
364+
365+ @pytest .mark .asyncio
366+ async def test_get_parent_element_with_complex_attributes (self , web_element ):
367+ """Test parent element with complex attribute list."""
368+ script_response = {
369+ 'result' : {
370+ 'result' : {
371+ 'objectId' : 'complex-parent-id'
372+ }
373+ }
374+ }
375+
376+ describe_response = {
377+ 'result' : {
378+ 'node' : {
379+ 'nodeName' : 'SECTION' ,
380+ 'attributes' : [
381+ 'id' , 'main-section' ,
382+ 'class' , 'content-wrapper' ,
383+ 'data-testid' , 'parent-element' ,
384+ 'aria-label' , 'Main content area'
385+ ]
386+ }
387+ }
388+ }
389+
390+ web_element ._connection_handler .execute_command .side_effect = [
391+ script_response ,
392+ describe_response ,
393+ ]
394+
395+ parent_element = await web_element .get_parent_element ()
396+
397+ assert isinstance (parent_element , WebElement )
398+ assert parent_element ._object_id == 'complex-parent-id'
399+ assert parent_element ._attributes == {
400+ 'id' : 'main-section' ,
401+ 'class_name' : 'content-wrapper' ,
402+ 'data-testid' : 'parent-element' ,
403+ 'aria-label' : 'Main content area' ,
404+ 'tag_name' : 'section'
405+ }
406+
407+ @pytest .mark .asyncio
408+ async def test_get_parent_element_root_element (self , web_element ):
409+ """Test getting parent of root element (should return document body)."""
410+ script_response = {
411+ 'result' : {
412+ 'result' : {
413+ 'objectId' : 'body-object-id'
414+ }
415+ }
416+ }
417+
418+ describe_response = {
419+ 'result' : {
420+ 'node' : {
421+ 'nodeName' : 'BODY' ,
422+ 'attributes' : ['class' , 'page-body' ]
423+ }
424+ }
425+ }
426+
427+ web_element ._connection_handler .execute_command .side_effect = [
428+ script_response ,
429+ describe_response ,
430+ ]
431+
432+ parent_element = await web_element .get_parent_element ()
433+
434+ assert isinstance (parent_element , WebElement )
435+ assert parent_element ._object_id == 'body-object-id'
436+ assert parent_element ._attributes == {
437+ 'class_name' : 'page-body' ,
438+ 'tag_name' : 'body'
439+ }
440+
317441
318442class TestWebElementKeyboardInteraction :
319443 """Test keyboard interaction methods."""
0 commit comments