|
| 1 | +"""Pure-logic tests for the page-bundle helpers (no browser, no I/O). |
| 2 | +
|
| 3 | +These functions transform the resource tree and rewrite asset URLs for the |
| 4 | +offline ``save_bundle`` zip. The end-to-end behaviour is covered by the |
| 5 | +real-Chrome suite; here we pin the branchy edge cases of the pure helpers: |
| 6 | +which resources are skipped, how filenames are derived, and how data-URI / |
| 7 | +unknown URLs are left untouched while known ones are rewritten or inlined. |
| 8 | +""" |
| 9 | + |
| 10 | +from __future__ import annotations |
| 11 | + |
| 12 | +from pydoll.protocol.network.types import ResourceType |
| 13 | +from pydoll.utils.bundle import ( |
| 14 | + build_asset_filename, |
| 15 | + collect_frame_resources, |
| 16 | + filter_fetchable_resources, |
| 17 | + inline_css_urls, |
| 18 | + rewrite_css_urls, |
| 19 | +) |
| 20 | + |
| 21 | + |
| 22 | +def _res(url, rtype=ResourceType.STYLESHEET, mime='text/css', **extra): |
| 23 | + return {'url': url, 'type': rtype, 'mimeType': mime, **extra} |
| 24 | + |
| 25 | + |
| 26 | +def test_filter_skips_failed_canceled_data_uri_page_and_nonbundleable(): |
| 27 | + page_url = 'http://x/' |
| 28 | + resources = [ |
| 29 | + ('f', _res('http://x/a.css')), |
| 30 | + ('f', _res('http://x/b.css', failed=True)), |
| 31 | + ('f', _res('http://x/c.css', canceled=True)), |
| 32 | + ('f', _res('data:image/png;base64,AA', ResourceType.IMAGE, 'image/png')), |
| 33 | + ('f', _res(page_url, ResourceType.DOCUMENT, 'text/html')), |
| 34 | + ('f', _res('http://x/data.json', ResourceType.XHR, 'application/json')), |
| 35 | + ] |
| 36 | + kept = [res['url'] for _fid, res in filter_fetchable_resources(resources, page_url)] |
| 37 | + assert kept == ['http://x/a.css'] |
| 38 | + |
| 39 | + |
| 40 | +def test_collect_frame_resources_recurses_into_child_frames(): |
| 41 | + tree = { |
| 42 | + 'frame': {'id': 'root'}, |
| 43 | + 'resources': [_res('http://x/a.css')], |
| 44 | + 'childFrames': [ |
| 45 | + { |
| 46 | + 'frame': {'id': 'child'}, |
| 47 | + 'resources': [_res('http://x/b.js', ResourceType.SCRIPT, 'text/javascript')], |
| 48 | + } |
| 49 | + ], |
| 50 | + } |
| 51 | + assert sorted(fid for fid, _res_ in collect_frame_resources(tree)) == ['child', 'root'] |
| 52 | + |
| 53 | + |
| 54 | +def test_build_asset_filename_derives_basename_and_extension(): |
| 55 | + assert build_asset_filename('http://x', 'text/css', 0).endswith('resource.css') |
| 56 | + assert build_asset_filename('http://x/style', 'text/css', 1).endswith('style.css') |
| 57 | + assert build_asset_filename('http://x/a.png', 'image/png', 2).endswith('a.png') |
| 58 | + |
| 59 | + |
| 60 | +def test_rewrite_css_urls_skips_data_uri_and_unknown_rewrites_known(): |
| 61 | + css = ( |
| 62 | + 'a{background:url("data:image/png;base64,AA")}' |
| 63 | + 'b{background:url("http://x/unknown.png")}' |
| 64 | + 'c{background:url("http://x/known.png")}' |
| 65 | + ) |
| 66 | + asset_map = {'http://x/known.png': ('0000_known.png', b'', 'image/png', ResourceType.IMAGE)} |
| 67 | + result = rewrite_css_urls(css, 'http://x/style.css', asset_map) |
| 68 | + assert 'data:image/png;base64,AA' in result |
| 69 | + assert 'http://x/unknown.png' in result |
| 70 | + assert 'url("0000_known.png")' in result |
| 71 | + |
| 72 | + |
| 73 | +def test_inline_css_urls_skips_data_uri_and_unknown_inlines_known(): |
| 74 | + css = ( |
| 75 | + 'a{background:url("data:image/png;base64,AA")}' |
| 76 | + 'b{background:url("http://x/unknown.png")}' |
| 77 | + 'c{background:url("http://x/known.png")}' |
| 78 | + ) |
| 79 | + asset_map = {'http://x/known.png': ('f', b'\x89PNG', 'image/png', ResourceType.IMAGE)} |
| 80 | + result = inline_css_urls(css, 'http://x/style.css', asset_map) |
| 81 | + assert 'data:image/png;base64,AA' in result |
| 82 | + assert 'http://x/unknown.png' in result |
| 83 | + assert 'url("data:image/png;base64,' in result |
0 commit comments