Commit 2f0dd05a authored by Makoto Shimazu's avatar Makoto Shimazu Committed by Commit Bot

Modernize WPT: resource-timing and navigation-timing.https.html

As a part of the effort to understand the current behavior of the
resource timing, I changed the tests to use async/await for readability
with adding a few comments.

Bug: 1128786
Change-Id: I45daee67e52a13c98ad3f2010131d858a58781d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2413927
Commit-Queue: Makoto Shimazu <shimazu@chromium.org>
Auto-Submit: Makoto Shimazu <shimazu@chromium.org>
Reviewed-by: default avatarKenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807845}
parent 14ac32ed
...@@ -32,81 +32,45 @@ function navigate_in_frame(frame, url) { ...@@ -32,81 +32,45 @@ function navigate_in_frame(frame, url) {
const worker_url = 'resources/navigation-timing-worker.js'; const worker_url = 'resources/navigation-timing-worker.js';
promise_test(t => { promise_test(async (t) => {
const scope = 'resources/empty.html'; const scope = 'resources/empty.html';
let frame; 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());
return service_worker_unregister_and_register(t, worker_url, scope) const timing = await navigate_in_frame(frame, scope);
.then(r => { assert_greater_than(timing.workerStart, 0);
return wait_for_state(t, r.installing, 'activated'); verify(timing);
})
.then(() => with_iframe(scope))
.then(f => {
frame = f;
return navigate_in_frame(frame, 'resources/empty.html');
})
.then(timing => {
assert_greater_than(timing.workerStart, 0);
verify(timing);
})
.catch(unreached_rejection(t))
.then(() => {
if (frame)
frame.remove();
return service_worker_unregister(t, scope);
});
}, 'Service worker controlled navigation timing'); }, 'Service worker controlled navigation timing');
promise_test(t => { promise_test(async (t) => {
const scope = 'resources/empty.html?network-fallback'; const scope = 'resources/empty.html?network-fallback';
let frame; 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());
return service_worker_unregister_and_register(t, worker_url, scope) const timing = await navigate_in_frame(frame, scope);
.then(r => { verify(timing);
return wait_for_state(t, r.installing, 'activated');
})
.then(() => with_iframe(scope))
.then(f => {
frame = f;
return navigate_in_frame(frame, 'resources/empty.html?network-fallback');
})
.then(timing => {
verify(timing);
})
.catch(unreached_rejection(t))
.then(() => {
if (frame)
frame.remove();
return service_worker_unregister(t, scope);
});
}, 'Service worker controlled navigation timing network fallback'); }, 'Service worker controlled navigation timing network fallback');
promise_test(t => { promise_test(async (t) => {
const scope = 'resources/redirect.py?Redirect=empty.html'; const scope = 'resources/redirect.py?Redirect=empty.html';
let frame; 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());
return service_worker_unregister_and_register(t, worker_url, scope) const timing = await navigate_in_frame(frame, scope);
.then(r => { verify(timing);
return wait_for_state(t, r.installing, 'activated'); // Additional checks for redirected navigation.
}) assert_true(timing.redirectStart <= timing.redirectEnd,
.then(() => with_iframe(scope)) 'Expected redirectStart <= redirectEnd');
.then(f => { assert_true(timing.redirectEnd <= timing.fetchStart,
frame = f; 'Expected redirectEnd <= fetchStart');
return navigate_in_frame(frame, 'resources/redirect.py?Redirect=empty.html');
})
.then(timing => {
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');
})
.catch(unreached_rejection(t))
.then(() => {
if (frame)
frame.remove();
return service_worker_unregister(t, scope);
});
}, 'Service worker controlled navigation timing redirect'); }, 'Service worker controlled navigation timing redirect');
</script> </script>
...@@ -4,138 +4,147 @@ ...@@ -4,138 +4,147 @@
<script src="resources/test-helpers.sub.js"></script> <script src="resources/test-helpers.sub.js"></script>
<script> <script>
function resourceUrl(path) { function resourceUrl(path) {
return "https://{{host}}:{{ports[https][0]}}" + base_path() + path; return "https://{{host}}:{{ports[https][0]}}" + base_path() + path;
} }
function crossOriginUrl(path) { function crossOriginUrl(path) {
return "https://{{hosts[alt][]}}:{{ports[https][0]}}" + base_path() + path; return "https://{{hosts[alt][]}}:{{ports[https][0]}}" + base_path() + path;
} }
// Verify existance of a PerformanceEntry and the order between the timings.
//
// |options| has these properties:
// performance: Performance interface to verify existance of the entry.
// resource: the path to the resource.
// mode: 'cross-origin' to load the resource from third-party origin.
// description: the description passed to each assertion.
// should_no_performance_entry: no entry is expected to be recorded when it's
// true.
function verify(options) { function verify(options) {
const url = options.mode === 'cross-origin' ? crossOriginUrl(options.resource) const url = options.mode === 'cross-origin' ? crossOriginUrl(options.resource)
: resourceUrl(options.resource); : resourceUrl(options.resource);
const entryList = options.performance.getEntriesByName(url, 'resource'); const entryList = options.performance.getEntriesByName(url, 'resource');
if (options.should_no_performance_entry) { if (options.should_no_performance_entry) {
// The performance timeline may not have an entry for a resource // The performance timeline may not have an entry for a resource
// which failed to load. // which failed to load.
assert_equals(entryList.length, 0, options.description); assert_equals(entryList.length, 0, options.description);
return; return;
} }
assert_equals(entryList.length, 1, options.description);
const entry = entryList[0]; assert_equals(entryList.length, 1, options.description);
assert_equals(entry.entryType, 'resource', options.description); const entry = entryList[0];
assert_greater_than(entry.workerStart, 0, options.description); assert_equals(entry.entryType, 'resource', options.description);
assert_greater_than_equal(entry.workerStart, entry.startTime, options.description);
assert_less_than_equal(entry.workerStart, entry.fetchStart, options.description); // workerStart is recorded between startTime and fetchStart.
if (options.mode === 'cross-origin') { assert_greater_than(entry.workerStart, 0, options.description);
assert_equals(entry.responseStart, 0, options.description); assert_greater_than_equal(entry.workerStart, entry.startTime, options.description);
assert_greater_than_equal(entry.responseEnd, entry.fetchStart, options.description); assert_less_than_equal(entry.workerStart, entry.fetchStart, options.description);
} else {
assert_greater_than_equal(entry.responseStart, entry.fetchStart, options.description); if (options.mode === 'cross-origin') {
assert_greater_than_equal(entry.responseEnd, entry.responseStart, options.description); assert_equals(entry.responseStart, 0, options.description);
} assert_greater_than_equal(entry.responseEnd, entry.fetchStart, options.description);
assert_greater_than(entry.responseEnd, entry.fetchStart, options.description); } else {
assert_greater_than(entry.duration, 0, options.description); assert_greater_than_equal(entry.responseStart, entry.fetchStart, options.description);
if (options.resource.indexOf('redirect.py') != -1) { assert_greater_than_equal(entry.responseEnd, entry.responseStart, options.description);
assert_less_than_equal(entry.workerStart, entry.redirectStart, }
options.description);
} else { // responseEnd follows fetchStart.
assert_equals(entry.redirectStart, 0, options.description); assert_greater_than(entry.responseEnd, entry.fetchStart, options.description);
} // duration always has some value.
assert_greater_than(entry.duration, 0, options.description);
if (options.resource.indexOf('redirect.py') != -1) {
assert_less_than_equal(entry.workerStart, entry.redirectStart,
options.description);
} else {
assert_equals(entry.redirectStart, 0, options.description);
}
} }
promise_test(function(t) { promise_test(async (t) => {
const worker_url = 'resources/resource-timing-worker.js'; const worker_url = 'resources/resource-timing-worker.js';
const scope = 'resources/resource-timing-iframe.sub.html'; const scope = 'resources/resource-timing-iframe.sub.html';
let registration;
return service_worker_unregister_and_register(t, worker_url, scope) const registration = await service_worker_unregister_and_register(t, worker_url, scope);
.then(function(r) { t.add_cleanup(() => registration.unregister());
registration = r; await wait_for_state(t, registration.installing, 'activated');
return wait_for_state(t, r.installing, 'activated'); const frame = await with_iframe(scope);
}) t.add_cleanup(() => frame.remove());
.then(function() {
return with_iframe(scope);
})
.then(function(frame) {
const performance = frame.contentWindow.performance;
verify({
performance: performance,
resource: 'resources/dummy.js',
mode: 'same-origin',
description: 'Generated response',
});
verify({
performance: performance,
resource: 'resources/empty.js',
mode: 'same-origin',
description: 'Network fallback',
});
verify({
performance: performance,
resource: 'resources/redirect.py?Redirect=empty.js',
mode: 'same-origin',
description: 'Redirect',
});
verify({
performance: performance,
resource: 'resources/square.png',
mode: 'same-origin',
description: 'Network fallback image',
});
// Test that worker start is available on cross-origin no-cors
// subresources.
verify({
performance: performance,
resource: 'resources/square.png',
mode: 'cross-origin',
description: 'Network fallback cross-origin image',
});
// Tests for resouces which failed to load. const performance = frame.contentWindow.performance;
verify({ verify({
performance: performance, performance: performance,
resource: 'resources/missing.jpg', resource: 'resources/dummy.js',
mode: 'same-origin', mode: 'same-origin',
description: 'Network fallback load failure', description: 'Generated response',
}); });
verify({ verify({
performance: performance, performance: performance,
resource: 'resources/missing.jpg', resource: 'resources/empty.js',
mode: 'cross-origin', mode: 'same-origin',
description: 'Network fallback cross-origin load failure', description: 'Network fallback',
}); });
// Tests for respondWith(fetch()). verify({
verify({ performance: performance,
performance: performance, resource: 'resources/redirect.py?Redirect=empty.js',
resource: 'resources/missing.jpg?SWRespondsWithFetch', mode: 'same-origin',
mode: 'same-origin', description: 'Redirect',
description: 'Resource in iframe, nonexistent but responded with fetch to another.', });
}); verify({
verify({ performance: performance,
performance: performance, resource: 'resources/square.png',
resource: 'resources/dummy.txt?SWFetched', mode: 'same-origin',
mode: 'same-origin', description: 'Network fallback image',
description: 'Resource fetched as response from missing.jpg?SWRespondsWithFetch.', });
should_no_performance_entry: true, // Test that worker start is available on cross-origin no-cors
}); // subresources.
// Test for a normal resource that is unaffected by the Service Worker. verify({
verify({ performance: performance,
performance: performance, resource: 'resources/square.png',
resource: 'resources/empty-worker.js', mode: 'cross-origin',
mode: 'same-origin', description: 'Network fallback cross-origin image',
description: 'Resource untouched by the Service Worker.', });
});
frame.remove(); // Tests for resouces which failed to load.
return registration.unregister(); verify({
}); performance: performance,
resource: 'resources/missing.jpg',
mode: 'same-origin',
description: 'Network fallback load failure',
});
verify({
performance: performance,
resource: 'resources/missing.jpg',
mode: 'cross-origin',
description: 'Network fallback cross-origin load failure',
});
// Tests for respondWith(fetch()).
verify({
performance: performance,
resource: 'resources/missing.jpg?SWRespondsWithFetch',
mode: 'same-origin',
description: 'Resource in iframe, nonexistent but responded with fetch to another.',
});
verify({
performance: performance,
resource: 'resources/dummy.txt?SWFetched',
mode: 'same-origin',
description: 'Resource fetched as response from missing.jpg?SWRespondsWithFetch.',
should_no_performance_entry: true,
});
// Test for a normal resource that is unaffected by the Service Worker.
verify({
performance: performance,
resource: 'resources/empty-worker.js',
mode: 'same-origin',
description: 'Resource untouched by the Service Worker.',
});
}, 'Controlled resource loads'); }, 'Controlled resource loads');
test(() => { test(() => {
const url = resourceUrl('resources/test-helpers.sub.js'); const url = resourceUrl('resources/test-helpers.sub.js');
const entry = window.performance.getEntriesByName(url, 'resource')[0]; const entry = window.performance.getEntriesByName(url, 'resource')[0];
assert_equals(entry.workerStart, 0, 'Non-controlled'); assert_equals(entry.workerStart, 0, 'Non-controlled');
}, 'Non-controlled resource loads'); }, 'Non-controlled resource loads');
</script> </script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment