https://github.com/web-platform-tests/wpt
Tip revision: 395be6a7bcb79ff93bd3e10aec665ce1dd2f9c54 authored by Mikhail Pozdnyakov on 13 April 2018, 11:21:15 UTC
Enable WPT tests for the Generic Sensor classes
Enable WPT tests for the Generic Sensor classes
Tip revision: 395be6a
fetch-event.https.html
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
var worker = 'resources/fetch-event-test-worker.js';
function wait(ms) {
return new Promise(resolve => step_timeout(resolve, ms));
}
async_test(function(t) {
const scope = 'resources/simple.html?headers';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
t.add_cleanup(function() { frame.remove(); });
const headers = JSON.parse(frame.contentDocument.body.textContent);
const header_names = {};
for (const [name, value] of headers) {
header_names[name] = true;
}
assert_true(
header_names.hasOwnProperty('accept'),
'request includes "Accept" header as inserted by Fetch'
);
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker headers in the request of a fetch event');
async_test(function(t) {
var scope = 'resources/simple.html?string';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'Test string',
'Service Worker should respond to fetch with a test string');
assert_equals(
frame.contentDocument.contentType,
'text/plain',
'The content type of the response created with a string should be text/plain');
assert_equals(
frame.contentDocument.characterSet,
'UTF-8',
'The character set of the response created with a string should be UTF-8');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with string');
async_test(function(t) {
var scope = 'resources/simple.html?string';
var frame;
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope) })
.then(function(f) {
frame = f;
return frame.contentWindow.fetch(scope + "#foo")
})
.then(function(response) { return response.text() })
.then(function(text) {
assert_equals(
text,
'Test string',
'Service Worker should respond to fetch with a test string');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event using request fragment with string');
async_test(function(t) {
var scope = 'resources/simple.html?blob';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'Test blob',
'Service Worker should respond to fetch with a test string');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with blob body');
async_test(function(t) {
var scope = 'resources/simple.html?referrer';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'Referrer: ' + document.location.href,
'Service Worker should respond to fetch with the referrer URL');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with the referrer URL');
async_test(function(t) {
var scope = 'resources/simple.html?clientId';
var frame;
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(f) {
frame = f;
assert_equals(
frame.contentDocument.body.textContent,
'Client ID Not Found',
'Service Worker should respond to fetch with a client id');
return frame.contentWindow.fetch('resources/other.html?clientId');
})
.then(function(response) { return response.text(); })
.then(function(response_text) {
var new_client_id = response_text.substr(17);
assert_equals(
response_text.substr(0, 15),
'Client ID Found',
'Service Worker should respond to fetch with an existing client id');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with an existing client id');
async_test(function(t) {
var scope = 'resources/simple.html?ignore';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(frame.contentDocument.body.textContent,
'Here\'s a simple html file.\n',
'Response should come from fallback to native fetch');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker does not respond to fetch event');
async_test(function(t) {
var scope = 'resources/simple.html?null';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(frame.contentDocument.body.textContent,
'',
'Response should be the empty string');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with null response body');
async_test(function(t) {
var scope = 'resources/simple.html?fetch';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(frame.contentDocument.body.textContent,
'Here\'s an other html file.\n',
'Response should come from fetched other file');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker fetches other file in fetch event');
// Creates a form and an iframe and does a form submission that navigates the
// frame to |action_url|. Returns the frame after navigation.
function submit_form(action_url) {
return new Promise(resolve => {
const frame = document.createElement('iframe');
frame.name = 'post-frame';
document.body.appendChild(frame);
const form = document.createElement('form');
form.target = frame.name;
form.action = action_url;
form.method = 'post';
const input1 = document.createElement('input');
input1.type = 'text';
input1.value = 'testValue1';
input1.name = 'testName1'
form.appendChild(input1);
const input2 = document.createElement('input');
input2.type = 'text';
input2.value = 'testValue2';
input2.name = 'testName2'
form.appendChild(input2);
document.body.appendChild(form);
frame.onload = function() {
form.remove();
resolve(frame);
};
form.submit();
});
}
promise_test(t => {
const scope = 'resources/simple.html?form-post';
let registration;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
registration = reg;
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return submit_form(scope);
})
.then(frame => {
assert_equals(frame.contentDocument.body.textContent,
'POST:application/x-www-form-urlencoded:' +
'testName1=testValue1&testName2=testValue2');
frame.remove();
return registration.unregister();
});
}, 'Service Worker responds to fetch event with POST form');
promise_test(t => {
// Add '?ignore' to scope so the service worker falls back to network.
const scope = 'resources/echo-content.py?ignore';
let registration;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
registration = reg;
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return submit_form(scope);
})
.then(frame => {
assert_equals(frame.contentDocument.body.textContent,
'testName1=testValue1&testName2=testValue2');
frame.remove();
return registration.unregister();
});
}, 'Service Worker falls back to network in fetch event with POST form');
async_test(function(t) {
var scope = 'resources/simple.html?multiple-respond-with';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'(0)(1)[InvalidStateError](2)[InvalidStateError]',
'Multiple calls of respondWith must throw InvalidStateErrors.');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Multiple calls of respondWith must throw InvalidStateErrors');
async_test(function(t) {
var scope = 'resources/simple.html?used-check';
var first_frame;
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(frame) {
assert_equals(frame.contentDocument.body.textContent,
'Here\'s an other html file.\n',
'Response should come from fetched other file');
first_frame = frame;
return with_iframe(scope);
})
.then(function(frame) {
// When we access to the scope in the second time, the content of the
// response is generated inside the ServiceWorker. The body contains
// the value of bodyUsed of the first response which is already
// consumed by FetchEvent.respondWith method.
assert_equals(
frame.contentDocument.body.textContent,
'bodyUsed: true',
'event.respondWith must set the used flag.');
first_frame.remove();
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker event.respondWith must set the used flag');
async_test(function(t) {
var scope = 'resources/simple.html?fragment-check';
var fragment = '#/some/fragment';
var first_frame;
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope + fragment); })
.then(function(frame) {
assert_equals(
frame.contentDocument.body.textContent,
'Fragment Found :' + fragment,
'Service worker should expose URL fragments in request.');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker should expose FetchEvent URL fragments.');
async_test(function(t) {
var scope = 'resources/simple.html?cache';
var frame;
var cacheTypes = [
undefined, 'default', 'no-store', 'reload', 'no-cache', 'force-cache', 'only-if-cached'
];
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(f) {
frame = f;
assert_equals(frame.contentWindow.document.body.textContent, 'default');
var tests = cacheTypes.map(function(type) {
return new Promise(function(resolve, reject) {
var init = {cache: type};
if (type === 'only-if-cached') {
// For privacy reasons, for the time being, only-if-cached
// requires the mode to be same-origin.
init.mode = 'same-origin';
}
return frame.contentWindow.fetch(scope + '=' + type, init)
.then(function(response) { return response.text(); })
.then(function(response_text) {
var expected = (type === undefined) ? 'default' : type;
assert_equals(response_text, expected,
'Service Worker should respond to fetch with the correct type');
})
.then(resolve)
.catch(reject);
});
});
return Promise.all(tests);
})
.then(function() {
return new Promise(function(resolve, reject) {
frame.addEventListener('load', function onLoad() {
frame.removeEventListener('load', onLoad);
try {
assert_equals(frame.contentWindow.document.body.textContent,
'no-cache');
resolve();
} catch (e) {
reject(e);
}
});
frame.contentWindow.location.reload();
});
})
.then(function() {
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with the correct cache types');
async_test(function(t) {
var scope = 'resources/simple.html?eventsource';
var frame;
function test_eventsource(opts) {
return new Promise(function(resolve, reject) {
var eventSource = new frame.contentWindow.EventSource(scope, opts);
eventSource.addEventListener('message', function(msg) {
eventSource.close();
try {
var data = JSON.parse(msg.data);
assert_equals(data.mode, 'cors',
'EventSource should make CORS requests.');
assert_equals(data.cache, 'no-store',
'EventSource should bypass the http cache.');
var expectedCredentials = opts.withCredentials ? 'include'
: 'same-origin';
assert_equals(data.credentials, expectedCredentials,
'EventSource should pass correct credentials mode.');
resolve();
} catch (e) {
reject(e);
}
});
eventSource.addEventListener('error', function(e) {
eventSource.close();
reject('The EventSource fired an error event.');
});
});
}
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(f) {
frame = f;
return test_eventsource({ withCredentials: false });
})
.then(function() {
return test_eventsource({ withCredentials: true });
})
.then(function() {
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker should intercept EventSource');
async_test(function(t) {
var scope = 'resources/simple.html?integrity';
var frame;
var integrity_metadata = 'gs0nqru8KbsrIt5YToQqS9fYao4GQJXtcId610g7cCU=';
service_worker_unregister_and_register(t, worker, scope)
.then(function(reg) {
return wait_for_state(t, reg.installing, 'activated');
})
.then(function() { return with_iframe(scope); })
.then(function(f) {
frame = f;
// A request has associated integrity metadata (a string).
// Unless stated otherwise, it is the empty string.
assert_equals(
frame.contentDocument.body.textContent, '');
return frame.contentWindow.fetch(scope, {'integrity': integrity_metadata});
})
.then(response => {
return response.text();
})
.then(response_text => {
assert_equals(response_text, integrity_metadata, 'integrity');
frame.remove();
return service_worker_unregister_and_done(t, scope);
})
.catch(unreached_rejection(t));
}, 'Service Worker responds to fetch event with the correct integrity_metadata');
// Test that the service worker can read FetchEvent#body when it is a string.
// It responds with request body it read.
promise_test(t => {
// Set scope to "?ignore" so the service worker falls back to network
// for the main resource request, and add a suffix to avoid colliding
// with other tests.
const scope = 'resources/simple.html?ignore-for-request-body-string';
let frame;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return with_iframe(scope); })
.then(f => {
frame = f;
return frame.contentWindow.fetch('simple.html?request-body', {
method: 'POST',
body: 'i am the request body'
});
})
.then(response => {
return response.text();
})
.then(response_text => {
frame.remove();
assert_equals(response_text, 'i am the request body');
});
}, 'FetchEvent#body is a string');
// Test that the request body is sent to network upon network fallback,
// for a string body.
promise_test(t => {
// Set scope to "?ignore" so the service worker falls back to network
// for the main resource request, and add a suffix to avoid colliding
// with other tests.
const scope = 'resources/?ignore-for-request-body-fallback-string';
let frame;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return with_iframe(scope); })
.then(f => {
frame = f;
// Add "?ignore" so the service worker falls back to echo-content.py.
const echo_url = '/fetch/api/resources/echo-content.py?ignore';
return frame.contentWindow.fetch(echo_url, {
method: 'POST',
body: 'i am the request body'
});
})
.then(response => {
return response.text();
})
.then(response_text => {
frame.remove();
assert_equals(
response_text,
'i am the request body',
'the network fallback request should include the request body');
});
}, 'FetchEvent#body is a string and is passed to network fallback');
// Test that the service worker can read FetchEvent#body when it is a blob.
// It responds with request body it read.
promise_test(t => {
// Set scope to "?ignore" so the service worker falls back to network
// for the main resource request, and add a suffix to avoid colliding
// with other tests.
const scope = 'resources/simple.html?ignore-for-request-body-blob';
let frame;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return with_iframe(scope); })
.then(f => {
frame = f;
const blob = new Blob(['it\'s me the blob', ' ', 'and more blob!']);
return frame.contentWindow.fetch('simple.html?request-body', {
method: 'POST',
body: blob
});
})
.then(response => {
return response.text();
})
.then(response_text => {
frame.remove();
assert_equals(response_text, 'it\'s me the blob and more blob!');
});
}, 'FetchEvent#body is a blob');
// Test that the request body is sent to network upon network fallback,
// for a blob body.
promise_test(t => {
// Set scope to "?ignore" so the service worker falls back to network
// for the main resource request, and add a suffix to avoid colliding
// with other tests.
const scope = 'resources/simple.html?ignore-for-request-body-fallback-blob';
let frame;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
add_completion_callback(() => { reg.unregister(); });
return wait_for_state(t, reg.installing, 'activated');
})
.then(() => {
return with_iframe(scope); })
.then(f => {
frame = f;
const blob = new Blob(['it\'s me the blob', ' ', 'and more blob!']);
// Add "?ignore" so the service worker falls back to echo-content.py.
const echo_url = '/fetch/api/resources/echo-content.py?ignore';
return frame.contentWindow.fetch(echo_url, {
method: 'POST',
body: blob
});
})
.then(response => {
return response.text();
})
.then(response_text => {
frame.remove();
assert_equals(
response_text,
'it\'s me the blob and more blob!',
'the network fallback request should include the request body');
});
}, 'FetchEvent#body is a blob and is passed to network fallback');
promise_test(async (t) => {
const scope = 'resources/simple.html?keepalive';
const reg = await service_worker_unregister_and_register(t, worker, scope);
await wait_for_state(t, reg.installing, 'activated');
const frame = await with_iframe(scope);
assert_equals(frame.contentDocument.body.textContent, 'false');
const response = await frame.contentWindow.fetch(scope, {keepalive: true});
const text = await response.text();
assert_equals(text, 'true');
frame.remove();
await service_worker_unregister_and_done(t, scope);
}, 'Service Worker responds to fetch event with the correct keepalive value');
promise_test(async (t) => {
const scope = 'resources/simple.html?isReloadNavigation';
let frame;
let reg;
try {
reg = await service_worker_unregister_and_register(t, worker, scope);
await wait_for_state(t, reg.installing, 'activated');
frame = await with_iframe(scope);
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = false');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.location.reload();
});
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = true');
} finally {
if (frame) {
frame.remove();
}
if (reg) {
await reg.unregister();
}
}
}, 'FetchEvent#request.isReloadNavigation is true (location.reload())');
promise_test(async (t) => {
const scope = 'resources/simple.html?isReloadNavigation';
let frame;
let reg;
try {
reg = await service_worker_unregister_and_register(t, worker, scope);
await wait_for_state(t, reg.installing, 'activated');
frame = await with_iframe(scope);
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = false');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.history.go(0);
});
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = true');
} finally {
if (frame) {
frame.remove();
}
if (reg) {
await reg.unregister();
}
}
}, 'FetchEvent#request.isReloadNavigation is true (history.go(0))');
promise_test(async (t) => {
const scope = 'resources/simple.html?isReloadNavigation';
let frame;
let reg;
try {
reg = await service_worker_unregister_and_register(t, worker, scope);
await wait_for_state(t, reg.installing, 'activated');
frame = await with_iframe(scope);
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = false');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
const form = frame.contentDocument.createElement('form');
form.method = 'POST';
form.name = 'form';
form.action = new Request(scope).url;
frame.contentDocument.body.appendChild(form);
form.submit();
});
assert_equals(frame.contentDocument.body.textContent,
'method = POST, isReloadNavigation = false');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.location.reload();
});
assert_equals(frame.contentDocument.body.textContent,
'method = POST, isReloadNavigation = true');
} finally {
if (frame) {
frame.remove();
}
if (reg) {
await reg.unregister();
}
}
}, 'FetchEvent#request.isReloadNavigation is true (POST + location.reload())');
promise_test(async (t) => {
const scope = 'resources/simple.html?isReloadNavigation';
const anotherUrl = new Request('resources/simple.html').url;
let frame;
let reg;
try {
reg = await service_worker_unregister_and_register(t, worker, scope);
await wait_for_state(t, reg.installing, 'activated');
frame = await with_iframe(scope);
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = false');
// Use step_timeout(0) to ensure the history entry is created for Blink
// and WebKit. See https://bugs.webkit.org/show_bug.cgi?id=42861.
await wait(0);
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.src = anotherUrl;
});
assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.history.go(-1);
});
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = false');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.history.go(0);
});
assert_equals(frame.contentDocument.body.textContent,
'method = GET, isReloadNavigation = true');
await new Promise((resolve) => {
frame.addEventListener('load', resolve);
frame.contentWindow.history.go(1);
});
assert_equals(frame.contentDocument.body.textContent, "Here's a simple html file.\n");
} finally {
if (frame) {
frame.remove();
}
if (reg) {
await reg.unregister();
}
}
}, 'FetchEvent#request.isReloadNavigation is true (with history traversal)');
</script>
</body>