prefetch-helper.js (2688B)
1 setup(_ => { 2 assert_implements_optional( 3 document.createElement('link').relList.supports('prefetch'), 4 "Browser supports prefetch."); 5 assert_implements_optional( 6 "PerformanceResourceTiming" in window, 7 "Browser supports performance APIs."); 8 }); 9 10 function assert_resource_not_downloaded(test, url) { 11 // CSP failures generate resource timing entries, so let's make sure that 12 // download sizes are 0. 13 const entries = performance.getEntriesByName(url, 'resource'); 14 for (const entry of entries) { 15 assert_equals(entry.transferSize, 0, 'transferSize'); 16 assert_equals(entry.encodedBodySize, 0, 'encodedBodySize'); 17 assert_equals(entry.decodedBodySize, 0, 'decodedBodySize'); 18 } 19 } 20 21 function assert_link_prefetches(test, link) { 22 assert_no_csp_event_for_url(test, link.href); 23 24 link.onerror = test.unreached_func('onerror should not fire.'); 25 26 // Test is finished when either the `load` event fires, or we get a performance 27 // entry showing that the resource loaded successfully. 28 link.onload = test.step_func(test.step_func_done()); 29 waitUntilResourceDownloaded(link.href).then(test.step_func_done()); 30 31 document.head.appendChild(link); 32 } 33 34 function assert_link_does_not_prefetch(test, link) { 35 let cspEvent = false; 36 let errorEvent = false; 37 38 waitUntilCSPEventForURL(test, link.href) 39 .then(test.step_func(e => { 40 cspEvent = true; 41 assert_equals(e.violatedDirective, "prefetch-src"); 42 assert_equals(e.effectiveDirective, "prefetch-src"); 43 44 if (errorEvent) 45 test.done(); 46 })); 47 48 link.onerror = test.step_func(e => { 49 errorEvent = true; 50 if (cspEvent) 51 test.done(); 52 }); 53 link.onload = test.unreached_func('onload should not fire.'); 54 55 document.head.appendChild(link); 56 } 57 58 async function try_to_prefetch(href, test) { 59 const url = new URL(href, location.href); 60 url.searchParams.set( 61 'pipe', 62 '|header(Cache-Control, max-age=604800)' + 63 '|header(Access-Control-Allow-Origin, *)' + 64 '|header(Timing-Allow-Origin, *)'); 65 url.searchParams.set('uuid', token()); 66 67 const link = document.createElement('link'); 68 link.rel = 'prefetch'; 69 link.href = url.toString(); 70 link.crossOrigin = 'anonymous'; 71 test.add_cleanup(() => link.remove()); 72 73 const didPrefetch = new Promise(resolve => { 74 const observer = new PerformanceObserver(list => { 75 const entries = list.getEntriesByName(link.href); 76 if (entries.length) { 77 resolve(entries[0]); 78 } 79 }); 80 observer.observe({entryTypes: ['resource']}) 81 }); 82 document.head.appendChild(link); 83 const entry = await didPrefetch; 84 return entry.requestStart > 0 && entry.decodedBodySize > 0; 85 }