assistant/tests/test_reply_click_d42.py

84 lines
3.8 KiB
Python

"""Only click a freshly checked, fully painted expand control."""
import json
import subprocess
from pathlib import Path
from types import SimpleNamespace
import pytest
from backend.browser import tools
FIXTURE = Path(__file__).with_name('reply_dom_fixture_d41.cjs')
def tree(*, clipped=False, viewport_edge=False):
control = {'attrs': {'id':'expand','class':'show-more'}, 'text':'展开1条回复'}
if viewport_edge:
control['rect'] = {'left':0,'right':100,'top':585,'bottom':620,'width':100,'height':35}
area = {'attrs': {'id':'reply-area','class':'reply-container'}, 'children':[control]}
if clipped:
area['style'] = {'overflowY':'auto'}
area['rect'] = {'left':0,'right':300,'top':0,'bottom':40,'width':300,'height':40}
root = {'attrs': {'id':'root-comment','class':'comment-item'}, 'children':[
{'attrs': {'id':'root-content','class':'content'},'text':'根评论'}]}
return {'attrs': {'id':'noteContainer'}, 'children':[
{'attrs': {'id':'detail-desc'},'text':'正文'},
{'attrs': {'id':'thread','class':'parent-comment'},'children':[root,area]}]}
def observe(code, arg, value):
result = subprocess.run(['node',str(FIXTURE)], input=json.dumps({'code':code,'arg':arg,'tree':value}),
capture_output=True,text=True,check=True,timeout=5)
return json.loads(result.stdout)
@pytest.mark.parametrize('options', [{'clipped':True},{'viewport_edge':True}])
def test_partial_control_can_use_an_actually_painted_point_without_implicit_scroll(options):
value = tree(**options)
inspected = observe(tools._INSPECT_SOURCE_CANDIDATES, {'max_comments':5}, value)
assert inspected['reply_controls'][0]['in_view'] is True
checked = observe(tools._OBSERVE_REPLY_CONTROL, {'selector':'#expand'}, value)
assert checked['click_point']['y'] < (600 if options.get('viewport_edge') else 40)
def test_full_control_has_a_program_observed_native_point():
result = observe(tools._OBSERVE_REPLY_CONTROL, {'selector':'#expand'}, tree())
assert result['click_point'] == {'x':150,'y':27,'viewport_width':400,'viewport_height':600}
def test_real_occlusion_is_rejected_by_paint_hit_testing():
value=tree();value['occluded']=True
result=observe(tools._OBSERVE_REPLY_CONTROL,{'selector':'#expand'},value)
assert result['error']=='reply_control_occluded'
async def test_changed_control_is_not_clicked_after_reading_candidates(tmp_path,monkeypatch):
tid = 'current-visible-point-d42'
tools.clear_task_context(tid)
tools.set_prospecting_context(tid)
monkeypatch.setattr(tools,'task_doc_dir',lambda _:tmp_path)
class Page:
observed = 0
clicks = 0
async def get_url(self):return 'https://www.xiaohongshu.com/explore/'+'a'*24
async def evaluate(self,code,arg=None):
if code==tools._OBSERVE_REPLY_CONTROL:
self.observed+=1
return {'url':await self.get_url(),'fingerprint':str(self.observed),'owner_identity':'stable-root',
'owner_selector':'#thread','reply_count':0,'visible_reply_selectors':[],
'reply_snapshot_complete':True,'click_point':{'x':150,'y':27,'viewport_width':400,'viewport_height':600}}
assert code==tools._INSPECT_SOURCE_CANDIDATES
return {'url':await self.get_url(),'candidates':[]}
async def get_elements_by_css_selector(self,_selector):return [SimpleNamespace()]
@property
async def mouse(self):
async def click(**_point):self.clicks+=1
return SimpleNamespace(click=click)
page=Page()
async def current():return page
with pytest.raises(ValueError,match='点击前回复入口或讨论已变化'):
await tools._expand_replies(tid,SimpleNamespace(get_current_page=current),'#expand')
assert page.clicks==0
tools.clear_task_context(tid)