§
    ¨\¿jÀM  ã                  óÐ  — d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlZddlZddlmZ ddlmZmZ ddlZ ee¦  «                             ¦   «         j        j        j        Ze
j                             d ee¦  «        ¦  «         ddlmZ  G d„ de¦  «        Z ej        d	¬
¦  «        d„ ¦   «         Z  ej        d	¬
¦  «        d„ ¦   «         Z!ddd„Z" G d„ d¦  «        Z#dS )añ  
Comprehensive End-to-End (E2E) Test Suite for FreeExile PC Desktop Web Client.
Enforces 4-Tier Testing Methodology (Features 1-25):
- Tier 1: Functional Feature Coverage (Fullscreen, Controls, HUD, i18n, Modals, Zero Errors)
- Tier 2: Boundary & Corner Cases (Ultrawide 21:9, Typing Guard, Context Menu, Rapid 9-Lang)
- Tier 3: Cross-Feature State Interleaving (Move while casting/drinking, Dual-docking, Dodge cancel)
- Tier 4: Real-World End-to-End Gameplay Loop & Mobile Zero-Regression Guard
é    )ÚannotationsN)ÚPath)ÚAnyÚList)ÚFreeExilePCRequestHandlerc                  ó   — e Zd ZdZd
d„Zd	S )ÚSilentPCRequestHandlerz=Suppresses HTTP request access logs during automated testing.ÚformatÚstrÚargsr   ÚreturnÚNonec                ó   — d S )N© )Úselfr
   r   s      ú=C:\Projects\FreeExile\tests\e2e\test_pc_desktop_client_e2e.pyÚlog_messagez"SilentPCRequestHandler.log_message   s   € Øˆó    N)r
   r   r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r	   r	      s.   € € € € € ØGÐGðð ð ð ð ð r   r	   Úmodule)Úscopec               #  ó  K  — t          j        dt          ¦  «        } | j        d         }t	          j        | j        d¬¦  «        }|                     ¦   «          d|› �V — |                      ¦   «          |  	                    ¦   «          dS )zGSpawns an ephemeral HTTP test server running FreeExilePCRequestHandler.)z	127.0.0.1r   é   T)ÚtargetÚdaemonzhttp://127.0.0.1:N)
ÚsocketserverÚ	TCPServerr	   Úserver_addressÚ	threadingÚThreadÚserve_foreverÚstartÚshutdownÚserver_close)ÚserverÚportÚthreads      r   Ú	pc_serverr+       sŠ   è è € õ Ô#Ð$4Õ6LÑMÔM€FØÔ  Ô#€DÝÔ VÔ%9À$ÐGÑGÔG€FØ
‡L‚L�N„N€NØ
$˜dÐ
$Ð
$Ð$Ð$Ð$Ø
‡O‚OÑÔÐØ
×ÒÑÔÐÐÐr   c               #  ó8  K  — ddl m}   | ¦   «                              ¦   «         }	 |j                             dd¬¦  «        }n+# t
          $ r |j                             d¬¦  «        }Y nw xY w|V — |                     ¦   «          |                     ¦   «          dS )z<Initializes headless Chromium / Edge browser via Playwright.r   )Úsync_playwrightÚmsedgeT)ÚchannelÚheadless)r0   N)Úplaywright.sync_apir-   r%   ÚchromiumÚlaunchÚ	ExceptionÚcloseÚstop)r-   ÚpÚbrowsers      r   Úbrowser_instancer9   ,   s²   è è € ð 4Ð3Ð3Ð3Ð3Ð3àˆÑÔ×ÒÑ!Ô!€Að3Ø”*×#Ò#¨H¸tÐ#ÑDÔDˆˆøÝð 3ð 3ð 3Ø”*×#Ò#¨TÐ#Ñ2Ô2ˆˆˆð3øøøà
€M€M€MØ‡M‚M�O„O€OØ‡F‚F�H„H€H€H€Hs   ¦A Á%A+Á*A+é€  é8  Úurlr   ÚwidthÚintÚheightc                ó¶   — |                       ||dœ¬¦  «        }|                     d¦  «         |                     |¦  «         |                     d¦  «         |S )zPHelper creating a PC client page with fullscreen mode and zero scrollbar checks.©r=   r?   ©ÚviewportzEtry { localStorage.setItem('fe_sim_mode', 'fullscreen'); } catch(e){}éú   )Únew_pageÚadd_init_scriptÚgotoÚwait_for_timeout)r9   r<   r=   r?   Úpages        r   Úopen_pc_pagerJ   ;   s]   € à×$Ò$¸ÈÐ.PÐ.PÐ$ÑQÔQ€DØ×ÒÐ`ÑaÔaÐaØ‡I‚Iˆc�N„N€NØ×Ò˜#ÑÔÐØ€Kr   c                  óº   — e Zd ZdZdd„Zdd„Zdd„Zdd„Zdd„Zdd	„Z	dd
„Z
dd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„ZdS )ÚTestPcDesktopClientE2EzEOpaque-box E2E test suite covering Tiers 1 to 4 on PC Desktop Client.r   r   c           
     ó–  — t          ||› d�¦  «        }|                     d¦  «        }|d         }|d         }d}||z   }||k    }	|	s”t          j        d|	fd||f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }
t          j        d	¦  «        d
z   d|
iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}	x}x}}|d         }|d         }d}||z   }||k    }	|	s”t          j        d|	fd||f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }
t          j        d¦  «        d
z   d|
iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}	x}x}}|j        }d} ||¦  «        }|j	        } |¦   «         }d}||k    }|�st          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}}|j        }d} ||¦  «        }|j	        } |¦   «         }d}||k    }|�st          j        d|fd||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}}|                     ¦   «          dS )zXTier 1: Verifies 100vw x 100vh canvas sizing with zero scrollbars and no mobile chassis.ú/index.htmlzˆ() => ({ sw: document.body.scrollWidth, cw: document.body.clientWidth, sh: document.body.scrollHeight, ch: document.body.clientHeight })ÚswÚcwr   ©ú<=©z%(py1)s <= (%(py4)s + %(py6)s)©Úpy1Úpy4Úpy6z$Zero horizontal scrollbars permittedú
>assert %(py9)sÚpy9NÚshÚchz"Zero vertical scrollbars permittedú.iphone-framer   ©ú==)z‚%(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.locator
}(%(py4)s)
}.count
}()
} == %(py13)srI   ©Úpy0Úpy2rV   rW   Úpy8Úpy10Úpy13z).iphone-frame must not exist in PC clientú
>assert %(py15)sÚpy15ú#simulator-barz*#simulator-bar must not exist in PC client)rJ   ÚevaluateÚ
@pytest_arÚ_call_reprcompareÚ	_safereprÚ_format_assertmsgÚAssertionErrorÚ_format_explanationÚlocatorÚcountÚ@py_builtinsÚlocalsÚ_should_repr_global_namer5   )r   r+   r9   rI   Úscroll_dimsÚ@py_assert0Ú@py_assert3Ú@py_assert5Ú@py_assert7Ú@py_assert2Ú@py_format8Ú@py_format10Ú@py_assert1Ú@py_assert9Ú@py_assert12Ú@py_assert11Ú@py_format14Ú@py_format16s                     r   Ú/test_tier1_fullscreen_canvas_and_mobile_absencezFTestPcDesktopClientE2E.test_tier1_fullscreen_canvas_and_mobile_absenceG   s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ—m’mð  %oñ  pô  pˆØ˜4Ô Ða K°Ô$5Ða¸ÐaÐ$5¸Ñ$9ÐaÐ Ð$9Ò9ÐaÐaÐaÕaÔaÐaÐaÐaÐaÐ Ð$9ÐaÑaÔaÕaÔaÐ ÑaÔaÕaÔaÐ$5ÑaÔaÕaÔa¸ÑaÔaÐaÐaÑaÐaÕaÔaÐ;aÑaÔaÐaÑaÐaÐaÐaÑaÐaÕaÕaÔaÐaÑaÔaÑaÔaÐaÐaÐaÐaÐaÐaÐaÐaÐaÐaÐaØ˜4Ô Ð_ K°Ô$5Ð_¸Ð_Ð$5¸Ñ$9Ð_Ð Ð$9Ò9Ð_Ð_Ð_Õ_Ô_Ð_Ð_Ð_Ð_Ð Ð$9Ð_Ñ_Ô_Õ_Ô_Ð Ñ_Ô_Õ_Ô_Ð$5Ñ_Ô_Õ_Ô_¸Ñ_Ô_Ð_Ð_Ñ_Ð_Õ_Ô_Ð;_Ñ_Ô_Ð_Ñ_Ð_Ð_Ð_Ñ_Ð_Õ_Õ_Ô_Ð_Ñ_Ô_Ñ_Ô_Ð_Ð_Ð_Ð_Ð_Ð_Ð_Ð_Ð_Ð_Ð_ØŒ|Ðf˜OÐfˆ|ˆ|˜OÑ,Ô,ÐfÐ,Ô2ÐfÐ2Ð2Ñ4Ô4Ðf¸ÐfÐ4¸Ò9ÐfÐfÑfÕfÔfÐfÐfÐfÐfÐ4¸ÐfÑfÔfÐfÕfÔfÑfÔfÐfÐfÕfÔfˆtÑfÔfÐfÕfÔfˆtÑfÔfÐfÐfÕfÔfˆ|ÑfÔfÕfÔf˜OÑfÔfÕfÔfÐ,ÑfÔfÕfÔfÐ2ÑfÔfÕfÔfÐ4ÑfÔfÕfÔf¸ÑfÔfÐfÐfÑfÐfÕfÔfÐ;fÑfÔfÐfÑfÐfÐfÐfÑfÐfÕfÕfÔfÐfÑfÔfÑfÔfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfØŒ|ÐhÐ,Ðhˆ|ˆ|Ð,Ñ-Ô-ÐhÐ-Ô3ÐhÐ3Ð3Ñ5Ô5Ðh¸ÐhÐ5¸Ò:ÐhÐhÑhÕhÔhÐhÐhÐhÐhÐ5¸ÐhÑhÔhÐhÕhÔhÑhÔhÐhÐhÕhÔhˆtÑhÔhÐhÕhÔhˆtÑhÔhÐhÐhÕhÔhˆ|ÑhÔhÕhÔhÐ,ÑhÔhÕhÔhÐ-ÑhÔhÕhÔhÐ3ÑhÔhÕhÔhÐ5ÑhÔhÕhÔh¸ÑhÔhÐhÐhÑhÐhÕhÔhÐ<hÑhÔhÐhÑhÐhÐhÐhÑhÐhÕhÕhÔhÐhÑhÔhÑhÔhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhÐhØ�
Š
‰Œˆˆˆr   c           
     ó¦  — t          ||› d�¦  «        }|                     d¦  «        }d}||k    }|s¬t          j        d|fd||f¦  «        dt	          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }t          j        d¦  «        d	z   d
|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}}|j        }d}	 ||	¦  «        }
|
j        } |¦   «         }d}||k    }|�st          j        d|fd||f¦  «        dt	          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        t          j        |	¦  «        t          j        |
¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        dœz  }t          j        d¦  «        dz   d|iz  }t          t          j
        |¦  «        ¦  «        ‚dx}x}	x}
x}x}x}}|                     d¦  «        }|szt          j        d¦  «        dz   ddt	          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndiz  }t          t          j
        |¦  «        ¦  «        ‚|                     ¦   «          dS )z^Tier 1: Verifies <base href> links webapp and hidden dummy joystick prevents null dereference.rN   z:() => document.querySelector('base')?.getAttribute('href')z
../webapp/r]   ©z%(py0)s == %(py3)sÚ	base_href©r`   Úpy3z"Base href must point to ../webapp/ú
>assert %(py5)sÚpy5Nz#joystick-stickr   ©ú>©z�%(py10)s
{%(py10)s = %(py8)s
{%(py8)s = %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.locator
}(%(py4)s)
}.count
}()
} > %(py13)srI   r_   z(#joystick-stick dummy element must existre   rf   z‡() => { const el = document.getElementById('joystick-zone'); return el?.style.display === 'none' || el?.classList.contains('hidden'); }z'Dummy joystick container must be hiddenú
>assert %(py0)sr`   Ú	is_hidden)rJ   rh   ri   rj   rq   rr   rs   rk   rl   rm   rn   ro   rp   r5   )r   r+   r9   rI   r…   ry   r|   Ú@py_format4Ú@py_format6rv   rw   rx   r}   r~   r   r€   r�   rŽ   Ú@py_format1s                      r   Ú-test_tier1_dummy_joystick_guard_and_base_hrefzDTestPcDesktopClientE2E.test_tier1_dummy_joystick_guard_and_base_hrefQ   s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ—M’MÐ"^Ñ_Ô_ˆ	Ø(ÐNˆy˜LÒ(ÐNÐNÐNÕNÔNÐNÐNÐNÐNˆy˜LÐNÑNÔNÐNÕNÔNÑNÔNÐNÐNÕNÔNˆyÑNÔNÐNÕNÔNˆyÑNÔNÐNÐNÕNÔN˜LÑNÔNÐNÐNÑNÐNÕNÔNÐ*NÑNÔNÐNÑNÐNÐNÐNÑNÐNÕNÕNÔNÐNÑNÔNÑNÔNÐNÐNÐNÐNÐNØŒ|ÐfÐ-Ðfˆ|ˆ|Ð-Ñ.Ô.ÐfÐ.Ô4ÐfÐ4Ð4Ñ6Ô6Ðf¸ÐfÐ6¸Ò:ÐfÐfÑfÕfÔfÐfÐfÐfÐfÐ6¸ÐfÑfÔfÐfÕfÔfÑfÔfÐfÐfÕfÔfˆtÑfÔfÐfÕfÔfˆtÑfÔfÐfÐfÕfÔfˆ|ÑfÔfÕfÔfÐ-ÑfÔfÕfÔfÐ.ÑfÔfÕfÔfÐ4ÑfÔfÕfÔfÐ6ÑfÔfÕfÔf¸ÑfÔfÐfÐfÑfÐfÕfÔfÐ<fÑfÔfÐfÑfÐfÐfÐfÑfÐfÕfÕfÔfÐfÑfÔfÑfÔfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfÐfØ—M’Mð  #lñ  mô  mˆ	ØÐCÕCÔCÐCÑCÔCÐCÑCÐCÐCÕCÔCÑCÔCÐCÐCÕCÔCˆyÑCÔCÐCÕCÔCˆyÑCÔCÐCÐCÐCÑCÐCÕCÕCÔCÐCÑCÔCÑCÔCÐCØ�
Š
‰Œˆˆˆr   c                óN  — t          ||› d�¦  «        }|j                             dd¦  «         |                     d¦  «         |                     d¦  «        }d}||u}|s¬t          j        d|fd||f¦  «        d	t          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        nd	t          j
        |¦  «        d
œz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )zMTier 1: Verifies left-click moves character accurately to target coordinates.rN   i$  éN  éd   z(() => window.player?.destination?.activeN©úis not©z%(py0)s is not %(py3)sÚdest_activer†   z(Player destination state must be definedrˆ   r‰   )rJ   ÚmouseÚclickrH   rh   ri   rj   rq   rr   rs   rk   rl   rm   rn   r5   )	r   r+   r9   rI   r™   ry   r|   r�   r�   s	            r   Ú#test_tier1_click_to_move_kinematicsz:TestPcDesktopClientE2E.test_tier1_click_to_move_kinematics[   s>  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ
×Ò˜ HÑ-Ô-Ð-Ø×Ò˜cÑ"Ô"Ð"Ø—m’mÐ$NÑOÔOˆØ"&ÐRˆ{ $Ð&ÐRÐRÐRÕRÔRÐRÐRÐRÐRˆ{ $ÐRÑRÔRÐRÕRÔRÑRÔRÐRÐRÕRÔRˆ{ÑRÔRÐRÕRÔRˆ{ÑRÔRÐRÐRÕRÔR $ÑRÔRÐRÐRÑRÐRÕRÔRÐ(RÑRÔRÐRÑRÐRÐRÐRÑRÐRÕRÕRÔRÐRÑRÔRÑRÔRÐRÐRÐRÐRÐRØ�
Š
‰Œˆˆˆr   c                ó*  — t          ||› d�¦  «        }|j                             d¦  «         |                     d¦  «         |                     d¦  «        }|                     d¦  «        }g }d}||u }|}	|s
d}
||
k    }|}	|	�smt          j        d|fd	||f¦  «        d
t          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        nd
t          j
        |¦  «        dœz  }dd|iz  }|                     |¦  «         |s‹t          j        d|fd||
f¦  «        dt          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        ndt          j
        |
¦  «        dœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}	x}x}x}x}}
|                     ¦   «          dS )zITier 1: Verifies Space triggers 0.25s i-frame window and dodge animState.rN   ÚSpaceé2   ú() => window.player?.isIFrameú() => window.player?.animStateTÚdodge©Úis)z%(py2)s is %(py5)sÚiframe_active©ra   r‰   ú%(py7)sÚpy7r]   )z%(py9)s == %(py12)sÚ
anim_state)rY   Úpy12ú%(py14)sÚpy14r   z/Dodge roll must initiate i-frame or dodge stateú
>assert %(py17)sÚpy17N)rJ   ÚkeyboardÚpressrH   rh   ri   rj   rq   rr   rs   rk   ÚappendÚ_format_booloprl   rm   rn   r5   )r   r+   r9   rI   r¥   r©   r|   Ú@py_assert4rv   ru   r   Ú@py_assert10r�   rz   Ú@py_format13Ú@py_format15r�   Ú@py_format18s                     r   Ú%test_tier1_spacebar_dodge_roll_iframez<TestPcDesktopClientE2E.test_tier1_spacebar_dodge_roll_iframed   sn  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŸšÐ&EÑFÔFˆØ—]’]Ð#CÑDÔDˆ
ØpÐp Ðpˆ} Ð$ÐpÐpÐpÐpÐp°gÐp¨
°gÒ(=ÐpÐpÐpÐpÑpÕpÔpÐpÐpÐpÐpˆ} ÐpÑpÔpÐpÕpÔpÑpÔpÐpÐpÕpÔpˆ}ÑpÔpÐpÕpÔpˆ}ÑpÔpÐpÐpÕpÔp ÑpÔpÐpÐpÑpÐpÐpÐpÐpÐpÑpÐpÐp×pÒpÐpÑpÔpÐpÐpÐpÕpÔpÐpÐpÐpÐp¨
°gÐpÑpÔpÐpÕpÔpÑpÔpÐpÐpÕpÔp¨
ÑpÔpÐpÕpÔp¨
ÑpÔpÐpÐpÕpÔp°gÑpÔpÐpÐpÑpÐpÐpÐpÐpÐpÑpÐpÐp×pÒpÐpÑpÔpÐpÕpÔpÐpÐpÑpÔpÐpÑpÐpÕpÔpÐ?pÑpÔpÐpÑpÐpÐpÐpÑpÐpÕpÕpÔpÐpÑpÔpÑpÔpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpÐpØ�
Š
‰Œˆˆˆr   c                óF  — t          ||› d�¦  «        }|j                             d¦  «         |                     d¦  «         |                     d¦  «        }| }|szt          j        d¦  «        dz   ddt          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        ndiz  }t          t          j        |¦  «        ¦  «        ‚d	}d
D ]1}|j                             |¦  «         |                     d¦  «         Œ2|                     ¦   «          d	S )zGTier 1: Verifies W is decoupled from movement and QWER activate skills.rN   ÚKeyWrŸ   z1() => window.keys?.['w'] || window.keys?.['KeyW']z-Key W must not be captured into movement keysz
>assert not %(py0)sr`   Úkeys_wN)ÚKeyQÚKeyEÚKeyRé   )rJ   r¯   r°   rH   rh   ri   rl   rq   rr   rs   rk   rm   rn   r5   )r   r+   r9   rI   r»   r|   Ú@py_format2Úks           r   Ú+test_tier1_qwer_martial_skills_w_decouplingzBTestPcDesktopClientE2E.test_tier1_qwer_martial_skills_w_decouplingn   s-  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!Ø—’ÐRÑSÔSˆØˆzÐJˆzÐJÕJÔJÐJÑJÔJÐJÑJÐJÐJÕJÔJÑJÔJÐJÐJÕJÔJ�6ÑJÔJÐJÕJÔJ�6ÑJÔJÐJÐJÐJÑJÐJÕJÕJÔJÐJÑJÔJÑJÔJÐJÐJÐJØ)ð 	&ð 	&ˆAØŒM×Ò Ñ"Ô"Ð"Ø×!Ò! "Ñ%Ô%Ð%Ð%Ø�
Š
‰Œˆˆˆr   c                ó  — t          ||› d�¦  «        }t          dd¦  «        D ]>}|j                             t	          |¦  «        ¦  «         |                     d¦  «         Œ?|                     d¦  «        }|szt          j        d¦  «        dz   dd	t          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd	iz  }t          t          j        |¦  «        ¦  «        ‚|                     ¦   «          d
S )zOTier 1: Verifies keys 1-5 trigger survival flasks and initialize flask entries.rN   r   é   r¿   z-() => !!window.PcInputController?.flasks?.[1]z#Survival flasks must be initializedr�   r`   Úflask_existsN)rJ   Úranger¯   r°   r   rH   rh   ri   rl   rq   rr   rs   rk   rm   rn   r5   )r   r+   r9   rI   ÚirÅ   r‘   s          r   Ú!test_tier1_survival_flasks_1_to_5z8TestPcDesktopClientE2E.test_tier1_survival_flasks_1_to_5z   s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆÝ�q˜!‘”ð 	&ð 	&ˆAØŒM×Ò¥ A¡¤Ñ'Ô'Ð'Ø×!Ò! "Ñ%Ô%Ð%Ð%Ø—}’}Ð%TÑUÔUˆØÐBÕBÔBÐBÑBÔBÐBÑBÐBÐBÕBÔBÑBÔBÐBÐBÕBÔBˆ|ÑBÔBÐBÕBÔBˆ|ÑBÔBÐBÐBÐBÑBÐBÕBÕBÔBÐBÑBÔBÑBÔBÐBØ�
Š
‰Œˆˆˆr   c           
     ó   — t          ||› d�¦  «        }|j                             d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |j        }d} ||¦  «        }|j        } |¦   «         }d}	||	k    }
|
�st          j        d|
fd	||	f¦  «        d
t          j	        ¦   «         v st          j
        |¦  «        rt          j        |¦  «        nd
t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |	¦  «        dœz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}x}
}	|                     ¦   «          dS )zPTier 1: Verifies I, C, and Esc toggle corresponding UI modals and pause overlay.rN   ÚKeyCrŸ   ÚKeyIÚEscapez#overlay-pauser   rŠ   rŒ   rI   r_   z,Pause overlay #overlay-pause must be presentre   rf   N)rJ   r¯   r°   rH   ro   rp   ri   rj   rq   rr   rs   rk   rl   rm   rn   r5   )r   r+   r9   rI   r|   rv   rw   rx   r}   r~   r   r€   r�   s                r   Ú&test_tier1_ui_modal_hotkeys_and_escapez=TestPcDesktopClientE2E.test_tier1_ui_modal_hotkeys_and_escape„   s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜HÑ%Ô%Ð%Ø×Ò˜bÑ!Ô!Ð!ØŒ|ÐiÐ,Ðiˆ|ˆ|Ð,Ñ-Ô-ÐiÐ-Ô3ÐiÐ3Ð3Ñ5Ô5Ði¸ÐiÐ5¸Ò9ÐiÐiÑiÕiÔiÐiÐiÐiÐiÐ5¸ÐiÑiÔiÐiÕiÔiÑiÔiÐiÐiÕiÔiˆtÑiÔiÐiÕiÔiˆtÑiÔiÐiÐiÕiÔiˆ|ÑiÔiÕiÔiÐ,ÑiÔiÕiÔiÐ-ÑiÔiÕiÔiÐ3ÑiÔiÕiÔiÐ5ÑiÔiÕiÔi¸ÑiÔiÐiÐiÑiÐiÕiÔiÐ;iÑiÔiÐiÑiÐiÐiÐiÑiÐiÕiÕiÔiÐiÑiÔiÑiÔiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiÐiØ�
Š
‰Œˆˆˆr   c                ó¦  ‡	— t          ||› d�¦  «        }g Š	|                     dˆ	fd„¦  «         |                     dˆ	fd„¦  «         |j                             dd¦  «         |j                             d¦  «         |                     d	¦  «         t          ‰	¦  «        }d
}||k    }|�s
t          j	        d|fd||f¦  «        dt          j        ¦   «         v st          j        t          ¦  «        rt          j        t          ¦  «        nddt          j        ¦   «         v st          j        ‰	¦  «        rt          j        ‰	¦  «        ndt          j        |¦  «        t          j        |¦  «        dœz  }t          j        d‰	› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}|                     ¦   «          dS )zPTier 1: Verifies clean browser runtime without unexpected JavaScript exceptions.rN   Ú	pageerrorc                ó4   •— ‰                      d| › �¦  «        S ©NzPageError: ©r±   ©ÚerrÚerrorss    €r   ú<lambda>zRTestPcDesktopClientE2E.test_tier1_zero_console_javascript_errors.<locals>.<lambda>”   ó   ø€ ¨¯ªÐ7JÀSÐ7JÐ7JÑ)KÔ)K€ r   Úconsolec                ój   •— | j         dk    r&d| j        vr‰                     d| j        › �¦  «        nd S ©NÚerrorÚfaviconzConsoleError: ©ÚtypeÚtextr±   ©ÚmrÕ   s    €r   rÖ   zRTestPcDesktopClientE2E.test_tier1_zero_console_javascript_errors.<locals>.<lambda>•   óF   ø€ ÐQRÔQWÐ[bÒQbÐQbÐgpÐxyÔx~Ðg~Ðg~ V§]¢]Ð3LÀAÄFÐ3LÐ3LÑ%MÔ%MÐ%Mð  EI€ r   éÀ  é  r¼   r•   r   r]   ©z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sÚlenrÕ   ©r`   rU   r‡   rW   z$Unexpected console errors detected: ú
>assert %(py8)srb   N)rJ   Úonrš   r›   r¯   r°   rH   ræ   ri   rj   rq   rr   rs   rk   rl   rm   rn   r5   )
r   r+   r9   rI   ry   rw   r³   Ú@py_format7Ú@py_format9rÕ   s
            @r   Ú)test_tier1_zero_console_javascript_errorsz@TestPcDesktopClientE2E.test_tier1_zero_console_javascript_errors�   sú  ø€ åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØˆØ�Š�ÐKÐKÐKÐKÑLÔLÐLØ�Š�	ð  Ið  Ið  Ið  Iñ  	Jô  	Jð  	JØŒ
×Ò˜˜cÑ"Ô"Ð"ØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜cÑ"Ô"Ð"Ý�6‰{Œ{ÐP˜aÐPˆ{˜aÒÐPÐPÑPÕPÔPÐPÐPÐPÐPˆ{˜aÐPÑPÔPÐPÕPÔPÑPÔPÐPÐPÕPÔP�sÑPÔPÐPÕPÔP�sÑPÔPÐPÐPÐPÕPÔPÑPÔPÐPÐPÕPÔP�6ÑPÔPÐPÕPÔP�6ÑPÔPÐPÐPÕPÔPˆ{ÑPÔPÕPÔP˜aÑPÔPÐPÐPÑPÐPÕPÔPÐ!PÈÐ!PÐ!PÑPÔPÐPÑPÐPÐPÐPÑPÐPÕPÕPÔPÐPÑPÔPÑPÔPÐPÐPÐPÐPÐPÐPÐPØ�
Š
‰Œˆˆˆr   c           	     óœ  — g d¢}|D �]Ã}|› |› �}t           j                             |¦  «        }	 t           j                             |¦  «        5 }d}|sZt	          j        d|› d|j        › �¦  «        dz   dt	          j        |¦  «        iz  }t          t	          j	        |¦  «        ¦  «        ‚d}ddd¦  «         n# 1 swxY w Y   ŒÁ# t           j
        j        $ rí}	|	j        }
d}|
|k    }|sËt	          j        d	|fd
|
|f¦  «        dt          j        ¦   «         v st	          j        |	¦  «        rt	          j        |	¦  «        ndt	          j        |
¦  «        t	          j        |¦  «        dœz  }t	          j        d|› d|	j        › d�¦  «        dz   d|iz  }t          t	          j	        |¦  «        ¦  «        ‚dx}
x}}Y d}	~	�Œ½d}	~	ww xY wdS )zFTier 1: Verifies server rejects path traversal attempts with HTTP 404.)	z/../../../../Windows/win.iniz/../../.git/configz#/web_pc/../../../../Windows/win.iniz#/webapp/../../../../Windows/win.iniz#/assets/../../../../Windows/win.iniz/..%2f..%2f..%2fWindows/win.iniz/%2e%2e/%2e%2e/Windows/win.iniz/..\..\..\Windows\win.iniz/C:/Windows/win.iniFz)Path traversal succeeded unexpectedly on z with status z
>assert %(py1)srU   Ni”  r]   )z,%(py2)s
{%(py2)s = %(py0)s.code
} == %(py5)sÚe)r`   ra   r‰   zPath traversal on z returned HTTP z instead of 404ú
>assert %(py7)sr¨   )ÚurllibÚrequestÚRequestÚurlopenri   rl   Ústatusrk   rm   rn   rÛ   Ú	HTTPErrorÚcoderj   rq   rr   rs   )r   r+   Útraversal_vectorsÚpathr<   ÚreqÚrespru   rÀ   rî   r|   r³   rv   r�   rz   s                  r   Ú+test_tier1_server_path_traversal_preventionzBTestPcDesktopClientE2E.test_tier1_server_path_traversal_preventionœ   s‚  € ð
ð 
ð 
Ðð &ð 	hñ 	hˆDØÐ& Ð&Ð&ˆCÝ”.×(Ò(¨Ñ-Ô-ˆCðhÝ”^×+Ò+¨CÑ0Ô0ð o°DØ Ðn˜5ÐnÕnÔnÐ"nÈdÐ"nÐ"nÐaeÔalÐ"nÐ"nÑnÔnÐnÑnÐnÕnÔn˜5ÑnÔnÐnÑnÐnÕnÕnÔnÐnÑnÔnÑnÔnÐnÐnÐnðoð oð oñ oô oð oð oð oð oð oð oøøøð oð oð oð oøøå”<Ô)ð hð hð hØ”vÐg Ðg�v ’}ÐgÐgÐgÕgÔgÐgÐgÐgÐg�v ÐgÑgÔgÐgÕgÔgÑgÔgÐgÐgÕgÔg�qÑgÔgÐgÕgÔg�qÑgÔgÐgÐgÕgÔg�vÑgÔgÕgÔg ÑgÔgÐgÐgÑgÐgÕgÔgÐ&g¸4Ð&gÐ&gÐPQÔPVÐ&gÐ&gÐ&gÑgÔgÐgÑgÐgÐgÐgÑgÐgÕgÕgÔgÐgÑgÔgÑgÔgÐgÐgÐgÐgÐgÐgÐgÐgÐgÐgÐgÑgøøøøðhøøøð	hð 	hs=   °CÁA!B<Â0CÂ<C 	Ã CÃC 	ÃCÃG	ÃC"GÇG	c                ór  — t          ||› d�¦  «        }|                     d¦  «         |                     dd¦  «         |                     d¦  «         |                     d¦  «        }d}||k    }|s¬t	          j        d|fd	||f¦  «        d
t          j        ¦   «         v st	          j        |¦  «        rt	          j	        |¦  «        nd
t	          j	        |¦  «        dœz  }t	          j
        d¦  «        dz   d|iz  }t          t	          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )zHTier 1: Verifies in-place 9-language translation with zero page reloads.rN   zw() => { window.__sessionNavCount = 1; window.addEventListener('beforeunload', () => { window.__sessionNavCount++; }); }ú#lang-selectÚenr•   z() => window.__sessionNavCountr   r]   r„   Ú	nav_countr†   z7Language switch must be reactive with zero page reloadsrˆ   r‰   N©rJ   rh   Úselect_optionrH   ri   rj   rq   rr   rs   rk   rl   rm   rn   r5   )	r   r+   r9   rI   rÿ   ry   r|   r�   r�   s	            r   Ú,test_tier1_reactive_i18n_without_page_reloadzCTestPcDesktopClientE2E.test_tier1_reactive_i18n_without_page_reload­   sZ  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ�Šð  Pñ  	Qô  	Qð  	QØ×Ò˜>¨4Ñ0Ô0Ð0Ø×Ò˜cÑ"Ô"Ð"Ø—M’MÐ"BÑCÔCˆ	ØÐXˆy˜AŠ~ÐXÐXÐXÕXÔXÐXÐXÐXÐXˆy˜AÐXÑXÔXÐXÕXÔXÑXÔXÐXÐXÕXÔXˆyÑXÔXÐXÕXÔXˆyÑXÔXÐXÐXÕXÔX˜AÑXÔXÐXÐXÑXÐXÕXÔXÐXÑXÔXÐXÑXÐXÐXÐXÑXÐXÕXÕXÔXÐXÑXÔXÑXÔXÐXÐXÐXÐXÐXØ�
Š
‰Œˆˆˆr   c                ó   — t          ||› d�¦  «        }|j                             dd¦  «         |j                             ¦   «          |j                             ddd¬¦  «         |                     d¦  «         |j                             d	d
d¬¦  «         |                     d¦  «         |j                             ¦   «          |                     d¦  «        }g }d}||u}|}|rd}	|	|v }
|
}|�smt          j        d|fd||f¦  «        dt          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }dd|iz  }|                     |¦  «         |r‹t          j        d|
fd|	|f¦  «        t          j        |	¦  «        dt          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nddœz  }dd|iz  }|                     |¦  «         t          j        |d¦  «        i z  }t          j        d¦  «        dz   d|iz  }t!          t          j        |¦  «        ¦  «        ‚dx}x}x}x}x}	}
|                     ¦   «          dS )zVTier 2: Verifies continuous hold-to-move pointer drag updates destination coordinates.rN   rã   rä   é  éX  é   )ÚstepsrŸ   i~  iŠ  ú () => window.player?.destinationNÚwxr–   )z%(py2)s is not %(py5)sÚdestr¦   r§   r¨   ©Úin)z%(py10)s in %(py12)s)rc   rª   r«   r¬   r   z8Hold-to-move must continuously update player destinationr­   r®   )rJ   rš   ÚmoveÚdownrH   Úuprh   ri   rj   rq   rr   rs   rk   r±   r²   rl   rm   rn   r5   )r   r+   r9   rI   r
  r|   r³   rv   ru   r}   r   r�   rz   rµ   r¶   r�   r·   s                    r   Ú+test_tier2_continuous_hold_to_move_draggingzBTestPcDesktopClientE2E.test_tier2_continuous_hold_to_move_dragging·   sÄ  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ
�Š˜˜SÑ!Ô!Ð!ØŒ
�ŠÑÔÐØŒ
�Š˜˜c¨ˆÑ+Ô+Ð+Ø×Ò˜bÑ!Ô!Ð!ØŒ
�Š˜˜c¨ˆÑ+Ô+Ð+Ø×Ò˜bÑ!Ô!Ð!ØŒ
�Š‰ŒˆØ�}Š}Ð?Ñ@Ô@ˆØlÐl˜4Ðlˆt˜4ÐÐlÐlÐlÐlÐl DÐl D¨D LÐlÐlÐlÐlÑlÕlÔlÐlÐlÐlÐlˆt˜4ÐlÑlÔlÐlÕlÔlÑlÔlÐlÐlÕlÔlˆtÑlÔlÐlÕlÔlˆtÑlÔlÐlÐlÕlÔl˜4ÑlÔlÐlÐlÑlÐlÐlÐlÐlÐlÑlÐlÐl×lÒlÐlÑlÔlÐlÐlÐlÕlÔlÐlÐlÐlÐl D¨DÐlÑlÔlÕlÔl DÑlÔlÐlÕlÔlÑlÔlÐlÐlÕlÔl¨DÑlÔlÐlÕlÔl¨DÑlÔlÐlÐlÐlÐlÑlÐlÐlÐlÐlÐlÑlÐlÐl×lÒlÐlÑlÔlÐlÕlÔlÐlÐlÑlÔlÐlÑlÐlÕlÔlÐ2lÑlÔlÐlÑlÐlÐlÐlÑlÐlÕlÕlÔlÐlÑlÔlÑlÔlÐlÐlÐlÐlÐlÐlÐlÐlÐlÐlÐlÐlÐlØ�
Š
‰Œˆˆˆr   c                óz  — t          ||› d�¦  «        }|                     d¦  «         g d¢}|D �]'}|                     d|¦  «         |                     d¦  «         |                     d¦  «        }||k    }|sÚt	          j        d|fd||f¦  «        d	t          j        ¦   «         v st	          j        |¦  «        rt	          j	        |¦  «        nd	d
t          j        ¦   «         v st	          j        |¦  «        rt	          j	        |¦  «        nd
dœz  }t	          j
        d|› �¦  «        dz   d|iz  }	t          t	          j        |	¦  «        ¦  «        ‚d}�Œ)|                     d¦  «        }
d}|
|k    }|s¬t	          j        d|fd|
|f¦  «        dt          j        ¦   «         v st	          j        |
¦  «        rt	          j	        |
¦  «        ndt	          j	        |¦  «        dœz  }t	          j
        d¦  «        dz   d|iz  }t          t	          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )zRTier 2: Rapidly cycles across all 9 supported languages without desync or reloads.rN   zs() => { window.__cycleNavCount = 1; window.addEventListener('beforeunload', () => { window.__cycleNavCount++; }); })
Úvirþ   ÚzhÚjaÚkoÚthÚdeÚruÚesr  rý   r¿   z3() => document.getElementById('lang-select')?.valuer]   )z%(py0)s == %(py2)sÚcurÚlang)r`   ra   zLocale selector must reflect z
>assert %(py4)srV   Nz() => window.__cycleNavCountr   r„   rÿ   r†   z5Rapid language cycling must never trigger page reloadrˆ   r‰   r   )r   r+   r9   rI   Ú	languagesr  r  r|   Ú@py_format3Ú@py_format5rÿ   ry   r�   r�   s                 r   Ú#test_tier2_rapid_9_language_cyclingz:TestPcDesktopClientE2E.test_tier2_rapid_9_language_cyclingÅ   s‡  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ�Šð  Lñ  	Mô  	Mð  	MØPÐPÐPˆ	Øð 	Gñ 	GˆDØ×Ò˜~¨tÑ4Ô4Ð4Ø×!Ò! "Ñ%Ô%Ð%Ø—-’-Ð UÑVÔVˆCØ˜$’;ÐFÐFÐFÕFÔFÐFÐFÐFÐF�3˜$ÐFÑFÔFÐFÕFÔFÑFÔFÐFÐFÕFÔF�3ÑFÔFÐFÕFÔF�3ÑFÔFÐFÐFÐFÕFÔFÑFÔFÐFÐFÕFÔF˜$ÑFÔFÐFÕFÔF˜$ÑFÔFÐFÐFÐFÐFÑFÐFÕFÔFÐ FÀÐ FÐ FÑFÔFÐFÑFÐFÐFÐFÑFÐFÕFÕFÔFÐFÑFÔFÑFÔFÐFÐFÐFÑFØ—M’MÐ"@ÑAÔAˆ	ØÐVˆy˜AŠ~ÐVÐVÐVÕVÔVÐVÐVÐVÐVˆy˜AÐVÑVÔVÐVÕVÔVÑVÔVÐVÐVÕVÔVˆyÑVÔVÐVÕVÔVˆyÑVÔVÐVÐVÕVÔV˜AÑVÔVÐVÐVÑVÐVÕVÔVÐVÑVÔVÐVÑVÐVÐVÐVÑVÐVÕVÕVÔVÐVÑVÔVÑVÔVÐVÐVÐVÐVÐVØ�
Š
‰Œˆˆˆr   c                ó`  — t          ||› d�¦  «        }|                     d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «        }d}g }|}|sd}|}||v }	|	�sddd	t          j        ¦   «         v st          j        |¦  «        rt          j	        |¦  «        nd	iz  }
| 
                    |
¦  «         |s.d
dt          j	        |¦  «        iz  }| 
                    |¦  «         t          j        |d¦  «        i z  }t          j        d|	fd||f¦  «        t          j	        |¦  «        |dœz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}	x}x}}|                     ¦   «          dS )zCTier 2: Verifies typing in chat input ignores all gameplay hotkeys.rN   z…() => { document.getElementById('chat-expanded-panel')?.classList.remove('hidden'); document.getElementById('chat-input')?.focus(); }rŸ   ÚQWER123z2() => document.getElementById('chat-input')?.valueÚ z%(py5)sr‰   Ú	input_valz%(py8)srb   r   r  )z%(py1)s in (%(py11)s))rU   Úpy11z%Chat input should receive text typingz
>assert %(py13)srd   N)rJ   rh   rH   r¯   rÞ   rq   rr   ri   rs   rk   r±   r²   rj   rl   rm   rn   r5   )r   r+   r9   rI   r#  ru   r³   rv   rx   ry   r�   rë   r{   Ú@py_format12r€   s                  r   Útest_tier2_typing_focus_guardz4TestPcDesktopClientE2E.test_tier2_typing_focus_guardÓ   s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ�Šð  ^ñ  	_ô  	_ð  	_Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜9Ñ%Ô%Ð%Ø—M’MÐ"VÑWÔWˆ	ØÐVÐVÐV˜YÐV˜YÐV¨"ÐV¨"ÐVˆyÐVÐ-ÐVÐVÑVÐVÐVÐVÕVÔVÑVÔVÐVÐVÕVÔV˜YÑVÔVÐVÕVÔV˜YÑVÔVÐVÐVÐVÑVÐVÐV×VÒVÐVÑVÔVÐV˜YÐVÐVÐVÕVÔV¨"ÑVÔVÐVÑVÐVÐV×VÒVÐVÑVÔVÐVÕVÔVÐVÐVÑVÔVÐVÑVÐVÕVÔVÐVÐVÐVÐVˆyÐVÐVÑVÔVÕVÔVˆyÑVÔVÐVÐVÐVÑVÐVÕVÔVÐ/VÑVÔVÐVÑVÐVÐVÐVÑVÐVÕVÕVÔVÐVÑVÔVÑVÔVÐVÐVÐVÐVÐVÐVÐVÐVÐVÐVÐVØ�
Š
‰Œˆˆˆr   c                óv  — t          ||› d�¦  «        }|                     d¦  «        }|szt          j        d¦  «        dz   ddt	          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndiz  }t          t          j	        |¦  «        ¦  «        ‚| 
                    ¦   «          dS )zNTier 2: Verifies native context menu is suppressed on right-click over canvas.rN   z±() => { const canvas = document.getElementById('game-canvas'); const ev = new MouseEvent('contextmenu', { bubbles: true, cancelable: true }); return !canvas.dispatchEvent(ev); }z3Context menu event must be prevented on game canvasr�   r`   Ú	preventedN)rJ   rh   ri   rl   rq   rr   rs   rk   rm   rn   r5   )r   r+   r9   rI   r(  r‘   s         r   Ú*test_tier2_browser_contextmenu_suppressionzATestPcDesktopClientE2E.test_tier2_browser_contextmenu_suppressionÝ   sÃ   € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØ—M’Mð  #Vñ  Wô  Wˆ	ØÐOÕOÔOÐOÑOÔOÐOÑOÐOÐOÕOÔOÑOÔOÐOÐOÕOÔOˆyÑOÔOÐOÕOÔOˆyÑOÔOÐOÐOÐOÑOÐOÕOÕOÔOÐOÑOÔOÑOÔOÐOØ�
Š
‰Œˆˆˆr   c                ó  — dD �]\  }}t          ||› d�||¬¦  «        }|                     d¦  «        }|d         }|d         }d}	||	z   }
||
k    }|sšt          j        d|fd	||
f¦  «        t          j        |¦  «        t          j        |¦  «        t          j        |	¦  «        d
œz  }t          j        d|› d|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}x}x}	}
|                     ¦   «          �Œ
dS )zWTier 2: Verifies 21:9 Ultrawide (2560x1080) and 16:10 (1920x1200) have zero scrollbars.))i 
  r;   )r:   i°  rN   rA   zH() => ({ sw: document.body.scrollWidth, cw: document.body.clientWidth })rO   rP   r   rQ   rS   rT   zZero scrollbar violation on ÚxrX   rY   N)	rJ   rh   ri   rj   rk   rl   rm   rn   r5   )r   r+   r9   ÚwÚhrI   Údimsru   rv   rw   rx   ry   rz   r{   s                 r   Ú,test_tier2_ultrawide_aspect_ratio_resiliencezCTestPcDesktopClientE2E.test_tier2_ultrawide_aspect_ratio_resilienceä   sW  € à0ð 	ñ 	‰DˆAˆqÝÐ 0°YÐ2KÐ2KÐ2KÐSTÐ]^Ð_Ñ_Ô_ˆDØ—=’=Ð!kÑlÔlˆDØ˜”:ÐW  d¤ÐW¨aÐW ¨a¡ÐW�: Ò/ÐWÐWÐWÕWÔWÐWÐWÐWÐW�: ÐWÑWÔWÕWÔW�:ÑWÔWÕWÔW ÑWÔWÕWÔW¨aÑWÔWÐWÐWÑWÐWÕWÔWÐ1WÐPQÐ1WÐ1WÐTUÐ1WÐ1WÑWÔWÐWÑWÐWÐWÐWÑWÐWÕWÕWÔWÐWÑWÔWÑWÔWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWÐWØ�JŠJ‰LŒLˆL‰Lð		ð 	r   c                óB  ‡— t          ||› d�¦  «        }g Š|                     dˆfd„¦  «         |                     dˆfd„¦  «         |                     d¦  «        }d}||k    }|s¯t          j        d|fd	||f¦  «        d
t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd
t          j        |¦  «        dœz  }t          j	        d|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|j                             d¦  «         |                     d¦  «         |                     d¦  «        }	|                     d¦  «        }
d}|	|k    }|s°t          j        d|fd	|	|f¦  «        dt          j        ¦   «         v st          j        |	¦  «        rt          j        |	¦  «        ndt          j        |¦  «        dœz  }t          j	        d|	› d�¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}d}|
|u }|s¬t          j        d|fd|
|f¦  «        dt          j        ¦   «         v st          j        |
¦  «        rt          j        |
¦  «        ndt          j        |¦  «        dœz  }t          j	        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|j                             d¦  «         |                     d¦  «         |                     d¦  «        }d}||k    }|s°t          j        d|fd	||f¦  «        dt          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }t          j	        d|› d�¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     dd ¬!¦  «         |                     d¦  «        }d"}||u }|s¬t          j        d|fd||f¦  «        d#t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd#t          j        |¦  «        dœz  }t          j	        d$¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}t!          ‰¦  «        }d%}||k    }|�s
t          j        d|fd&||f¦  «        d't          j        ¦   «         v st          j        t           ¦  «        rt          j        t           ¦  «        nd'd(t          j        ¦   «         v st          j        ‰¦  «        rt          j        ‰¦  «        nd(t          j        |¦  «        t          j        |¦  «        d)œz  }t          j	        d*‰› �¦  «        d+z   d,|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}|j                             d¦  «         |                     d¦  «         |                     d¦  «        }d-}||k    }|s¯t          j        d|fd	||f¦  «        d.t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd.t          j        |¦  «        dœz  }t          j	        d/|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     dd ¬!¦  «         |j                             d¦  «         |                     d¦  «         |                     d¦  «        }|                     d0¦  «        }d%}||k    }|s¯t          j        d|fd	||f¦  «        d1t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd1t          j        |¦  «        dœz  }t          j	        d2|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}d}||u }|s¬t          j        d|fd||f¦  «        d3t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd3t          j        |¦  «        dœz  }t          j	        d4¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|j                             d¦  «         |                     d¦  «         |                     d¦  «        }d%}||k    }|s¯t          j        d|fd	||f¦  «        d5t          j        ¦   «         v st          j        |¦  «        rt          j        |¦  «        nd5t          j        |¦  «        dœz  }t          j	        d6|› �¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}t!          ‰¦  «        }d%}||k    }|�s
t          j        d|fd&||f¦  «        d't          j        ¦   «         v st          j        t           ¦  «        rt          j        t           ¦  «        nd'd(t          j        ¦   «         v st          j        ‰¦  «        rt          j        ‰¦  «        nd(t          j        |¦  «        t          j        |¦  «        d)œz  }t          j	        d7‰› �¦  «        d+z   d,|iz  }t          t          j        |¦  «        ¦  «        ‚dx}x}}|                     ¦   «          dS )8zÒTier 2: Verifies single space tap decrements exactly 1 charge (3 -> 2),
        spamming Space during i-frame does NOT waste charges, and i-frame expiry
        completes without TypeError classList exceptions.rN   rÏ   c                ó4   •— ‰                      d| › �¦  «        S rÑ   rÒ   rÓ   s    €r   rÖ   ziTestPcDesktopClientE2E.test_tier2_spacebar_dodge_charge_accounting_and_iframe_lifecycle.<locals>.<lambda>ò   r×   r   rØ   c                ój   •— | j         dk    r&d| j        vr‰                     d| j        › �¦  «        nd S rÚ   rÝ   rà   s    €r   rÖ   ziTestPcDesktopClientE2E.test_tier2_spacebar_dodge_charge_accounting_and_iframe_lifecycle.<locals>.<lambda>ó   râ   r   z=() => window.skillBarController?.slots?.get('dodge')?.chargesr  r]   r„   Úinit_chargesr†   z&Expected 3 initial dodge charges, got rˆ   r‰   Nrž   rŸ   r    é   Úcharges_after_1zBSingle Space tap must decrement exactly 1 charge (expected 2, got ú)Tr£   )z%(py0)s is %(py3)sÚis_iframe_1z(i-Frame must be active during dodge rollr¿   Úcharges_during_iframezFPressing Space while dodging must NOT consume charge (expected 2, got z() => !window.player?.isIFrameiÐ  )ÚtimeoutFÚis_iframe_expiredz"i-Frame must expire after durationr   rå   ræ   rÕ   rç   z3Expected zero errors after i-frame expiration, got rè   rb   r   Úcharges_after_2z&Second dodge must leave 1 charge, got z:() => window.skillBarController?.isSlotOnCooldown('dodge')Úcharges_after_3z+Third dodge must deplete charges to 0, got Úis_on_cdz0Dodge slot must be on cooldown when charges == 0Úcharges_depletedz-Depleted dodge must remain at 0 charges, got z/Unexpected errors during depleted dodge press: )rJ   ré   rh   ri   rj   rq   rr   rs   rk   rl   rm   rn   r¯   r°   rH   Úwait_for_functionræ   r5   )r   r+   r9   rI   r3  ry   r|   r�   r�   r5  r7  r8  r:  rw   r³   rê   rë   r;  r<  r=  r>  rÕ   s                        @r   Ú@test_tier2_spacebar_dodge_charge_accounting_and_iframe_lifecyclezWTestPcDesktopClientE2E.test_tier2_spacebar_dodge_charge_accounting_and_iframe_lifecycleì   s%  ø€ õ Ð,°Ð.GÐ.GÐ.GÑHÔHˆØˆØ�Š�ÐKÐKÐKÐKÑLÔLÐLØ�Š�	ð  Ið  Ið  Ið  Iñ  	Jô  	Jð  	Jð —}’}Ð%dÑeÔeˆØ ÐYˆ|˜qÒ ÐYÐYÐYÕYÔYÐYÐYÐYÐYˆ|˜qÐYÑYÔYÐYÕYÔYÑYÔYÐYÐYÕYÔYˆ|ÑYÔYÐYÕYÔYˆ|ÑYÔYÐYÐYÕYÔY˜qÑYÔYÐYÐYÑYÐYÕYÔYÐ"YÈ<Ð"YÐ"YÑYÔYÐYÑYÐYÐYÐYÑYÐYÕYÕYÔYÐYÑYÔYÑYÔYÐYÐYÐYÐYÐYàŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŸ-š-Ð(gÑhÔhˆØ—m’mÐ$CÑDÔDˆØ"#Ð|ˆ !Ò#Ð|Ð|Ð|Õ|Ô|Ð|Ð|Ð|Ð|ˆ !Ð|Ñ|Ô|Ð|Õ|Ô|Ñ|Ô|Ð|Ð|Õ|Ô|ˆÑ|Ô|Ð|Õ|Ô|ˆÑ|Ô|Ð|Ð|Õ|Ô| !Ñ|Ô|Ð|Ð|Ñ|Ð|Õ|Ô|Ð%|ÐjyÐ%|Ð%|Ð%|Ñ|Ô|Ð|Ñ|Ð|Ð|Ð|Ñ|Ð|Õ|Õ|Ô|Ð|Ñ|Ô|Ñ|Ô|Ð|Ð|Ð|Ð|Ð|Ø"ÐNˆ{˜dÐ"ÐNÐNÐNÕNÔNÐNÐNÐNÐNˆ{˜dÐNÑNÔNÐNÕNÔNÑNÔNÐNÐNÕNÔNˆ{ÑNÔNÐNÕNÔNˆ{ÑNÔNÐNÐNÕNÔN˜dÑNÔNÐNÐNÑNÐNÕNÔNÐ$NÑNÔNÐNÑNÐNÐNÐNÑNÐNÕNÕNÔNÐNÑNÔNÑNÔNÐNÐNÐNÐNÐNàŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!Ø $§¢Ð.mÑ nÔ nÐØ()ð  	MÐ$¨Ò)ð  	Mð  	Mð  	Mõ  	Mô  	Mð  	Mð  	Mð  	Mð  	MÐ$¨ð  	Mñ  	Mô  	Mð  	Mõ  	Mô  	Mñ  	Mô  	Mð  	Mð  	Mõ  	Mô  	MÐ$ñ  	Mô  	Mð  	Mõ  	Mô  	MÐ$ñ  	Mô  	Mð  	Mð  	Mõ  	Mô  	M¨ñ  	Mô  	Mð  	Mð  	Mñ  	Mð  	Mõ  	Mô  	Mð  ,Mð  uJð  ,Mð  ,Mð  ,Mñ  	Mô  	Mð  	Mñ  	Mð  	Mð  	Mð  	Mñ  	Mð  	Mõ  	Mõ  	Mô  	Mð  	Mñ  	Mô  	Mñ  	Mô  	Mð  	Mð  	Mð  	Mð  	Mð  	Mà×ÒÐ?ÈÐÑNÔNÐNØ ŸMšMÐ*IÑJÔJÐØ$)ÐOÐ  EÐ)ÐOÐOÐOÕOÔOÐOÐOÐOÐOÐ  EÐOÑOÔOÐOÕOÔOÑOÔOÐOÐOÕOÔOÐ ÑOÔOÐOÕOÔOÐ ÑOÔOÐOÐOÕOÔO EÑOÔOÐOÐOÑOÐOÕOÔOÐ+OÑOÔOÐOÑOÐOÐOÐOÑOÐOÕOÕOÔOÐOÑOÔOÑOÔOÐOÐOÐOÐOÐOÝ�6‰{Œ{Ð_˜aÐ_ˆ{˜aÒÐ_Ð_Ñ_Õ_Ô_Ð_Ð_Ð_Ð_ˆ{˜aÐ_Ñ_Ô_Ð_Õ_Ô_Ñ_Ô_Ð_Ð_Õ_Ô_�sÑ_Ô_Ð_Õ_Ô_�sÑ_Ô_Ð_Ð_Ð_Õ_Ô_Ñ_Ô_Ð_Ð_Õ_Ô_�6Ñ_Ô_Ð_Õ_Ô_�6Ñ_Ô_Ð_Ð_Õ_Ô_ˆ{Ñ_Ô_Õ_Ô_˜aÑ_Ô_Ð_Ð_Ñ_Ð_Õ_Ô_Ð!_ÐW]Ð!_Ð!_Ñ_Ô_Ð_Ñ_Ð_Ð_Ð_Ñ_Ð_Õ_Õ_Ô_Ð_Ñ_Ô_Ñ_Ô_Ð_Ð_Ð_Ð_Ð_Ð_Ð_àŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŸ-š-Ð(gÑhÔhˆØ"#Ð_ˆ !Ò#Ð_Ð_Ð_Õ_Ô_Ð_Ð_Ð_Ð_ˆ !Ð_Ñ_Ô_Ð_Õ_Ô_Ñ_Ô_Ð_Ð_Õ_Ô_ˆÑ_Ô_Ð_Õ_Ô_ˆÑ_Ô_Ð_Ð_Õ_Ô_ !Ñ_Ô_Ð_Ð_Ñ_Ð_Õ_Ô_Ð%_ÈoÐ%_Ð%_Ñ_Ô_Ð_Ñ_Ð_Ð_Ð_Ñ_Ð_Õ_Õ_Ô_Ð_Ñ_Ô_Ñ_Ô_Ð_Ð_Ð_Ð_Ð_à×ÒÐ?ÈÐÑNÔNÐNØŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŸ-š-Ð(gÑhÔhˆØ—=’=Ð!]Ñ^Ô^ˆØ"#Ðdˆ !Ò#ÐdÐdÐdÕdÔdÐdÐdÐdÐdˆ !ÐdÑdÔdÐdÕdÔdÑdÔdÐdÐdÕdÔdˆÑdÔdÐdÕdÔdˆÑdÔdÐdÐdÕdÔd !ÑdÔdÐdÐdÑdÐdÕdÔdÐ%dÐSbÐ%dÐ%dÑdÔdÐdÑdÐdÐdÐdÑdÐdÕdÕdÔdÐdÑdÔdÑdÔdÐdÐdÐdÐdÐdØÐSˆx˜4ÐÐSÐSÐSÕSÔSÐSÐSÐSÐSˆx˜4ÐSÑSÔSÐSÕSÔSÑSÔSÐSÐSÕSÔSˆxÑSÔSÐSÕSÔSˆxÑSÔSÐSÐSÕSÔS˜4ÑSÔSÐSÐSÑSÐSÕSÔSÐ!SÑSÔSÐSÑSÐSÐSÐSÑSÐSÕSÕSÔSÐSÑSÔSÑSÔSÐSÐSÐSÐSÐSàŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŸ=š=Ð)hÑiÔiÐØ#$ÐhÐ 1Ò$ÐhÐhÐhÕhÔhÐhÐhÐhÐhÐ 1ÐhÑhÔhÐhÕhÔhÑhÔhÐhÐhÕhÔhÐÑhÔhÐhÕhÔhÐÑhÔhÐhÐhÕhÔh 1ÑhÔhÐhÐhÑhÐhÕhÔhÐ&hÐVfÐ&hÐ&hÑhÔhÐhÑhÐhÐhÐhÑhÐhÕhÕhÔhÐhÑhÔhÑhÔhÐhÐhÐhÐhÐhÝ�6‰{Œ{Ð[˜aÐ[ˆ{˜aÒÐ[Ð[Ñ[Õ[Ô[Ð[Ð[Ð[Ð[ˆ{˜aÐ[Ñ[Ô[Ð[Õ[Ô[Ñ[Ô[Ð[Ð[Õ[Ô[�sÑ[Ô[Ð[Õ[Ô[�sÑ[Ô[Ð[Ð[Ð[Õ[Ô[Ñ[Ô[Ð[Ð[Õ[Ô[�6Ñ[Ô[Ð[Õ[Ô[�6Ñ[Ô[Ð[Ð[Õ[Ô[ˆ{Ñ[Ô[Õ[Ô[˜aÑ[Ô[Ð[Ð[Ñ[Ð[Õ[Ô[Ð![ÐSYÐ![Ð![Ñ[Ô[Ð[Ñ[Ð[Ð[Ð[Ñ[Ð[Õ[Õ[Ô[Ð[Ñ[Ô[Ñ[Ô[Ð[Ð[Ð[Ð[Ð[Ð[Ð[Ø�
Š
‰Œˆˆˆr   c                ó¶  — t          ||› d�¦  «        }|j                             dd¦  «         |j                             d¦  «         |j                             d¦  «         |                     d¦  «         |                     d¦  «        }d}||u}|s¬t          j        d	|fd
||f¦  «        dt          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }t          j        d¦  «        dz   d|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )zRTier 3: Interleaves movement kinematics with simultaneous flask and skill actions.rN   r  r  Ú1r¼   r•   r  Nr–   r˜   r
  r†   zEInterleaved movement and skill inputs must preserve destination staterˆ   r‰   )rJ   rš   r›   r¯   r°   rH   rh   ri   rj   rq   rr   rs   rk   rl   rm   rn   r5   )	r   r+   r9   rI   r
  ry   r|   r�   r�   s	            r   Ú2test_tier3_click_to_move_while_casting_or_drinkingzITestPcDesktopClientE2E.test_tier3_click_to_move_while_casting_or_drinking  sj  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ
×Ò˜˜sÑ#Ô#Ð#ØŒ×Ò˜CÑ Ô Ð ØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜cÑ"Ô"Ð"Ø�}Š}Ð?Ñ@Ô@ˆØÐhˆt˜4ÐÐhÐhÐhÕhÔhÐhÐhÐhÐhˆt˜4ÐhÑhÔhÐhÕhÔhÑhÔhÐhÐhÕhÔhˆtÑhÔhÐhÕhÔhˆtÑhÔhÐhÐhÕhÔh˜4ÑhÔhÐhÐhÑhÐhÕhÔhÐ!hÑhÔhÐhÑhÐhÐhÐhÑhÐhÕhÕhÔhÐhÑhÔhÑhÔhÐhÐhÐhÐhÐhØ�
Š
‰Œˆˆˆr   c                óì  — t          ||› d�¦  «        }|j                             d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |                     d¦  «                             ¦   «         dk    }|                     d¦  «                             ¦   «         dk    }g }|}|r|}|�s	dd	d
t          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        nd
iz  }|                     |¦  «         |rYdddt          j        ¦   «         v st          j	        |¦  «        rt          j
        |¦  «        ndiz  }	|                     |	¦  «         t          j        |d¦  «        i z  }
t          j        d¦  «        dz   d|
iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )z[Tier 3: Verifies Character ('C') and Inventory ('I') dock side-by-side without obstruction.rN   rÊ   rŸ   rË   z#modal-characterr   z
#modal-bagz%(py2)sra   Úchar_existsz%(py4)srV   Ú
bag_existsz;Both Character and Inventory modals must mount concurrentlyrï   r¨   N)rJ   r¯   r°   rH   ro   rp   rq   rr   ri   rs   rk   r±   r²   rl   rm   rn   r5   )r   r+   r9   rI   rE  rF  r|   ru   r  r  r�   rz   s               r   Ú4test_tier3_concurrent_dual_docking_character_and_bagzKTestPcDesktopClientE2E.test_tier3_concurrent_dual_docking_character_and_bag)  s  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!Ø—l’lÐ#5Ñ6Ô6×<Ò<Ñ>Ô>ÀÒBˆØ—\’\ ,Ñ/Ô/×5Ò5Ñ7Ô7¸!Ò;ˆ
ØhÐhˆ{Ðhˆ{Ðh˜zÐhÐhÑhÐhÐhÐhÕhÔhÑhÔhÐhÐhÕhÔhˆ{ÑhÔhÐhÕhÔhˆ{ÑhÔhÐhÐhÐhÑhÐhÐh×hÒhÐhÑhÔhÐhˆ{ÐhÐhÐhÐhÕhÔhÑhÔhÐhÐhÕhÔh˜zÑhÔhÐhÕhÔh˜zÑhÔhÐhÐhÐhÑhÐhÐh×hÒhÐhÑhÔhÐhÕhÔhÐhÐhÑhÔhÐhÑhÐhÕhÔhÐ+hÑhÔhÐhÑhÐhÐhÐhÑhÐhÕhÕhÔhÐhÑhÔhÑhÔhÐhÐhÐhÐhÐhØ�
Š
‰Œˆˆˆr   c                ó`  — t          ||› d�¦  «        }|j                             ddd¬¦  «         |j                             d¦  «         |                     d¦  «         |                     d¦  «        }g d	¢}||v }|s—t          j        d
|fd||f¦  «        dt          j
        ¦   «         v st          j        |¦  «        rt          j        |¦  «        ndt          j        |¦  «        dœz  }dd|iz  }t          t          j        |¦  «        ¦  «        ‚dx}}|                     ¦   «          dS )zNTier 3: Verifies Space dodge cancels active attack and restores evasion state.rN   iò  r”   Úright)Úbuttonrž   rŸ   r¡   )r¢   ÚidleÚrunÚattack_slashNr  )z%(py0)s in %(py3)sr©   r†   zassert %(py5)sr‰   N)rJ   rš   r›   r¯   r°   rH   rh   ri   rj   rq   rr   rs   rk   rm   rn   r5   )	r   r+   r9   rI   r©   ry   r|   r�   r�   s	            r   Ú-test_tier3_cross_feature_dodge_cancels_attackzDTestPcDesktopClientE2E.test_tier3_cross_feature_dodge_cancels_attack5  sP  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ
×Ò˜ 8°GÐÑ<Ô<Ð<ØŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!Ø—]’]Ð#CÑDÔDˆ
ØKÐKÐKÐKˆzÐKÐKÐKÐKÐKÕKÔKÐKÐKÐKÐKˆzÐKÐKÑKÔKÐKÕKÔKÑKÔKÐKÐKÕKÔKˆzÑKÔKÐKÕKÔKˆzÑKÔKÐKÐKÕKÔKÐKÑKÔKÐKÐKÑKÐKÐKÐKÐKÐKÑKÐKÕKÕKÔKÐKÑKÔKÑKÔKÐKÐKÐKÐKÐKØ�
Š
‰Œˆˆˆr   c                ó‚  — t          ||› d�¦  «        }|j                             dd¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |j                             d¦  «         |                     d¦  «         |                     dd	¦  «         |                     d¦  «         |j                             d
¦  «         |                     d¦  «         |                     ¦   «          dS )zPTier 4: End-to-end user loop (Move -> Flask -> Dodge -> Combo -> Lang -> Pause).rN   r  r  rŸ   rB  rž   r¼   rý   r  rÌ   N)rJ   rš   r›   rH   r¯   r°   r  r5   )r   r+   r9   rI   s       r   Ú!test_tier4_complete_gameplay_loopz8TestPcDesktopClientE2E.test_tier4_complete_gameplay_loop?  s*  € åÐ,°Ð.GÐ.GÐ.GÑHÔHˆØŒ
×Ò˜˜sÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜CÑ Ô Ð Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜GÑ$Ô$Ð$Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜FÑ#Ô#Ð#Ø×Ò˜bÑ!Ô!Ð!Ø×Ò˜>¨4Ñ0Ô0Ð0Ø×Ò˜bÑ!Ô!Ð!ØŒ×Ò˜HÑ%Ô%Ð%Ø×Ò˜bÑ!Ô!Ð!Ø�
Š
‰Œˆˆˆr   c                ó€  — |                      dddœ¬¦  «        }|                     d¦  «         |                     |› d�¦  «         |                     d¦  «         |                     d¦  «                             ¦   «         d	k    }|                     d
¦  «                             ¦   «         d	k    }|szt          j        d¦  «        dz   ddt          j	        ¦   «         v st          j
        |¦  «        rt          j        |¦  «        ndiz  }t          t          j        |¦  «        ¦  «        ‚|szt          j        d¦  «        dz   ddt          j	        ¦   «         v st          j
        |¦  «        rt          j        |¦  «        ndiz  }t          t          j        |¦  «        ¦  «        ‚|                     ¦   «          dS )zUTier 4: Verifies mobile client at webapp/index.html retains mobile chassis and works.r:   r;   rA   rB   zAtry { localStorage.setItem('fe_sim_mode', 'iphone'); } catch(e){}z/webapp/index.htmli,  r\   r   rg   z*Mobile simulator must retain .iphone-framer�   r`   Úhas_iphone_framez+Mobile simulator must retain #simulator-barÚhas_simulator_barN)rE   rF   rG   rH   ro   rp   ri   rl   rq   rr   rs   rk   rm   rn   r5   )r   r+   r9   rI   rR  rS  r‘   s          r   Ú(test_tier4_mobile_webapp_zero_regressionz?TestPcDesktopClientE2E.test_tier4_mobile_webapp_zero_regressionP  s¸  € à×(Ò(¸DÈDÐ2QÐ2QÐ(ÑRÔRˆØ×ÒÐ`ÑaÔaÐaØ�	Š	�YÐ2Ð2Ð2Ñ3Ô3Ð3Ø×Ò˜cÑ"Ô"Ð"ØŸ<š<¨Ñ8Ô8×>Ò>Ñ@Ô@À1ÒDÐØ ŸLšLÐ)9Ñ:Ô:×@Ò@ÑBÔBÀQÒFÐØÐMÕMÔMÐ!MÑMÔMÐMÑMÐMÐMÕMÔMÑMÔMÐMÐMÕMÔMÐÑMÔMÐMÕMÔMÐÑMÔMÐMÐMÐMÑMÐMÕMÕMÔMÐMÑMÔMÑMÔMÐMØ ÐOÕOÔOÐ"OÑOÔOÐOÑOÐOÐOÕOÔOÑOÔOÐOÐOÕOÔOÐ ÑOÔOÐOÕOÔOÐ ÑOÔOÐOÐOÐOÑOÐOÕOÕOÔOÐOÑOÔOÑOÔOÐOØ�
Š
‰Œˆˆˆr   N)r   r   )r   r   r   r   r‚   r’   rœ   r¸   rÂ   rÈ   rÍ   rì   rû   r  r  r  r&  r)  r/  r@  rC  rG  rN  rP  rT  r   r   r   rL   rL   D   sÃ  € € € € € ØOÐOðð ð ð ðð ð ð ðð ð ð ðð ð ð ð
ð 
ð 
ð 
ðð ð ð ð
ð 
ð 
ð 
ð
ð 
ð 
ð 
ðhð hð hð hð"ð ð ð ðð ð ð ðð ð ð ðð ð ð ðð ð ð ðð ð ð ð0ð 0ð 0ð 0ðd	ð 	ð 	ð 	ð
ð 
ð 
ð 
ðð ð ð ðð ð ð ð"
ð 
ð 
ð 
ð 
ð 
r   rL   )r:   r;   )r<   r   r=   r>   r?   r>   )$r   Ú
__future__r   Úbuiltinsrq   Ú_pytest.assertion.rewriteÚ	assertionÚrewriteri   r   Úsysr"   Úurllib.requestrð   Úurllib.errorÚpathlibr   Útypingr   r   ÚpytestÚ__file__ÚresolveÚparentÚPROJECT_ROOTrø   Úinsertr   Útools.serve_web_pcr   r	   Úfixturer+   r9   rJ   rL   r   r   r   ú<module>rg     sÔ  ððð ð #Ð "Ð "Ð "Ð "Ð "Ø  € € € € € € € € € € € € Ð Ð Ð Ð Ø 
€
€
€
Ø Ð Ð Ð Ø Ð Ð Ð Ø Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ð Ð Ø €€€àˆt�H‰~Œ~×%Ò%Ñ'Ô'Ô.Ô5Ô<€Ø „‡‚��3�3�|Ñ$Ô$Ñ %Ô %Ð %Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8ðð ð ð ð Ð6ñ ô ð ð €„�hÐÑÔðð ñ  Ôðð €„�hÐÑÔðð ñ  Ôððð ð ð ð ðVð Vð Vð Vð Vñ Vô Vð Vð Vð Vr   