| <!DOCTYPE html> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/test-helpers.sub.js"></script> |
| |
| <script> |
| const timingEventOrder = [ |
| 'startTime', |
| 'workerStart', |
| 'fetchStart', |
| 'requestStart', |
| 'responseStart', |
| 'responseEnd', |
| ]; |
| |
| function verify(timing) { |
| for (let i = 0; i < timingEventOrder.length - 1; i++) { |
| assert_true(timing[timingEventOrder[i]] <= timing[timingEventOrder[i + 1]], |
| `Expected ${timingEventOrder[i]} <= ${timingEventOrder[i + 1]}`); |
| } |
| } |
| |
| function navigate_in_frame(frame, url) { |
| frame.contentWindow.location = url; |
| return new Promise((resolve) => { |
| frame.addEventListener('load', () => { |
| const timing = frame.contentWindow.performance.getEntriesByType('navigation')[0]; |
| resolve(timing); |
| }); |
| }); |
| } |
| |
| const worker_url = 'resources/navigation-timing-worker.js'; |
| |
| promise_test(async (t) => { |
| const scope = 'resources/empty.html'; |
| const registration = await service_worker_unregister_and_register(t, worker_url, scope); |
| t.add_cleanup(() => registration.unregister()); |
| await wait_for_state(t, registration.installing, 'activated'); |
| const frame = await with_iframe(scope); |
| t.add_cleanup(() => frame.remove()); |
| |
| const timing = await navigate_in_frame(frame, scope); |
| assert_greater_than(timing.workerStart, 0); |
| verify(timing); |
| }, 'Service worker controlled navigation timing'); |
| |
| promise_test(async (t) => { |
| const scope = 'resources/empty.html?network-fallback'; |
| const registration = await service_worker_unregister_and_register(t, worker_url, scope); |
| t.add_cleanup(() => registration.unregister()); |
| await wait_for_state(t, registration.installing, 'activated'); |
| const frame = await with_iframe(scope); |
| t.add_cleanup(() => frame.remove()); |
| |
| const timing = await navigate_in_frame(frame, scope); |
| verify(timing); |
| }, 'Service worker controlled navigation timing network fallback'); |
| |
| promise_test(async (t) => { |
| const scope = 'resources/redirect.py?Redirect=empty.html'; |
| const registration = await service_worker_unregister_and_register(t, worker_url, scope); |
| t.add_cleanup(() => registration.unregister()); |
| await wait_for_state(t, registration.installing, 'activated'); |
| const frame = await with_iframe(scope); |
| t.add_cleanup(() => frame.remove()); |
| |
| const timing = await navigate_in_frame(frame, scope); |
| verify(timing); |
| // Additional checks for redirected navigation. |
| assert_true(timing.redirectStart <= timing.redirectEnd, |
| 'Expected redirectStart <= redirectEnd'); |
| assert_true(timing.redirectEnd <= timing.fetchStart, |
| 'Expected redirectEnd <= fetchStart'); |
| }, 'Service worker controlled navigation timing redirect'); |
| </script> |