
    i]                       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
mZ ddlmZmZmZ ddlZ	 ddlmZmZmZ 	 	 d	 	 	 	 	 ddZdddZ G d	 d
      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Zej@                  jB                   G d d             Z"y# e$ r	 dZdZdZY w xY w)u   
Lightpanda 크롤러 래퍼 테스트

단위 테스트: mock 사용 (네트워크 불필요)
통합 테스트: @pytest.mark.integration — 실제 lightpanda 서버(ws://127.0.0.1:9333) 필요
    )annotationsN)fields)	AsyncMock	MagicMockpatch)
CrawlErrorCrawlResultLightpandaCrawlerc                &   t               }t        |       |_        t        |      |_        t        t        d            |_        t               |_        d|_        t        d      |_        t        d      |_        t        g       |_	        |S )u$   playwright Page 모의 객체 생성return_value   )statushttps://example.com	Test PageN)
r   r   titlecontentgotocloseurlevaluatequery_selectorquery_selector_all)r   r   pages      2/home/jay/workspace/tools/tests/test_lightpanda.py_make_mock_pager      so    
 ;D.DJ'2DLy'<=DIDJ$DH;7DM#6D'R8DK    c                    | 
t               } t               }t        |       |_        t               |_        t        d      |_        |S )u'   playwright Browser 모의 객체 생성r   T)r   r   r   new_pager   is_connected)r   browsers     r   _make_mock_browserr"   /   s>    | kG d3GKGM$$7GNr   c                  ,    e Zd ZddZddZddZddZy)TestLightpandaCrawlerInitc                >   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}t               }|j                  }d	}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u;   CDP endpoint 기본값이 ws://127.0.0.1:9333 인지 확인Nis notz%(py0)s is not %(py3)sr
   py0py3u   LightpandaCrawler import 실패
>assert %(py5)spy5zws://127.0.0.1:9333==z4%(py2)s
{%(py2)s = %(py0)s.cdp_endpoint
} == %(py5)scrawlerr*   py2r-   assert %(py7)spy7)r
   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationcdp_endpoint	self@py_assert2@py_assert1@py_format4@py_format6r1   @py_assert4@py_assert3@py_format8s	            r   test_default_cdp_endpointz3TestLightpandaCrawlerInit.test_default_cdp_endpoint@   s    (,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#%##<'<<#'<<<<<#'<<<<<<<w<<<w<<<#<<<'<<<<<<<<r   c                   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d	      }|j                  }d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u$   사용자 지정 CDP endpoint 설정Nr&   r(   r
   r)   assert %(py5)sr-   zws://localhost:9999)r?   r.   r0   r1   r2   r4   r5   )
r
   r6   r7   r8   r9   r:   r;   r=   r>   r?   r@   s	            r   test_custom_cdp_endpointz2TestLightpandaCrawlerInit.test_custom_cdp_endpointF   s    (,, ,,,, ,,,,,, ,,, ,,,,,,,,,,#1FG##<'<<#'<<<<<#'<<<<<<<w<<<w<<<#<<<'<<<<<<<<r   c                   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               }|j                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   기본 타임아웃 30000msNr&   r(   r
   r)   rK   r-   i0u  r.   )z2%(py2)s
{%(py2)s = %(py0)s.timeout_ms
} == %(py5)sr1   r2   r4   r5   )
r
   r6   r7   r8   r9   r:   r;   r=   r>   
timeout_msr@   s	            r   test_default_timeoutz.TestLightpandaCrawlerInit.test_default_timeoutL   s    (,, ,,,, ,,,,,, ,,, ,,,,,,,,,,#%!!*U*!U****!U******w***w***!***U*******r   c                   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               }|j                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u)   Chrome fallback endpoint 기본값 확인Nr&   r(   r
   r)   rK   r-   zws://127.0.0.1:9222r.   )z7%(py2)s
{%(py2)s = %(py0)s.chrome_endpoint
} == %(py5)sr1   r2   r4   r5   )
r
   r6   r7   r8   r9   r:   r;   r=   r>   chrome_endpointr@   s	            r   test_chrome_fallback_endpointz7TestLightpandaCrawlerInit.test_chrome_fallback_endpointR   s    (,, ,,,, ,,,,,, ,,, ,,,,,,,,,,#%&&?*??&*?????&*???????w???w???&???*????????r   NreturnNone)__name__
__module____qualname__rI   rL   rO   rR    r   r   r$   r$   ?   s    ==+@r   r$   c                  $    e Zd ZddZddZddZy)TestCrawlResultDataclassc                    d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}t        t               D ch c]  }|j                   }}h d	}|j                  } ||      }|st        j                  d
||z
         dz   dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            dx}}yc c}w )u>   CrawlResult 에 필수 필드가 모두 존재하는지 확인Nr&   r(   r	   r)   u   CrawlResult import 실패r,   r-   >	   r   htmlmetatextlinksr   enginer   
elapsed_msu   누락 필드: zL
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.issubset
}(%(py3)s)
}requiredfield_namesr*   r3   r+   r-   )r	   r6   r7   r8   r9   r:   r;   r<   r=   r>   r   nameissubset)	rA   rB   rC   rD   rE   frd   rc   rF   s	            r   test_required_fields_existz3TestCrawlResultDataclass.test_required_fields_exist_   s!   "&C{$&CCC{$CCCCCC{CCC{CCC$CCC(CCCCCCC'-k':;!qvv;;f  Y -Y-YYKAW@X/YYYYYYYxYYYxYYY YYYYYYYYYYYY-YYYYYY <s   G;c                	   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        dd	d
ddgddiddd	      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }t        |t              }	|	sd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                  |      dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |	      dz  }
t        t        j                  |
            dx}}	|j                  }t        |t              }	|	sd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                  |      dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |	      dz  }
t        t        j                  |
            dx}}	y) u   CrawlResult 인스턴스 생성Nr&   r(   r	   r)   rK   r-   r   ExamplezHello worldz<html></html>zhttps://example.com/pagedescriptiontestr   g      Y@
lightpanda	r   r   r_   r]   r`   r^   r   rb   ra   r.   z+%(py2)s
{%(py2)s = %(py0)s.url
} == %(py5)sresultr2   r4   r5   )z.%(py2)s
{%(py2)s = %(py0)s.engine
} == %(py5)sPassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.links
}, %(py4)s)
}
isinstancelistr*   py1r+   py4py6zOassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.meta
}, %(py4)s)
}dict)r	   r6   r7   r8   r9   r:   r;   r=   r>   r   ra   r`   rs   rt   r^   ry   )rA   rB   rC   rD   rE   rq   rF   rG   rH   @py_assert5@py_format7s              r   test_instantiationz+TestCrawlResultDataclass.test_instantiationf   s   "&&{$&&&&{$&&&&&&{&&&{&&&$&&&&&&&% -.(

 zz222z22222z2222222v222v222z22222222222}},,},,,,},,,,,,v,,,v,,,},,,,,,,,,, ,,-z,--------z---z------&---&---,------------------- ++,z+t,,,,,,,,z,,,z,,,,,,&,,,&,,,+,,,,,,t,,,t,,,,,,,,,,r   c                   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}dD ]  }t        d	d
d
d
g i dd|	      }|j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j
                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            dx}} y)u8   engine 필드는 'lightpanda' 또는 'chrome' 중 하나Nr&   r(   r	   r)   rK   r-   rn   chromezhttps://x.com r   g        ro   r.   )z.%(py2)s
{%(py2)s = %(py0)s.engine
} == %(py4)srra   r*   r3   rw   zassert %(py6)srx   )
r	   r6   r7   r8   r9   r:   r;   r=   r>   ra   )
rA   rB   rC   rD   rE   ra   r   rG   @py_format5r{   s
             r   test_engine_field_valuesz1TestCrawlResultDataclass.test_engine_field_valuesy   s   "&&{$&&&&{$&&&&&&{&&&{&&&$&&&&&&&. 	&F#
A 88%8v%%%%8v%%%%%%1%%%1%%%8%%%%%%v%%%v%%%%%%%	&r   NrS   )rV   rW   rX   ri   r|   r   rY   r   r   r[   r[   ^   s    Z-&&r   r[   c                     e Zd Zej                  d        Zej                  j                  dd       Zej                  j                  dd       Z	ej                  j                  dd       Z
ej                  j                  dd       Zy)TestFetchUnitc              #  :  K   t        d      5 }t               }t        |      |j                  _        t        d      |j                  _        t               }t        |      }t        |      |j                  _        |||f ddd       y# 1 sw Y   yxY ww)z playwright connect_over_cdp mock)tools.lightpanda_crawler.async_playwrightr   FN	r   r   r   
__aenter__	__aexit__r   r"   chromiumconnect_over_cdprA   mock_pwmock_instancer   r!   s        r   mock_playwright_connectz%TestFetchUnit.mock_playwright_connect   s      >? 		)7%KM.7].SG  +-6E-JG  *"$D(.G6?W6UM""37D((		) 		) 		)   BA8B	BBBc                x  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  d       d{   }
ddd      d{    t        
t              }|sd	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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}y7 O7 97 ,# 1 d{  7  sw Y   =xY ww)u2   fetch() 가 CrawlResult 를 반환하는지 확인Nr&   r(   r
   r)   rK   r-   r   5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}rs   rq   r	   r*   rv   r3   rw   )r
   r6   r7   r8   r9   r:   r;   r=   r>   fetchrs   r	   )rA   r   rB   rC   rD   rE   _r!   r   r1   rq   rG   r   s                r   test_fetch_returns_crawl_resultz-TestFetchUnit.test_fetch_returns_crawl_result   sQ     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	@ 	@'"==)>??F	@ 	@ &+........z...z......&...&......+...+..........	@?	@ 	@ 	@ 	@s[   C
H:HH:H$%H&H$*H:5H!6D&H:H$!H:$H7*H-+H72H:c                	  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  d       d{   }
ddd      d{    d	}t        
|      }|sd
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        t        j                  |            dx}}d}t        |
|      }|sd
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        t        j                  |            dx}}d}t        |
|      }|sd
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        t        j                  |            dx}}d}t        |
|      }|sd
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        t        j                  |            dx}}y7 7 7 # 1 d{  7  sw Y   xY ww)uB   fetch() 결과에 title/text/html/links 필드가 있는지 확인Nr&   r(   r
   r)   rK   r-   r   r   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py1)s, %(py3)s)
}hasattrrq   )r*   rv   r+   r-   r_   r]   r`   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   )rA   r   rB   rC   rD   rE   r   r!   r   r1   rq   rF   s               r   %test_fetch_result_has_required_fieldsz3TestFetchUnit.test_fetch_result_has_required_fields   s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	@ 	@'"==)>??F	@ 	@  ''wvw''''''''w'''w''''''v'''v'''w''''''''''%&wvv&&&&&&&&w&&&w&&&&&&v&&&v&&&v&&&&&&&&&&%&wvv&&&&&&&&w&&&w&&&&&&v&&&v&&&v&&&&&&&&&&&'wvw''''''''w'''w''''''v'''v'''w''''''''''	@?	@ 	@ 	@ 	@s[   C
SR#SR,%R&&R,*S5R)6N.S&R,)S,R?2R53R?:Sc                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  d       d{   }
ddd      d{    
j                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j
                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 7 # 1 d{  7  sw Y   xY ww)u6   fetch() 결과에 요청 URL이 저장되는지 확인Nr&   r(   r
   r)   rK   r-   r   r.   rp   rq   r2   r4   r5   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   rA   r   rB   rC   rD   rE   r   r!   r   r1   rq   rF   rG   rH   s                 r   test_fetch_url_stored_correctlyz-TestFetchUnit.test_fetch_url_stored_correctly   s:     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	@ 	@'"==)>??F	@ 	@ zz222z22222z2222222v222v222z22222222222	@?	@ 	@ 	@ 	@[   C
GGGG	%G&G	*G5G6CGG	G	GGGGc                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  d       d{   }
ddd      d{    
j                  }d	}||k\  }|st        j                  d
|fd||f      dt        j                         v st        j
                  |
      rt        j                  |
      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 7 # 1 d{  7  sw Y   xY ww)u*   fetch() elapsed_ms 가 양수인지 확인Nr&   r(   r
   r)   rK   r-   r   r   )>=)z2%(py2)s
{%(py2)s = %(py0)s.elapsed_ms
} >= %(py5)srq   r2   r4   r5   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   rb   r   s                 r   test_fetch_elapsed_ms_positivez,TestFetchUnit.test_fetch_elapsed_ms_positive   s;     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	@ 	@'"==)>??F	@ 	@   %A% A%%%% A%%%%%%v%%%v%%% %%%A%%%%%%%	@?	@ 	@ 	@ 	@r   NrS   )rV   rW   rX   pytestfixturer   markasyncior   r   r   r   rY   r   r   r   r      s    ^^) ) [[/ / [[( ( [[3 3 [[& &r   r   c                  R   e Zd Zej                  d        Zej                  j                  dd       Zej                  j                  dd       Z	ej                  j                  dd       Z
ej                  j                  dd       Zej                  j                  dd       Zy)	TestFetchManyUnitc              #  :  K   t        d      5 }t               }t        |      |j                  _        t        d      |j                  _        t               }t        |      }t        |      |j                  _        |||f d d d        y # 1 sw Y   y xY ww)Nr   r   Fr   r   s        r   r   z)TestFetchManyUnit.mock_playwright_connect   s     >? 		)7%KM.7].SG  +-6E-JG  *"$D(.G6?W6UM""37D((		) 		) 		)r   c                t  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}g d}t               4 d{   }|j                  |       d{   }ddd      d{    t        t              }	|	sd	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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |	      dz  }
t        t        j                  |
            d}	y7 O7 97 ,# 1 d{  7  sw Y   =xY ww)u4   fetch_many() 가 리스트를 반환하는지 확인Nr&   r(   r
   r)   rK   r-   r   https://example.orgzhttps://example.netr   rs   resultsrt   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   
fetch_manyrs   rt   rA   r   rB   rC   rD   rE   urlsr1   r   rG   r   s              r   test_fetch_many_returns_listz.TestFetchManyUnit.test_fetch_many_returns_list   sB     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,T$& 	5 	5'#..t44G	5 	5 '4((((((((z(((z(((((('((('((((((4(((4((((((((((	54	5 	5 	5 	5s[   CH8
HH8H"#H$H"(H83H4D&H8H"H8"H5(H+)H50H8c                T  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}g d}t               4 d{   }|j                  |       d{   }ddd      d{    t              }d	}	||	k(  }
|
st        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  }dd|iz  }t        t        j                  |            dx}x}
}	y7 ?7 )7 # 1 d{  7  sw Y   -xY ww)uC   fetch_many() 결과 수가 입력 URL 수와 일치하는지 확인Nr&   r(   r
   r)   rK   r-   r      r.   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr   r*   rv   r+   rx   assert %(py8)spy8r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   rA   r   rB   rC   rD   rE   r   r1   r   rz   rF   r{   @py_format9s                r   #test_fetch_many_count_matches_inputz5TestFetchManyUnit.test_fetch_many_count_matches_input   sF     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,T$& 	5 	5'#..t44G	5 	5 7| q |q    |q      s   s      7   7   |   q       	54	5 	5 	5 	5s[   CH(
H	H(H#H$H(H(3H4DH(HH(H%HH% H(c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}g d}t               4 d{   }|j                  |       d{   }ddd      d{    d	 D        }t        |      }	|	sd
dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}}	y7 7 7 # 1 d{  7  sw Y   xY ww)uC   fetch_many() 결과가 모두 CrawlResult 인스턴스인지 확인Nr&   r(   r
   r)   rK   r-   r   c              3  <   K   | ]  }t        |t                y wNrs   r	   .0r   s     r   	<genexpr>zFTestFetchManyUnit.test_fetch_many_all_crawl_results.<locals>.<genexpr>       ?!:a-?   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allr   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   s              r   !test_fetch_many_all_crawl_resultsz3TestFetchManyUnit.test_fetch_many_all_crawl_results   s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,T$& 	5 	5'#..t44G	5 	5 @w??s?????????s???s??????????????	54	5 	5 	5 	5s[   CG
F(GF.#F*$F.(G3F,4B5G*F.,G.G 4F75G <Gc                p  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               4 d{   }|j                  g        d{   }ddd      d{    g }|k(  }|st        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}}y7 7 7 # 1 d{  7  sw Y   xY ww)u:   fetch_many() 빈 리스트 입력 시 빈 리스트 반환Nr&   r(   r
   r)   rK   r-   r.   z%(py0)s == %(py3)sr   )
r
   r6   r7   r8   r9   r:   r;   r=   r>   r   )rA   r   rB   rC   rD   rE   r1   r   s           r   test_fetch_many_empty_listz,TestFetchManyUnit.test_fetch_many_empty_list  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$& 	3 	3'#..r22G	3 	3 w"}w"ww"	32	3 	3 	3 	3s[   CF6FF6
F!F F!$F6/F0B,F6F!F6!F3'F*(F3/F6c                X  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}dd	g}t               4 d{   }|j                  |d
       d{   }ddd      d{    t              }d}	||	k(  }
|
st        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  }dd|iz  }t        t        j                  |            dx}x}
}	y7 A7 )7 # 1 d{  7  sw Y   -xY ww)u?   fetch_many() concurrency 파라미터가 수용되는지 확인Nr&   r(   r
   r)   rK   r-   r   r      concurrency   r.   r   r   r   r   r   r   r   r   s                r   !test_fetch_many_concurrency_paramz3TestFetchManyUnit.test_fetch_many_concurrency_param  sZ     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,%'<=$& 	D 	D'#..t.CCG	D 	D 7| q |q    |q      s   s      7   7   |   q       	DC	D 	D 	D 	Ds[   CH*
HH*H%H&H*H*5H6DH*HH*H'HH'"H*NrS   )rV   rW   rX   r   r   r   r   r   r   r   r   r   r   rY   r   r   r   r      s    ^^
) 
) [[) ) [[! ! [[@ @ [[  [[! !r   r   c                      e Zd Zej                  d        Zej                  j                  dd       Zej                  j                  dd       Z	y)TestEvaluateUnitc              #  \  K   t        d      5 }t               }t        |      |j                  _        t        d      |j                  _        t               }t        d      |_        t        |      }t        |      |j                  _	        |||f d d d        y # 1 sw Y   y xY ww)Nr   r   FExample Domain)
r   r   r   r   r   r   r   r"   r   r   r   s        r   r   z(TestEvaluateUnit.mock_playwright_connect  s     >? 
	)7%KM.7].SG  +-6E-JG  *"$D%3CDDM(.G6?W6UM""37D((
	) 
	) 
	)s   B,B	B 	B, B)%B,c                ~  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  dd	       d{   }
ddd      d{    d
}
|k(  }|st        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}}y7 7 7 # 1 d{  7  sw Y   xY ww)u9   evaluate() 가 JS 실행 결과를 반환하는지 확인Nr&   r(   r
   r)   rK   r-   r   document.titler   r.   r   rq   )
r
   r6   r7   r8   r9   r:   r;   r=   r>   r   )rA   r   rB   rC   rD   rE   r   r!   r   r1   rq   s              r   test_evaluate_returns_valuez,TestEvaluateUnit.test_evaluate_returns_value-  s*     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	U 	U'"++,ACSTTF	U 	U *)v)))))v)))))))v)))v)))))))))))	UT	U 	U 	U 	Us[   C
F=F"F=F(&F$'F(+F=6F&7B,F=$F(&F=(F:.F1/F:6F=c                f  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}t               4 d{   }	|	j                  dd	       d{    ddd      d{    |j                  j                          y7 I7 17 ## 1 d{  7  sw Y   3xY ww)
u7   evaluate() 가 page.evaluate 를 호출하는지 확인Nr&   r(   r
   r)   rK   r-   r   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   assert_called_once)
rA   r   rB   rC   rD   rE   r   r!   r   r1   s
             r   !test_evaluate_calls_page_evaluatez2TestEvaluateUnit.test_evaluate_calls_page_evaluate8  s      )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,27D$& 	L 	L'""#8:JKKK	L 	L 	((*	LK	L 	L 	L 	LsZ   C
D1DD1D&D'D+D16D7 D1DD1D."D%#D.*D1NrS   )
rV   rW   rX   r   r   r   r   r   r   r   rY   r   r   r   r     sT    ^^) ) [[* * [[+ +r   r   c                     e Zd Zej                  d        Zej                  j                  dd       Zej                  j                  dd       Z	ej                  j                  dd       Z
ej                  j                  dd       Zy)TestExtractStructuredUnitc              #    K   t        d      5 }t               }t        |      |j                  _        t        d      |j                  _        t               }t        d      |_        t        d      |_        t               }t        |      |_	        t        ||g      |_
        t        |      }t        |      |j                  _        ||||f d d d        y # 1 sw Y   y xY ww)Nr   r   FzHello World
attr_value)r   r   r   r   r   r   
inner_textget_attributer   r   r   r"   r   r   )rA   r   r   mock_elr   r!   s         r   r   z1TestExtractStructuredUnit.mock_playwright_connectJ  s     >? 	27%KM.7].SG  +-6E-JG  *kG!*!FG$-<$HG!"$D"+"AD&/gw=O&PD#(.G6?W6UM""37D'11	2 	2 	2s   C,C	C 	C, C)%C,c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}}	t               4 d{   }
|
j                  dd	d
i       d{   }ddd      d{    t        t              }|sd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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}y7 R7 97 ,# 1 d{  7  sw Y   =xY ww)u8   extract_structured() 가 dict 를 반환하는지 확인Nr&   r(   r
   r)   rK   r-   r   r   h1r   rs   rq   ry   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   extract_structuredrs   ry   )rA   r   rB   rC   rD   rE   r   r!   r   r   r1   rq   rG   r   s                 r   $test_extract_structured_returns_dictz>TestExtractStructuredUnit.test_extract_structured_returns_dict]  s\     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$;!7D'$& 	^ 	^'"556KgW[_]]F	^ 	^ &$''''''''z'''z''''''&'''&''''''$'''$''''''''''	^]	^ 	^ 	^ 	^s[   CH>HH>H()H"*H(.H>9H%:D&H>"H(%H>(H;.H1/H;6H>c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}}	t               4 d{   }
|
j                  dd	d
i       d{   }ddd      d{    d	}|v }|st        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        t        j                  |            dx}}y7 7 7 # 1 d{  7  sw Y   xY ww)u@   extract_structured() 결과에 요청한 키가 있는지 확인Nr&   r(   r
   r)   rK   r-   r   r   r   inz%(py1)s in %(py3)srq   rv   r+   
r
   r6   r7   r8   r9   r:   r;   r=   r>   r   rA   r   rB   rC   rD   rE   r   r!   r   r   r1   rq   @py_assert0s                r   #test_extract_structured_key_presentz=TestExtractStructuredUnit.test_extract_structured_key_presenth  s-     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$;!7D'$& 	^ 	^'"556KgW[_]]F	^ 	^  w&    w&   w      &   &       	^]	^ 	^ 	^ 	^[   CF?F$F?F*)F&*F*.F?9F(:B+F?&F*(F?*F<0F31F<8F?c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}}	t               4 d{   }
|
j                  dd	d
i       d{   }ddd      d{    d	}|v }|st        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        t        j                  |            dx}}y7 7 7 # 1 d{  7  sw Y   xY ww)u;   ::attr(name) 문법으로 속성 추출 가능한지 확인Nr&   r(   r
   r)   rK   r-   r   hrefza::attr(href)r   r   rq   r   r   r   s                r   #test_extract_structured_attr_syntaxz=TestExtractStructuredUnit.test_extract_structured_attr_syntaxs  s.     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$;!7D'$& 	h 	h'"556KfVeMfggF	h 	h vvv	hg	h 	h 	h 	hr   c           
     0  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|\  }}}}	t               4 d{   }
|
j                  dd	d
i       d{   }ddd      d{    j                  }d	} ||      }t        |t              }|sGd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                  |      t        j                  |      dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            dx}x}x}}y7 7 7 # 1 d{  7  sw Y   xY ww)u;   복수형 키(links)는 리스트를 반환하는지 확인Nr&   r(   r
   r)   rK   r-   r   r`   aznassert %(py10)s
{%(py10)s = %(py0)s(%(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.get
}(%(py5)s)
}, %(py8)s)
}rs   rq   rt   )r*   rv   r+   r-   r5   r   py10)r
   r6   r7   r8   r9   r:   r;   r=   r>   r   getrs   rt   )rA   r   rB   rC   rD   rE   r   r!   r   r   r1   rq   rF   @py_assert6@py_assert9@py_format11s                   r   /test_extract_structured_plural_key_returns_listzITestExtractStructuredUnit.test_extract_structured_plural_key_returns_list~  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$;!7D'$& 	] 	]'"556KgWZ^\\F	] 	] !**4W4*W-4z-t44444444z444z444444&444&444*444W444-444444t444t4444444444	]\	] 	] 	] 	]s[   CJI7JJ )I:*J .J9I=:E>J:J =J JJ	JJNrS   )rV   rW   rX   r   r   r   r   r   r   r   r   r   rY   r   r   r   r   I  s    ^^2 2$ [[( ( [[! ! [[    [[5 5r   r   c                      e Zd Zej                  j
                  dd       Zej                  j
                  dd       Zej                  j
                  dd       Zy)TestChromeFallbackc           	       K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      5 }t               }t        |	      |j                  _        t        d
	      |j                  _        t               }t        |      }t        t!        d      |g      |j"                  _        t               4 d{   }	|	j&                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j
                  |	      rt        j                  |	      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
ddd      d{    ddd       y7 7 # 1 d{  7  sw Y   xY w# 1 sw Y   yxY ww)uC   Lightpanda 연결 실패 시 Chrome으로 fallback 되는지 확인Nr&   r(   r
   r)   rK   r-   r   r   FzLightpanda connection refusedside_effectr   r.   z/%(py2)s
{%(py2)s = %(py0)s._engine
} == %(py5)sr1   r2   r4   r5   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r"   	Exceptionr   r   _engine)rA   rB   rC   rD   rE   r   r   r   chrome_browserr1   rF   rG   rH   s                r   *test_chrome_fallback_on_lightpanda_failurez=TestChromeFallback.test_chrome_fallback_on_lightpanda_failure  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,>? 	37%KM.7].SG  +-6E-JG  *"$D/5N 7@=>"7M""3 )* 3 3g2(2(2222(222222w222w222222(22222223 3!	3 	3 3 3 3 3 3!	3 	3sh   CIB
IH3IC	H7I%H5&I*	I3I5I7I		=I >I		IIIc           	       K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      5 }t               }t        |	      |j                  _        t        d
	      |j                  _        t               }t        |      }t        |	      |j                   _        t               4 d{   }	|	j$                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j
                  |	      rt        j                  |	      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
ddd      d{    ddd       y7 7 # 1 d{  7  sw Y   xY w# 1 sw Y   yxY ww)uB   Lightpanda 연결 성공 시 engine 이 'lightpanda' 인지 확인Nr&   r(   r
   r)   rK   r-   r   r   Frn   r.   r  r1   r2   r4   r5   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r"   r   r   r  )rA   rB   rC   rD   rE   r   r   r   
lp_browserr1   rF   rG   rH   s                r   $test_engine_is_lightpanda_on_successz7TestChromeFallback.test_engine_is_lightpanda_on_success  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,>? 
	77%KM.7].SG  +-6E-JG  *"$D+D1J6?Z6XM""3(* 7 7g6,6,6666,666666w666w666666,66666667 7
	7 
	77 7 7 7 7
	7 
	7sh   CIA?IH(IC	H,IH*I	I(I*I,H>	2H53H>	:II
Ic           	     n  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      5 }t               }t        |	      |j                  _        t        d
	      |j                  _        t               }t        |      }t        |	      |j                   _        t               4 d{   }	|	j%                  d       d{   }
|
j&                  }|	j(                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |
      rt        j                  |
      ndt        j                  |      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}x}}ddd      d{    ddd       y7 J7 47 # 1 d{  7  sw Y   #xY w# 1 sw Y   yxY ww)uE   CrawlResult.engine 이 실제 사용 엔진과 일치하는지 확인Nr&   r(   r
   r)   rK   r-   r   r   Fr   r.   )zK%(py2)s
{%(py2)s = %(py0)s.engine
} == %(py6)s
{%(py6)s = %(py4)s._engine
}rq   r1   )r*   r3   rw   rx   r   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r"   r   r   r   ra   r  )rA   rB   rC   rD   rE   r   r   r   r  r1   rq   rz   rG   r{   r   s                  r   (test_crawl_result_engine_matches_crawlerz;TestChromeFallback.test_crawl_result_engine_matches_crawler  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,>? 	87%KM.7].SG  +-6E-JG  *"$D+D1J6?Z6XM""3(* 8 8g&}}-BCC}}77}7777}777777v777v777}77777777777777777778 8	8 	88C8 8 8 8	8 	8sz   CJ5A?J)JJ)JJDJ3J)>J?J)	J5J)JJ)J&	JJ&	"J))J2.J5NrS   )	rV   rW   rX   r   r   r   r  r  r
  rY   r   r   r   r     sZ    [[3 3. [[7 7  [[8 8r   r   c                      e Zd ZddZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	y)TestErrorHandlingc                   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            dx}}t        t         t              }|sd	d
t        j                         v st        j
                  t              rt        j                  t              nd
dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}y)u5   CrawlError 커스텀 예외가 존재하는지 확인Nr&   r(   r   r)   u   CrawlError import 실패r,   r-   r   
issubclassr  r   )r   r6   r7   r8   r9   r:   r;   r<   r=   r>   r  r  )rA   rB   rC   rD   rE   rG   r   s          r   test_crawl_error_existsz)TestErrorHandling.test_crawl_error_exists  s    !%Az%AAAzAAAAAAzAAAzAAAAAA'AAAAAAA*i00000000z000z000000*000*000000i000i0000000000r   c           	       K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}d}t        |u}|st        j                  d|fdt        |f      dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d	      5 }t               }t        |
      |j                  _        t        d
      |j                  _        t        t        d            |j                   _        t%        j&                  t              5  t               4 d{   }	 ddd      d{    ddd       ddd       y7 &7 # 1 d{  7  sw Y   'xY w# 1 sw Y   +xY w# 1 sw Y   yxY ww)u7   Lightpanda + Chrome 모두 실패 시 CrawlError 발생Nr&   r(   r
   r)   rK   r-   r   r   r   FzConnection refusedr   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r  r   r   r   raises)rA   rB   rC   rD   rE   r   r   r1   s           r   +test_both_endpoints_fail_raises_crawl_errorz=TestErrorHandling.test_both_endpoints_fail_raises_crawl_error  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,!%%z%%%%z%%%%%%z%%%z%%%%%%%%%%>? 		7%KM.7].SG  +-6E-JG  *6?IVjLk6lM""3z* ,.  ' 		 		     		 		s   E6I8A>I6IH,
I	H0IH.II#	I,I.I0I6H97I>II	
IIIc           
       K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      5 }t               }t        |	      |j                  _        t        d
	      |j                  _        t               }t        |      }t        |	      |j                   _        t               4 d{   }	t%        j&                  t(              5 }
|	j+                  d       d{    ddd       g }d}
j,                  }t/        |      }||v }|}|sd}|
j,                  }t/        |      }||v }|}|s:t        j                  d|fd||f      t        j                  |      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  }dd|iz  }|j1                  |       |st        j                  dfdf      t        j                  |      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  }dd|iz  }|j1                  |       t        j2                  |d      i z  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}x}x}x}}ddd      d{    ddd       y7 7 # 1 sw Y   xY w7  # 1 d{  7  sw Y   0xY w# 1 sw Y   yxY ww)u2   screenshot() 호출 시 NotImplementedError 발생Nr&   r(   r
   r)   rK   r-   r   r   Fr   zPlaywright+Chromeu   스크린샷r   )zM%(py3)s in %(py10)s
{%(py10)s = %(py5)s(%(py8)s
{%(py8)s = %(py6)s.value
})
}strexc_info)r+   r-   rx   r   r   z%(py12)spy12)zR%(py15)s in %(py22)s
{%(py22)s = %(py17)s(%(py20)s
{%(py20)s = %(py18)s.value
})
})py15py17py18py20py22z%(py24)spy24   zassert %(py27)spy27)r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r"   r   r   r   r  NotImplementedError
screenshotvaluer  append_format_boolop)rA   rB   rC   rD   rE   r   r   r   r!   r1   r  @py_assert7r   rF   r   @py_assert14@py_assert19@py_assert21@py_assert16r   @py_format13@py_format23@py_format25@py_format26@py_format28s                            r   &test_screenshot_raises_not_implementedz8TestErrorHandling.test_screenshot_raises_not_implemented  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,>? 	k7%KM.7].SG  +-6E-JG  *"$D(.G6?W6UM""3(* k kg]]#67 D8!,,-BCCCDj*j(..jc..Aj*.AAj^j[c[i[ijWZ[iWjj^WjEjjjjj*.Ajjj*jjjjjjcjjjcjjjjjj(jjj(jjj.jjj.Ajjjjjjj^Wjjjj^jjjjjjWZjjjWZjjjjjj[cjjj[cjjj[ijjjWjjjjjjjjjjjjjjjjk k	k 	kkCD Dk k k k	k 	ks   CQ$A?QP.QQ P45P1
6P4:JQQ Q!Q%	Q$.Q1P44P>9QQQ		Q
Q	QQ!Q$c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      5 }t               }t        |	      |j                  _        t        d
	      |j                  _        t               }t        |      }t        |	      |j                   _        t               4 d{   }	t%        j&                  t(              5  |	j+                  d       d{    ddd       ddd      d{    ddd       y7 X7 '# 1 sw Y   &xY w7 # 1 d{  7  sw Y   -xY w# 1 sw Y   yxY ww)u+   pdf() 호출 시 NotImplementedError 발생Nr&   r(   r
   r)   rK   r-   r   r   Fr   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   r   r   r   r"   r   r   r   r  r  pdf)
rA   rB   rC   rD   rE   r   r   r   r!   r1   s
             r   test_pdf_raises_not_implementedz1TestErrorHandling.test_pdf_raises_not_implemented  sL     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,>? 	=7%KM.7].SG  +-6E-JG  *"$D(.G6?W6UM""3(* = =g]]#67 =!++&;<<<== =	= 	==<= == = = =	= 	=s   CGA?GFGF- F5F
6F:F-GF+G	GGFF($F-+G-F?	3F64F?	;GGGNrS   )
rV   rW   rX   r  r   r   r   r  r.  r1  rY   r   r   r  r    sc    1
 [[   [[k k$ [[= =r   r  c                      e Zd Zej                  j
                  dd       Zej                  j
                  dd       Zej                  j
                  dd       Zej                  j
                  dd       Z	y)TestIntegrationc                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               4 d{   }|j                  d       d{   }ddd      d{    t        t              }|sd	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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}|j                  }|syddt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }	t        t        j                  |	            d}|j                  }|syddt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }	t        t        j                  |	            d}|j                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
|j                  }t        |t               }|sd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                  |      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }t        t        j                  |            dx}}|j"                  }d}
||
kD  }|st        j                  d|fd||
f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
|j$                  }d}
||
v }|st        j                  d|fd||
f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
y7 7 7 # 1 d{  7  sw Y   xY ww)uK   실제 example.com 크롤링 — title/text/html/links 필드 존재 확인Nr&   r(   r
   r)   rK   r-   r   r   rs   rq   r	   r   z)assert %(py2)s
{%(py2)s = %(py0)s.title
})r*   r3   z(assert %(py2)s
{%(py2)s = %(py0)s.html
}r.   rp   r2   r4   r5   rr   rt   ru   r   >)z1%(py2)s
{%(py2)s = %(py0)s.elapsed_ms
} > %(py5)sr~   r   )z.%(py2)s
{%(py2)s = %(py0)s.engine
} in %(py5)s)r
   r6   r7   r8   r9   r:   r;   r=   r>   r   rs   r	   r   r]   r   r`   rt   rb   ra   )rA   rB   rC   rD   rE   r1   rq   rG   r   @py_format3rF   rH   rz   r{   s                 r   test_fetch_example_comz&TestIntegration.test_fetch_example_com  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$& 	@ 	@'"==)>??F	@ 	@ &+........z...z......&...&......+...+..........|||vv|{{{vv{zz222z22222z2222222v222v222z22222222222 ,,-z,--------z---z------&---&---,-------------------  $1$ 1$$$$ 1$$$$$$v$$$v$$$ $$$1$$$$$$$}}8 88} 88888} 8888888v888v888}888 88888888	@?	@ 	@ 	@ 	@s[   C[[ [
[	[ [	$[/[0W[[	[	[[[[c                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}g d}t               4 d{   }|j                  |d	
       d{   }ddd      d{    t              }d	}||k(  }	|	st        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  }
dd|
iz  }t        t        j                  |            dx}x}	}d |D        }t        |      }|sddt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            dx}}y7 7 7 # 1 d{  7  sw Y   xY ww)u/   3개 URL 병렬 크롤링 — 결과 수 확인Nr&   r(   r
   r)   rK   r-   r   r   r   r.   r   r   r   r   r   r   c              3  <   K   | ]  }t        |t                y wr   r   r   s     r   r   z=TestIntegration.test_fetch_many_three_urls.<locals>.<genexpr>1  r   r   r   r   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   r   r   )rA   rB   rC   rD   rE   r   r1   r   rz   rF   r{   r   rG   r   s                 r   test_fetch_many_three_urlsz*TestIntegration.test_fetch_many_three_urls$  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,

 %& 	D 	D'#..t.CCG	D 	D 7| q |q    |q      s   s      7   7   |   q       ?w??s?????????s???s??????????????		DC	D 	D 	D 	Ds[   CK
J:KK%J=&K*K5K 6GK=K KK	K
KKc                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               4 d{   }|j                  dd	       d{   }ddd      d{    t        t              }|sd
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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}t        |      }d}	||	kD  }
|
st        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  }dd|iz  }t        t        j                  |            dx}x}
}	y7 `7 I7 <# 1 d{  7  sw Y   MxY ww)u+   evaluate() 로 document.title 반환 확인Nr&   r(   r
   r)   rK   r-   r   r   r   rs   r   r  r   r   r5  )z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)sr   r   r   r   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   rs   r  r   )rA   rB   rC   rD   rE   r1   r   rG   r   rz   rF   r{   r   s                r   test_evaluate_document_titlez,TestIntegration.test_evaluate_document_title3  s     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$& 	T 	T'!**+@BRSSE	T 	T %%%%%%%%%z%%%z%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5zAzA~zAss55zA		TS	T 	T 	T 	Ts[   CML&M
L/ L)!L/%M0L,1H6M)L/,M/M5L86M=Mc                  K   d}t         |u}|st        j                  d|fdt         |f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t               4 d{   }|j                  dd	d
d       d{   }ddd      d{    t        t              }|sd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dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d}d}	|	|v }|st        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        t        j                  |            dx}	}d}	|	|v }|st        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        t        j                  |            dx}	}|d   }t        |t              }
|
sddt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |      dt        j                         v st        j
                  t              rt        j                  t              ndt        j                  |
      dz  }t        t        j                  |            dx}}
y7 7 |7 o# 1 d{  7  sw Y   xY ww)u+   CSS 셀렉터로 구조화 데이터 추출Nr&   r(   r
   r)   rK   r-   r   r   r   )headingr`   r   rs   rq   ry   r   r?  r   r   r   r`   z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}rt   re   )r
   r6   r7   r8   r9   r:   r;   r=   r>   r   rs   ry   rt   )rA   rB   rC   rD   rE   r1   rq   rG   r   r   rF   s              r   test_extract_structured_cssz+TestIntegration.test_extract_structured_css=  s{     )-, ,,,, ,,,,,, ,,, ,,,,,,,,,,$& 	 	'"55% 3/ F	 	 &$''''''''z'''z''''''&'''&''''''$'''$''''''''''"yF""""yF"""y""""""F"""F""""""" w&    w&   w      &   &        /0z/400000000z000z000/000000400040000000000		 	 	 	s[   CQ;QQ;
Q%#Q$Q%(Q;3Q"4M)Q;Q%"Q;%Q8+Q.,Q83Q;NrS   )
rV   rW   rX   r   r   r   r8  r;  r=  r@  rY   r   r   r3  r3    sz    [[9 9 [[@ @ [[  [[1 1r   r3  )r   zx<html><head><title>Test Page</title></head><body><h1>Hello</h1><a href='https://example.com/link'>link</a></body></html>)r   r  r   r  rT   r   r   )r   zMagicMock | NonerT   r   )#__doc__
__future__r   builtinsr8   _pytest.assertion.rewrite	assertionrewriter6   r   dataclassesr   unittest.mockr   r   r   r   tools.lightpanda_crawlerr   r	   r
   ImportErrorr   r"   r$   r[   r   r   r   r   r   r  r   integrationr3  rY   r   r   <module>rL     s    #     5 5 SS  N " @ @>*& *&d<& <&HB! B!T#+ #+V>5 >5L:8 :8D:= :=D 61 61 61C  KJs   
B> >CC