navigation-timing-requestStart-responseStart.https.html (5542B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="/common/dispatcher/dispatcher.js"></script> 5 <script src="/common/utils.js"></script> 6 <script src="../resources/utils.js"></script> 7 <script src="resources/utils.sub.js"></script> 8 <script src="/common/subset-tests-by-key.js"></script> 9 10 <meta name="variant" content="?include=noPrefetch"> 11 <meta name="variant" content="?include=afterResponse"> 12 <meta name="variant" content="?include=waitingForResponse"> 13 <meta name="variant" content="?include=waitingForRedirect"> 14 15 <script> 16 const setupProperties = {}; 17 if (shouldRunSubTest('waitingForResponse') || shouldRunSubTest('waitingForRedirect')) { 18 // These tests rely on the relationship between these timeouts, the delays 19 // on the server, and any vendor specific timeouts. Force a multiplier of 1, 20 // since using setTimeout directly incurs the wrath of `wpt lint`. 21 setupProperties.timeout_multiplier = 1; 22 } 23 setup(() => assertSpeculationRulesIsSupported(), setupProperties); 24 25 subsetTestByKey('noPrefetch', promise_test, async t => { 26 const agent = await spawnWindow(t); 27 const landingUrl = agent.getExecutorURL({page: 2}); 28 29 await agent.navigate(landingUrl); 30 assert_not_prefetched(await agent.getRequestHeaders(), `${landingUrl} should not be prefetched.`); 31 32 // It's generally expected that events occur in this order: 33 // ... -> connectEnd --> requestStart --> responseStart --> ... 34 const [entry] = await agent.execute_script( 35 () => performance.getEntriesByType('navigation')); 36 assert_less_than_equal(entry.connectEnd, entry.requestStart); 37 assert_less_than_equal(entry.requestStart, entry.responseStart); 38 }, "PerformanceNavigationTiming data should be in the correct order (no prefetch)"); 39 40 subsetTestByKey('afterResponse', promise_test, async t => { 41 const agent = await spawnWindow(t); 42 const landingUrl = agent.getExecutorURL({page: 2}); 43 await agent.forceSinglePrefetch(landingUrl); 44 45 await agent.navigate(landingUrl); 46 assert_prefetched(await agent.getRequestHeaders(), `${landingUrl} should have been prefetched.`); 47 48 // Since the response should have started before the navigation, these should 49 // all have the same value (i.e., the start of the fetch). 50 const [entry] = await agent.execute_script( 51 () => performance.getEntriesByType('navigation')); 52 assert_equals(entry.connectEnd, entry.requestStart); 53 assert_equals(entry.requestStart, entry.responseStart); 54 }, "PerformanceNavigationTiming data should show 'instantaneous' events completed beforehand"); 55 56 subsetTestByKey('waitingForResponse', promise_test, async t => { 57 const agent = await spawnWindow(t); 58 const landingUrl = agent.getExecutorURL({executor: 'slow-executor.py', delay: '3', page: 2}); 59 await agent.forceSinglePrefetch(landingUrl, {}, /*wait_for_completion=*/false); 60 61 // Chromium, at least, will give up the prefetch if the response head doesn't 62 // come back within 1 second of navigation. So since the server will take 63 // 3 seconds to respond, we wait 2.5 seconds before navigating, to ensure the 64 // response comes back within about 0.5 seconds. 65 await new Promise(resolve => t.step_timeout(resolve, 2_500)); 66 67 await agent.navigate(landingUrl); 68 assert_prefetched(await agent.getRequestHeaders(), `${landingUrl} should have been prefetched.`); 69 70 // Unlike the `afterResponse` test, we expect delays between `requestStart` 71 // and `responseStart` here. If our timing was perfect and server round-trips 72 // were instantaneous, that delay would be 0.5 seconds. To give ourselves a 73 // bit of wiggle room, instead we assert that it's at least 0.1 seconds. 74 const [entry] = await agent.execute_script( 75 () => performance.getEntriesByType('navigation')); 76 assert_less_than_equal(entry.connectEnd, entry.requestStart, "connectEnd must be before requestStart"); 77 assert_greater_than(entry.responseStart, entry.requestStart + 100, "responseStart must be > 100 ms after requestStart"); 78 }, "PerformanceNavigationTiming data should show noticeable TTFB if the response is slow"); 79 80 subsetTestByKey('waitingForRedirect', promise_test, async t => { 81 const agent = await spawnWindow(t); 82 const landingUrl = agent.getExecutorURL({page: 2}); 83 const slowRedirectUrl = new URL(`/common/slow-redirect.py?delay=3&location=${encodeURIComponent(landingUrl)}`, document.baseURI); 84 await agent.forceSinglePrefetch(slowRedirectUrl, {}, /*wait_for_completion=*/false); 85 86 // Considerations here are the same as for `waitingForResponse`. 87 await new Promise(resolve => t.step_timeout(resolve, 2_500)); 88 89 await agent.navigate(slowRedirectUrl, {expectedDestinationUrl: landingUrl}); 90 assert_prefetched(await agent.getRequestHeaders(), `${landingUrl} should have been prefetched.`); 91 92 // As in `waitingForResponse`, we expect at least 0.1 seconds TTFB. Unlike in 93 // that test, the delta isn't captured by `requestStart` vs. `responseStart`, 94 // because these stats only measure the final request/response pair, which is 95 // not delayed. 96 const [entry] = await agent.execute_script( 97 () => performance.getEntriesByType('navigation')); 98 assert_less_than_equal(entry.connectEnd, entry.requestStart, "connectEnd must be before requestStart"); 99 assert_less_than_equal(entry.requestStart, entry.responseStart, "requestStart must be before responseStart"); 100 assert_greater_than(entry.connectEnd, 100, "connectEnd must be > 100 ms"); 101 }, "PerformanceNavigationTiming data should show noticeable TTFB if the response is slow"); 102 </script>