summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webstorage
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webstorage')
-rw-r--r--testing/web-platform/tests/webstorage/META.yml6
-rw-r--r--testing/web-platform/tests/webstorage/README.md4
-rw-r--r--testing/web-platform/tests/webstorage/defineProperty.window.js57
-rw-r--r--testing/web-platform/tests/webstorage/document-domain.html20
-rw-r--r--testing/web-platform/tests/webstorage/eventTestHarness.js54
-rw-r--r--testing/web-platform/tests/webstorage/event_basic.html15
-rw-r--r--testing/web-platform/tests/webstorage/event_basic.js128
-rw-r--r--testing/web-platform/tests/webstorage/event_body_attribute.html15
-rw-r--r--testing/web-platform/tests/webstorage/event_body_attribute.js116
-rw-r--r--testing/web-platform/tests/webstorage/event_case_sensitive.html15
-rw-r--r--testing/web-platform/tests/webstorage/event_case_sensitive.js52
-rw-r--r--testing/web-platform/tests/webstorage/event_constructor.window.js69
-rw-r--r--testing/web-platform/tests/webstorage/event_initstorageevent.window.js60
-rw-r--r--testing/web-platform/tests/webstorage/event_local_key.html38
-rw-r--r--testing/web-platform/tests/webstorage/event_local_newvalue.html38
-rw-r--r--testing/web-platform/tests/webstorage/event_local_oldvalue.html38
-rw-r--r--testing/web-platform/tests/webstorage/event_local_removeitem.html45
-rw-r--r--testing/web-platform/tests/webstorage/event_local_storagearea.html39
-rw-r--r--testing/web-platform/tests/webstorage/event_local_url.html43
-rw-r--r--testing/web-platform/tests/webstorage/event_no_duplicates.html111
-rw-r--r--testing/web-platform/tests/webstorage/event_session_key.html38
-rw-r--r--testing/web-platform/tests/webstorage/event_session_newvalue.html40
-rw-r--r--testing/web-platform/tests/webstorage/event_session_oldvalue.html38
-rw-r--r--testing/web-platform/tests/webstorage/event_session_removeitem.html44
-rw-r--r--testing/web-platform/tests/webstorage/event_session_storagearea.html40
-rw-r--r--testing/web-platform/tests/webstorage/event_session_url.html43
-rw-r--r--testing/web-platform/tests/webstorage/event_setattribute.html15
-rw-r--r--testing/web-platform/tests/webstorage/event_setattribute.js115
-rw-r--r--testing/web-platform/tests/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html75
-rw-r--r--testing/web-platform/tests/webstorage/localstorage-basic-partitioned.tentative.sub.html61
-rw-r--r--testing/web-platform/tests/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js27
-rw-r--r--testing/web-platform/tests/webstorage/missing_arguments.window.js17
-rw-r--r--testing/web-platform/tests/webstorage/resources/event_basic.html16
-rw-r--r--testing/web-platform/tests/webstorage/resources/event_body_handler.html14
-rw-r--r--testing/web-platform/tests/webstorage/resources/event_setattribute_handler.html15
-rw-r--r--testing/web-platform/tests/webstorage/resources/local_change_item_iframe.html18
-rw-r--r--testing/web-platform/tests/webstorage/resources/local_set_item_clear_iframe.html17
-rw-r--r--testing/web-platform/tests/webstorage/resources/local_set_item_iframe.html16
-rw-r--r--testing/web-platform/tests/webstorage/resources/local_set_item_remove_iframe.html11
-rw-r--r--testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-iframe.html41
-rw-r--r--testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-win-open.html37
-rw-r--r--testing/web-platform/tests/webstorage/resources/partitioning-utils.js20
-rw-r--r--testing/web-platform/tests/webstorage/resources/sessionStorage-about-blank-partitioned-iframe.html44
-rw-r--r--testing/web-platform/tests/webstorage/resources/session_change_item_iframe.html18
-rw-r--r--testing/web-platform/tests/webstorage/resources/session_set_item_clear_iframe.html17
-rw-r--r--testing/web-platform/tests/webstorage/resources/session_set_item_iframe.html16
-rw-r--r--testing/web-platform/tests/webstorage/resources/session_set_item_remove_iframe.html11
-rw-r--r--testing/web-platform/tests/webstorage/resources/storage_local_window_open_second.html36
-rw-r--r--testing/web-platform/tests/webstorage/resources/storage_session_window_noopener_second.html34
-rw-r--r--testing/web-platform/tests/webstorage/resources/storage_session_window_open_second.html41
-rw-r--r--testing/web-platform/tests/webstorage/sessionStorage-basic-partitioned.tentative.sub.html73
-rw-r--r--testing/web-platform/tests/webstorage/set.window.js102
-rw-r--r--testing/web-platform/tests/webstorage/storage_builtins.window.js16
-rw-r--r--testing/web-platform/tests/webstorage/storage_clear.window.js16
-rw-r--r--testing/web-platform/tests/webstorage/storage_enumerate.window.js55
-rw-r--r--testing/web-platform/tests/webstorage/storage_functions_not_overwritten.window.js37
-rw-r--r--testing/web-platform/tests/webstorage/storage_getitem.window.js34
-rw-r--r--testing/web-platform/tests/webstorage/storage_in.window.js22
-rw-r--r--testing/web-platform/tests/webstorage/storage_indexing.window.js28
-rw-r--r--testing/web-platform/tests/webstorage/storage_key.window.js51
-rw-r--r--testing/web-platform/tests/webstorage/storage_key_empty_string.window.js10
-rw-r--r--testing/web-platform/tests/webstorage/storage_length.window.js23
-rw-r--r--testing/web-platform/tests/webstorage/storage_local-manual.html40
-rw-r--r--testing/web-platform/tests/webstorage/storage_local_setitem_quotaexceedederr.window.js16
-rw-r--r--testing/web-platform/tests/webstorage/storage_local_window_open.window.js16
-rw-r--r--testing/web-platform/tests/webstorage/storage_removeitem.window.js44
-rw-r--r--testing/web-platform/tests/webstorage/storage_session-manual.html39
-rw-r--r--testing/web-platform/tests/webstorage/storage_session_setitem_quotaexceedederr.window.js16
-rw-r--r--testing/web-platform/tests/webstorage/storage_session_window_noopener.window.js21
-rw-r--r--testing/web-platform/tests/webstorage/storage_session_window_open.window.js17
-rw-r--r--testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js26
-rw-r--r--testing/web-platform/tests/webstorage/storage_set_value_enumerate.window.js21
-rw-r--r--testing/web-platform/tests/webstorage/storage_setitem.window.js215
-rw-r--r--testing/web-platform/tests/webstorage/storage_string_conversion.window.js32
-rw-r--r--testing/web-platform/tests/webstorage/storage_supported_property_names.window.js15
-rw-r--r--testing/web-platform/tests/webstorage/symbol-props.window.js81
76 files changed, 3004 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webstorage/META.yml b/testing/web-platform/tests/webstorage/META.yml
new file mode 100644
index 0000000000..020075c3f2
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/META.yml
@@ -0,0 +1,6 @@
+spec: https://html.spec.whatwg.org/multipage/webstorage.html
+suggested_reviewers:
+ - siusin
+ - inexorabletash
+ - zqzhang
+ - jdm
diff --git a/testing/web-platform/tests/webstorage/README.md b/testing/web-platform/tests/webstorage/README.md
new file mode 100644
index 0000000000..2bbc5fbfb6
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/README.md
@@ -0,0 +1,4 @@
+These are the storage (`localStorage`, `sessionStorage`) tests for the
+[Web storage chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/webstorage.html).
+
+IDL is covered by `/html/dom/idlharness.https.html`.
diff --git a/testing/web-platform/tests/webstorage/defineProperty.window.js b/testing/web-platform/tests/webstorage/defineProperty.window.js
new file mode 100644
index 0000000000..d8ab163df6
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/defineProperty.window.js
@@ -0,0 +1,57 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ [9, "x"].forEach(function(key) {
+ test(function() {
+ var desc = {
+ value: "value",
+ };
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], undefined);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(Object.defineProperty(storage, key, desc), storage);
+ assert_equals(storage[key], "value");
+ assert_equals(storage.getItem(key), "value");
+ }, "Defining data property for key " + key + " on " + name);
+
+ test(function() {
+ var desc1 = {
+ value: "value",
+ };
+ var desc2 = {
+ value: "new value",
+ };
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], undefined);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(Object.defineProperty(storage, key, desc1), storage);
+ assert_equals(storage[key], "value");
+ assert_equals(storage.getItem(key), "value");
+
+ assert_equals(Object.defineProperty(storage, key, desc2), storage);
+ assert_equals(storage[key], "new value");
+ assert_equals(storage.getItem(key), "new value");
+ }, "Defining data property for key " + key + " on " + name + " twice");
+
+ test(function() {
+ var desc = {
+ value: {
+ toString: function() { return "value"; }
+ },
+ };
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], undefined);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(Object.defineProperty(storage, key, desc), storage);
+ assert_equals(storage[key], "value");
+ assert_equals(storage.getItem(key), "value");
+ }, "Defining data property with toString for key " + key + " on " + name);
+ });
+});
diff --git a/testing/web-platform/tests/webstorage/document-domain.html b/testing/web-platform/tests/webstorage/document-domain.html
new file mode 100644
index 0000000000..3232b0d508
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/document-domain.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>localStorage and document.domain</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<iframe></iframe>
+<script>
+ async_test(function(t) {
+ frames[0].addEventListener("storage", function(e) {
+ t.step(function() {
+ localStorage.clear()
+ t.done()
+ })
+ })
+ frames[0].document.domain = document.domain
+ localStorage.setItem("test", "test")
+ })
+</script>
diff --git a/testing/web-platform/tests/webstorage/eventTestHarness.js b/testing/web-platform/tests/webstorage/eventTestHarness.js
new file mode 100644
index 0000000000..0a98546ace
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/eventTestHarness.js
@@ -0,0 +1,54 @@
+storageEventList = [];
+iframe = document.createElement("IFRAME");
+document.body.appendChild(iframe);
+
+function runAfterNStorageEvents(callback, expectedNumEvents)
+{
+ countStorageEvents(callback, expectedNumEvents, 0)
+}
+
+function countStorageEvents(callback, expectedNumEvents, times)
+{
+ function onTimeout()
+ {
+ var currentCount = storageEventList.length;
+ if (currentCount == expectedNumEvents) {
+ callback();
+ } else if (currentCount > expectedNumEvents) {
+ msg = "got at least " + currentCount + ", expected only " + expectedNumEvents + " events";
+ callback(msg);
+ } else if (times > 50) {
+ msg = "Timeout: only got " + currentCount + ", expected " + expectedNumEvents + " events";
+ callback(msg);
+ } else {
+ countStorageEvents(callback, expectedNumEvents, times+1);
+ }
+ }
+ setTimeout(onTimeout, 20);
+}
+
+function clearStorage(storageName, callback)
+{
+ if (window[storageName].length === 0) {
+ storageEventList = [];
+ setTimeout(callback, 0);
+ } else {
+ window[storageName].clear();
+ runAfterNStorageEvents(function() {
+ storageEventList = [];
+ callback();
+ }, 1);
+ }
+}
+
+function testStorages(testCallback)
+{
+ testCallback("sessionStorage");
+ var hit = false;
+ add_result_callback(function() {
+ if (!hit) {
+ hit = true;
+ testCallback("localStorage");
+ }
+ });
+}
diff --git a/testing/web-platform/tests/webstorage/event_basic.html b/testing/web-platform/tests/webstorage/event_basic.html
new file mode 100644
index 0000000000..407e41c4b1
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_basic.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta name="timeout" content="long">
+<title>WebStorage Test: StorageEvent - window.onstorage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script src="eventTestHarness.js"></script>
+<script src="event_basic.js"></script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/webstorage/event_basic.js b/testing/web-platform/tests/webstorage/event_basic.js
new file mode 100644
index 0000000000..09f5f1bfb9
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_basic.js
@@ -0,0 +1,128 @@
+testStorages(function(storageString) {
+ async_test(function(t) {
+ assert_true(storageString in window, storageString + " exist");
+ var storage = window[storageString];
+ t.add_cleanup(function() { storage.clear() });
+
+ clearStorage(storageString, t.step_func(loadiframe));
+ assert_equals(storage.length, 0, "storage.length");
+
+ function loadiframe(msg)
+ {
+ iframe.onload = t.step_func(step1);
+ iframe.src = "resources/event_basic.html";
+ }
+
+ function step1(msg)
+ {
+ storage.setItem('FOO', 'BAR');
+
+ runAfterNStorageEvents(t.step_func(step2), 1);
+ }
+
+ function step2(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 1);
+ assert_equals(storageEventList[0].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[0].key, "FOO");
+ assert_equals(storageEventList[0].oldValue, null);
+ assert_equals(storageEventList[0].newValue, "BAR");
+
+ storage.setItem('FU', 'BAR');
+ storage.setItem('a', '1');
+ storage.setItem('b', '2');
+ storage.setItem('b', '3');
+
+ runAfterNStorageEvents(t.step_func(step3), 5);
+ }
+
+ function step3(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 5);
+ assert_equals(storageEventList[1].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[1].key, "FU");
+ assert_equals(storageEventList[1].oldValue, null);
+ assert_equals(storageEventList[1].newValue, "BAR");
+
+ assert_equals(storageEventList[2].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[2].key, "a");
+ assert_equals(storageEventList[2].oldValue, null);
+ assert_equals(storageEventList[2].newValue, "1");
+
+ assert_equals(storageEventList[3].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[3].key, "b");
+ assert_equals(storageEventList[3].oldValue, null);
+ assert_equals(storageEventList[3].newValue, "2");
+
+ assert_equals(storageEventList[4].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[4].key, "b");
+ assert_equals(storageEventList[4].oldValue, "2");
+ assert_equals(storageEventList[4].newValue, "3");
+
+ storage.removeItem('FOO');
+
+ runAfterNStorageEvents(t.step_func(step4), 6);
+ }
+
+ function step4(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 6);
+ assert_equals(storageEventList[5].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[5].key, "FOO");
+ assert_equals(storageEventList[5].oldValue, "BAR");
+ assert_equals(storageEventList[5].newValue, null);
+
+ storage.removeItem('FU');
+
+ runAfterNStorageEvents(t.step_func(step5), 7);
+ }
+
+ function step5(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 7);
+ assert_equals(storageEventList[6].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[6].key, "FU");
+ assert_equals(storageEventList[6].oldValue, "BAR");
+ assert_equals(storageEventList[6].newValue, null);
+
+ storage.clear();
+
+ runAfterNStorageEvents(t.step_func(step6), 8);
+ }
+
+ function step6(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 8);
+ assert_equals(storageEventList[7].storageAreaString, storageString,
+ "Storage event came from wrong storage type.");
+ assert_equals(storageEventList[7].key, null);
+ assert_equals(storageEventList[7].oldValue, null);
+ assert_equals(storageEventList[7].newValue, null);
+
+ t.done();
+ }
+
+ }, storageString + " mutations fire StorageEvents that are caught by the event listener set via window.onstorage.");
+});
diff --git a/testing/web-platform/tests/webstorage/event_body_attribute.html b/testing/web-platform/tests/webstorage/event_body_attribute.html
new file mode 100644
index 0000000000..80ec676186
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_body_attribute.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta name="timeout" content="long">
+<title>WebStorage Test: StorageEvent - set onstorage as body attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script src="eventTestHarness.js"></script>
+<script src="event_body_attribute.js"></script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/webstorage/event_body_attribute.js b/testing/web-platform/tests/webstorage/event_body_attribute.js
new file mode 100644
index 0000000000..a0e596da95
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_body_attribute.js
@@ -0,0 +1,116 @@
+testStorages(function(storageString) {
+ async_test(function(t) {
+ assert_true(storageString in window, storageString + " exist");
+ var storage = window[storageString];
+ t.add_cleanup(function() { storage.clear() });
+
+ clearStorage(storageString, t.step_func(step0));
+ assert_equals(storage.length, 0, "storage.length");
+
+ function step0(msg)
+ {
+ iframe.onload = t.step_func(step1);
+ // Null out the existing handler eventTestHarness.js set up;
+ // otherwise this test won't be testing much of anything useful.
+ iframe.contentWindow.onstorage = null;
+ iframe.src = "resources/event_body_handler.html";
+ }
+
+ function step1(msg)
+ {
+ storageEventList = new Array();
+ storage.setItem('FOO', 'BAR');
+
+ runAfterNStorageEvents(t.step_func(step2), 1);
+ }
+
+ function step2(msg)
+ {
+ if (msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 1);
+ assert_equals(storageEventList[0].key, "FOO");
+ assert_equals(storageEventList[0].oldValue, null);
+ assert_equals(storageEventList[0].newValue, "BAR");
+
+ storage.setItem('FU', 'BAR');
+ storage.setItem('a', '1');
+ storage.setItem('b', '2');
+ storage.setItem('b', '3');
+
+ runAfterNStorageEvents(t.step_func(step3), 5);
+ }
+
+ function step3(msg)
+ {
+ if (msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 5);
+ assert_equals(storageEventList[1].key, "FU");
+ assert_equals(storageEventList[1].oldValue, null);
+ assert_equals(storageEventList[1].newValue, "BAR");
+
+ assert_equals(storageEventList[2].key, "a");
+ assert_equals(storageEventList[2].oldValue, null);
+ assert_equals(storageEventList[2].newValue, "1");
+
+ assert_equals(storageEventList[3].key, "b");
+ assert_equals(storageEventList[3].oldValue, null);
+ assert_equals(storageEventList[3].newValue, "2");
+
+ assert_equals(storageEventList[4].key, "b");
+ assert_equals(storageEventList[4].oldValue, "2");
+ assert_equals(storageEventList[4].newValue, "3");
+
+ storage.removeItem('FOO');
+
+ runAfterNStorageEvents(t.step_func(step4), 6);
+ }
+
+ function step4(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 6);
+ assert_equals(storageEventList[5].key, "FOO");
+ assert_equals(storageEventList[5].oldValue, "BAR");
+ assert_equals(storageEventList[5].newValue, null);
+
+ storage.removeItem('FU');
+
+ runAfterNStorageEvents(t.step_func(step5), 7);
+ }
+
+ function step5(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 7);
+ assert_equals(storageEventList[6].key, "FU");
+ assert_equals(storageEventList[6].oldValue, "BAR");
+ assert_equals(storageEventList[6].newValue, null);
+
+ storage.clear();
+
+ runAfterNStorageEvents(t.step_func(step6), 8);
+ }
+
+ function step6(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 8);
+ assert_equals(storageEventList[7].key, null);
+ assert_equals(storageEventList[7].oldValue, null);
+ assert_equals(storageEventList[7].newValue, null);
+
+ t.done();
+ }
+
+ }, storageString + " mutations fire StorageEvents that are caught by the event listener specified as an attribute on the body.");
+});
diff --git a/testing/web-platform/tests/webstorage/event_case_sensitive.html b/testing/web-platform/tests/webstorage/event_case_sensitive.html
new file mode 100644
index 0000000000..916b230412
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_case_sensitive.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta name="timeout" content="long">
+<title>WebStorage Test: StorageEvent - the case of value changed</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script src="eventTestHarness.js"></script>
+<script src="event_case_sensitive.js"></script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/webstorage/event_case_sensitive.js b/testing/web-platform/tests/webstorage/event_case_sensitive.js
new file mode 100644
index 0000000000..9c9397fd5a
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_case_sensitive.js
@@ -0,0 +1,52 @@
+testStorages(function(storageString) {
+ async_test(function(t) {
+ assert_true(storageString in window, storageString + " exist");
+ var storage = window[storageString];
+ t.add_cleanup(function() { storage.clear() });
+
+ clearStorage(storageString, t.step_func(loadiframe));
+ assert_equals(storage.length, 0, "storage.length");
+
+ function loadiframe(msg)
+ {
+ iframe.onload = t.step_func(step0);
+ iframe.src = "resources/event_basic.html";
+ }
+
+ function step0(msg)
+ {
+ storage.foo = "test";
+ runAfterNStorageEvents(t.step_func(step1), 1);
+ }
+
+ function step1(msg)
+ {
+ storageEventList = new Array();
+ storage.foo = "test";
+
+ runAfterNStorageEvents(t.step_func(step2), 0);
+ }
+
+ function step2(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 0);
+
+ storage.foo = "TEST";
+
+ runAfterNStorageEvents(t.step_func(step3), 1);
+ }
+
+ function step3(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 1);
+
+ t.done();
+ }
+ }, storageString + " storage events fire even when only the case of the value changes.");
+});
diff --git a/testing/web-platform/tests/webstorage/event_constructor.window.js b/testing/web-platform/tests/webstorage/event_constructor.window.js
new file mode 100644
index 0000000000..ba7dd91965
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_constructor.window.js
@@ -0,0 +1,69 @@
+test(function() {
+ assert_throws_js(TypeError, () => new StorageEvent());
+ // should be redundant, but .length can be wrong with custom bindings
+ assert_equals(StorageEvent.length, 1, 'StorageEvent.length');
+}, 'constructor with no arguments');
+
+test(function() {
+ var event = new StorageEvent('type');
+ assert_equals(event.type, 'type', 'type');
+ assert_equals(event.key, null, 'key');
+ assert_equals(event.oldValue, null, 'oldValue');
+ assert_equals(event.newValue, null, 'newValue');
+ assert_equals(event.url, '', 'url');
+ assert_equals(event.storageArea, null, 'storageArea');
+}, 'constructor with just type argument');
+
+test(function() {
+ assert_not_equals(localStorage, null, 'localStorage'); // precondition
+
+ var event = new StorageEvent('storage', {
+ bubbles: true,
+ cancelable: true,
+ key: 'key',
+ oldValue: 'oldValue',
+ newValue: 'newValue',
+ url: 'url', // not an absolute URL to ensure it isn't resolved
+ storageArea: localStorage
+ });
+ assert_equals(event.type, 'storage', 'type');
+ assert_equals(event.bubbles, true, 'bubbles');
+ assert_equals(event.cancelable, true, 'cancelable');
+ assert_equals(event.key, 'key', 'key');
+ assert_equals(event.oldValue, 'oldValue', 'oldValue');
+ assert_equals(event.newValue, 'newValue', 'newValue');
+ assert_equals(event.url, 'url', 'url');
+ assert_equals(event.storageArea, localStorage, 'storageArea');
+}, 'constructor with sensible type argument and members');
+
+test(function() {
+ var event = new StorageEvent(null, {
+ key: null,
+ oldValue: null,
+ newValue: null,
+ url: null,
+ storageArea: null
+ });
+ assert_equals(event.type, 'null', 'type');
+ assert_equals(event.key, null, 'key');
+ assert_equals(event.oldValue, null, 'oldValue');
+ assert_equals(event.newValue, null, 'newValue');
+ assert_equals(event.url, 'null', 'url');
+ assert_equals(event.storageArea, null, 'storageArea');
+}, 'constructor with null type argument and members');
+
+test(function() {
+ var event = new StorageEvent(undefined, {
+ key: undefined,
+ oldValue: undefined,
+ newValue: undefined,
+ url: undefined,
+ storageArea: undefined
+ });
+ assert_equals(event.type, 'undefined', 'type');
+ assert_equals(event.key, null, 'key');
+ assert_equals(event.oldValue, null, 'oldValue');
+ assert_equals(event.newValue, null, 'newValue');
+ assert_equals(event.url, '', 'url'); // not 'undefined'!
+ assert_equals(event.storageArea, null, 'storageArea');
+}, 'constructor with undefined type argument and members');
diff --git a/testing/web-platform/tests/webstorage/event_initstorageevent.window.js b/testing/web-platform/tests/webstorage/event_initstorageevent.window.js
new file mode 100644
index 0000000000..ac0a757021
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_initstorageevent.window.js
@@ -0,0 +1,60 @@
+test(() => {
+ const event = new StorageEvent('storage');
+ assert_throws_js(TypeError, () => event.initStorageEvent());
+ // should be redundant, but .length can be wrong with custom bindings
+ assert_equals(event.initStorageEvent.length, 1, 'event.initStorageEvent.length');
+}, 'initStorageEvent with 0 arguments');
+
+test(() => {
+ const event = new StorageEvent('storage');
+ event.initStorageEvent('type');
+ assert_equals(event.type, 'type', 'event.type');
+ assert_equals(event.bubbles, false, 'event.bubbles');
+ assert_equals(event.cancelable, false, 'event.cancelable');
+ assert_equals(event.key, null, 'event.key');
+ assert_equals(event.oldValue, null, 'event.oldValue');
+ assert_equals(event.newValue, null, 'event.newValue');
+ assert_equals(event.url, '', 'event.url');
+ assert_equals(event.storageArea, null, 'event.storageArea');
+}, 'initStorageEvent with 1 argument');
+
+test(() => {
+ assert_not_equals(localStorage, null, 'localStorage'); // precondition
+
+ const event = new StorageEvent('storage');
+ event.initStorageEvent('type', true, true, 'key', 'oldValue', 'newValue', 'url', localStorage);
+ assert_equals(event.type, 'type', 'event.type');
+ assert_equals(event.bubbles, true, 'event.bubbles');
+ assert_equals(event.cancelable, true, 'event.cancelable');
+ assert_equals(event.key, 'key', 'event.key');
+ assert_equals(event.oldValue, 'oldValue', 'event.oldValue');
+ assert_equals(event.newValue, 'newValue', 'event.newValue');
+ assert_equals(event.url, 'url', 'event.url');
+ assert_equals(event.storageArea, localStorage, 'event.storageArea');
+}, 'initStorageEvent with 8 sensible arguments');
+
+test(() => {
+ const event = new StorageEvent('storage');
+ event.initStorageEvent(null, null, null, null, null, null, null, null);
+ assert_equals(event.type, 'null', 'event.type');
+ assert_equals(event.bubbles, false, 'event.bubbles');
+ assert_equals(event.cancelable, false, 'event.cancelable');
+ assert_equals(event.key, null, 'event.key');
+ assert_equals(event.oldValue, null, 'event.oldValue');
+ assert_equals(event.newValue, null, 'event.newValue');
+ assert_equals(event.url, 'null', 'event.url');
+ assert_equals(event.storageArea, null, 'event.storageArea');
+}, 'initStorageEvent with 8 null arguments');
+
+test(() => {
+ const event = new StorageEvent('storage');
+ event.initStorageEvent(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
+ assert_equals(event.type, 'undefined', 'event.type');
+ assert_equals(event.bubbles, false, 'event.bubbles');
+ assert_equals(event.cancelable, false, 'event.cancelable');
+ assert_equals(event.key, null, 'event.key');
+ assert_equals(event.oldValue, null, 'event.oldValue');
+ assert_equals(event.newValue, null, 'event.newValue');
+ assert_equals(event.url, '', 'event.url');
+ assert_equals(event.storageArea, null, 'event.storageArea');
+}, 'initStorageEvent with 8 undefined arguments');
diff --git a/testing/web-platform/tests/webstorage/event_local_key.html b/testing/web-platform/tests/webstorage/event_local_key.html
new file mode 100644
index 0000000000..84512da2d2
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_key.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: localStorage event - key</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_local_key</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = ['name', null]
+ function onStorageEvent(event) {
+ assert_equals(event.key, expected.shift());
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_set_item_clear_iframe.html');
+ document.body.appendChild(el);
+ }, "key property test of local event - Local event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_local_newvalue.html b/testing/web-platform/tests/webstorage/event_local_newvalue.html
new file mode 100644
index 0000000000..2b743c37bf
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_newvalue.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: localStorage event - newValue</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_local_newValue</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = ['user1', 'user2', null]
+ function onStorageEvent(event) {
+ assert_equals(event.newValue, expected.shift());
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_change_item_iframe.html');
+ document.body.appendChild(el);
+ }, "newValue property test of local event - Local event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_local_oldvalue.html b/testing/web-platform/tests/webstorage/event_local_oldvalue.html
new file mode 100644
index 0000000000..87c79aa07d
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_oldvalue.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: localStorage event - oldValue</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_local_oldValue</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = [null, 'user1', null]
+ function onStorageEvent(event) {
+ assert_equals(event.oldValue, expected.shift());
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_change_item_iframe.html');
+ document.body.appendChild(el);
+ }, "oldValue property test of local event - Local event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_local_removeitem.html b/testing/web-platform/tests/webstorage/event_local_removeitem.html
new file mode 100644
index 0000000000..7b81ea2bac
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_removeitem.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Web Storage Test: event - localStorage removeItem</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+
+<script>
+
+async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.step = function(f) { t.step(f); };
+
+ var event_index = 0;
+ window.addEventListener('storage', t.step_func(function(event) {
+ switch(++event_index) {
+ case 1:
+ assert_equals(event.key, "name", "set key");
+ assert_equals(event.oldValue, null, "set oldValue");
+ assert_equals(event.newValue, "user1", "set newValue");
+ assert_equals(event.url, el.contentDocument.documentURI, "set url");
+ assert_equals(event.storageArea, localStorage, "set storageArea");
+ break;
+ case 2:
+ assert_equals(event.key, "name", "remove key");
+ assert_equals(event.oldValue, "user1", "remove oldValue");
+ assert_equals(event.newValue, null, "remove newValue");
+ assert_equals(event.url, el.contentDocument.documentURI, "remove url");
+ assert_equals(event.storageArea, localStorage, "remove storageArea");
+ t.done();
+ break;
+ }
+ }), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_set_item_remove_iframe.html');
+ document.body.appendChild(el);
+}, "key property test of local event");
+
+</script>
diff --git a/testing/web-platform/tests/webstorage/event_local_storagearea.html b/testing/web-platform/tests/webstorage/event_local_storagearea.html
new file mode 100644
index 0000000000..db4b114a95
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_storagearea.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: localStorage event - storageArea</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_local_storageArea</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ function onStorageEvent(event) {
+ assert_equals(event.storageArea.length, 1);
+ var key = event.storageArea.key(0);
+ var value = event.storageArea.getItem(key);
+ assert_equals(key, "name");
+ assert_equals(value, "user1");
+ t.done();
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_set_item_iframe.html');
+ document.body.appendChild(el);
+ }, "storageArea property test of local event - Local event is fired due to an invocation of the setItem() method.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_local_url.html b/testing/web-platform/tests/webstorage/event_local_url.html
new file mode 100644
index 0000000000..7345ce3736
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_local_url.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: localStorage event - url</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_local_url</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ localStorage.clear();
+ t.add_cleanup(function() { localStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ function onStorageEvent(event) {
+ var url = window.location.href;
+
+ var pos = url.lastIndexOf("/");
+ if (pos != -1) {
+ url = url.substr(0, pos + 1);
+ url = url + "resources/local_set_item_iframe.html";
+ }
+
+ assert_equals(event.url, url);
+ t.done();
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/local_set_item_iframe.html');
+ document.body.appendChild(el);
+ }, "url property test of local event - Local event is fired due to an invocation of the setItem() method.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_no_duplicates.html b/testing/web-platform/tests/webstorage/event_no_duplicates.html
new file mode 100644
index 0000000000..8fbea2bef9
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_no_duplicates.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<title>WebStorage Test: StorageEvent - only if something changes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+const iframe = document.createElement('iframe');
+
+function tests(storageName) {
+ test(t => assert_true(storageName in window), storageName + ' exists');
+
+ const storage = window[storageName];
+ const iframeStorage = iframe.contentWindow[storageName];
+
+ add_completion_callback(() => {
+ storage.clear();
+ });
+
+ promise_test(t => {
+ const w = new EventWatcher(t, iframe.contentWindow, 'storage');
+
+ // Random key to make sure we don't conflict with any cruft leftover from
+ // earlier runs. Any synchronization would be really hard with localStorage
+ // limited guarantees.
+ const testKey = Math.random().toString(36).slice(2);
+
+ storage.setItem(testKey, 'foo');
+ storage.setItem(testKey, 'foo');
+ storage.setItem(testKey, 'bar');
+ return w.wait_for('storage')
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, testKey);
+ assert_equals(e.newValue, 'foo');
+ return w.wait_for('storage');
+ })
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, testKey);
+ assert_equals(e.oldValue, 'foo');
+ assert_equals(e.newValue, 'bar');
+ });
+ }, 'Setting to same value does not trigger event for ' + storageName);
+
+ promise_test(t => {
+ const w = new EventWatcher(t, iframe.contentWindow, 'storage');
+
+ // Random key to make sure we don't conflict with any cruft leftover from
+ // earlier runs. Any synchronization would be really hard with localStorage
+ // limited guarantees.
+ const testKey1 = Math.random().toString(36).slice(2);
+ const testKey2 = Math.random().toString(36).slice(2);
+
+ storage.removeItem(testKey1);
+ storage.setItem(testKey2, 'foo');
+ return w.wait_for('storage')
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, testKey2);
+ assert_equals(e.newValue, 'foo');
+ });
+ }, 'Deleting non-existent key does not trigger event for ' + storageName);
+
+
+ promise_test(t => {
+ const w = new EventWatcher(t, iframe.contentWindow, 'storage');
+
+ // Random key to make sure we don't conflict with any cruft leftover from
+ // earlier runs. Any synchronization would be really hard with localStorage
+ // limited guarantees.
+ const testKey = Math.random().toString(36).slice(2);
+
+ storage.setItem(testKey, 'foo');
+ storage.clear();
+ storage.clear();
+ storage.setItem(testKey, 'bar');
+ return w.wait_for('storage')
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, testKey);
+ assert_equals(e.newValue, 'foo');
+ return w.wait_for('storage');
+ })
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, null);
+ assert_equals(e.oldValue, null);
+ assert_equals(e.newValue, null);
+ return w.wait_for('storage');
+ })
+ .then(e => {
+ assert_equals(e.storageArea, iframeStorage);
+ assert_equals(e.key, testKey);
+ assert_equals(e.oldValue, null);
+ assert_equals(e.newValue, 'bar');
+ });
+ }, 'Clearing empty storage does not trigger event for ' + storageName);
+
+}
+
+iframe.src = "resources/event_basic.html";
+iframe.onload = () => {
+ tests('sessionStorage');
+ tests('localStorage');
+};
+document.body.appendChild(iframe);
+</script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/webstorage/event_session_key.html b/testing/web-platform/tests/webstorage/event_session_key.html
new file mode 100644
index 0000000000..62600aa394
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_key.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: sessionStorage event - key</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_session_key</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = ['name', null]
+ function onStorageEvent(event) {
+ assert_equals(event.key, expected.shift());
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_set_item_clear_iframe.html');
+ document.body.appendChild(el);
+ }, "key property test of session event - Session event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_session_newvalue.html b/testing/web-platform/tests/webstorage/event_session_newvalue.html
new file mode 100644
index 0000000000..1f367988e0
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_newvalue.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: sessionStorage event - newValue</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_session_newValue</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = ['user1', 'user2', null]
+ function onStorageEvent(event) {
+ t.step(function() {
+ assert_equals(event.newValue, expected.shift());
+ });
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_change_item_iframe.html');
+ document.body.appendChild(el);
+ }, "newvalue property test of session event - Session event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_session_oldvalue.html b/testing/web-platform/tests/webstorage/event_session_oldvalue.html
new file mode 100644
index 0000000000..00400df252
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_oldvalue.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: sessionStorage event - oldValue</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_session_oldValue</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ var expected = [null, 'user1', null]
+ function onStorageEvent(event) {
+ assert_equals(event.oldValue, expected.shift());
+ if (!expected.length) {
+ t.done();
+ }
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_change_item_iframe.html');
+ document.body.appendChild(el);
+ }, "oldvalue property test of session event - Session event is fired due to an invocation of the setItem(), clear() methods.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_session_removeitem.html b/testing/web-platform/tests/webstorage/event_session_removeitem.html
new file mode 100644
index 0000000000..7b3c6446ed
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_removeitem.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Web Storage Test: event - sessionStorage removeItem</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id="log"></div>
+
+<script>
+
+async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.step = function(f) { t.step(f); };
+
+ var event_index = 0;
+ window.addEventListener('storage', t.step_func(function(event) {
+ switch(++event_index) {
+ case 1:
+ assert_equals(event.key, "name", "set key");
+ assert_equals(event.oldValue, null, "set oldValue");
+ assert_equals(event.newValue, "user1", "set newValue");
+ assert_equals(event.url, el.contentDocument.documentURI, "set url");
+ assert_equals(event.storageArea, sessionStorage, "set storageArea");
+ break;
+ case 2:
+ assert_equals(event.key, "name", "remove key");
+ assert_equals(event.oldValue, "user1", "remove oldValue");
+ assert_equals(event.newValue, null, "remove newValue");
+ assert_equals(event.url, el.contentDocument.documentURI, "remove url");
+ assert_equals(event.storageArea, sessionStorage, "remove storageArea");
+ t.done();
+ break;
+ }
+ }), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_set_item_remove_iframe.html');
+ document.body.appendChild(el);
+}, "key property test of session event");
+</script>
diff --git a/testing/web-platform/tests/webstorage/event_session_storagearea.html b/testing/web-platform/tests/webstorage/event_session_storagearea.html
new file mode 100644
index 0000000000..d2c2ba437e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_storagearea.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: sessionStorage event - storageArea</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_session_storageArea</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ function onStorageEvent(event) {
+ assert_equals(event.storageArea.length, 1);
+ var key = event.storageArea.key(0);
+ var value = event.storageArea.getItem(key);
+ assert_equals(key, "name");
+ assert_equals(value, "user1");
+ t.done();
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_set_item_iframe.html');
+ document.body.appendChild(el);
+ }, "storageArea property test of session event - session event is fired due to an invocation of the setItem() method.");
+ </script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_session_url.html b/testing/web-platform/tests/webstorage/event_session_url.html
new file mode 100644
index 0000000000..85250acc2b
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_session_url.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>WebStorage Test: sessionStorage event - url</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <h1>event_session_url</h1>
+ <div id="log"></div>
+ <script>
+ async_test(function(t) {
+ sessionStorage.clear();
+ t.add_cleanup(function() { sessionStorage.clear() });
+
+ self.fail = t.step_func(function(msg) {
+ assert_unreached(msg);
+ t.done();
+ });
+
+ function onStorageEvent(event) {
+ var url = window.location.href;
+
+ var pos = url.lastIndexOf("/");
+ if (pos != -1) {
+ url = url.substr(0, pos + 1);
+ url = url + "resources/session_set_item_iframe.html";
+ }
+
+ assert_equals(event.url, url);
+ t.done();
+ }
+
+ window.addEventListener('storage', t.step_func(onStorageEvent), false);
+
+ var el = document.createElement("iframe");
+ el.setAttribute('id', 'ifrm');
+ el.setAttribute('src', 'resources/session_set_item_iframe.html');
+ document.body.appendChild(el);
+ }, "url property test of session event - Session event is fired due to an invocation of the setItem() method.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/event_setattribute.html b/testing/web-platform/tests/webstorage/event_setattribute.html
new file mode 100644
index 0000000000..c48a2e0fc3
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_setattribute.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta name="timeout" content="long">
+<title>WebStorage Test: StorageEvent - attached setAttribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<script src="eventTestHarness.js"></script>
+<script src="event_setattribute.js"></script>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/webstorage/event_setattribute.js b/testing/web-platform/tests/webstorage/event_setattribute.js
new file mode 100644
index 0000000000..8070938baf
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/event_setattribute.js
@@ -0,0 +1,115 @@
+testStorages(function(storageString) {
+ async_test(function(t) {
+ assert_true(storageString in window, storageString + " exist");
+ var storage = window[storageString];
+ t.add_cleanup(function() { storage.clear() });
+
+ clearStorage(storageString, t.step_func(step0));
+ assert_equals(storage.length, 0, "storage.length");
+
+ function step0(msg)
+ {
+ iframe.onload = t.step_func(step1);
+ // Null out the existing handler eventTestHarness.js set up;
+ // otherwise this test won't be testing much of anything useful.
+ iframe.contentWindow.onstorage = null;
+ iframe.src = "resources/event_setattribute_handler.html";
+ }
+
+ function step1(msg)
+ {
+ storage.setItem('FOO', 'BAR');
+
+ runAfterNStorageEvents(t.step_func(step2), 1);
+ }
+
+ function step2(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 1);
+ assert_equals(storageEventList[0].key, "FOO");
+ assert_equals(storageEventList[0].oldValue, null);
+ assert_equals(storageEventList[0].newValue, "BAR");
+
+ storage.setItem('FU', 'BAR');
+ storage.setItem('a', '1');
+ storage.setItem('b', '2');
+ storage.setItem('b', '3');
+
+ runAfterNStorageEvents(t.step_func(step3), 5);
+ }
+
+ function step3(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 5);
+ assert_equals(storageEventList[1].key, "FU");
+ assert_equals(storageEventList[1].oldValue, null);
+ assert_equals(storageEventList[1].newValue, "BAR");
+
+ assert_equals(storageEventList[2].key, "a");
+ assert_equals(storageEventList[2].oldValue, null);
+ assert_equals(storageEventList[2].newValue, "1");
+
+ assert_equals(storageEventList[3].key, "b");
+ assert_equals(storageEventList[3].oldValue, null);
+ assert_equals(storageEventList[3].newValue, "2");
+
+ assert_equals(storageEventList[4].key, "b");
+ assert_equals(storageEventList[4].oldValue, "2");
+ assert_equals(storageEventList[4].newValue, "3");
+
+ storage.removeItem('FOO');
+
+ runAfterNStorageEvents(t.step_func(step4), 6);
+ }
+
+ function step4(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 6);
+ assert_equals(storageEventList[5].key, "FOO");
+ assert_equals(storageEventList[5].oldValue, "BAR");
+ assert_equals(storageEventList[5].newValue, null);
+
+ storage.removeItem('FU');
+
+ runAfterNStorageEvents(t.step_func(step5), 7);
+ }
+
+ function step5(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 7);
+ assert_equals(storageEventList[6].key, "FU");
+ assert_equals(storageEventList[6].oldValue, "BAR");
+ assert_equals(storageEventList[6].newValue, null);
+
+ storage.clear();
+
+ runAfterNStorageEvents(t.step_func(step6), 8);
+ }
+
+ function step6(msg)
+ {
+ if(msg != undefined) {
+ assert_unreached(msg);
+ }
+ assert_equals(storageEventList.length, 8);
+ assert_equals(storageEventList[7].key, null);
+ assert_equals(storageEventList[7].oldValue, null);
+ assert_equals(storageEventList[7].newValue, null);
+
+ t.done();
+ }
+
+ }, storageString + " mutations fire StorageEvents that are caught by the event listener attached via setattribute.");
+});
diff --git a/testing/web-platform/tests/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html b/testing/web-platform/tests/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html
new file mode 100644
index 0000000000..de94fb2cf4
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/localstorage-about-blank-3P-iframe-opens-3P-window.partitioned.tentative.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>localStorage: about:blank partitioning</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/webstorage/resources/partitioning-utils.js"></script>
+<body>
+<script>
+const path =
+ "webstorage/resources/localstorage-about-blank-partitioned-win-open.html";
+const crossSiteURL = `${get_host_info().HTTP_NOTSAMESITE_ORIGIN}/${path}`;
+const sameSiteURL = `${get_host_info().HTTP_ORIGIN}/${path}`;
+let firstPartyID = getOrCreateID("userID3");
+let crossSiteIframeID;
+let sameSiteIframeID;
+let crossSiteIframe;
+let crossSiteIframeAboutBlankID;
+let frameMessageCount = 0;
+
+promise_test(async t => {
+ localStorage.clear();
+
+ // Step 1. Add a cross-site iframe
+ return addIframePromise(crossSiteURL).then(async crossSiteIframe => {
+ return new Promise(resolve => {
+ window.addEventListener("message", async e => {
+ const payload = {
+ command: "open about:blank window"
+ }
+
+ if (e.data.message === "window loaded") {
+ // Step 2. cross-site iframe is loaded, capture reference to its ID
+ crossSiteIframeID = e.data.userID;
+ // Step 3. Ask the cross-site iframe to create an about:blank window
+ crossSiteIframe.contentWindow.postMessage(payload, e.origin);
+ }
+
+ if (e.data.message === "about:blank frame ID") {
+ // Step 4. capture reference to 3P iframe's about:blank window ID
+ crossSiteIframeAboutBlankID = e.data.userID;
+ crossSiteIframe.contentWindow.postMessage(
+ {command: "close about:blank window"}, "*");
+ }
+
+ if (e.data.message === "about:blank window closed") {
+ resolve({crossSiteIframeID, crossSiteIframeAboutBlankID});
+ }
+ });
+ }).then(ids => {
+ const {
+ crossSiteIframeID,
+ crossSiteIframeAboutBlankID
+ } = ids;
+ // Step 5. Assert some things
+ for (let id in ids) {
+ assert_true(id !== undefined, "id is not undefined");
+ }
+ // Note: we use assert_true, rather than assert_equals becuase we're
+ // setting random numbers as IDs - this would mean expectations
+ // files wouldn't work as intended.
+ assert_true(crossSiteIframeAboutBlankID !== crossSiteIframeID,
+ "about:blank window opened by 3P iframe does not inherit 3P iframe's StorageKey");
+ assert_true(firstPartyID !== crossSiteIframeAboutBlankID,
+ "about:blank window open by 3P iframe does not inherit 1P StorageKey");
+
+ localStorage.clear();
+ })
+ });
+
+
+}, "StorageKey: test 3P about:blank window opened from a 3P iframe");
+</script>
+</body>
diff --git a/testing/web-platform/tests/webstorage/localstorage-basic-partitioned.tentative.sub.html b/testing/web-platform/tests/webstorage/localstorage-basic-partitioned.tentative.sub.html
new file mode 100644
index 0000000000..7ed49b1e9a
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/localstorage-basic-partitioned.tentative.sub.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>localStorage: partitioned storage test</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="shared-iframe" src="http://{{host}}:{{ports[http][0]}}/webstorage/resources/localstorage-about-blank-partitioned-iframe.html"></iframe>
+<body>
+<script>
+// Here's the set-up for this test:
+// Step 1. (window) set up listeners for main window.
+// Step 2. (window) set up load listener for same-site iframe.
+// Step 3. (same-site iframe) loads, send it a message to createOrGet a "userID".
+// Step 4. (same-site iframe) receives the message, creates the "userID".
+// Step 5. (window) receives "storage got set" message from same-site iframe.
+// Step 6. (window) opens cross-site window w/ shared (same-site to us currently) iframe.
+// Step 7. (cross-site iframe) loads, sends back the userID key from the iframe.
+// Step 8. (window) asserts that the IDs should be different, as they should have a different StorageKey.
+const altOrigin = "http://{{hosts[alt][]}}:{{ports[http][0]}}";
+
+async_test(t => {
+ let crossSiteWindow;
+ let crossSiteID;
+ let sameSiteID;
+ const iframe = document.getElementById("shared-iframe");
+
+ iframe.addEventListener("load", t.step_func(e => {
+ const payload = {
+ command: "create ID",
+ key: "userID",
+ };
+ iframe.contentWindow.postMessage(payload, iframe.origin);
+ }), {once: true});
+
+ window.addEventListener("message", t.step_func(e => {
+ if (e.data.message === "ID created") {
+ sameSiteID = e.data.userID;
+ assert_true(typeof sameSiteID === "string");
+
+ if (location.origin !== altOrigin) {
+ crossSiteWindow = window.open(`${altOrigin}/webstorage/localstorage-basic-partitioned.tentative.sub.html`, "", "noopener=false");
+ t.add_cleanup(() => crossSiteWindow.close());
+ }
+ }
+
+ if (e.data.message === "cross-site window iframe loaded") {
+ crossSiteID = e.data.userID;
+ t.step(() => {
+ assert_true(typeof crossSiteID === "string");
+ assert_true(sameSiteID !== crossSiteID, "IDs pulled from two partitioned iframes are different.")
+ });
+
+ // clean up after ourselves.
+ iframe.contentWindow.localStorage.clear();
+ crossSiteWindow.postMessage({command: "clearStorage"}, altOrigin);
+ t.done();
+ };
+ }));
+}, "Simple test for partitioned localStorage");
+</script>
+</body>
diff --git a/testing/web-platform/tests/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js b/testing/web-platform/tests/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js
new file mode 100644
index 0000000000..39812f27a0
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/localstorage-cross-origin-iframe.tentative.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/utils.js
+// META: script=/common/dispatcher/dispatcher.js
+// META: script=/html/cross-origin-embedder-policy/credentialless/resources/common.js
+// META: script=/html/anonymous-iframe/resources/common.js
+
+promise_test(async test => {
+ const same_origin= get_host_info().HTTPS_ORIGIN;
+ const cross_origin = get_host_info().HTTPS_REMOTE_ORIGIN;
+ const reply_token = token();
+
+ for(iframe of [
+ newIframe(same_origin),
+ newIframe(cross_origin),
+ ]) {
+ send(iframe, `
+ try {
+ let c = window.localStorage;
+ send("${reply_token}","OK");
+ } catch (exception) {
+ send("${reply_token}","ERROR");
+ }
+ `);
+ }
+ assert_equals(await receive(reply_token), "OK");
+ assert_equals(await receive(reply_token), "OK");
+ }, "LocalStorage should be accessible on both same_origin and cross_origin iframes"); \ No newline at end of file
diff --git a/testing/web-platform/tests/webstorage/missing_arguments.window.js b/testing/web-platform/tests/webstorage/missing_arguments.window.js
new file mode 100644
index 0000000000..2e41a22ec7
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/missing_arguments.window.js
@@ -0,0 +1,17 @@
+var tests = [
+ function() { localStorage.key(); },
+ function() { localStorage.getItem(); },
+ function() { localStorage.setItem(); },
+ function() { localStorage.setItem("a"); },
+ function() { localStorage.removeItem(); },
+ function() { sessionStorage.key(); },
+ function() { sessionStorage.getItem(); },
+ function() { sessionStorage.setItem(); },
+ function() { sessionStorage.setItem("a"); },
+ function() { sessionStorage.removeItem(); },
+];
+tests.forEach(function(fun) {
+ test(function() {
+ assert_throws_js(TypeError, fun);
+ }, "Should throw TypeError for " + format_value(fun) + ".");
+});
diff --git a/testing/web-platform/tests/webstorage/resources/event_basic.html b/testing/web-platform/tests/webstorage/resources/event_basic.html
new file mode 100644
index 0000000000..5933b40eeb
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/event_basic.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script>
+function handleStorageEvent(e) {
+ if (window.sessionStorage === e.storageArea)
+ e.storageAreaString = "sessionStorage";
+ else if (window.localStorage === e.storageArea)
+ e.storageAreaString = "localStorage";
+ window.parent.storageEventList.push(e);
+}
+</script>
+</head>
+<body onstorage="handleStorageEvent(event);">
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/event_body_handler.html b/testing/web-platform/tests/webstorage/resources/event_body_handler.html
new file mode 100644
index 0000000000..11d8ec9447
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/event_body_handler.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<script>
+
+function handleStorageEvent(e) {
+ window.parent.storageEventList.push(e);
+}
+
+</script>
+</head>
+<body onstorage="handleStorageEvent(event);">
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/event_setattribute_handler.html b/testing/web-platform/tests/webstorage/resources/event_setattribute_handler.html
new file mode 100644
index 0000000000..b9e2f04021
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/event_setattribute_handler.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head></head>
+<body>
+<script>
+
+function handleStorageEvent(e) {
+ window.parent.storageEventList.push(e);
+}
+
+document.body.setAttribute("onstorage", "handleStorageEvent(event);");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/local_change_item_iframe.html b/testing/web-platform/tests/webstorage/resources/local_change_item_iframe.html
new file mode 100644
index 0000000000..17be8fb26e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/local_change_item_iframe.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('localStorage' in window) && window.localStorage !== null){
+ try {
+ localStorage.setItem("name", "user1");
+ localStorage.setItem("name", "user2");
+ } catch (e) {
+ parent.fail("setItem method is failed.");
+ }
+ localStorage.clear();
+ } else {
+ parent.fail("localStorage is not supported.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/local_set_item_clear_iframe.html b/testing/web-platform/tests/webstorage/resources/local_set_item_clear_iframe.html
new file mode 100644
index 0000000000..742b7dad1a
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/local_set_item_clear_iframe.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('localStorage' in window) && window.localStorage !== null){
+ try {
+ localStorage.setItem("name", "user1");
+ } catch (e) {
+ parent.fail("setItem method is failed.");
+ }
+ localStorage.clear();
+ } else {
+ parent.fail("localStorage is not supported.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/local_set_item_iframe.html b/testing/web-platform/tests/webstorage/resources/local_set_item_iframe.html
new file mode 100644
index 0000000000..0693824e5d
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/local_set_item_iframe.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('localStorage' in window) && window.localStorage !== null){
+ try {
+ localStorage.setItem("name", "user1");
+ } catch (e) {
+ parent.fail("setItem method is failed.");
+ }
+ } else {
+ parent.fail("localStorage is not supported.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/local_set_item_remove_iframe.html b/testing/web-platform/tests/webstorage/resources/local_set_item_remove_iframe.html
new file mode 100644
index 0000000000..7451594c89
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/local_set_item_remove_iframe.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ parent.step(function() {
+ localStorage.setItem("name", "user1");
+ localStorage.removeItem('name');
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-iframe.html b/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-iframe.html
new file mode 100644
index 0000000000..5cb2c4f7e2
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-iframe.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<meta charset="utf-8">
+<script>
+function getOrCreateID(key) {
+ if (!localStorage.getItem(key)) {
+ const newID = +new Date() + "-" + Math.random();
+ localStorage.setItem(key, newID);
+ }
+ return localStorage.getItem(key);
+}
+
+window.addEventListener("load", () => {
+ // if we have an opener, we know that we are loaded inside a cross-site
+ // iframe (because we opened it ourselves).
+ if (parent.opener) {
+ const payload = {
+ message: "cross-site window iframe loaded",
+ userID: getOrCreateID("userID"),
+ }
+ parent.opener.postMessage(payload, parent.opener.origin);
+ }
+});
+
+window.addEventListener("message", (e) => {
+ if (e.data.command == "create ID") {
+ getOrCreateID(e.data.key);
+
+ // storage is set, call back to window.
+ const payload = {
+ message: "ID created",
+ userID: localStorage.getItem("userID"),
+ }
+
+ e.source.postMessage(payload, e.source.origin);
+ }
+
+ if (e.data.command == "clearStorage") {
+ localStorage.clear();
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-win-open.html b/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-win-open.html
new file mode 100644
index 0000000000..90d3a4309e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/localstorage-about-blank-partitioned-win-open.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="./partitioning-utils.js"></script>
+<script>
+window.addEventListener("load", () => {
+ localStorage.clear();
+
+ const userID = getOrCreateID("userID4");
+ const payload = {
+ message: "window loaded",
+ userID,
+ }
+
+ let win = window.opener ? window.opener : window.parent;
+ win.postMessage(payload, "*");
+});
+
+window.addEventListener("message", e => {
+ let win = window.opener ? parent.window.opener : window.parent;
+
+ if (e.data.command == "open about:blank window") {
+ window.blankWindow = window.open("about:blank");
+ const payload = {
+ message: "about:blank frame ID",
+ userID: window.blankWindow?.localStorage["userID4"],
+ }
+
+ let win = window.opener ? parent.window.opener : window.parent;
+ win.postMessage(payload, "*");
+ }
+
+ if (e.data.command == "close about:blank window") {
+ window.blankWindow.close();
+ win.postMessage({message: "about:blank window closed"}, "*");
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/webstorage/resources/partitioning-utils.js b/testing/web-platform/tests/webstorage/resources/partitioning-utils.js
new file mode 100644
index 0000000000..9d9e0b8ac5
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/partitioning-utils.js
@@ -0,0 +1,20 @@
+function getOrCreateID(key) {
+ if (!localStorage.getItem(key)) {
+ const newID = +new Date() + "-" + Math.random();
+ localStorage.setItem(key, newID);
+ }
+ return localStorage.getItem(key);
+}
+
+function addIframePromise(url) {
+ return new Promise(resolve => {
+ const iframe = document.createElement("iframe");
+ iframe.style.display = "none";
+ iframe.src = url;
+ iframe.addEventListener("load", (e) => {
+ resolve(iframe);
+ }, {once: true});
+
+ document.body.appendChild(iframe);
+ });
+}
diff --git a/testing/web-platform/tests/webstorage/resources/sessionStorage-about-blank-partitioned-iframe.html b/testing/web-platform/tests/webstorage/resources/sessionStorage-about-blank-partitioned-iframe.html
new file mode 100644
index 0000000000..dd530a7c22
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/sessionStorage-about-blank-partitioned-iframe.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<meta charset="utf-8">
+<script>
+
+function getOrCreateID(key) {
+ if (!sessionStorage.getItem(key)) {
+ const newID = new Date() + "-" + Math.random();
+ sessionStorage.setItem(key, newID);
+ }
+ return sessionStorage.getItem(key);
+}
+
+window.addEventListener("load", () => {
+ // In this testing set-up, only cross-site iframes will have an opener.
+ if (parent.opener) {
+ const payload = {
+ message: "cross-site window iframe loaded",
+ userID: getOrCreateID("userID"),
+ }
+ // Once the cross-site iframe has loaded, we send a message back to
+ // the main window with the ID from sessionStorage.
+ parent.opener.postMessage(payload, parent.opener.origin);
+ }
+});
+
+window.addEventListener("message", (e) => {
+ if (e.data.command == "create ID") {
+ // e.data.key is equivalent to "userID"
+ getOrCreateID(e.data.key);
+
+ const payload = {
+ message: "ID created",
+ userID: sessionStorage.getItem("userID"),
+ }
+ // Return the ID from sessionStorage to the main window.
+ e.source.postMessage(payload, e.source.origin);
+ }
+
+ // Additional functionality for clean-up at the end of the test.
+ if (e.data.command == "clearStorage") {
+ sessionStorage.clear();
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/webstorage/resources/session_change_item_iframe.html b/testing/web-platform/tests/webstorage/resources/session_change_item_iframe.html
new file mode 100644
index 0000000000..1e1867e51e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/session_change_item_iframe.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('sessionStorage' in window) && window.sessionStorage !== null){
+ try {
+ sessionStorage.setItem("name", "user1");
+ sessionStorage.setItem("name", "user2");
+ } catch (e) {
+ parent.fail("setItem method is failed.");
+ }
+ sessionStorage.clear();
+ } else {
+ parent.fail("sessionStorage is not supported.");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/session_set_item_clear_iframe.html b/testing/web-platform/tests/webstorage/resources/session_set_item_clear_iframe.html
new file mode 100644
index 0000000000..7deaa9b17c
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/session_set_item_clear_iframe.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('sessionStorage' in window) && window.sessionStorage !== null){
+ try {
+ sessionStorage.setItem('name', 'user1');
+ } catch (e) {
+ parent.fail('setItem method is failed.');
+ }
+ sessionStorage.clear();
+ } else {
+ parent.fail('sessionStorage is not supported.');
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/session_set_item_iframe.html b/testing/web-platform/tests/webstorage/resources/session_set_item_iframe.html
new file mode 100644
index 0000000000..de844cca45
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/session_set_item_iframe.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ if (('sessionStorage' in window) && window.sessionStorage !== null){
+ try {
+ sessionStorage.setItem('name', 'user1');
+ } catch (e) {
+ parent.fail('setItem method is failed.');
+ }
+ } else {
+ parent.fail('sessionStorage is not supported.');
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/session_set_item_remove_iframe.html b/testing/web-platform/tests/webstorage/resources/session_set_item_remove_iframe.html
new file mode 100644
index 0000000000..60303e70f5
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/session_set_item_remove_iframe.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <script>
+ parent.step(function() {
+ sessionStorage.setItem("name", "user1");
+ sessionStorage.removeItem('name');
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/storage_local_window_open_second.html b/testing/web-platform/tests/webstorage/resources/storage_local_window_open_second.html
new file mode 100644
index 0000000000..3c8405adcf
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/storage_local_window_open_second.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>WebStorage Test: localStorage - second page</title>
+</head>
+<body>
+<script>
+
+var storage = window.localStorage;
+
+var assertions = [];
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: "BAR",
+ message: "storage.getItem('FOO')"
+});
+
+storage.setItem("FOO", "BAR-NEWWINDOW");
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: "BAR-NEWWINDOW",
+ message: "value for FOO after changing"
+});
+assertions.push({
+ actual: window.opener.localStorage.getItem("FOO"),
+ expected: "BAR-NEWWINDOW",
+ message: "value for FOO in my opening window"
+});
+
+window.opener.postMessage(assertions, '*');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/storage_session_window_noopener_second.html b/testing/web-platform/tests/webstorage/resources/storage_session_window_noopener_second.html
new file mode 100644
index 0000000000..7e477375ae
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/storage_session_window_noopener_second.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>WebStorage Test: sessionStorage - second page</title>
+</head>
+<body>
+<script>
+
+var storage = window.sessionStorage;
+
+var assertions = [];
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: null,
+ message: "storage.getItem('FOO')"
+});
+
+storage.setItem("FOO", "BAR-NEWWINDOW");
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: "BAR-NEWWINDOW",
+ message: "value for FOO after changing"
+});
+
+let channel = new BroadcastChannel('storage_session_window_noopener');
+channel.postMessage(assertions, '*');
+
+window.close();
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/resources/storage_session_window_open_second.html b/testing/web-platform/tests/webstorage/resources/storage_session_window_open_second.html
new file mode 100644
index 0000000000..2eeff0b865
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/resources/storage_session_window_open_second.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<title>WebStorage Test: sessionStorage - second page</title>
+</head>
+<body>
+<script>
+
+var storage = window.sessionStorage;
+
+var assertions = [];
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: "BAR",
+ message: "storage.getItem('FOO')"
+});
+
+storage.setItem("FOO", "BAR-NEWWINDOW");
+
+assertions.push({
+ actual: storage.getItem("FOO"),
+ expected: "BAR-NEWWINDOW",
+ message: "value for FOO after changing"
+});
+assertions.push({
+ actual: window.opener.sessionStorage.getItem("FOO"),
+ expected: "BAR",
+ message: "value for FOO in my opening window"
+});
+assertions.push({
+ actual: storage.getItem("BAZ"),
+ expected: null,
+ message: "value for BAZ set after window.open(), is not set in new window"
+});
+
+window.opener.postMessage(assertions, '*');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webstorage/sessionStorage-basic-partitioned.tentative.sub.html b/testing/web-platform/tests/webstorage/sessionStorage-basic-partitioned.tentative.sub.html
new file mode 100644
index 0000000000..30575bfaf1
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/sessionStorage-basic-partitioned.tentative.sub.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>sessionStorage: partitioned storage test</title>
+<meta name=help href="https://privacycg.github.io/storage-partitioning/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe id="shared-iframe" src="http://{{host}}:{{ports[http][0]}}/webstorage/resources/sessionStorage-about-blank-partitioned-iframe.html"></iframe>
+<body>
+<script>
+// Here's the set-up for this test:
+// Step 1. (main window) set up messaging and same-site iframe load listeners.
+// Step 2. (same-site iframe) loads, requests sessionStorage for "userID".
+// Step 3. (same-site iframe) receives the message, gets or allocates sessionStorage,
+// and returns the generated ID to the main frame.
+// Step 4. (main window) receives "storage got set" message from same-site iframe.
+// Step 5. (main window) opens a new cross-site window with the shared-iframe inside.
+// Step 6. (cross-site iframe) loads, requests sessionStorage for "userID", gets or
+// allocates that sessionStorage, and returns the generated ID to the main frame.
+// Step 7. (main window) asserts that the generated IDs should be different, as
+// they should have a different StorageKey.
+const altOrigin = "http://{{hosts[alt][]}}:{{ports[http][0]}}";
+
+async_test(t => {
+ let crossSiteWindow;
+ let crossSiteID;
+ let sameSiteID;
+ // Retrieve the iframe we created in the HTML above.
+ const iframe = document.getElementById("shared-iframe");
+
+ // Once the iframe loads, we request sessionStorage.
+ iframe.addEventListener("load", t.step_func(e => {
+ const payload = {
+ command: "create ID",
+ key: "userID",
+ };
+ iframe.contentWindow.postMessage(payload, iframe.origin);
+ }), {once: true});
+
+ window.addEventListener("message", t.step_func(e => {
+ // Once we get or allocate the sessionStorage, we expect the iframe
+ // to message us back with the generated ID.
+ if (e.data.message === "ID created") {
+ sameSiteID = e.data.userID;
+ assert_true(typeof sameSiteID === "string");
+
+ // Now that same-site storage has been secured, we need to open a
+ // new cross-site window that contains our shared-iframe to repeat
+ // the process in a cross-site environment.
+ if (location.origin !== altOrigin) {
+ crossSiteWindow = window.open(`${altOrigin}/webstorage/sessionStorage-basic-partitioned.tentative.sub.html`, "", "noopener=false");
+ t.add_cleanup(() => crossSiteWindow.close());
+ }
+ }
+
+ // We expect that once the cross-site iframe requests sessionStorage,
+ // it will message us back with the generated ID.
+ if (e.data.message === "cross-site window iframe loaded") {
+ crossSiteID = e.data.userID;
+ t.step(() => {
+ // Same and cross-site iframes should have different generated IDs.
+ assert_true(typeof crossSiteID === "string");
+ assert_true(sameSiteID !== crossSiteID, "IDs pulled from two partitioned iframes are different.")
+ });
+
+ // Clear storage state to clean up after the test.
+ iframe.contentWindow.sessionStorage.clear();
+ crossSiteWindow.postMessage({command: "clearStorage"}, altOrigin);
+ t.done();
+ };
+ }));
+}, "Simple test for partitioned sessionStorage");
+</script>
+</body>
diff --git a/testing/web-platform/tests/webstorage/set.window.js b/testing/web-platform/tests/webstorage/set.window.js
new file mode 100644
index 0000000000..8e671d2ded
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/set.window.js
@@ -0,0 +1,102 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ [9, "x"].forEach(function(key) {
+ test(function() {
+ var expected = "value for " + this.name;
+ var value = expected;
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], undefined);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(storage[key] = value, value);
+ assert_equals(storage[key], expected);
+ assert_equals(storage.getItem(key), expected);
+ }, "Setting property for key " + key + " on " + name);
+
+ test(function() {
+ var expected = "value for " + this.name;
+ var value = {
+ toString: function() { return expected; }
+ };
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], undefined);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(storage[key] = value, value);
+ assert_equals(storage[key], expected);
+ assert_equals(storage.getItem(key), expected);
+ }, "Setting property with toString for key " + key + " on " + name);
+
+ test(function() {
+ var proto = "proto for " + this.name;
+ Storage.prototype[key] = proto;
+ this.add_cleanup(function() { delete Storage.prototype[key]; });
+
+ var value = "value for " + this.name;
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], proto);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(storage[key] = value, value);
+ // Hidden because no [LegacyOverrideBuiltIns].
+ assert_equals(storage[key], proto);
+ assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
+ assert_equals(storage.getItem(key), value);
+ }, "Setting property for key " + key + " on " + name + " with data property on prototype");
+
+ test(function() {
+ var proto = "proto for " + this.name;
+ Storage.prototype[key] = proto;
+ this.add_cleanup(function() { delete Storage.prototype[key]; });
+
+ var value = "value for " + this.name;
+ var existing = "existing for " + this.name;
+
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem(key, existing);
+
+ // Hidden because no [LegacyOverrideBuiltIns].
+ assert_equals(storage[key], proto);
+ assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
+ assert_equals(storage.getItem(key), existing);
+ assert_equals(storage[key] = value, value);
+ assert_equals(storage[key], proto);
+ assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
+ assert_equals(storage.getItem(key), value);
+ }, "Setting property for key " + key + " on " + name + " with data property on prototype and existing item");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ var proto = "proto getter for " + this.name;
+ Object.defineProperty(Storage.prototype, key, {
+ "get": function() { return proto; },
+ "set": this.unreached_func("Should not call [[Set]] on prototype"),
+ "configurable": true,
+ });
+ this.add_cleanup(function() {
+ delete Storage.prototype[key];
+ delete storage[key];
+ assert_false(key in storage);
+ });
+
+ var value = "value for " + this.name;
+
+ assert_equals(storage[key], proto);
+ assert_equals(storage.getItem(key), null);
+ assert_equals(storage[key] = value, value);
+ // Property is hidden because no [LegacyOverrideBuiltIns].
+ assert_equals(storage[key], proto);
+ assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined);
+ assert_equals(storage.getItem(key), value);
+ }, "Setting property for key " + key + " on " + name + " with accessor property on prototype");
+ });
+});
diff --git a/testing/web-platform/tests/webstorage/storage_builtins.window.js b/testing/web-platform/tests/webstorage/storage_builtins.window.js
new file mode 100644
index 0000000000..72bb90db21
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_builtins.window.js
@@ -0,0 +1,16 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ assert_equals(storage.length, 0, "storage.length");
+
+ var builtins = ["key", "getItem", "setItem", "removeItem", "clear"];
+ var origBuiltins = builtins.map(function(b) { return Storage.prototype[b]; });
+ assert_array_equals(builtins.map(function(b) { return storage[b]; }), origBuiltins, "a");
+ builtins.forEach(function(b) { storage[b] = b; });
+ assert_array_equals(builtins.map(function(b) { return storage[b]; }), origBuiltins, "b");
+ assert_array_equals(builtins.map(function(b) { return storage.getItem(b); }), builtins, "c");
+
+ assert_equals(storage.length, builtins.length, "storage.length");
+ }, "Builtins in " + name);
+});
diff --git a/testing/web-platform/tests/webstorage/storage_clear.window.js b/testing/web-platform/tests/webstorage/storage_clear.window.js
new file mode 100644
index 0000000000..6f42bf85f7
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_clear.window.js
@@ -0,0 +1,16 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ assert_equals(storage.getItem("name"), "user1");
+ assert_equals(storage.name, "user1");
+ assert_equals(storage.length, 1);
+
+ storage.clear();
+ assert_equals(storage.getItem("name"), null, "storage.getItem('name')");
+ assert_equals(storage.name, undefined, "storage.name");
+ assert_equals(storage.length, 0, "storage.length");
+ }, "Clear in " + name);
+});
diff --git a/testing/web-platform/tests/webstorage/storage_enumerate.window.js b/testing/web-platform/tests/webstorage/storage_enumerate.window.js
new file mode 100644
index 0000000000..fcc71e1c9e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_enumerate.window.js
@@ -0,0 +1,55 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ assert_true(name in window, name + " exist");
+
+ var storage = window[name];
+ storage.clear();
+
+ Storage.prototype.prototypeTestKey = "prototypeTestValue";
+ storage.foo = "bar";
+ storage.fu = "baz";
+ storage.batman = "bin suparman";
+ storage.bar = "foo";
+ storage.alpha = "beta";
+ storage.zeta = "gamma";
+
+ const enumeratedArray = Object.keys(storage);
+ enumeratedArray.sort(); // Storage order is implementation-defined.
+
+ const expectArray = ["alpha", "bar", "batman", "foo", "fu", "zeta"];
+ assert_array_equals(enumeratedArray, expectArray);
+
+ // 'prototypeTestKey' is not an actual storage key, it is just a
+ // property set on Storage's prototype object.
+ assert_equals(storage.length, 6);
+ assert_equals(storage.getItem("prototypeTestKey"), null);
+ assert_equals(storage.prototypeTestKey, "prototypeTestValue");
+ }, name + ": enumerate a Storage object and get only the keys as a result and the built-in properties of the Storage object should be ignored");
+
+ test(function() {
+ const storage = window[name];
+ storage.clear();
+
+ storage.setItem("foo", "bar");
+ storage.baz = "quux";
+ storage.setItem(0, "alpha");
+ storage[42] = "beta";
+
+ for (let prop in storage) {
+ if (!storage.hasOwnProperty(prop))
+ continue;
+ const desc = Object.getOwnPropertyDescriptor(storage, prop);
+ assert_true(desc.configurable);
+ assert_true(desc.enumerable);
+ assert_true(desc.writable);
+ }
+
+ const keys = Object.keys(storage);
+ keys.sort(); // Storage order is implementation-defined.
+ assert_array_equals(keys, ["0", "42", "baz", "foo"]);
+
+ const values = Object.values(storage);
+ values.sort(); // Storage order is implementation-defined.
+ assert_array_equals(values, ["alpha", "bar", "beta", "quux"]);
+ }, name + ": test enumeration of numeric and non-numeric keys");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_functions_not_overwritten.window.js b/testing/web-platform/tests/webstorage/storage_functions_not_overwritten.window.js
new file mode 100644
index 0000000000..693743de90
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_functions_not_overwritten.window.js
@@ -0,0 +1,37 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ runTest();
+ function doWedgeThySelf() {
+ storage.setItem("clear", "almost");
+ storage.setItem("key", "too");
+ storage.setItem("getItem", "funny");
+ storage.setItem("removeItem", "to");
+ storage.setItem("length", "be");
+ storage.setItem("setItem", "true");
+ }
+
+ function runTest() {
+ doWedgeThySelf();
+
+ assert_equals(storage.getItem('clear'), "almost");
+ assert_equals(storage.getItem('key'), "too");
+ assert_equals(storage.getItem('getItem'), "funny");
+ assert_equals(storage.getItem('removeItem'), "to");
+ assert_equals(storage.getItem('length'), "be");
+ assert_equals(storage.getItem('setItem'), "true");
+
+ // Test to see if an exception is thrown for any of the built in
+ // functions.
+ storage.setItem("test", "123");
+ storage.key(0);
+ storage.getItem("test");
+ storage.removeItem("test");
+ storage.clear();
+ assert_equals(storage.length, 0);
+ }
+
+ }, name + " should be not rendered unusable by setting a key with the same name as a storage function such that the function is hidden");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_getitem.window.js b/testing/web-platform/tests/webstorage/storage_getitem.window.js
new file mode 100644
index 0000000000..8a5896836d
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_getitem.window.js
@@ -0,0 +1,34 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ storage.setItem("name", "x");
+ storage.setItem("undefined", "foo");
+ storage.setItem("null", "bar");
+ storage.setItem("", "baz");
+
+ test(function() {
+ assert_equals(storage.length, 4);
+ }, "All items should be added to " + name + ".");
+
+ test(function() {
+ assert_equals(storage["unknown"], undefined, "storage['unknown']")
+ assert_equals(storage["name"], "x", "storage['name']")
+ assert_equals(storage["undefined"], "foo", "storage['undefined']")
+ assert_equals(storage["null"], "bar", "storage['null']")
+ assert_equals(storage[undefined], "foo", "storage[undefined]")
+ assert_equals(storage[null], "bar", "storage[null]")
+ assert_equals(storage[""], "baz", "storage['']")
+ }, "Named access to " + name + " should be correct");
+
+ test(function() {
+ assert_equals(storage.getItem("unknown"), null, "storage.getItem('unknown')")
+ assert_equals(storage.getItem("name"), "x", "storage.getItem('name')")
+ assert_equals(storage.getItem("undefined"), "foo", "storage.getItem('undefined')")
+ assert_equals(storage.getItem("null"), "bar", "storage.getItem('null')")
+ assert_equals(storage.getItem(undefined), "foo", "storage.getItem(undefined)")
+ assert_equals(storage.getItem(null), "bar", "storage.getItem(null)")
+ assert_equals(storage.getItem(""), "baz", "storage.getItem('')")
+ }, name + ".getItem should be correct")
+ }, "Get value by getIten(key) and named access in " + name + ".");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_in.window.js b/testing/web-platform/tests/webstorage/storage_in.window.js
new file mode 100644
index 0000000000..148285a1eb
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_in.window.js
@@ -0,0 +1,22 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ assert_false("name" in storage);
+ storage["name"] = "user1";
+ assert_true("name" in storage);
+ }, "The in operator in " + name + ": property access");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ assert_false("name" in storage);
+ storage.setItem("name", "user1");
+ assert_true("name" in storage);
+ assert_equals(storage.name, "user1");
+ storage.removeItem("name");
+ assert_false("name" in storage);
+ }, "The in operator in " + name + ": method access");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_indexing.window.js b/testing/web-platform/tests/webstorage/storage_indexing.window.js
new file mode 100644
index 0000000000..685b6b67fb
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_indexing.window.js
@@ -0,0 +1,28 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ storage["name"] = "user1";
+ storage["age"] = "42";
+
+ test(function() {
+ assert_equals(storage[-1], undefined);
+ assert_equals(storage[0], undefined);
+ assert_equals(storage[1], undefined);
+ assert_equals(storage[2], undefined);
+ }, "Getting number properties on " + name);
+
+ test(function() {
+ assert_equals(storage["-1"], undefined);
+ assert_equals(storage["0"], undefined);
+ assert_equals(storage["1"], undefined);
+ assert_equals(storage["2"], undefined);
+ }, "Getting number-valued string properties on " + name);
+
+ test(function() {
+ storage.setItem(1, "number");
+ assert_equals(storage[1], "number");
+ assert_equals(storage["1"], "number");
+ }, "Getting existing number-valued properties on " + name);
+ }, "Indexed getter on " + name);
+});
diff --git a/testing/web-platform/tests/webstorage/storage_key.window.js b/testing/web-platform/tests/webstorage/storage_key.window.js
new file mode 100644
index 0000000000..723f6563d7
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_key.window.js
@@ -0,0 +1,51 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ storage.setItem("age", "20");
+ storage.setItem("a", "1");
+ storage.setItem("b", "2");
+
+ var keys = ["name", "age", "a", "b"];
+ function doTest(index) {
+ test(function() {
+ var key = storage.key(index);
+ assert_not_equals(key, null);
+ assert_true(keys.indexOf(key) >= 0,
+ "Unexpected key " + key + " found.");
+ }, name + ".key(" + index + ") should return the right thing.");
+ }
+ for (var i = 0; i < keys.length; ++i) {
+ doTest(i);
+ doTest(i + 0x100000000);
+ }
+
+ test(function() {
+ assert_equals(storage.key(-1), null, "storage.key(-1)");
+ assert_equals(storage.key(4), null, "storage.key(4)");
+ }, name + ".key() should return null for out-of-range arguments.");
+ }, name + ".key");
+
+ test(function() {
+ var get_keys = function(s) {
+ var keys = [];
+ for (var i = 0; i < s.length; ++i) {
+ keys.push(s.key(i));
+ }
+ return keys;
+ };
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ storage.setItem("age", "20");
+ storage.setItem("a", "1");
+ storage.setItem("b", "2");
+
+ var expected_keys = get_keys(storage);
+ storage.setItem("name", "user2");
+ assert_array_equals(get_keys(storage), expected_keys);
+ }, name + ".key with value changes");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_key_empty_string.window.js b/testing/web-platform/tests/webstorage/storage_key_empty_string.window.js
new file mode 100644
index 0000000000..c3d59c42b8
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_key_empty_string.window.js
@@ -0,0 +1,10 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function () {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("", "empty string");
+ assert_equals(storage.getItem(""), "empty string");
+
+ }, name + ".key with empty string");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_length.window.js b/testing/web-platform/tests/webstorage/storage_length.window.js
new file mode 100644
index 0000000000..9648e48c8d
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_length.window.js
@@ -0,0 +1,23 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ assert_equals(storage.length, 0, "storage.length")
+
+ storage["name"] = "user1";
+ storage["age"] = "20";
+
+ assert_equals(storage.length, 2, "storage.length")
+ }, name + ".length (method access)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ assert_equals(storage.length, 0, "storage.length")
+
+ storage.setItem("name", "user1");
+ storage.setItem("age", "20");
+
+ assert_equals(storage.length, 2, "storage.length")
+ }, name + ".length (proprty access)");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_local-manual.html b/testing/web-platform/tests/webstorage/storage_local-manual.html
new file mode 100644
index 0000000000..d039773b5b
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_local-manual.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebStorage Test: local storage</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<meta name="flags" content="interact">
+
+<h2>Description</h2>
+<p>
+ This test validates that store data using Local Storage which means that close the page, and re-open it, the data saved before should be loaded again.
+</p>
+
+<h2>Preconditions</h2>
+<ol class="instructions">
+ <li>
+ Click the "Clear" button, refresh the page once and then check if the page shows "You have viewed this page 1 time(s)"
+ </li>
+ <li>
+ Close the page, re-open it and then check if the page still shows "You have viewed this page 2 time(s)"
+ </li>
+ <li>
+ If the above two steps are all true the test case pass, otherwise it fail
+ </li>
+</ol>
+
+<p>
+ <h2>You have viewed this page
+ <span id="count">an untold number of</span>
+ time(s).</h2>
+ <button type="button" onclick="javascript:localStorage.pageLoadCount = 0;"><h3>Clear</h3></button>
+</p>
+
+<script>
+
+ if (!localStorage.pageLoadCount) {
+ localStorage.pageLoadCount = 0;
+ }
+ localStorage.pageLoadCount = parseInt(localStorage.pageLoadCount) + 1;
+ document.getElementById('count').textContent = localStorage.pageLoadCount;
+
+</script>
diff --git a/testing/web-platform/tests/webstorage/storage_local_setitem_quotaexceedederr.window.js b/testing/web-platform/tests/webstorage/storage_local_setitem_quotaexceedederr.window.js
new file mode 100644
index 0000000000..fff7d6444a
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_local_setitem_quotaexceedederr.window.js
@@ -0,0 +1,16 @@
+test(function() {
+ localStorage.clear();
+
+ var index = 0;
+ var key = "name";
+ var val = "x".repeat(1024);
+
+ assert_throws_dom("QUOTA_EXCEEDED_ERR", function() {
+ while (true) {
+ index++;
+ localStorage.setItem("" + key + index, "" + val + index);
+ }
+ });
+
+ localStorage.clear();
+}, "Throws QuotaExceededError when the quota has been exceeded");
diff --git a/testing/web-platform/tests/webstorage/storage_local_window_open.window.js b/testing/web-platform/tests/webstorage/storage_local_window_open.window.js
new file mode 100644
index 0000000000..8c67289400
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_local_window_open.window.js
@@ -0,0 +1,16 @@
+async_test(function(t) {
+
+ var storage = window.localStorage;
+ storage.clear();
+
+ storage.setItem("FOO", "BAR");
+ var win = window.open("resources/storage_local_window_open_second.html");
+ window.addEventListener('message', t.step_func(function(e) {
+ e.data.forEach(t.step_func(function(assertion) {
+ assert_equals(assertion.actual, assertion.expected, assertion.message);
+ }));
+ win.close();
+ t.done();
+ }));
+
+}, "A new window to make sure there is a copy of the previous window's localStorage, and that they do not diverge after a change");
diff --git a/testing/web-platform/tests/webstorage/storage_removeitem.window.js b/testing/web-platform/tests/webstorage/storage_removeitem.window.js
new file mode 100644
index 0000000000..be3174a89b
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_removeitem.window.js
@@ -0,0 +1,44 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ assert_equals(storage.getItem("name"), "user1");
+
+ storage.removeItem("name");
+ storage.removeItem("unknown");
+ assert_equals(storage.getItem("name"), null, "storage.getItem('name')")
+ }, name + ".removeItem()");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ assert_equals(storage.getItem("name"), "user1");
+ delete storage["name"];
+ delete storage["unknown"];
+ assert_equals(storage.getItem("name"), null, "storage.getItem('name')")
+ }, "delete " + name + "[]");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("null", "test");
+ assert_true("null" in storage);
+ storage.removeItem(null);
+ assert_false("null" in storage);
+ }, name + ".removeItem(null)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("undefined", "test");
+ assert_true("undefined" in storage);
+ storage.removeItem(undefined);
+ assert_false("undefined" in storage);
+ }, name + ".removeItem(undefined)");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_session-manual.html b/testing/web-platform/tests/webstorage/storage_session-manual.html
new file mode 100644
index 0000000000..c2676af14d
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_session-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebStorage Test: session storage</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<meta name="flags" content="interact">
+
+<h2>Description</h2>
+<p>
+ This test validates that store the data using Session Storage which means that even if you close the page, and re-open it, the data saved before should be lost.
+</p>
+
+<ol class="instructions">
+ <li>
+ Click the "Clear" button, refresh the page once and then check if the page shows "You have viewed this page 1 time(s)"
+ </li>
+ <li>
+ Close the page, re-open it and then check if the page still shows "You have viewed this page 1 time(s)"
+ </li>
+ <li>
+ If the above two steps are all true the test case pass, otherwise it fail.<br>
+ </li>
+</ol>
+
+<p>
+ <h2>You have viewed this page
+ <span id="count">an untold number of</span>
+ time(s).</h2>
+ <button type="button" onclick="javascript:sessionStorage.pageLoadCount = 0;"><h3>Clear</h3></button>
+</p>
+
+<script>
+
+ if (!sessionStorage.pageLoadCount) {
+ sessionStorage.pageLoadCount = 0;
+ }
+ sessionStorage.pageLoadCount = parseInt(sessionStorage.pageLoadCount) + 1;
+ document.getElementById('count').textContent = sessionStorage.pageLoadCount;
+
+</script>
diff --git a/testing/web-platform/tests/webstorage/storage_session_setitem_quotaexceedederr.window.js b/testing/web-platform/tests/webstorage/storage_session_setitem_quotaexceedederr.window.js
new file mode 100644
index 0000000000..42a895470e
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_session_setitem_quotaexceedederr.window.js
@@ -0,0 +1,16 @@
+test(function() {
+ sessionStorage.clear();
+
+ var index = 0;
+ var key = "name";
+ var val = "x".repeat(1024);
+
+ assert_throws_dom("QUOTA_EXCEEDED_ERR", function() {
+ while (true) {
+ index++;
+ sessionStorage.setItem("" + key + index, "" + val + index);
+ }
+ });
+
+ sessionStorage.clear();
+}, "Throws QuotaExceededError when the quota has been exceeded");
diff --git a/testing/web-platform/tests/webstorage/storage_session_window_noopener.window.js b/testing/web-platform/tests/webstorage/storage_session_window_noopener.window.js
new file mode 100644
index 0000000000..fe131059d8
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_session_window_noopener.window.js
@@ -0,0 +1,21 @@
+async_test(function(t) {
+
+ var storage = window.sessionStorage;
+ storage.clear();
+
+ storage.setItem("FOO", "BAR");
+
+ let channel = new BroadcastChannel("storage_session_window_noopener");
+ channel.addEventListener("message", t.step_func(function(e) {
+ e.data.forEach(t.step_func(function(assertion) {
+ assert_equals(assertion.actual, assertion.expected, assertion.message);
+ }));
+ assert_equals(storage.getItem("FOO"), "BAR", "value for FOO in original window");
+ t.done();
+ }));
+
+ var win = window.open("resources/storage_session_window_noopener_second.html",
+ "_blank",
+ "noopener");
+
+}, "A new noopener window to make sure there is a not copy of the previous window's sessionStorage");
diff --git a/testing/web-platform/tests/webstorage/storage_session_window_open.window.js b/testing/web-platform/tests/webstorage/storage_session_window_open.window.js
new file mode 100644
index 0000000000..83d4447017
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_session_window_open.window.js
@@ -0,0 +1,17 @@
+async_test(function(t) {
+
+ var storage = window.sessionStorage;
+ storage.clear();
+
+ storage.setItem("FOO", "BAR");
+ var win = window.open("resources/storage_session_window_open_second.html");
+ storage.setItem("BAZ", "QUX");
+ window.addEventListener('message', t.step_func(function(e) {
+ e.data.forEach(t.step_func(function(assertion) {
+ assert_equals(assertion.actual, assertion.expected, assertion.message);
+ }));
+ win.close();
+ t.done();
+ }));
+
+}, "A new window to make sure there is a copy of the previous window's sessionStorage, and that they diverge after a change");
diff --git a/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js b/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js
new file mode 100644
index 0000000000..1ce17d47f1
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_session_window_reopen.window.js
@@ -0,0 +1,26 @@
+test(function() {
+ var popup = window.open("", "sessionStorageTestWindow");
+
+ sessionStorage.setItem("FOO", "BAR");
+
+ var reopened = window.open("", "sessionStorageTestWindow");
+
+ assert_equals(
+ popup,
+ reopened,
+ "window.open with the same name should re-open the same window"
+ );
+
+ assert_equals(
+ sessionStorage.getItem("FOO"),
+ "BAR",
+ "local sessionStorage is correct"
+ );
+ assert_equals(
+ popup.sessionStorage.getItem("FOO"),
+ null,
+ "popup sessionStorage is correct"
+ );
+
+ popup.close();
+}, "ensure that re-opening a named window doesn't copy sessionStorage");
diff --git a/testing/web-platform/tests/webstorage/storage_set_value_enumerate.window.js b/testing/web-platform/tests/webstorage/storage_set_value_enumerate.window.js
new file mode 100644
index 0000000000..09a55ad454
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_set_value_enumerate.window.js
@@ -0,0 +1,21 @@
+var store_list = [
+ ["key0", "value0"],
+ ["key1", "value1"],
+ ["key2", "value2"]
+];
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function () {
+ var storage = window[name];
+ storage.clear();
+
+ store_list.forEach(function(item) {
+ storage.setItem(item[0], item[1]);
+ });
+
+ for (var i = 0; i < store_list.length; i++) {
+ var value = storage.getItem("key" + i);
+ assert_equals(value, "value" + i);
+ }
+ }, "enumerate a " + name + " object with the key and get the values");
+});
+
diff --git a/testing/web-platform/tests/webstorage/storage_setitem.window.js b/testing/web-platform/tests/webstorage/storage_setitem.window.js
new file mode 100644
index 0000000000..97817da1d8
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_setitem.window.js
@@ -0,0 +1,215 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ var test_error = { name: "test" };
+ var interesting_strs = ["\uD7FF", "\uD800", "\uDBFF", "\uDC00",
+ "\uDFFF", "\uE000", "\uFFFD", "\uFFFE", "\uFFFF",
+ "\uD83C\uDF4D", "\uD83Ca", "a\uDF4D",
+ "\uDBFF\uDFFF"];
+
+ for (var i = 0; i <= 0xFF; i++) {
+ interesting_strs.push(String.fromCharCode(i));
+ }
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("name", "user1");
+ assert_equals(storage.length, 1, "localStorage.setItem")
+ }, name + ".setItem()");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["name"] = "user1";
+ assert_true("name" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("name"), "user1");
+ assert_equals(storage["name"], "user1");
+ }, name + "[]");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["name"] = "user1";
+ storage["name"] = "user2";
+ assert_true("name" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("name"), "user2");
+ assert_equals(storage["name"], "user2");
+ }, name + "[] update");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("age", null);
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "null");
+ assert_equals(storage["age"], "null");
+ }, name + ".setItem(_, null)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["age"] = null;
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "null");
+ assert_equals(storage["age"], "null");
+ }, name + "[] = null");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("age", undefined);
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "undefined");
+ assert_equals(storage["age"], "undefined");
+ }, name + ".setItem(_, undefined)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["age"] = undefined;
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "undefined");
+ assert_equals(storage["age"], "undefined");
+ }, name + "[] = undefined");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("age", "10");
+ assert_throws_exactly(test_error, function() {
+ storage.setItem("age",
+ { toString: function() { throw test_error; } });
+ });
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "10");
+ assert_equals(storage["age"], "10");
+ }, name + ".setItem({ throws })");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem("age", "10");
+ assert_throws_exactly(test_error, function() {
+ storage["age"] =
+ { toString: function() { throw test_error; } };
+ });
+ assert_true("age" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("age"), "10");
+ assert_equals(storage["age"], "10");
+ }, name + "[] = { throws }");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem(undefined, "test");
+ assert_true("undefined" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("undefined"), "test");
+ assert_equals(storage["undefined"], "test");
+ }, name + ".setItem(undefined, _)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage[undefined] = "test2";
+ assert_true("undefined" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("undefined"), "test2");
+ assert_equals(storage["undefined"], "test2");
+ }, name + "[undefined]");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage.setItem(null, "test");
+ assert_true("null" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("null"), "test");
+ assert_equals(storage["null"], "test");
+ }, name + ".setItem(null, _)");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage[null] = "test2";
+ assert_true("null" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("null"), "test2");
+ assert_equals(storage["null"], "test2");
+ }, name + "[null]");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["foo\0bar"] = "user1";
+ assert_true("foo\0bar" in storage);
+ assert_false("foo\0" in storage);
+ assert_false("foo\0baz" in storage);
+ assert_false("foo" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("foo\0bar"), "user1");
+ assert_equals(storage.getItem("foo\0"), null);
+ assert_equals(storage.getItem("foo\0baz"), null);
+ assert_equals(storage.getItem("foo"), null);
+ assert_equals(storage["foo\0bar"], "user1");
+ assert_equals(storage["foo\0"], undefined);
+ assert_equals(storage["foo\0baz"], undefined);
+ assert_equals(storage["foo"], undefined);
+ }, name + " key containing null");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["name"] = "foo\0bar";
+ assert_true("name" in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("name"), "foo\0bar");
+ assert_equals(storage["name"], "foo\0bar");
+ }, name + " value containing null");
+
+ for (i = 0; i < interesting_strs.length; i++) {
+ var str = interesting_strs[i];
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage[str] = "user1";
+ assert_true(str in storage);
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem(str), "user1");
+ assert_equals(storage[str], "user1");
+ }, name + "[" + format_value(str) + "]");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["name"] = str;
+ assert_equals(storage.length, 1, "storage.length")
+ assert_equals(storage.getItem("name"), str);
+ assert_equals(storage["name"], str);
+ }, name + "[] = " + format_value(str));
+ }
+});
diff --git a/testing/web-platform/tests/webstorage/storage_string_conversion.window.js b/testing/web-platform/tests/webstorage/storage_string_conversion.window.js
new file mode 100644
index 0000000000..51b07a3a38
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_string_conversion.window.js
@@ -0,0 +1,32 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ assert_true(name in window, name + " exist");
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage.length, 0);
+
+ storage.a = null;
+ assert_equals(storage.a, "null");
+ storage.b = 0;
+ assert_equals(storage.b, "0");
+ storage.c = function(){};
+ assert_equals(storage.c, "function(){}");
+
+ storage.setItem('d', null);
+ assert_equals(storage.d, "null");
+ storage.setItem('e', 0);
+ assert_equals(storage.e, "0");
+ storage.setItem('f', function(){});
+ assert_equals(storage.f, "function(){}");
+
+ storage['g'] = null;
+ assert_equals(storage.g, "null");
+ storage['h'] = 0;
+ assert_equals(storage.h, "0");
+ storage['i'] = function(){};
+ assert_equals(storage.f, "function(){}");
+
+ }, name + " only stores strings");
+});
diff --git a/testing/web-platform/tests/webstorage/storage_supported_property_names.window.js b/testing/web-platform/tests/webstorage/storage_supported_property_names.window.js
new file mode 100644
index 0000000000..08c5d77afc
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/storage_supported_property_names.window.js
@@ -0,0 +1,15 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+
+ storage["name"] = "user1";
+ assert_array_equals(Object.getOwnPropertyNames(storage), ['name']);
+ }, "Object.getOwnPropertyNames on " + name + " Storage");
+
+ test(function() {
+ var storage = window[name];
+ storage.clear();
+ assert_array_equals(Object.getOwnPropertyNames(storage), []);
+ }, "Object.getOwnPropertyNames on " + name + " storage with empty collection");
+});
diff --git a/testing/web-platform/tests/webstorage/symbol-props.window.js b/testing/web-platform/tests/webstorage/symbol-props.window.js
new file mode 100644
index 0000000000..61dd8f83dc
--- /dev/null
+++ b/testing/web-platform/tests/webstorage/symbol-props.window.js
@@ -0,0 +1,81 @@
+["localStorage", "sessionStorage"].forEach(function(name) {
+ test(function() {
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ storage[key] = "test";
+ assert_equals(storage[key], "test");
+ }, name + ": plain set + get (loose)");
+
+ test(function() {
+ "use strict";
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ storage[key] = "test";
+ assert_equals(storage[key], "test");
+ }, name + ": plain set + get (strict)");
+
+ test(function() {
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ Object.defineProperty(storage, key, { "value": "test" });
+ assert_equals(storage[key], "test");
+ }, name + ": defineProperty + get");
+
+ test(function() {
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ Object.defineProperty(storage, key, { "value": "test", "configurable": false });
+ assert_equals(storage[key], "test");
+ var desc = Object.getOwnPropertyDescriptor(storage, key);
+ assert_true(desc.configurable, "configurable");
+
+ assert_true(delete storage[key]);
+ assert_equals(storage[key], undefined);
+ }, name + ": defineProperty not configurable");
+
+ test(function() {
+ var key = Symbol();
+ Storage.prototype[key] = "test";
+ this.add_cleanup(function() { delete Storage.prototype[key]; });
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_equals(storage[key], "test");
+ var desc = Object.getOwnPropertyDescriptor(storage, key);
+ assert_equals(desc, undefined);
+ }, name + ": get with symbol on prototype");
+
+ test(function() {
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ storage[key] = "test";
+ assert_true(delete storage[key]);
+ assert_equals(storage[key], undefined);
+ }, name + ": delete existing property");
+
+ test(function() {
+ var key = Symbol();
+
+ var storage = window[name];
+ storage.clear();
+
+ assert_true(delete storage[key]);
+ assert_equals(storage[key], undefined);
+ }, name + ": delete non-existent property");
+});