mirror of
https://github.com/servo/servo.git
synced 2025-08-25 23:28:21 +01:00
Update web-platform-tests to revision 8ae1ddbc812733c3a73b103eafad56fb43a2f4b5
This commit is contained in:
parent
d44e9aced2
commit
0e5e5db397
109 changed files with 2053 additions and 708 deletions
|
@ -0,0 +1,177 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test clients.get(resultingClientId)</title>
|
||||
<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>
|
||||
<script>
|
||||
const scope = "resources/";
|
||||
let worker;
|
||||
|
||||
// Setup. Keep this as the first promise_test.
|
||||
promise_test(async (t) => {
|
||||
const registration = await service_worker_unregister_and_register(
|
||||
t, 'resources/get-resultingClientId-worker.js',
|
||||
scope);
|
||||
worker = registration.installing;
|
||||
await wait_for_state(t, worker, 'activated');
|
||||
}, 'global setup');
|
||||
|
||||
// Sends |command| to the worker and returns a promise that resolves to its
|
||||
// response. There should only be one inflight command at a time.
|
||||
async function sendCommand(command) {
|
||||
const saw_message = new Promise((resolve) => {
|
||||
navigator.serviceWorker.onmessage = (event) => {
|
||||
resolve(event.data);
|
||||
};
|
||||
});
|
||||
worker.postMessage(command);
|
||||
return saw_message;
|
||||
}
|
||||
|
||||
// Wrapper for 'startTest' command. Tells the worker a test is starting,
|
||||
// so it resets state and keeps itself alive until 'finishTest'.
|
||||
async function startTest(t) {
|
||||
const result = await sendCommand({command: 'startTest'});
|
||||
assert_equals(result, 'ok', 'startTest');
|
||||
|
||||
t.add_cleanup(async () => {
|
||||
return finishTest();
|
||||
});
|
||||
}
|
||||
|
||||
// Wrapper for 'finishTest' command.
|
||||
async function finishTest() {
|
||||
const result = await sendCommand({command: 'finishTest'});
|
||||
assert_equals(result, 'ok', 'finishTest');
|
||||
}
|
||||
|
||||
// Wrapper for 'getResultingClient' command. Tells the worker to return
|
||||
// clients.get(event.resultingClientId) for the navigation that occurs
|
||||
// during this test.
|
||||
//
|
||||
// The return value describes how clients.get() settled. It also includes
|
||||
// |queriedId| which is the id passed to clients.get() (the resultingClientId
|
||||
// in this case).
|
||||
//
|
||||
// Example value:
|
||||
// {
|
||||
// queriedId: 'abc',
|
||||
// promiseState: fulfilled,
|
||||
// promiseValue: client,
|
||||
// client: {
|
||||
// id: 'abc',
|
||||
// url: '//example.com/client'
|
||||
// }
|
||||
// }
|
||||
async function getResultingClient() {
|
||||
return sendCommand({command: 'getResultingClient'});
|
||||
}
|
||||
|
||||
// Wrapper for 'getClient' command. Tells the worker to return
|
||||
// clients.get(|id|). The return value is as in the getResultingClient()
|
||||
// documentation.
|
||||
async function getClient(id) {
|
||||
return sendCommand({command: 'getClient', id: id});
|
||||
}
|
||||
|
||||
// Navigates to |url|. Returns the result of clients.get() on the
|
||||
// resultingClientId.
|
||||
async function navigateAndGetResultingClient(t, url) {
|
||||
const resultPromise = getResultingClient();
|
||||
const frame = await with_iframe(url);
|
||||
t.add_cleanup(() => {
|
||||
frame.remove();
|
||||
});
|
||||
const result = await resultPromise;
|
||||
const resultingClientId = result.queriedId;
|
||||
|
||||
// First test clients.get(event.resultingClientId) inside the fetch event. The
|
||||
// behavior of this is subtle due to the use of iframes and about:blank
|
||||
// replacement. The spec probably requires that it resolve to the original
|
||||
// about:blank client, and that later that client should be discarded after
|
||||
// load if the load was to another origin. Implementations might differ. For
|
||||
// now, this test just asserts that the promise resolves. See
|
||||
// https://github.com/w3c/ServiceWorker/issues/1385.
|
||||
assert_equals(result.promiseState, 'fulfilled',
|
||||
'get(event.resultingClientId) in the fetch event should fulfill');
|
||||
|
||||
// Test clients.get() on the previous resultingClientId again. By this
|
||||
// time the load finished, so it's more straightforward how this promise
|
||||
// should settle. Return the result of this promise.
|
||||
return await getClient(resultingClientId);
|
||||
}
|
||||
|
||||
// Test get(resultingClientId) in the basic same-origin case.
|
||||
promise_test(async (t) => {
|
||||
await startTest(t);
|
||||
|
||||
const url = new URL('resources/empty.html', window.location);
|
||||
const result = await navigateAndGetResultingClient(t, url);
|
||||
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
|
||||
assert_equals(result.promiseValue, 'client', 'promiseValue');
|
||||
assert_equals(result.client.url, url.href, 'client.url',);
|
||||
assert_equals(result.client.id, result.queriedId, 'client.id');
|
||||
}, 'get(resultingClientId) for same-origin document');
|
||||
|
||||
// Test get(resultingClientId) when the response redirects to another origin.
|
||||
promise_test(async (t) => {
|
||||
await startTest(t);
|
||||
|
||||
// Navigate to a URL that redirects to another origin.
|
||||
const base_url = new URL('.', window.location);
|
||||
const host_info = get_host_info();
|
||||
const other_origin_url = new URL(base_url.pathname + 'resources/empty.html',
|
||||
host_info['HTTPS_REMOTE_ORIGIN']);
|
||||
const url = new URL('resources/empty.html', window.location);
|
||||
const pipe = `status(302)|header(Location, ${other_origin_url})`;
|
||||
url.searchParams.set('pipe', pipe);
|
||||
|
||||
// The original reserved client should have been discarded on cross-origin
|
||||
// redirect.
|
||||
const result = await navigateAndGetResultingClient(t, url);
|
||||
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
|
||||
assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
|
||||
}, 'get(resultingClientId) on cross-origin redirect');
|
||||
|
||||
// Test get(resultingClientId) when the document is sandboxed to a unique
|
||||
// origin using a CSP HTTP response header.
|
||||
promise_test(async (t) => {
|
||||
await startTest(t);
|
||||
|
||||
// Navigate to a URL that has CSP sandboxing set in the HTTP response header.
|
||||
const url = new URL('resources/empty.html', window.location);
|
||||
const pipe = 'header(Content-Security-Policy, sandbox)';
|
||||
url.searchParams.set('pipe', pipe);
|
||||
|
||||
// The original reserved client should have been discarded upon loading
|
||||
// the sandboxed document.
|
||||
const result = await navigateAndGetResultingClient(t, url);
|
||||
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
|
||||
assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
|
||||
}, 'get(resultingClientId) for document sandboxed by CSP header');
|
||||
|
||||
// Test get(resultingClientId) when the document is sandboxed with
|
||||
// allow-same-origin.
|
||||
promise_test(async (t) => {
|
||||
await startTest(t);
|
||||
|
||||
// Navigate to a URL that has CSP sandboxing set in the HTTP response header.
|
||||
const url = new URL('resources/empty.html', window.location);
|
||||
const pipe = 'header(Content-Security-Policy, sandbox allow-same-origin)';
|
||||
url.searchParams.set('pipe', pipe);
|
||||
|
||||
// The client should be the original reserved client, as it's same-origin.
|
||||
const result = await navigateAndGetResultingClient(t, url);
|
||||
assert_equals(result.promiseState, 'fulfilled', 'promiseState');
|
||||
assert_equals(result.promiseValue, 'client', 'promiseValue');
|
||||
assert_equals(result.client.url, url.href, 'client.url',);
|
||||
assert_equals(result.client.id, result.queriedId, 'client.id');
|
||||
}, 'get(resultingClientId) for document sandboxed by CSP header with allow-same-origin');
|
||||
|
||||
// Cleanup. Keep this as the last promise_test.
|
||||
promise_test(async (t) => {
|
||||
return service_worker_unregister(t, scope);
|
||||
}, 'global cleanup');
|
||||
</script>
|
|
@ -0,0 +1,107 @@
|
|||
// This worker expects a fetch event for a navigation and messages back the
|
||||
// result of clients.get(event.resultingClientId).
|
||||
|
||||
// Resolves when the test finishes.
|
||||
let testFinishPromise;
|
||||
let resolveTestFinishPromise;
|
||||
let rejectTestFinishPromise;
|
||||
|
||||
// Resolves to clients.get(event.resultingClientId) from the fetch event.
|
||||
let getPromise;
|
||||
let resolveGetPromise;
|
||||
let rejectGetPromise;
|
||||
|
||||
let resultingClientId;
|
||||
|
||||
function startTest() {
|
||||
testFinishPromise = new Promise((resolve, reject) => {
|
||||
resolveTestFinishPromise = resolve;
|
||||
rejectTestFinishPromise = reject;
|
||||
});
|
||||
|
||||
getPromise = new Promise((resolve, reject) => {
|
||||
resolveGetPromise = resolve;
|
||||
rejectGetPromise = reject;
|
||||
});
|
||||
}
|
||||
|
||||
async function describeGetPromiseResult(promise) {
|
||||
const result = {};
|
||||
|
||||
await promise.then(
|
||||
(client) => {
|
||||
result.promiseState = 'fulfilled';
|
||||
if (client === undefined) {
|
||||
result.promiseValue = 'undefinedValue';
|
||||
} else if (client instanceof Client) {
|
||||
result.promiseValue = 'client';
|
||||
result.client = {
|
||||
id: client.id,
|
||||
url: client.url
|
||||
};
|
||||
} else {
|
||||
result.promiseValue = 'unknown';
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
result.promiseState = 'rejected';
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function handleGetResultingClient(event) {
|
||||
// Note that this message can arrive before |resultingClientId| is populated.
|
||||
const result = await describeGetPromiseResult(getPromise);
|
||||
// |resultingClientId| must be populated by now.
|
||||
result.queriedId = resultingClientId;
|
||||
event.source.postMessage(result);
|
||||
};
|
||||
|
||||
async function handleGetClient(event) {
|
||||
const id = event.data.id;
|
||||
const result = await describeGetPromiseResult(self.clients.get(id));
|
||||
result.queriedId = id;
|
||||
event.source.postMessage(result);
|
||||
};
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
if (event.data.command == 'startTest') {
|
||||
startTest();
|
||||
event.waitUntil(testFinishPromise);
|
||||
event.source.postMessage('ok');
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.command == 'finishTest') {
|
||||
resolveTestFinishPromise();
|
||||
event.source.postMessage('ok');
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.command == 'getResultingClient') {
|
||||
event.waitUntil(handleGetResultingClient(event));
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.command == 'getClient') {
|
||||
event.waitUntil(handleGetClient(event));
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
async function handleFetch(event) {
|
||||
try {
|
||||
resultingClientId = event.resultingClientId;
|
||||
const client = await self.clients.get(resultingClientId);
|
||||
resolveGetPromise(client);
|
||||
} catch (error) {
|
||||
rejectGetPromise(error);
|
||||
}
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.mode != 'navigate')
|
||||
return;
|
||||
event.waitUntil(handleFetch(event));
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue