зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1460490
[wpt PR 10946] - Async Cookies: Change events in service workers., a=testonly
Automatic update from web-platform-testsAsync Cookies: Change events in service workers. While installing, a service worker may call cookieStore.subscribeToChanges() to express interest in observing the changes to the list of cookies sent in a request to a specific URL. After the service worker becomes active, it is notified of changes to the cookies it is interested in via "cookiechange" events, which are dispatched to the service worker's global scope. This CL lays the last piece in the foundation of the Async Cookies API, which is currently gated by the Experimental Web Platform Features flag. This CL focuses on the core functionality and plumbing. Follow-up CLs will add more tests, fix the handling of edge cases, and improve performance. Bug: 729800 Change-Id: I52f2e550d7901d746ed1a973426d3181ea091147 Reviewed-on: https://chromium-review.googlesource.com/979334 Reviewed-by: Jeremy Roman <jbroman@chromium.org> Reviewed-by: Kinuko Yasuda <kinuko@chromium.org> Reviewed-by: Matt Falkenhagen <falken@chromium.org> Reviewed-by: Marijn Kruisselbrink <mek@chromium.org> Reviewed-by: Joshua Bell <jsbell@chromium.org> Reviewed-by: Mark Pearson <mpearson@chromium.org> Commit-Queue: Jeremy Roman <jbroman@chromium.org> Cr-Commit-Position: refs/heads/master@{#558682} -- wpt-commits: c16fdfb6fe53019649d14179bce3e50acdefa3b4 wpt-pr: 10946
This commit is contained in:
Родитель
19633055bf
Коммит
1fea07d2d4
|
@ -216294,6 +216294,16 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions_basic.js": [
|
||||
[
|
||||
{}
|
||||
]
|
||||
],
|
||||
"cookies/OWNERS": [
|
||||
[
|
||||
{}
|
||||
|
@ -315103,6 +315113,18 @@
|
|||
{}
|
||||
]
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html": [
|
||||
[
|
||||
"/cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html": [
|
||||
[
|
||||
"/cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html",
|
||||
{}
|
||||
]
|
||||
],
|
||||
"cookies/http-state/attribute-tests.html": [
|
||||
[
|
||||
"/cookies/http-state/attribute-tests.html",
|
||||
|
@ -429907,11 +429929,11 @@
|
|||
"testharness"
|
||||
],
|
||||
"cookie-store/idlharness.tentative.html": [
|
||||
"2a588a0b80a3cee80af52b9109770fe8ec17becd",
|
||||
"42be9e73d8e6ad3760a4c9871f6f633962f2ab85",
|
||||
"testharness"
|
||||
],
|
||||
"cookie-store/idlharness_serviceworker.js": [
|
||||
"aceb00f593b0447853fa70c8c971902cf02a164b",
|
||||
"516a0596c03b9db2446ca77d70d3eb95f060e895",
|
||||
"support"
|
||||
],
|
||||
"cookie-store/idlharness_serviceworker.tentative.https.html": [
|
||||
|
@ -429994,6 +430016,22 @@
|
|||
"0700dc72bc1e00832546d4a6826a5474600af06c",
|
||||
"testharness"
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions.js": [
|
||||
"932a140052fdd95c256bb8a7dfa24522774b569e",
|
||||
"support"
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html": [
|
||||
"4389e108fcbad909506ce6ea0d30e32f5973bfce",
|
||||
"testharness"
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions_basic.js": [
|
||||
"90300c01688cfecd10140078bf36d3801566c2ea",
|
||||
"support"
|
||||
],
|
||||
"cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html": [
|
||||
"3836f1d36746ae11b76ee420ba34d902d48bc0af",
|
||||
"testharness"
|
||||
],
|
||||
"cookies/OWNERS": [
|
||||
"15417c1a9e90762ae826b0258fe3619cc6a78b0e",
|
||||
"support"
|
||||
|
@ -582539,7 +582577,7 @@
|
|||
"support"
|
||||
],
|
||||
"interfaces/cookie-store.idl": [
|
||||
"0d74ef8e7681fddddfb786b75075a1dd0ddb9147",
|
||||
"bb4c385873deafd746f186058b111193c8aebf01",
|
||||
"support"
|
||||
],
|
||||
"interfaces/css-font-loading.idl": [
|
||||
|
|
|
@ -42,6 +42,11 @@ promise_test(async t => {
|
|||
'EventModifierInit',
|
||||
] });
|
||||
|
||||
idl_array.add_untested_idls(
|
||||
`dictionary ExtendableEventInit {};`);
|
||||
idl_array.add_untested_idls(
|
||||
`[Global=ExtendableEvent, Exposed=ServiceWorker]
|
||||
interface ExtendableEvent : Event {};`);
|
||||
idl_array.add_untested_idls(
|
||||
`[Global=ServiceWorker, Exposed=ServiceWorker]
|
||||
interface ServiceWorkerGlobalScope {};`);
|
||||
|
|
|
@ -16,8 +16,12 @@ promise_test(async t => {
|
|||
idl_array.add_untested_idls(
|
||||
`[Global=Event, Exposed=ServiceWorker]
|
||||
interface Event {};`);
|
||||
idl_array.add_untested_idls(
|
||||
`[Global=ExtendableEvent, Exposed=ServiceWorker]
|
||||
interface ExtendableEvent : Event {};`);
|
||||
idl_array.add_untested_idls('dictionary EventHandler {};');
|
||||
idl_array.add_untested_idls('dictionary EventInit {};');
|
||||
idl_array.add_untested_idls('dictionary ExtendableEventInit {};');
|
||||
idl_array.add_untested_idls(
|
||||
`[Global=EventTarget, Exposed=ServiceWorker]
|
||||
interface EventTarget {};`);
|
||||
|
@ -32,7 +36,8 @@ promise_test(async t => {
|
|||
|
||||
idl_array.add_objects({
|
||||
CookieStore: [self.cookieStore],
|
||||
CookieChangeEvent: [new CookieChangeEvent('change')],
|
||||
ExtendableCookieChangeEvent: [
|
||||
new ExtendableCookieChangeEvent('cookiechange')],
|
||||
});
|
||||
idl_array.test();
|
||||
}, 'Interface test');
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
self.GLOBAL = {
|
||||
isWindow: function() { return false; },
|
||||
isWorker: function() { return true; },
|
||||
};
|
||||
importScripts("/resources/testharness.js");
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil((async () => {
|
||||
// The subscribeToChanges calls are not done in parallel on purpose. Having
|
||||
// multiple in-flight requests introduces failure modes aside from the
|
||||
// cookie change logic that this test aims to cover.
|
||||
await cookieStore.subscribeToChanges([
|
||||
{ name: 'cookie-name1', matchType: 'equals', url: '/scope/path1' }]);
|
||||
await cookieStore.subscribeToChanges([
|
||||
{ }, // Test the default values for subscription properties.
|
||||
{ name: 'cookie-prefix', matchType: 'startsWith' },
|
||||
]);
|
||||
})());
|
||||
});
|
||||
|
||||
// Workaround because add_cleanup doesn't support async functions yet.
|
||||
// See https://github.com/w3c/web-platform-tests/issues/6075
|
||||
async function async_cleanup(cleanup_function) {
|
||||
try {
|
||||
await cleanup_function();
|
||||
} catch (e) {
|
||||
// Errors in cleanup functions shouldn't result in test failures.
|
||||
}
|
||||
}
|
||||
|
||||
// Resolves when the service worker receives the 'activate' event.
|
||||
const kServiceWorkerActivatedPromise = new Promise(resolve => {
|
||||
self.addEventListener('activate', event => { resolve(); });
|
||||
});
|
||||
|
||||
// sort() comparator that uses the < operator.
|
||||
//
|
||||
// This is intended to be used for sorting strings. Using < is preferred to
|
||||
// localeCompare() because the latter has some implementation-dependent
|
||||
// behavior.
|
||||
function CompareStrings(a, b) {
|
||||
return a < b ? -1 : (b < a ? 1 : 0);
|
||||
}
|
||||
|
||||
promise_test(async testCase => {
|
||||
await kServiceWorkerActivatedPromise;
|
||||
|
||||
const subscriptions = await cookieStore.getChangeSubscriptions();
|
||||
assert_equals(subscriptions.length, 3);
|
||||
|
||||
subscriptions.sort((a, b) => CompareStrings(`${a.name}`, `${b.name}`));
|
||||
|
||||
assert_equals(subscriptions[0].name, 'cookie-name1');
|
||||
assert_equals('equals', subscriptions[0].matchType);
|
||||
|
||||
assert_equals(subscriptions[1].name, 'cookie-prefix');
|
||||
assert_equals('startsWith', subscriptions[1].matchType);
|
||||
|
||||
assert_false('name' in subscriptions[2]);
|
||||
assert_equals('startsWith', subscriptions[2].matchType);
|
||||
}, 'getChangeSubscriptions returns subscriptions passed to subscribeToChanges');
|
||||
|
||||
promise_test(async testCase => {
|
||||
promise_rejects(
|
||||
testCase, new TypeError(),
|
||||
cookieStore.subscribeToChanges([{ name: 'cookie-name2' }]));
|
||||
}, 'subscribeToChanges rejects when called outside the install handler');
|
||||
|
||||
|
||||
// Accumulates cookiechange events dispatched to the service worker.
|
||||
let g_cookie_changes = [];
|
||||
|
||||
// Resolved when a cookiechange event is received. Rearmed by
|
||||
// ResetCookieChangeReceivedPromise().
|
||||
let g_cookie_change_received_promise = null;
|
||||
let g_cookie_change_received_promise_resolver = null;
|
||||
self.addEventListener('cookiechange', (event) => {
|
||||
g_cookie_changes.push(event);
|
||||
if (g_cookie_change_received_promise_resolver)
|
||||
g_cookie_change_received_promise_resolver();
|
||||
});
|
||||
function RearmCookieChangeReceivedPromise() {
|
||||
g_cookie_change_received_promise = new Promise((resolve) => {
|
||||
g_cookie_change_received_promise_resolver = resolve;
|
||||
});
|
||||
}
|
||||
RearmCookieChangeReceivedPromise();
|
||||
|
||||
promise_test(async testCase => {
|
||||
await kServiceWorkerActivatedPromise;
|
||||
|
||||
await cookieStore.set('cookie-name', 'cookie-value');
|
||||
|
||||
await g_cookie_change_received_promise;
|
||||
|
||||
assert_equals(g_cookie_changes.length, 1);
|
||||
const event = g_cookie_changes[0]
|
||||
assert_equals(event.type, 'cookiechange');
|
||||
assert_equals(event.changed.length, 1);
|
||||
assert_equals(event.changed[0].name, 'cookie-name');
|
||||
assert_equals(event.changed[0].value, 'cookie-value');
|
||||
assert_equals(event.deleted.length, 0);
|
||||
assert_true(event instanceof ExtendableCookieChangeEvent);
|
||||
assert_true(event instanceof ExtendableEvent);
|
||||
|
||||
await async_cleanup(() => {
|
||||
cookieStore.delete('cookie-name');
|
||||
g_cookie_changes = [];
|
||||
RearmCookieChangeReceivedPromise();
|
||||
});
|
||||
}, 'cookiechange dispatched with cookie change that matches subscription');
|
||||
|
||||
done();
|
|
@ -0,0 +1,22 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Async Cookies: cookie change events in ServiceWorker</title>
|
||||
<link rel="help" href="https://github.com/WICG/cookie-store">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
(async () => {
|
||||
const scope = 'scope';
|
||||
|
||||
let registration = await navigator.serviceWorker.getRegistration(scope);
|
||||
if (registration)
|
||||
await registration.unregister();
|
||||
registration = await navigator.serviceWorker.register(
|
||||
'serviceworker_cookieStore_subscriptions.js', {scope});
|
||||
|
||||
fetch_tests_from_worker(registration.installing);
|
||||
})();
|
||||
</script>
|
|
@ -0,0 +1,63 @@
|
|||
self.GLOBAL = {
|
||||
isWindow: function() { return false; },
|
||||
isWorker: function() { return true; },
|
||||
};
|
||||
importScripts("/resources/testharness.js");
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil((async () => {
|
||||
cookieStore.subscribeToChanges([
|
||||
{ name: 'cookie-name', matchType: 'equals', url: '/scope/path' }]);
|
||||
})());
|
||||
});
|
||||
|
||||
// Workaround because add_cleanup doesn't support async functions yet.
|
||||
// See https://github.com/w3c/web-platform-tests/issues/6075
|
||||
async function async_cleanup(cleanup_function) {
|
||||
try {
|
||||
await cleanup_function();
|
||||
} catch (e) {
|
||||
// Errors in cleanup functions shouldn't result in test failures.
|
||||
}
|
||||
}
|
||||
|
||||
// Resolves when the service worker receives the 'activate' event.
|
||||
const kServiceWorkerActivatedPromise = new Promise(resolve => {
|
||||
self.addEventListener('activate', event => { resolve(); });
|
||||
});
|
||||
|
||||
promise_test(async testCase => {
|
||||
await kServiceWorkerActivatedPromise;
|
||||
|
||||
const subscriptions = await cookieStore.getChangeSubscriptions();
|
||||
assert_equals(subscriptions.length, 1);
|
||||
|
||||
assert_equals(subscriptions[0].name, 'cookie-name');
|
||||
assert_equals('equals', subscriptions[0].matchType);
|
||||
}, 'getChangeSubscriptions returns a subscription passed to subscribeToChanges');
|
||||
|
||||
|
||||
promise_test(async testCase => {
|
||||
await kServiceWorkerActivatedPromise;
|
||||
|
||||
cookie_change_received_promise = new Promise((resolve) => {
|
||||
self.addEventListener('cookiechange', (event) => {
|
||||
resolve(event);
|
||||
});
|
||||
});
|
||||
|
||||
await cookieStore.set('cookie-name', 'cookie-value');
|
||||
|
||||
const event = await cookie_change_received_promise;
|
||||
assert_equals(event.type, 'cookiechange');
|
||||
assert_equals(event.changed.length, 1);
|
||||
assert_equals(event.changed[0].name, 'cookie-name');
|
||||
assert_equals(event.changed[0].value, 'cookie-value');
|
||||
assert_equals(event.deleted.length, 0);
|
||||
assert_true(event instanceof ExtendableCookieChangeEvent);
|
||||
assert_true(event instanceof ExtendableEvent);
|
||||
|
||||
await async_cleanup(() => { cookieStore.delete('cookie-name'); });
|
||||
}, 'cookiechange dispatched with cookie change that matches subscription');
|
||||
|
||||
done();
|
|
@ -0,0 +1,22 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Async Cookies: cookie change events in ServiceWorker</title>
|
||||
<link rel="help" href="https://github.com/WICG/cookie-store">
|
||||
<link rel="author" href="pwnall@chromium.org" title="Victor Costan">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
(async () => {
|
||||
const scope = 'scope';
|
||||
|
||||
let registration = await navigator.serviceWorker.getRegistration(scope);
|
||||
if (registration)
|
||||
await registration.unregister();
|
||||
registration = await navigator.serviceWorker.register(
|
||||
'serviceworker_cookieStore_subscriptions_basic.js', {scope});
|
||||
|
||||
fetch_tests_from_worker(registration.installing);
|
||||
})();
|
||||
</script>
|
|
@ -13,13 +13,26 @@ dictionary CookieChangeEventInit : EventInit {
|
|||
};
|
||||
|
||||
[
|
||||
Exposed=(ServiceWorker,Window),
|
||||
Exposed=Window,
|
||||
Constructor(DOMString type, optional CookieChangeEventInit eventInitDict)
|
||||
] interface CookieChangeEvent : Event {
|
||||
readonly attribute CookieList changed;
|
||||
readonly attribute CookieList deleted;
|
||||
};
|
||||
|
||||
dictionary ExtendableCookieChangeEventInit : ExtendableEventInit {
|
||||
CookieList changed;
|
||||
CookieList deleted;
|
||||
};
|
||||
|
||||
[
|
||||
Exposed=ServiceWorker,
|
||||
Constructor(DOMString type, optional ExtendableCookieChangeEventInit eventInitDict)
|
||||
] interface ExtendableCookieChangeEvent : ExtendableEvent {
|
||||
readonly attribute CookieList changed;
|
||||
readonly attribute CookieList deleted;
|
||||
};
|
||||
|
||||
enum CookieMatchType {
|
||||
"equals",
|
||||
"startsWith"
|
||||
|
@ -59,7 +72,11 @@ dictionary CookieStoreSetOptions {
|
|||
Promise<void> delete(USVString name, optional CookieStoreSetOptions options);
|
||||
Promise<void> delete(CookieStoreSetOptions options);
|
||||
|
||||
attribute EventHandler onchange;
|
||||
[Exposed=ServiceWorker] Promise<void> subscribeToChanges(sequence<CookieStoreGetOptions> subscriptions);
|
||||
|
||||
[Exposed=ServiceWorker] Promise<sequence<CookieStoreGetOptions>> getChangeSubscriptions();
|
||||
|
||||
[Exposed=Window] attribute EventHandler onchange;
|
||||
};
|
||||
|
||||
partial interface Window {
|
||||
|
|
Загрузка…
Ссылка в новой задаче