summaryrefslogtreecommitdiffstats
path: root/devtools/client/storage
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/storage')
-rw-r--r--devtools/client/storage/storage.xul8
-rw-r--r--devtools/client/storage/test/browser.ini10
-rw-r--r--devtools/client/storage/test/browser_storage_basic.js52
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_add.js20
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_delete_all.js106
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_domain.js12
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_edit.js21
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_edit_keyboard.js5
-rw-r--r--devtools/client/storage/test/browser_storage_cookies_tab_navigation.js3
-rw-r--r--devtools/client/storage/test/browser_storage_delete.js10
-rw-r--r--devtools/client/storage/test/browser_storage_delete_all.js6
-rw-r--r--devtools/client/storage/test/browser_storage_delete_tree.js18
-rw-r--r--devtools/client/storage/test/browser_storage_dom_cache_disabled.js37
-rw-r--r--devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js188
-rw-r--r--devtools/client/storage/test/browser_storage_dynamic_updates_localStorage.js70
-rw-r--r--devtools/client/storage/test/browser_storage_dynamic_updates_sessionStorage.js83
-rw-r--r--devtools/client/storage/test/browser_storage_empty_objectstores.js10
-rw-r--r--devtools/client/storage/test/browser_storage_indexeddb_delete.js6
-rw-r--r--devtools/client/storage/test/browser_storage_indexeddb_delete_blocked.js10
-rw-r--r--devtools/client/storage/test/browser_storage_indexeddb_duplicate_names.js31
-rw-r--r--devtools/client/storage/test/browser_storage_localstorage_add.js20
-rw-r--r--devtools/client/storage/test/browser_storage_overflow.js64
-rw-r--r--devtools/client/storage/test/browser_storage_sessionstorage_add.js20
-rw-r--r--devtools/client/storage/test/browser_storage_sidebar.js14
-rw-r--r--devtools/client/storage/test/browser_storage_sidebar_update.js2
-rw-r--r--devtools/client/storage/test/browser_storage_values.js18
-rw-r--r--devtools/client/storage/test/head.js123
-rw-r--r--devtools/client/storage/test/storage-indexeddb-duplicate-names.html50
-rw-r--r--devtools/client/storage/test/storage-listings.html16
-rw-r--r--devtools/client/storage/test/storage-overflow.html2
-rw-r--r--devtools/client/storage/test/storage-secured-iframe.html5
-rw-r--r--devtools/client/storage/test/storage-unsecured-iframe.html3
-rw-r--r--devtools/client/storage/test/storage-updates.html4
-rw-r--r--devtools/client/storage/ui.js300
34 files changed, 1159 insertions, 188 deletions
diff --git a/devtools/client/storage/storage.xul b/devtools/client/storage/storage.xul
index 9fbef5199..a91900add 100644
--- a/devtools/client/storage/storage.xul
+++ b/devtools/client/storage/storage.xul
@@ -26,13 +26,18 @@
<menupopup id="storage-tree-popup">
<menuitem id="storage-tree-popup-delete-all"
label="&storage.popupMenu.deleteAllLabel;"/>
+ <menuitem id="storage-tree-popup-delete-all-session-cookies"
+ label="&storage.popupMenu.deleteAllSessionCookiesLabel;"/>
<menuitem id="storage-tree-popup-delete"/>
</menupopup>
<menupopup id="storage-table-popup">
+ <menuitem id="storage-table-popup-add"/>
<menuitem id="storage-table-popup-delete"/>
<menuitem id="storage-table-popup-delete-all-from"/>
<menuitem id="storage-table-popup-delete-all"
label="&storage.popupMenu.deleteAllLabel;"/>
+ <menuitem id="storage-table-popup-delete-all-session-cookies"
+ label="&storage.popupMenu.deleteAllSessionCookiesLabel;"/>
</menupopup>
</popupset>
@@ -41,6 +46,9 @@
<splitter class="devtools-side-splitter"/>
<vbox flex="1">
<hbox id="storage-toolbar" class="devtools-toolbar">
+ <button id="add-button"
+ class="devtools-button add-button"></button>
+ <spacer flex="1"/>
<textbox id="storage-searchbox"
class="devtools-filterinput"
type="search"
diff --git a/devtools/client/storage/test/browser.ini b/devtools/client/storage/test/browser.ini
index dd7f48bd7..1250d35d5 100644
--- a/devtools/client/storage/test/browser.ini
+++ b/devtools/client/storage/test/browser.ini
@@ -7,6 +7,7 @@ support-files =
storage-cookies.html
storage-empty-objectstores.html
storage-idb-delete-blocked.html
+ storage-indexeddb-duplicate-names.html
storage-listings.html
storage-localstorage.html
storage-overflow.html
@@ -21,6 +22,7 @@ support-files =
[browser_storage_basic.js]
[browser_storage_cache_delete.js]
[browser_storage_cache_error.js]
+[browser_storage_cookies_add.js]
[browser_storage_cookies_delete_all.js]
[browser_storage_cookies_domain.js]
[browser_storage_cookies_edit.js]
@@ -29,15 +31,21 @@ support-files =
[browser_storage_delete.js]
[browser_storage_delete_all.js]
[browser_storage_delete_tree.js]
-[browser_storage_dynamic_updates.js]
+[browser_storage_dom_cache_disabled.js]
+[browser_storage_dynamic_updates_cookies.js]
+[browser_storage_dynamic_updates_localStorage.js]
+[browser_storage_dynamic_updates_sessionStorage.js]
[browser_storage_empty_objectstores.js]
[browser_storage_indexeddb_delete.js]
[browser_storage_indexeddb_delete_blocked.js]
+[browser_storage_indexeddb_duplicate_names.js]
+[browser_storage_localstorage_add.js]
[browser_storage_localstorage_edit.js]
[browser_storage_localstorage_error.js]
[browser_storage_overflow.js]
[browser_storage_search.js]
[browser_storage_search_keyboard_trap.js]
+[browser_storage_sessionstorage_add.js]
[browser_storage_sessionstorage_edit.js]
[browser_storage_sidebar.js]
[browser_storage_sidebar_update.js]
diff --git a/devtools/client/storage/test/browser_storage_basic.js b/devtools/client/storage/test/browser_storage_basic.js
index 343d46170..7585eed1f 100644
--- a/devtools/client/storage/test/browser_storage_basic.js
+++ b/devtools/client/storage/test/browser_storage_basic.js
@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/* import-globals-from head.js */
+
// Basic test to assert that the storage tree and table corresponding to each
// item in the storage tree is correctly displayed
@@ -21,10 +23,30 @@
"use strict";
const testCases = [
- [["cookies", "test1.example.org"],
- ["c1", "cs2", "c3", "uc1"]],
- [["cookies", "sectest1.example.org"],
- ["uc1", "cs2", "sc1"]],
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c3", "test1.example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
+ [
+ ["cookies", "sectest1.example.org"],
+ [
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("sc1", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("sc2", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
[["localStorage", "http://test1.example.org"],
["ls1", "ls2"]],
[["localStorage", "http://sectest1.example.org"],
@@ -38,28 +60,28 @@ const testCases = [
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1"]],
[["indexedDB", "http://test1.example.org"],
- ["idb1", "idb2"]],
- [["indexedDB", "http://test1.example.org", "idb1"],
+ ["idb1 (default)", "idb2 (default)"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)"],
["obj1", "obj2"]],
- [["indexedDB", "http://test1.example.org", "idb2"],
+ [["indexedDB", "http://test1.example.org", "idb2 (default)"],
["obj3"]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[1, 2, 3]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj2"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
[1]],
- [["indexedDB", "http://test1.example.org", "idb2", "obj3"],
+ [["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
[]],
[["indexedDB", "http://sectest1.example.org"],
[]],
[["indexedDB", "https://sectest1.example.org"],
- ["idb-s1", "idb-s2"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s1"],
+ ["idb-s1 (default)", "idb-s2 (default)"]],
+ [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)"],
["obj-s1"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s2"],
+ [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
["obj-s2"]],
- [["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
+ [["indexedDB", "https://sectest1.example.org", "idb-s1 (default)", "obj-s1"],
[6, 7]],
- [["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
+ [["indexedDB", "https://sectest1.example.org", "idb-s2 (default)", "obj-s2"],
[16]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js",
diff --git a/devtools/client/storage/test/browser_storage_cookies_add.js b/devtools/client/storage/test/browser_storage_cookies_add.js
new file mode 100644
index 000000000..ac66eb92c
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_cookies_add.js
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Basic test to check the adding of cookies.
+
+"use strict";
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
+ showAllColumns(true);
+
+ yield performAdd(["cookies", "http://test1.example.org"]);
+ yield performAdd(["cookies", "http://test1.example.org"]);
+ yield performAdd(["cookies", "http://test1.example.org"]);
+ yield performAdd(["cookies", "http://test1.example.org"]);
+ yield performAdd(["cookies", "http://test1.example.org"]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_cookies_delete_all.js b/devtools/client/storage/test/browser_storage_cookies_delete_all.js
index 6e6008e66..4640ebecb 100644
--- a/devtools/client/storage/test/browser_storage_cookies_delete_all.js
+++ b/devtools/client/storage/test/browser_storage_cookies_delete_all.js
@@ -8,11 +8,13 @@
// Test deleting all cookies
-function* performDelete(store, rowName, deleteAll) {
+function* performDelete(store, rowName, action) {
let contextMenu = gPanelWindow.document.getElementById(
"storage-table-popup");
let menuDeleteAllItem = contextMenu.querySelector(
"#storage-table-popup-delete-all");
+ let menuDeleteAllSessionCookiesItem = contextMenu.querySelector(
+ "#storage-table-popup-delete-all-session-cookies");
let menuDeleteAllFromItem = contextMenu.querySelector(
"#storage-table-popup-delete-all-from");
@@ -21,17 +23,23 @@ function* performDelete(store, rowName, deleteAll) {
yield selectTreeItem(store);
let eventWait = gUI.once("store-objects-updated");
+ let cells = getRowCells(rowName, true);
- let cells = getRowCells(rowName);
yield waitForContextMenu(contextMenu, cells.name, () => {
info(`Opened context menu in ${storeName}, row '${rowName}'`);
- if (deleteAll) {
- menuDeleteAllItem.click();
- } else {
- menuDeleteAllFromItem.click();
- let hostName = cells.host.value;
- ok(menuDeleteAllFromItem.getAttribute("label").includes(hostName),
+ switch (action) {
+ case "deleteAll":
+ menuDeleteAllItem.click();
+ break;
+ case "deleteAllSessionCookies":
+ menuDeleteAllSessionCookiesItem.click();
+ break;
+ case "deleteAllFrom":
+ menuDeleteAllFromItem.click();
+ let hostName = cells.host.value;
+ ok(menuDeleteAllFromItem.getAttribute("label").includes(hostName),
`Context menu item label contains '${hostName}'`);
+ break;
}
});
@@ -43,24 +51,94 @@ add_task(function* () {
info("test state before delete");
yield checkState([
- [["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
- [["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
+ [
+ ["cookies", "test1.example.org"], [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("c3", "test1.example.org", "/"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
+ [
+ ["cookies", "sectest1.example.org"], [
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("sc1", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("sc2", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
]);
info("delete all from domain");
// delete only cookies that match the host exactly
- yield performDelete(["cookies", "test1.example.org"], "c1", false);
+ let id = getCookieId("c1", "test1.example.org", "/browser");
+ yield performDelete(["cookies", "test1.example.org"], id, "deleteAllFrom");
+ yield performDelete(["cookies", "test1.example.org"], id, false);
info("test state after delete all from domain");
yield checkState([
// Domain cookies (.example.org) must not be deleted.
- [["cookies", "test1.example.org"], ["cs2", "uc1"]],
- [["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
+ [
+ ["cookies", "sectest1.example.org"],
+ [
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/"),
+ getCookieId("sc1", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("sc2", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+
+ info("delete all session cookies");
+ // delete only session cookies
+ id = getCookieId("cs2", ".example.org", "/");
+ yield performDelete(["cookies", "sectest1.example.org"], id,
+ "deleteAllSessionCookies");
+
+ info("test state after delete all session cookies");
+ yield checkState([
+ // Cookies with expiry date must not be deleted.
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
+ [
+ ["cookies", "sectest1.example.org"],
+ [
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/"),
+ getCookieId("sc2", "sectest1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
]);
info("delete all");
// delete all cookies for host, including domain cookies
- yield performDelete(["cookies", "sectest1.example.org"], "uc1", true);
+ id = getCookieId("uc2", ".example.org", "/");
+ yield performDelete(["cookies", "sectest1.example.org"], id, "deleteAll");
info("test state after delete all");
yield checkState([
diff --git a/devtools/client/storage/test/browser_storage_cookies_domain.js b/devtools/client/storage/test/browser_storage_cookies_domain.js
index dc93d6e67..7b194b73e 100644
--- a/devtools/client/storage/test/browser_storage_cookies_domain.js
+++ b/devtools/client/storage/test/browser_storage_cookies_domain.js
@@ -13,8 +13,16 @@ add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
yield checkState([
- [["cookies", "test1.example.org"],
- ["test1", "test2", "test3", "test4", "test5"]],
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("test1", ".test1.example.org", "/browser"),
+ getCookieId("test2", "test1.example.org", "/browser"),
+ getCookieId("test3", ".test1.example.org", "/browser"),
+ getCookieId("test4", "test1.example.org", "/browser"),
+ getCookieId("test5", ".test1.example.org", "/browser")
+ ]
+ ],
]);
yield finishTests();
diff --git a/devtools/client/storage/test/browser_storage_cookies_edit.js b/devtools/client/storage/test/browser_storage_cookies_edit.js
index 5818e4864..14944b398 100644
--- a/devtools/client/storage/test/browser_storage_cookies_edit.js
+++ b/devtools/client/storage/test/browser_storage_cookies_edit.js
@@ -10,13 +10,20 @@ add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
showAllColumns(true);
- yield editCell("test3", "name", "newTest3");
- yield editCell("newTest3", "path", "/");
- yield editCell("newTest3", "host", "test1.example.org");
- yield editCell("newTest3", "expires", "Tue, 14 Feb 2040 17:41:14 GMT");
- yield editCell("newTest3", "value", "newValue3");
- yield editCell("newTest3", "isSecure", "true");
- yield editCell("newTest3", "isHttpOnly", "true");
+ let id = getCookieId("test3", ".test1.example.org", "/browser");
+ yield editCell(id, "name", "newTest3");
+
+ id = getCookieId("newTest3", ".test1.example.org", "/browser");
+ yield editCell(id, "host", "test1.example.org");
+
+ id = getCookieId("newTest3", "test1.example.org", "/browser");
+ yield editCell(id, "path", "/");
+
+ id = getCookieId("newTest3", "test1.example.org", "/");
+ yield editCell(id, "expires", "Tue, 14 Feb 2040 17:41:14 GMT");
+ yield editCell(id, "value", "newValue3");
+ yield editCell(id, "isSecure", "true");
+ yield editCell(id, "isHttpOnly", "true");
yield finishTests();
});
diff --git a/devtools/client/storage/test/browser_storage_cookies_edit_keyboard.js b/devtools/client/storage/test/browser_storage_cookies_edit_keyboard.js
index 1208c4376..4bbb63fbe 100644
--- a/devtools/client/storage/test/browser_storage_cookies_edit_keyboard.js
+++ b/devtools/client/storage/test/browser_storage_cookies_edit_keyboard.js
@@ -10,10 +10,11 @@ add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
showAllColumns(true);
- yield startCellEdit("test4", "name");
+ let id = getCookieId("test4", "test1.example.org", "/browser");
+ yield startCellEdit(id, "name");
yield typeWithTerminator("test6", "VK_TAB");
- yield typeWithTerminator("/", "VK_TAB");
yield typeWithTerminator(".example.org", "VK_TAB");
+ yield typeWithTerminator("/", "VK_TAB");
yield typeWithTerminator("Tue, 25 Dec 2040 12:00:00 GMT", "VK_TAB");
yield typeWithTerminator("test6value", "VK_TAB");
yield typeWithTerminator("false", "VK_TAB");
diff --git a/devtools/client/storage/test/browser_storage_cookies_tab_navigation.js b/devtools/client/storage/test/browser_storage_cookies_tab_navigation.js
index 783a0c844..5da359b8d 100644
--- a/devtools/client/storage/test/browser_storage_cookies_tab_navigation.js
+++ b/devtools/client/storage/test/browser_storage_cookies_tab_navigation.js
@@ -10,7 +10,8 @@ add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
showAllColumns(true);
- yield startCellEdit("test1", "name");
+ let id = getCookieId("test1", ".test1.example.org", "/browser");
+ yield startCellEdit(id, "name");
PressKeyXTimes("VK_TAB", 18);
is(getCurrentEditorValue(), "value3",
diff --git a/devtools/client/storage/test/browser_storage_delete.js b/devtools/client/storage/test/browser_storage_delete.js
index c0e2b0ad7..a3ef7c290 100644
--- a/devtools/client/storage/test/browser_storage_delete.js
+++ b/devtools/client/storage/test/browser_storage_delete.js
@@ -13,9 +13,11 @@ const TEST_CASES = [
"ls1", "name"],
[["sessionStorage", "http://test1.example.org"],
"ss1", "name"],
- [["cookies", "test1.example.org"],
- "c1", "name"],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ [
+ ["cookies", "test1.example.org"],
+ getCookieId("c1", "test1.example.org", "/browser"), "name"
+ ],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
1, "name"],
[["Cache", "http://test1.example.org", "plop"],
MAIN_DOMAIN + "404_cached_file.js", "url"],
@@ -41,7 +43,7 @@ add_task(function* () {
yield waitForContextMenu(contextMenu, row[cellToClick], () => {
info(`Opened context menu in ${treeItemName}, row '${rowName}'`);
menuDeleteItem.click();
- let truncatedRowName = String(rowName).substr(0, 16);
+ let truncatedRowName = String(rowName).replace(SEPARATOR_GUID, "-").substr(0, 16);
ok(menuDeleteItem.getAttribute("label").includes(truncatedRowName),
`Context menu item label contains '${rowName}' (maybe truncated)`);
});
diff --git a/devtools/client/storage/test/browser_storage_delete_all.js b/devtools/client/storage/test/browser_storage_delete_all.js
index c4b6048fb..60b417bdb 100644
--- a/devtools/client/storage/test/browser_storage_delete_all.js
+++ b/devtools/client/storage/test/browser_storage_delete_all.js
@@ -29,7 +29,7 @@ add_task(function* () {
["iframe-u-ss1", "iframe-u-ss2"]],
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1"]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[1, 2, 3]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
@@ -41,7 +41,7 @@ add_task(function* () {
const deleteHosts = [
[["localStorage", "https://sectest1.example.org"], "iframe-s-ls1", "name"],
[["sessionStorage", "https://sectest1.example.org"], "iframe-s-ss1", "name"],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"], 1, "name"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], 1, "name"],
[["Cache", "http://test1.example.org", "plop"],
MAIN_DOMAIN + "404_cached_file.js", "url"],
];
@@ -78,7 +78,7 @@ add_task(function* () {
["iframe-u-ss1", "iframe-u-ss2"]],
[["sessionStorage", "https://sectest1.example.org"],
[]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[]],
[["Cache", "http://test1.example.org", "plop"],
[]],
diff --git a/devtools/client/storage/test/browser_storage_delete_tree.js b/devtools/client/storage/test/browser_storage_delete_tree.js
index 867a1c8b6..2bca4c344 100644
--- a/devtools/client/storage/test/browser_storage_delete_tree.js
+++ b/devtools/client/storage/test/browser_storage_delete_tree.js
@@ -17,10 +17,20 @@ add_task(function* () {
info("test state before delete");
yield checkState([
- [["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("cs2", ".example.org", "/"),
+ getCookieId("c3", "test1.example.org", "/"),
+ getCookieId("c4", ".example.org", "/"),
+ getCookieId("uc1", ".example.org", "/"),
+ getCookieId("uc2", ".example.org", "/")
+ ]
+ ],
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
[["sessionStorage", "http://test1.example.org"], ["ss1"]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"], [1, 2, 3]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], [1, 2, 3]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
]);
@@ -30,7 +40,7 @@ add_task(function* () {
["cookies", "test1.example.org"],
["localStorage", "http://test1.example.org"],
["sessionStorage", "http://test1.example.org"],
- ["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ ["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
["Cache", "http://test1.example.org", "plop"],
];
@@ -59,7 +69,7 @@ add_task(function* () {
[["cookies", "test1.example.org"], []],
[["localStorage", "http://test1.example.org"], []],
[["sessionStorage", "http://test1.example.org"], []],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"], []],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"], []],
[["Cache", "http://test1.example.org", "plop"], []],
]);
diff --git a/devtools/client/storage/test/browser_storage_dom_cache_disabled.js b/devtools/client/storage/test/browser_storage_dom_cache_disabled.js
new file mode 100644
index 000000000..db0aca392
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_dom_cache_disabled.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* import-globals-from ../../framework/test/shared-head.js */
+
+"use strict";
+
+// Test the storage inspector when dom.caches.enabled=false.
+
+add_task(function* () {
+ // Disable the DOM cache
+ Services.prefs.setBoolPref(DOM_CACHE, false);
+
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
+
+ const state = [
+ [["localStorage", "http://test1.example.org"],
+ ["ls1", "ls2"]],
+ [["localStorage", "http://sectest1.example.org"],
+ ["iframe-u-ls1"]],
+ [["localStorage", "https://sectest1.example.org"],
+ ["iframe-s-ls1"]],
+ [["sessionStorage", "http://test1.example.org"],
+ ["ss1"]],
+ [["sessionStorage", "http://sectest1.example.org"],
+ ["iframe-u-ss1", "iframe-u-ss2"]],
+ [["sessionStorage", "https://sectest1.example.org"],
+ ["iframe-s-ss1"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
+ [1, 2, 3]],
+ ];
+
+ yield checkState(state);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js b/devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js
new file mode 100644
index 000000000..6cf52f2d3
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js
@@ -0,0 +1,188 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test dynamic updates in the storage inspector for cookies.
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
+
+ gUI.tree.expandAll();
+
+ ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
+ let c1id = getCookieId("c1", "test1.example.org", "/browser");
+ yield selectTableItem(c1id);
+
+ // test that value is something initially
+ let initialValue = [[
+ {name: "c1", value: "1.2.3.4.5.6.7"},
+ {name: "c1.Path", value: "/browser"}
+ ], [
+ {name: "c1", value: "Array"},
+ {name: "c1.0", value: "1"},
+ {name: "c1.6", value: "7"}
+ ]];
+
+ // test that value is something initially
+ let finalValue = [[
+ {name: "c1", value: '{"foo": 4,"bar":6}'},
+ {name: "c1.Path", value: "/browser"}
+ ], [
+ {name: "c1", value: "Object"},
+ {name: "c1.foo", value: "4"},
+ {name: "c1.bar", value: "6"}
+ ]];
+
+ // Check that sidebar shows correct initial value
+ yield findVariableViewProperties(initialValue[0], false);
+
+ yield findVariableViewProperties(initialValue[1], true);
+ // Check if table shows correct initial value
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("c2", "test1.example.org", "/browser")
+ ]
+ ],
+ ]);
+ checkCell(c1id, "value", "1.2.3.4.5.6.7");
+
+ gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
+ yield gUI.once("sidebar-updated");
+
+ yield findVariableViewProperties(finalValue[0], false);
+ yield findVariableViewProperties(finalValue[1], true);
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("c2", "test1.example.org", "/browser")
+ ]
+ ],
+ ]);
+ checkCell(c1id, "value", '{"foo": 4,"bar":6}');
+
+ // Add a new entry
+ gWindow.addCookie("c3", "booyeah");
+
+ // Wait once for update and another time for value fetching
+ yield gUI.once("store-objects-updated");
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("c2", "test1.example.org", "/browser"),
+ getCookieId("c3", "test1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+ let c3id = getCookieId("c3", "test1.example.org",
+ "/browser/devtools/client/storage/test/");
+ checkCell(c3id, "value", "booyeah");
+
+ // Add another
+ gWindow.addCookie("c4", "booyeah");
+
+ // Wait once for update and another time for value fetching
+ yield gUI.once("store-objects-updated");
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c1", "test1.example.org", "/browser"),
+ getCookieId("c2", "test1.example.org", "/browser"),
+ getCookieId("c3", "test1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("c4", "test1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+ let c4id = getCookieId("c4", "test1.example.org",
+ "/browser/devtools/client/storage/test/");
+ checkCell(c4id, "value", "booyeah");
+
+ // Removing cookies
+ gWindow.removeCookie("c1", "/browser");
+
+ yield gUI.once("sidebar-updated");
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c2", "test1.example.org", "/browser"),
+ getCookieId("c3", "test1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ getCookieId("c4", "test1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+
+ ok(!gUI.sidebar.hidden, "Sidebar still visible for next row");
+
+ // Check if next element's value is visible in sidebar
+ yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
+
+ // Keep deleting till no rows
+ gWindow.removeCookie("c3");
+
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c2", "test1.example.org", "/browser"),
+ getCookieId("c4", "test1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+
+ // Check if next element's value is visible in sidebar
+ yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
+
+ gWindow.removeCookie("c2", "/browser");
+
+ yield gUI.once("sidebar-updated");
+
+ yield checkState([
+ [
+ ["cookies", "test1.example.org"],
+ [
+ getCookieId("c4", "test1.example.org",
+ "/browser/devtools/client/storage/test/")
+ ]
+ ],
+ ]);
+
+ // Check if next element's value is visible in sidebar
+ yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
+
+ gWindow.removeCookie("c4");
+
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [["cookies", "test1.example.org"], [ ]],
+ ]);
+
+ ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_dynamic_updates_localStorage.js b/devtools/client/storage/test/browser_storage_dynamic_updates_localStorage.js
new file mode 100644
index 000000000..35912ce3a
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_dynamic_updates_localStorage.js
@@ -0,0 +1,70 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test dynamic updates in the storage inspector for localStorage.
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
+
+ gUI.tree.expandAll();
+
+ ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
+
+ yield checkState([
+ [
+ ["localStorage", "http://test1.example.org"],
+ ["ls1", "ls2", "ls3", "ls4", "ls5", "ls6", "ls7"]
+ ],
+ ]);
+
+ gWindow.localStorage.removeItem("ls4");
+
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["localStorage", "http://test1.example.org"],
+ ["ls1", "ls2", "ls3", "ls5", "ls6", "ls7"]
+ ],
+ ]);
+
+ gWindow.localStorage.setItem("ls4", "again");
+
+ yield gUI.once("store-objects-updated");
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["localStorage", "http://test1.example.org"],
+ ["ls1", "ls2", "ls3", "ls4", "ls5", "ls6", "ls7"]
+ ],
+ ]);
+ // Updating a row
+ gWindow.localStorage.setItem("ls2", "ls2-changed");
+
+ yield gUI.once("store-objects-updated");
+ yield gUI.once("store-objects-updated");
+
+ checkCell("ls2", "value", "ls2-changed");
+
+ // Clearing items. Bug 1233497 makes it so that we can no longer yield
+ // CPOWs from Tasks. We work around this by calling clear via a ContentTask
+ // instead.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+ return Task.spawn(content.wrappedJSObject.clear);
+ });
+
+ yield gUI.once("store-objects-cleared");
+
+ yield checkState([
+ [
+ ["localStorage", "http://test1.example.org"],
+ [ ]
+ ],
+ ]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_dynamic_updates_sessionStorage.js b/devtools/client/storage/test/browser_storage_dynamic_updates_sessionStorage.js
new file mode 100644
index 000000000..8c2f2537e
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_dynamic_updates_sessionStorage.js
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Test dynamic updates in the storage inspector for sessionStorage.
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
+
+ gUI.tree.expandAll();
+
+ ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
+ yield checkState([
+ [
+ ["sessionStorage", "http://test1.example.org"],
+ ["ss1", "ss2", "ss3"]
+ ],
+ ]);
+
+ gWindow.sessionStorage.setItem("ss4", "new-item");
+
+ yield gUI.once("store-objects-updated");
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["sessionStorage", "http://test1.example.org"],
+ ["ss1", "ss2", "ss3", "ss4"]
+ ],
+ ]);
+
+ // deleting item
+
+ gWindow.sessionStorage.removeItem("ss3");
+
+ yield gUI.once("store-objects-updated");
+
+ gWindow.sessionStorage.removeItem("ss1");
+
+ yield gUI.once("store-objects-updated");
+
+ yield checkState([
+ [
+ ["sessionStorage", "http://test1.example.org"],
+ ["ss2", "ss4"]
+ ],
+ ]);
+
+ yield selectTableItem("ss2");
+
+ ok(!gUI.sidebar.hidden, "sidebar is visible");
+
+ // Checking for correct value in sidebar before update
+ yield findVariableViewProperties([{name: "ss2", value: "foobar"}]);
+
+ gWindow.sessionStorage.setItem("ss2", "changed=ss2");
+
+ yield gUI.once("sidebar-updated");
+
+ checkCell("ss2", "value", "changed=ss2");
+
+ yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
+
+ // Clearing items. Bug 1233497 makes it so that we can no longer yield
+ // CPOWs from Tasks. We work around this by calling clear via a ContentTask
+ // instead.
+ yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
+ return Task.spawn(content.wrappedJSObject.clear);
+ });
+
+ yield gUI.once("store-objects-cleared");
+
+ yield checkState([
+ [
+ ["sessionStorage", "http://test1.example.org"],
+ [ ]
+ ],
+ ]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_empty_objectstores.js b/devtools/client/storage/test/browser_storage_empty_objectstores.js
index 1749c91b8..e6f259742 100644
--- a/devtools/client/storage/test/browser_storage_empty_objectstores.js
+++ b/devtools/client/storage/test/browser_storage_empty_objectstores.js
@@ -21,14 +21,14 @@
// storage-secured-iframe.html and storage-unsecured-iframe.html
const storeItems = [
[["indexedDB", "http://test1.example.org"],
- ["idb1", "idb2"]],
- [["indexedDB", "http://test1.example.org", "idb1"],
+ ["idb1 (default)", "idb2 (default)"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)"],
["obj1", "obj2"]],
- [["indexedDB", "http://test1.example.org", "idb2"],
+ [["indexedDB", "http://test1.example.org", "idb2 (default)"],
[]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"],
[1, 2, 3]],
- [["indexedDB", "http://test1.example.org", "idb1", "obj2"],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"],
[1]]
];
diff --git a/devtools/client/storage/test/browser_storage_indexeddb_delete.js b/devtools/client/storage/test/browser_storage_indexeddb_delete.js
index 18a0daf69..5c499c9e9 100644
--- a/devtools/client/storage/test/browser_storage_indexeddb_delete.js
+++ b/devtools/client/storage/test/browser_storage_indexeddb_delete.js
@@ -16,11 +16,11 @@ add_task(function* () {
info("test state before delete");
yield checkState([
- [["indexedDB", "http://test1.example.org"], ["idb1", "idb2"]],
+ [["indexedDB", "http://test1.example.org"], ["idb1 (default)", "idb2 (default)"]],
]);
info("do the delete");
- const deletedDb = ["indexedDB", "http://test1.example.org", "idb1"];
+ const deletedDb = ["indexedDB", "http://test1.example.org", "idb1 (default)"];
yield selectTreeItem(deletedDb);
@@ -40,7 +40,7 @@ add_task(function* () {
info("test state after delete");
yield checkState([
- [["indexedDB", "http://test1.example.org"], ["idb2"]],
+ [["indexedDB", "http://test1.example.org"], ["idb2 (default)"]],
]);
yield finishTests();
diff --git a/devtools/client/storage/test/browser_storage_indexeddb_delete_blocked.js b/devtools/client/storage/test/browser_storage_indexeddb_delete_blocked.js
index 6e89c4f28..2d77896f3 100644
--- a/devtools/client/storage/test/browser_storage_indexeddb_delete_blocked.js
+++ b/devtools/client/storage/test/browser_storage_indexeddb_delete_blocked.js
@@ -13,19 +13,19 @@ add_task(function* () {
info("test state before delete");
yield checkState([
- [["indexedDB", "http://test1.example.org"], ["idb"]]
+ [["indexedDB", "http://test1.example.org"], ["idb (default)"]]
]);
info("do the delete");
yield selectTreeItem(["indexedDB", "http://test1.example.org"]);
- let actor = gUI.getCurrentActor();
- let result = yield actor.removeDatabase("http://test1.example.org", "idb");
+ let front = gUI.getCurrentFront();
+ let result = yield front.removeDatabase("http://test1.example.org", "idb (default)");
ok(result.blocked, "removeDatabase attempt is blocked");
info("test state after blocked delete");
yield checkState([
- [["indexedDB", "http://test1.example.org"], ["idb"]]
+ [["indexedDB", "http://test1.example.org"], ["idb (default)"]]
]);
let eventWait = gUI.once("store-objects-updated");
@@ -47,7 +47,7 @@ add_task(function* () {
info("try to delete database from nonexistent host");
let errorThrown = false;
try {
- result = yield actor.removeDatabase("http://test2.example.org", "idb");
+ result = yield front.removeDatabase("http://test2.example.org", "idb (default)");
} catch (ex) {
errorThrown = true;
}
diff --git a/devtools/client/storage/test/browser_storage_indexeddb_duplicate_names.js b/devtools/client/storage/test/browser_storage_indexeddb_duplicate_names.js
new file mode 100644
index 000000000..8316d22c5
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_indexeddb_duplicate_names.js
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Test to verify that indexedDBs with duplicate names (different types / paths)
+// work as expected.
+
+"use strict";
+
+add_task(function* () {
+ const TESTPAGE = MAIN_DOMAIN + "storage-indexeddb-duplicate-names.html";
+
+ setPermission(TESTPAGE, "indexedDB");
+
+ yield openTabAndSetupStorage(TESTPAGE);
+
+ yield checkState([
+ [
+ ["indexedDB", "http://test1.example.org"], [
+ "idb1 (default)",
+ "idb1 (temporary)",
+ "idb1 (persistent)",
+ "idb2 (default)",
+ "idb2 (temporary)",
+ "idb2 (persistent)"
+ ]
+ ]
+ ]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_localstorage_add.js b/devtools/client/storage/test/browser_storage_localstorage_add.js
new file mode 100644
index 000000000..de40957b8
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_localstorage_add.js
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Basic test to check the adding of localStorage entries.
+
+"use strict";
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-localstorage.html");
+ showAllColumns(true);
+
+ yield performAdd(["localStorage", "http://test1.example.org"]);
+ yield performAdd(["localStorage", "http://test1.example.org"]);
+ yield performAdd(["localStorage", "http://test1.example.org"]);
+ yield performAdd(["localStorage", "http://test1.example.org"]);
+ yield performAdd(["localStorage", "http://test1.example.org"]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_overflow.js b/devtools/client/storage/test/browser_storage_overflow.js
index 88181ca05..21b931c8e 100644
--- a/devtools/client/storage/test/browser_storage_overflow.js
+++ b/devtools/client/storage/test/browser_storage_overflow.js
@@ -2,40 +2,58 @@
// inspector table.
"use strict";
+const ITEMS_PER_PAGE = 50;
+
add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-overflow.html");
- let $ = id => gPanelWindow.document.querySelector(id);
- let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
-
gUI.tree.expandAll();
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
+ checkCellLength(ITEMS_PER_PAGE);
+
+ yield scroll();
+ checkCellLength(ITEMS_PER_PAGE * 2);
- let table = $("#storage-table .table-widget-body");
- let cellHeight = $(".table-widget-cell").getBoundingClientRect().height;
+ yield scroll();
+ checkCellLength(ITEMS_PER_PAGE * 3);
- is($$("#value .table-widget-cell").length, 50,
- "Table should initially display 50 items");
+ // Check that the columns are sorted in a human readable way (ascending).
+ checkCellValues("ASC");
- let onStoresUpdate = gUI.once("store-objects-updated");
- table.scrollTop += cellHeight * 50;
- yield onStoresUpdate;
+ // Sort descending.
+ clickColumnHeader("name");
- is($$("#value .table-widget-cell").length, 100,
- "Table should display 100 items after scrolling");
+ // Check that the columns are sorted in a human readable way (descending).
+ checkCellValues("DEC");
- onStoresUpdate = gUI.once("store-objects-updated");
- table.scrollTop += cellHeight * 50;
- yield onStoresUpdate;
+ yield finishTests();
+});
- is($$("#value .table-widget-cell").length, 150,
- "Table should display 150 items after scrolling");
+function checkCellLength(len) {
+ let cells = gPanelWindow.document
+ .querySelectorAll("#name .table-widget-cell");
+ let msg = `Table should initially display ${len} items`;
- onStoresUpdate = gUI.once("store-objects-updated");
+ is(cells.length, len, msg);
+}
+
+function checkCellValues(order) {
+ let cells = [...gPanelWindow.document
+ .querySelectorAll("#name .table-widget-cell")];
+ cells.forEach(function (cell, index, arr) {
+ let i = order === "ASC" ? index + 1 : arr.length - index;
+ is(cell.value, `item-${i}`, `Cell value is correct (${order}).`);
+ });
+}
+
+function* scroll() {
+ let $ = id => gPanelWindow.document.querySelector(id);
+
+ let table = $("#storage-table .table-widget-body");
+ let cell = $("#name .table-widget-cell");
+ let cellHeight = cell.getBoundingClientRect().height;
+
+ let onStoresUpdate = gUI.once("store-objects-updated");
table.scrollTop += cellHeight * 50;
yield onStoresUpdate;
-
- is($$("#value .table-widget-cell").length, 160,
- "Table should display all 160 items after scrolling");
- yield finishTests();
-});
+}
diff --git a/devtools/client/storage/test/browser_storage_sessionstorage_add.js b/devtools/client/storage/test/browser_storage_sessionstorage_add.js
new file mode 100644
index 000000000..8f220bc81
--- /dev/null
+++ b/devtools/client/storage/test/browser_storage_sessionstorage_add.js
@@ -0,0 +1,20 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Basic test to check the adding of sessionStorage entries.
+
+"use strict";
+
+add_task(function* () {
+ yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-sessionstorage.html");
+ showAllColumns(true);
+
+ yield performAdd(["sessionStorage", "http://test1.example.org"]);
+ yield performAdd(["sessionStorage", "http://test1.example.org"]);
+ yield performAdd(["sessionStorage", "http://test1.example.org"]);
+ yield performAdd(["sessionStorage", "http://test1.example.org"]);
+ yield performAdd(["sessionStorage", "http://test1.example.org"]);
+
+ yield finishTests();
+});
diff --git a/devtools/client/storage/test/browser_storage_sidebar.js b/devtools/client/storage/test/browser_storage_sidebar.js
index 9b60026a0..6712ac013 100644
--- a/devtools/client/storage/test/browser_storage_sidebar.js
+++ b/devtools/client/storage/test/browser_storage_sidebar.js
@@ -20,22 +20,22 @@ const testCases = [
sidebarHidden: true
},
{
- location: "cs2",
+ location: getCookieId("cs2", ".example.org", "/"),
sidebarHidden: false
},
{
sendEscape: true
},
{
- location: "cs2",
+ location: getCookieId("cs2", ".example.org", "/"),
sidebarHidden: false
},
{
- location: "uc1",
+ location: getCookieId("uc1", ".example.org", "/"),
sidebarHidden: false
},
{
- location: "uc1",
+ location: getCookieId("uc1", ".example.org", "/"),
sidebarHidden: false
},
@@ -72,17 +72,17 @@ const testCases = [
sidebarHidden: true
},
{
- location: "idb2",
+ location: "idb2 (default)",
sidebarHidden: false
},
{
- location: ["indexedDB", "http://test1.example.org", "idb2", "obj3"],
+ location: ["indexedDB", "http://test1.example.org", "idb2 (default)", "obj3"],
sidebarHidden: true
},
{
- location: ["indexedDB", "https://sectest1.example.org", "idb-s2"],
+ location: ["indexedDB", "https://sectest1.example.org", "idb-s2 (default)"],
sidebarHidden: true
},
{
diff --git a/devtools/client/storage/test/browser_storage_sidebar_update.js b/devtools/client/storage/test/browser_storage_sidebar_update.js
index 419d63020..92547815a 100644
--- a/devtools/client/storage/test/browser_storage_sidebar_update.js
+++ b/devtools/client/storage/test/browser_storage_sidebar_update.js
@@ -26,7 +26,7 @@ add_task(function* () {
for (let i = 0; i < UPDATE_COUNT; i++) {
info(`Performing update #${i}`);
updates.push(gUI.once("sidebar-updated"));
- gUI.displayObjectSidebar();
+ gUI.updateObjectSidebar();
}
yield promise.all(updates);
diff --git a/devtools/client/storage/test/browser_storage_values.js b/devtools/client/storage/test/browser_storage_values.js
index 920ce350e..1d3e9ff76 100644
--- a/devtools/client/storage/test/browser_storage_values.js
+++ b/devtools/client/storage/test/browser_storage_values.js
@@ -17,7 +17,7 @@
const LONG_WORD = "a".repeat(1000);
const testCases = [
- ["cs2", [
+ [getCookieId("cs2", ".example.org", "/"), [
{name: "cs2", value: "sessionCookie"},
{name: "cs2.Path", value: "/"},
{name: "cs2.HostOnly", value: "false"},
@@ -26,7 +26,7 @@ const testCases = [
{name: "cs2.Expires", value: "Session"},
{name: "cs2.Secure", value: "false"},
]],
- ["c1", [
+ [getCookieId("c1", "test1.example.org", "/browser"), [
{name: "c1", value: JSON.stringify(["foo", "Bar", {foo: "Bar"}])},
{name: "c1.Path", value: "/browser"},
{name: "c1.HostOnly", value: "true"},
@@ -42,9 +42,13 @@ const testCases = [
{name: "c1.2", value: "Object"},
{name: "c1.2.foo", value: "Bar"},
], true],
- ["c_encoded", [
- {name: "c_encoded", value: encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}))}
- ]],
+ [
+ getCookieId("c_encoded", "test1.example.org",
+ "/browser/devtools/client/storage/test/"),
+ [
+ {name: "c_encoded", value: encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}))}
+ ]
+ ],
[null, [
{name: "c_encoded", value: "Object"},
{name: "c_encoded.foo", value: "Object"},
@@ -120,7 +124,7 @@ const testCases = [
{name: "ss5.3", value: `${LONG_WORD}&${LONG_WORD}`},
{name: "ss5.4", value: `${LONG_WORD}&${LONG_WORD}`},
], true],
- [["indexedDB", "http://test1.example.org", "idb1", "obj1"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj1"]],
[1, [
{name: 1, value: JSON.stringify({id: 1, name: "foo", email: "foo@bar.com"})}
]],
@@ -129,7 +133,7 @@ const testCases = [
{name: "1.name", value: "foo"},
{name: "1.email", value: "foo@bar.com"},
], true],
- [["indexedDB", "http://test1.example.org", "idb1", "obj2"]],
+ [["indexedDB", "http://test1.example.org", "idb1 (default)", "obj2"]],
[1, [
{name: 1, value: JSON.stringify({
id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"
diff --git a/devtools/client/storage/test/head.js b/devtools/client/storage/test/head.js
index 9662393cf..181132a45 100644
--- a/devtools/client/storage/test/head.js
+++ b/devtools/client/storage/test/head.js
@@ -15,6 +15,7 @@ Services.scriptloader.loadSubScript(
const {TableWidget} = require("devtools/client/shared/widgets/TableWidget");
const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
const STORAGE_PREF = "devtools.storage.enabled";
+const DOM_CACHE = "dom.caches.enabled";
const DUMPEMIT_PREF = "devtools.dump.emit";
const DEBUGGERLOG_PREF = "devtools.debugger.log";
// Allows Cache API to be working on usage `http` test page
@@ -24,6 +25,11 @@ const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
+// GUID to be used as a separator in compound keys. This must match the same
+// constant in devtools/server/actors/storage.js,
+// devtools/client/storage/ui.js and devtools/server/tests/browser/head.js
+const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
+
var gToolbox, gPanelWindow, gWindow, gUI;
// Services.prefs.setBoolPref(DUMPEMIT_PREF, true);
@@ -33,11 +39,12 @@ Services.prefs.setBoolPref(STORAGE_PREF, true);
Services.prefs.setBoolPref(CACHES_ON_HTTP_PREF, true);
registerCleanupFunction(() => {
gToolbox = gPanelWindow = gWindow = gUI = null;
- Services.prefs.clearUserPref(STORAGE_PREF);
- Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
- Services.prefs.clearUserPref(DUMPEMIT_PREF);
- Services.prefs.clearUserPref(DEBUGGERLOG_PREF);
Services.prefs.clearUserPref(CACHES_ON_HTTP_PREF);
+ Services.prefs.clearUserPref(DEBUGGERLOG_PREF);
+ Services.prefs.clearUserPref(DOM_CACHE);
+ Services.prefs.clearUserPref(DUMPEMIT_PREF);
+ Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
+ Services.prefs.clearUserPref(STORAGE_PREF);
});
/**
@@ -505,10 +512,16 @@ function* selectTreeItem(ids) {
* The id of the row in the table widget
*/
function* selectTableItem(id) {
- let selector = ".table-widget-cell[data-id='" + id + "']";
+ let table = gUI.table;
+ let selector = ".table-widget-column#" + table.uniqueId +
+ " .table-widget-cell[value='" + id + "']";
let target = gPanelWindow.document.querySelector(selector);
ok(target, "table item found with ids " + id);
+ if (!target) {
+ showAvailableIds();
+ }
+
yield click(target);
yield gUI.once("sidebar-updated");
}
@@ -586,22 +599,39 @@ function getRowCells(id, includeHidden = false) {
if (!item) {
ok(false, "Row id '" + id + "' exists");
+
+ showAvailableIds();
}
- let index = table.columns.get(table.uniqueId).visibleCellNodes.indexOf(item);
+ let index = table.columns.get(table.uniqueId).cellNodes.indexOf(item);
let cells = {};
for (let [name, column] of [...table.columns]) {
if (!includeHidden && column.column.parentNode.hidden) {
continue;
}
- cells[name] = column.visibleCellNodes[index];
+ cells[name] = column.cellNodes[index];
}
return cells;
}
/**
+ * Show available ids.
+ */
+function showAvailableIds() {
+ let doc = gPanelWindow.document;
+ let table = gUI.table;
+
+ info("Available ids:");
+ let cells = doc.querySelectorAll(".table-widget-column#" + table.uniqueId +
+ " .table-widget-cell");
+ for (let cell of cells) {
+ info(" - " + cell.getAttribute("value"));
+ }
+}
+
+/**
* Get a cell value.
*
* @param {String} id
@@ -704,6 +734,20 @@ function showColumn(id, state) {
}
/**
+ * Toggle sort direction on a column by clicking on the column header.
+ *
+ * @param {String} id
+ * The uniqueId of the given column.
+ */
+function clickColumnHeader(id) {
+ let columns = gUI.table.columns;
+ let column = columns.get(id);
+ let header = column.header;
+
+ header.click();
+}
+
+/**
* Show or hide all columns.
*
* @param {Boolean} state
@@ -798,9 +842,18 @@ function* checkState(state) {
is(items.size, names.length,
`There is correct number of rows in ${storeName}`);
+
+ if (names.length === 0) {
+ showAvailableIds();
+ }
+
for (let name of names) {
ok(items.has(name),
`There is item with name '${name}' in ${storeName}`);
+
+ if (!items.has(name)) {
+ showAvailableIds();
+ }
}
}
}
@@ -838,3 +891,59 @@ var focusSearchBoxUsingShortcut = Task.async(function* (panelWin, callback) {
callback();
}
});
+
+function getCookieId(name, domain, path) {
+ return `${name}${SEPARATOR_GUID}${domain}${SEPARATOR_GUID}${path}`;
+}
+
+function setPermission(url, permission) {
+ const nsIPermissionManager = Components.interfaces.nsIPermissionManager;
+
+ let uri = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService)
+ .newURI(url, null, null);
+ let ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
+ .getService(Ci.nsIScriptSecurityManager);
+ let principal = ssm.createCodebasePrincipal(uri, {});
+
+ Components.classes["@mozilla.org/permissionmanager;1"]
+ .getService(nsIPermissionManager)
+ .addFromPrincipal(principal, permission,
+ nsIPermissionManager.ALLOW_ACTION);
+}
+
+/**
+ * Add an item.
+ * @param {Array} store
+ * An array containing the path to the store to which we wish to add an
+ * item.
+ */
+function* performAdd(store) {
+ let storeName = store.join(" > ");
+ let toolbar = gPanelWindow.document.getElementById("storage-toolbar");
+ let type = store[0];
+
+ yield selectTreeItem(store);
+
+ let menuAdd = toolbar.querySelector(
+ "#add-button");
+
+ if (menuAdd.hidden) {
+ is(menuAdd.hidden, false,
+ `performAdd called for ${storeName} but it is not supported`);
+ return;
+ }
+
+ let eventEdit = gUI.table.once("row-edit");
+ let eventWait = gUI.once("store-objects-updated");
+
+ menuAdd.click();
+
+ let rowId = yield eventEdit;
+ yield eventWait;
+
+ let key = type === "cookies" ? "uniqueKey" : "name";
+ let value = getCellValue(rowId, key);
+
+ is(rowId, value, `Row '${rowId}' was successfully added.`);
+}
diff --git a/devtools/client/storage/test/storage-indexeddb-duplicate-names.html b/devtools/client/storage/test/storage-indexeddb-duplicate-names.html
new file mode 100644
index 000000000..d8c76dc2a
--- /dev/null
+++ b/devtools/client/storage/test/storage-indexeddb-duplicate-names.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta charset="utf-8">
+ <title>Storage inspector IndexedDBs with duplicate names</title>
+
+ <script type="application/javascript;version=1.7">
+ "use strict";
+
+ function createIndexedDBs() {
+ createIndexedDB("idb1", "temporary");
+ createIndexedDB("idb1", "default");
+ createIndexedDB("idb1", "persistent");
+ createIndexedDB("idb2", "temporary");
+ createIndexedDB("idb2", "default");
+ createIndexedDB("idb2", "persistent");
+ }
+
+ function createIndexedDB(name, storage) {
+ let open = indexedDB.open(name, {storage: storage});
+
+ open.onsuccess = function () {
+ let db = open.result;
+ db.close();
+ };
+ }
+
+ function deleteDB(dbName, storage) {
+ return new Promise(resolve => {
+ dump(`removing database ${dbName} (${storage}) from ${document.location}\n`);
+ indexedDB.deleteDatabase(dbName, { storage: storage }).onsuccess = resolve;
+ });
+ }
+
+ window.clear = function* () {
+ yield deleteDB("idb1", "temporary");
+ yield deleteDB("idb1", "default");
+ yield deleteDB("idb1", "persistent");
+ yield deleteDB("idb2", "temporary");
+ yield deleteDB("idb2", "default");
+ yield deleteDB("idb2", "persistent");
+
+ dump(`removed indexedDB data from ${document.location}\n`);
+ };
+ </script>
+</head>
+<body onload="createIndexedDBs()">
+ <h1>storage-indexeddb-duplicate-names.html</h1>
+</body>
+</html>
diff --git a/devtools/client/storage/test/storage-listings.html b/devtools/client/storage/test/storage-listings.html
index de3054d3a..313b36b71 100644
--- a/devtools/client/storage/test/storage-listings.html
+++ b/devtools/client/storage/test/storage-listings.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
<html>
<!--
Bug 970517 - Storage inspector front end - tests
@@ -20,7 +20,10 @@ document.cookie = "c1=foobar; expires=" +
new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
document.cookie = "c3=foobar-2; expires=" +
- new Date(cookieExpiresTime2).toGMTString() + "; path=/";
+ new Date(cookieExpiresTime1).toGMTString() + "; path=/";
+document.cookie = "c4=foobar-3; expires=" +
+ new Date(cookieExpiresTime2).toGMTString() + "; path=/; domain=" +
+ partialHostname;
// ... and some local storage items ..
localStorage.setItem("ls1", "foobar");
localStorage.setItem("ls2", "foobar-2");
@@ -110,14 +113,19 @@ let cacheGenerator = function*() {
window.setup = function*() {
yield idbGenerator();
- yield cacheGenerator();
+
+ if (window.caches) {
+ yield cacheGenerator();
+ }
};
window.clear = function*() {
yield deleteDB("idb1");
yield deleteDB("idb2");
- yield caches.delete("plop");
+ if (window.caches) {
+ yield caches.delete("plop");
+ }
dump("removed indexedDB and cache data from " + document.location + "\n");
};
diff --git a/devtools/client/storage/test/storage-overflow.html b/devtools/client/storage/test/storage-overflow.html
index ee8db36e6..6309046b3 100644
--- a/devtools/client/storage/test/storage-overflow.html
+++ b/devtools/client/storage/test/storage-overflow.html
@@ -11,7 +11,7 @@ Bug 1171903 - Storage Inspector endless scrolling
<script type="text/javascript;version=1.8">
"use strict";
-for (let i = 0; i < 160; i++) {
+for (let i = 1; i < 151; i++) {
localStorage.setItem(`item-${i}`, `value-${i}`);
}
</script>
diff --git a/devtools/client/storage/test/storage-secured-iframe.html b/devtools/client/storage/test/storage-secured-iframe.html
index 8424fd4cd..9e1ef60a0 100644
--- a/devtools/client/storage/test/storage-secured-iframe.html
+++ b/devtools/client/storage/test/storage-secured-iframe.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
<html>
<!--
Iframe for testing multiple host detetion in storage actor
@@ -9,7 +9,10 @@ Iframe for testing multiple host detetion in storage actor
<body>
<script type="application/javascript;version=1.7">
"use strict";
+let cookieExpiresTime = 2000000000000;
document.cookie = "sc1=foobar;";
+document.cookie = "sc2=foobar-2; expires=" +
+ new Date(cookieExpiresTime).toGMTString() + ";";
localStorage.setItem("iframe-s-ls1", "foobar");
sessionStorage.setItem("iframe-s-ss1", "foobar-2");
dump("added cookies and storage from secured iframe\n");
diff --git a/devtools/client/storage/test/storage-unsecured-iframe.html b/devtools/client/storage/test/storage-unsecured-iframe.html
index a69ffdfd1..cd08a6164 100644
--- a/devtools/client/storage/test/storage-unsecured-iframe.html
+++ b/devtools/client/storage/test/storage-unsecured-iframe.html
@@ -9,7 +9,10 @@ Iframe for testing multiple host detetion in storage actor
<body>
<script>
"use strict";
+let cookieExpiresTime = 2000000000000;
document.cookie = "uc1=foobar; domain=.example.org; path=/";
+document.cookie = "uc2=foobar-2; expires=" +
+ new Date(cookieExpiresTime).toGMTString() + "; path=/; domain=.example.org";
localStorage.setItem("iframe-u-ls1", "foobar");
sessionStorage.setItem("iframe-u-ss1", "foobar1");
sessionStorage.setItem("iframe-u-ss2", "foobar2");
diff --git a/devtools/client/storage/test/storage-updates.html b/devtools/client/storage/test/storage-updates.html
index a009814b2..341992f61 100644
--- a/devtools/client/storage/test/storage-updates.html
+++ b/devtools/client/storage/test/storage-updates.html
@@ -38,8 +38,10 @@ window.removeCookie = function(name, path) {
* can be tested.
*/
window.clear = function*() {
- sessionStorage.clear();
+ localStorage.clear();
+ dump("removed localStorage from " + document.location + "\n");
+ sessionStorage.clear();
dump("removed sessionStorage from " + document.location + "\n");
};
diff --git a/devtools/client/storage/ui.js b/devtools/client/storage/ui.js
index 6af493e44..ef07a8e88 100644
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -12,6 +12,12 @@ const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
const JSOL = require("devtools/client/shared/vendor/jsol");
const {KeyCodes} = require("devtools/client/shared/keycodes");
+// GUID to be used as a separator in compound keys. This must match the same
+// constant in devtools/server/actors/storage.js,
+// devtools/client/storage/test/head.js and
+// devtools/server/tests/browser/head.js
+const SEPARATOR_GUID = "{9d414cc5-8319-0a04-0586-c0a6ae01670a}";
+
loader.lazyRequireGetter(this, "TreeWidget",
"devtools/client/shared/widgets/TreeWidget", true);
loader.lazyRequireGetter(this, "TableWidget",
@@ -36,13 +42,6 @@ const GENERIC_VARIABLES_VIEW_SETTINGS = {
preventDescriptorModifiers: true
};
-// Columns which are hidden by default in the storage table
-const HIDDEN_COLUMNS = [
- "creationTime",
- "isDomain",
- "isSecure"
-];
-
const REASON = {
NEW_ROW: "new-row",
NEXT_50_ITEMS: "next-50-items",
@@ -114,8 +113,8 @@ function StorageUI(front, target, panelWin, toolbox) {
cellContextMenuId: "storage-table-popup"
});
- this.displayObjectSidebar = this.displayObjectSidebar.bind(this);
- this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar);
+ this.updateObjectSidebar = this.updateObjectSidebar.bind(this);
+ this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
this.handleScrollEnd = this.handleScrollEnd.bind(this);
this.table.on(TableWidget.EVENTS.SCROLL_END, this.handleScrollEnd);
@@ -161,11 +160,20 @@ function StorageUI(front, target, panelWin, toolbox) {
this._tablePopup = this._panelDoc.getElementById("storage-table-popup");
this._tablePopup.addEventListener("popupshowing", this.onTablePopupShowing);
+ this.onAddItem = this.onAddItem.bind(this);
this.onRemoveItem = this.onRemoveItem.bind(this);
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
this.onRemoveAll = this.onRemoveAll.bind(this);
+ this.onRemoveAllSessionCookies = this.onRemoveAllSessionCookies.bind(this);
this.onRemoveTreeItem = this.onRemoveTreeItem.bind(this);
+ this._addButton = this._panelDoc.getElementById("add-button");
+ this._addButton.addEventListener("command", this.onAddItem);
+
+ this._tablePopupAddItem = this._panelDoc.getElementById(
+ "storage-table-popup-add");
+ this._tablePopupAddItem.addEventListener("command", this.onAddItem);
+
this._tablePopupDelete = this._panelDoc.getElementById(
"storage-table-popup-delete");
this._tablePopupDelete.addEventListener("command", this.onRemoveItem);
@@ -179,10 +187,20 @@ function StorageUI(front, target, panelWin, toolbox) {
"storage-table-popup-delete-all");
this._tablePopupDeleteAll.addEventListener("command", this.onRemoveAll);
+ this._tablePopupDeleteAllSessionCookies = this._panelDoc.getElementById(
+ "storage-table-popup-delete-all-session-cookies");
+ this._tablePopupDeleteAllSessionCookies.addEventListener("command",
+ this.onRemoveAllSessionCookies);
+
this._treePopupDeleteAll = this._panelDoc.getElementById(
"storage-tree-popup-delete-all");
this._treePopupDeleteAll.addEventListener("command", this.onRemoveAll);
+ this._treePopupDeleteAllSessionCookies = this._panelDoc.getElementById(
+ "storage-tree-popup-delete-all-session-cookies");
+ this._treePopupDeleteAllSessionCookies.addEventListener("command",
+ this.onRemoveAllSessionCookies);
+
this._treePopupDelete = this._panelDoc.getElementById("storage-tree-popup-delete");
this._treePopupDelete.addEventListener("command", this.onRemoveTreeItem);
}
@@ -199,7 +217,7 @@ StorageUI.prototype = {
},
destroy: function () {
- this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar);
+ this.table.off(TableWidget.EVENTS.ROW_SELECTED, this.updateObjectSidebar);
this.table.off(TableWidget.EVENTS.SCROLL_END, this.handleScrollEnd);
this.table.off(TableWidget.EVENTS.CELL_EDIT, this.editItem);
this.table.destroy();
@@ -211,13 +229,19 @@ StorageUI.prototype = {
this.searchBox = null;
this._treePopup.removeEventListener("popupshowing", this.onTreePopupShowing);
+ this._addButton.removeEventListener("command", this.onAddItem);
+ this._tablePopupAddItem.removeEventListener("command", this.onAddItem);
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
+ this._treePopupDeleteAllSessionCookies.removeEventListener("command",
+ this.onRemoveAllSessionCookies);
this._treePopupDelete.removeEventListener("command", this.onRemoveTreeItem);
this._tablePopup.removeEventListener("popupshowing", this.onTablePopupShowing);
this._tablePopupDelete.removeEventListener("command", this.onRemoveItem);
this._tablePopupDeleteAllFrom.removeEventListener("command", this.onRemoveAllFrom);
this._tablePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
+ this._tablePopupDeleteAllSessionCookies.removeEventListener("command",
+ this.onRemoveAllSessionCookies);
},
/**
@@ -229,7 +253,7 @@ StorageUI.prototype = {
this.table.clearSelection();
},
- getCurrentActor: function () {
+ getCurrentFront: function () {
let type = this.table.datatype;
return this.storageTypes[type];
@@ -250,9 +274,9 @@ StorageUI.prototype = {
},
editItem: function (eventType, data) {
- let actor = this.getCurrentActor();
+ let front = this.getCurrentFront();
- actor.editItem(data);
+ front.editItem(data);
},
/**
@@ -261,17 +285,16 @@ StorageUI.prototype = {
* being removed was selected.
*/
removeItemFromTable: function (name) {
- if (this.table.isSelected(name)) {
+ if (this.table.isSelected(name) && this.table.items.size > 1) {
if (this.table.selectedIndex == 0) {
this.table.selectNextRow();
} else {
this.table.selectPreviousRow();
}
- this.table.remove(name);
- this.displayObjectSidebar();
- } else {
- this.table.remove(name);
}
+
+ this.table.remove(name);
+ this.updateObjectSidebar();
},
/**
@@ -454,22 +477,24 @@ StorageUI.prototype = {
* @param {object} See onUpdate docs
*/
handleChangedItems: function (changed) {
- let [type, host, db, objectStore] = this.tree.selectedItem;
- if (!changed[type] || !changed[type][host] ||
- changed[type][host].length == 0) {
- return;
- }
- try {
- let toUpdate = [];
- for (let name of changed[type][host]) {
- let names = JSON.parse(name);
- if (names[0] == db && names[1] == objectStore && names[2]) {
- toUpdate.push(name);
+ if (this.tree.selectedItem) {
+ let [type, host, db, objectStore] = this.tree.selectedItem;
+ if (!changed[type] || !changed[type][host] ||
+ changed[type][host].length == 0) {
+ return;
+ }
+ try {
+ let toUpdate = [];
+ for (let name of changed[type][host]) {
+ let names = JSON.parse(name);
+ if (names[0] == db && names[1] == objectStore && names[2]) {
+ toUpdate.push(name);
+ }
}
+ this.fetchStorageObjects(type, host, toUpdate, REASON.UPDATE);
+ } catch (ex) {
+ this.fetchStorageObjects(type, host, changed[type][host], REASON.UPDATE);
}
- this.fetchStorageObjects(type, host, toUpdate, REASON.UPDATE);
- } catch (ex) {
- this.fetchStorageObjects(type, host, changed[type][host], REASON.UPDATE);
}
},
@@ -504,7 +529,7 @@ StorageUI.prototype = {
// The indexedDB type could have sub-type data to fetch.
// If having names specified, then it means
// we are fetching details of specific database or of object store.
- if (type == "indexedDB" && names) {
+ if (type === "indexedDB" && names) {
let [ dbName, objectStoreName ] = JSON.parse(names[0]);
if (dbName) {
subType = "database";
@@ -513,6 +538,15 @@ StorageUI.prototype = {
subType = "object store";
}
}
+
+ this.actorSupportsAddItem = yield this._target.actorHasMethod(type, "addItem");
+ this.actorSupportsRemoveItem =
+ yield this._target.actorHasMethod(type, "removeItem");
+ this.actorSupportsRemoveAll =
+ yield this._target.actorHasMethod(type, "removeAll");
+ this.actorSupportsRemoveAllSessionCookies =
+ yield this._target.actorHasMethod(type, "removeAllSessionCookies");
+
yield this.resetColumns(type, host, subType);
}
@@ -520,6 +554,7 @@ StorageUI.prototype = {
if (data.length) {
this.populateTable(data, reason);
}
+ yield this.updateToolbar();
this.emit("store-objects-updated");
} catch (ex) {
console.error(ex);
@@ -527,6 +562,27 @@ StorageUI.prototype = {
}),
/**
+ * Updates the toolbar hiding and showing buttons as appropriate.
+ */
+ updateToolbar: Task.async(function* () {
+ let item = this.tree.selectedItem;
+ let howManyNodesIn = item ? item.length : 0;
+
+ // The first node is just a title e.g. "Cookies" so we need to be at least
+ // 2 nodes in to show the add button.
+ let canAdd = this.actorSupportsAddItem && howManyNodesIn > 1;
+
+ if (canAdd) {
+ this._addButton.hidden = false;
+ this._addButton.setAttribute("tooltiptext",
+ L10N.getFormatStr("storage.popupMenu.addItemLabel"));
+ } else {
+ this._addButton.hidden = true;
+ this._addButton.removeAttribute("tooltiptext");
+ }
+ }),
+
+ /**
* Populates the storage tree which displays the list of storages present for
* the page.
*
@@ -574,23 +630,28 @@ StorageUI.prototype = {
},
/**
- * Populates the selected entry from teh table in the sidebar for a more
+ * Populates the selected entry from the table in the sidebar for a more
* detailed view.
*/
- displayObjectSidebar: Task.async(function* () {
+ updateObjectSidebar: Task.async(function* () {
let item = this.table.selectedRow;
- if (!item) {
- // Make sure that sidebar is hidden and return
- this.sidebar.hidden = true;
- return;
- }
+ let value;
// Get the string value (async action) and the update the UI synchronously.
- let value;
- if (item.name && item.valueActor) {
+ if (item && item.name && item.valueActor) {
value = yield item.valueActor.string();
}
+ // Bail if the selectedRow is no longer selected, the item doesn't exist or the state
+ // changed in another way during the above yield.
+ if (this.table.items.size === 0 ||
+ !item ||
+ !this.table.selectedRow ||
+ item.uniqueKey !== this.table.selectedRow.uniqueKey) {
+ this.hideSidebar();
+ return;
+ }
+
// Start updating the UI. Everything is sync beyond this point.
this.sidebar.hidden = false;
this.view.empty();
@@ -616,6 +677,11 @@ StorageUI.prototype = {
let otherProps = itemProps.filter(
e => !["name", "value", "valueActor"].includes(e));
for (let prop of otherProps) {
+ let column = this.table.columns.get(prop);
+ if (column && column.private) {
+ continue;
+ }
+
let cookieProp = COOKIE_KEY_MAP[prop] || prop;
// The pseduo property of HostOnly refers to converse of isDomain property
rawObject[cookieProp] = (prop === "isDomain") ? !item[prop] : item[prop];
@@ -627,6 +693,11 @@ StorageUI.prototype = {
} else {
// Case when displaying IndexedDB db/object store properties.
for (let key in item) {
+ let column = this.table.columns.get(key);
+ if (column && column.private) {
+ continue;
+ }
+
mainScope.addItem(key, {}, true).setGrip(item[key]);
this.parseItemValue(key, item[key]);
}
@@ -751,11 +822,19 @@ StorageUI.prototype = {
* the storage tree
*/
onHostSelect: function (event, item) {
+ if (!item) {
+ return;
+ }
this.table.clear();
this.hideSidebar();
this.searchBox.value = "";
let [type, host] = item;
+ this.table.host = host;
+ this.table.datatype = type;
+
+ this.updateToolbar();
+
let names = null;
if (!host) {
return;
@@ -786,7 +865,9 @@ StorageUI.prototype = {
let uniqueKey = null;
let columns = {};
let editableFields = [];
- let fields = yield this.getCurrentActor().getFields(subtype);
+ let hiddenFields = [];
+ let privateFields = [];
+ let fields = yield this.getCurrentFront().getFields(subtype);
fields.forEach(f => {
if (!uniqueKey) {
@@ -797,10 +878,21 @@ StorageUI.prototype = {
editableFields.push(f.name);
}
+ if (f.hidden) {
+ hiddenFields.push(f.name);
+ }
+
+ if (f.private) {
+ privateFields.push(f.name);
+ }
+
columns[f.name] = f.name;
let columnName;
try {
- columnName = L10N.getStr("table.headers." + type + "." + f.name);
+ // Path key names for l10n in the case of a string change.
+ let name = f.name === "keyPath" ? "keyPath2" : f.name;
+
+ columnName = L10N.getStr("table.headers." + type + "." + name);
} catch (e) {
columnName = COOKIE_KEY_MAP[f.name];
}
@@ -812,7 +904,7 @@ StorageUI.prototype = {
}
});
- this.table.setColumns(columns, null, HIDDEN_COLUMNS);
+ this.table.setColumns(columns, null, hiddenFields, privateFields);
this.hideSidebar();
yield this.makeFieldsEditable(editableFields);
@@ -857,7 +949,7 @@ StorageUI.prototype = {
case REASON.UPDATE:
this.table.update(item);
if (item == this.table.selectedRow && !this.sidebar.hidden) {
- this.displayObjectSidebar();
+ this.updateObjectSidebar();
}
break;
}
@@ -910,27 +1002,53 @@ StorageUI.prototype = {
},
/**
- * Fires before a cell context menu with the "Delete" action is shown.
- * If the currently selected storage object doesn't support removing items, prevent
- * showing the menu.
+ * Fires before a cell context menu with the "Add" or "Delete" action is
+ * shown. If the currently selected storage object doesn't support adding or
+ * removing items, prevent showing the menu.
*/
onTablePopupShowing: function (event) {
let selectedItem = this.tree.selectedItem;
let type = selectedItem[0];
- let actor = this.getCurrentActor();
// IndexedDB only supports removing items from object stores (level 4 of the tree)
- if (!actor.removeItem || (type === "indexedDB" && selectedItem.length !== 4)) {
+ if ((!this.actorSupportsAddItem && !this.actorSupportsRemoveItem &&
+ type !== "cookies") ||
+ (type === "indexedDB" && selectedItem.length !== 4)) {
event.preventDefault();
return;
}
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
- let name = addEllipsis(data[this.table.uniqueId]);
- this._tablePopupDelete.setAttribute("label",
- L10N.getFormatStr("storage.popupMenu.deleteLabel", name));
+ if (this.actorSupportsRemoveItem) {
+ let name = data[this.table.uniqueId];
+ let separatorRegex = new RegExp(SEPARATOR_GUID, "g");
+ let label = addEllipsis((name + "").replace(separatorRegex, "-"));
+
+ this._tablePopupDelete.hidden = false;
+ this._tablePopupDelete.setAttribute("label",
+ L10N.getFormatStr("storage.popupMenu.deleteLabel", label));
+ } else {
+ this._tablePopupDelete.hidden = true;
+ }
+
+ if (this.actorSupportsAddItem) {
+ this._tablePopupAddItem.hidden = false;
+ this._tablePopupAddItem.setAttribute("label",
+ L10N.getFormatStr("storage.popupMenu.addItemLabel"));
+ } else {
+ this._tablePopupAddItem.hidden = true;
+ }
+
+ let showDeleteAllSessionCookies = false;
+ if (this.actorSupportsRemoveAllSessionCookies) {
+ if (type === "cookies" && selectedItem.length === 2) {
+ showDeleteAllSessionCookies = true;
+ }
+ }
+
+ this._tablePopupDeleteAllSessionCookies.hidden = !showDeleteAllSessionCookies;
if (type === "cookies") {
let host = addEllipsis(data.host);
@@ -949,13 +1067,12 @@ StorageUI.prototype = {
if (selectedItem) {
let type = selectedItem[0];
- let actor = this.storageTypes[type];
// The delete all (aka clear) action is displayed for IndexedDB object stores
// (level 4 of tree), for Cache objects (level 3) and for the whole host (level 2)
// for other storage types (cookies, localStorage, ...).
let showDeleteAll = false;
- if (actor.removeAll) {
+ if (this.actorSupportsRemoveAll) {
let level;
if (type == "indexedDB") {
level = 4;
@@ -972,6 +1089,17 @@ StorageUI.prototype = {
this._treePopupDeleteAll.hidden = !showDeleteAll;
+ // The delete all session cookies action is displayed for cookie object stores
+ // (level 2 of tree)
+ let showDeleteAllSessionCookies = false;
+ if (this.actorSupportsRemoveAllSessionCookies) {
+ if (type === "cookies" && selectedItem.length === 2) {
+ showDeleteAllSessionCookies = true;
+ }
+ }
+
+ this._treePopupDeleteAllSessionCookies.hidden = !showDeleteAllSessionCookies;
+
// The delete action is displayed for:
// - IndexedDB databases (level 3 of the tree)
// - Cache objects (level 3 of the tree)
@@ -993,31 +1121,54 @@ StorageUI.prototype = {
},
/**
+ * Handles adding an item from the storage
+ */
+ onAddItem: function () {
+ if (!this.tree.selectedItem) {
+ return;
+ }
+ let front = this.getCurrentFront();
+ let [, host] = this.tree.selectedItem;
+
+ // Prepare to scroll into view.
+ this.table.scrollIntoViewOnUpdate = true;
+ this.table.editBookmark = createGUID();
+ front.addItem(this.table.editBookmark, host);
+ },
+
+ /**
* Handles removing an item from the storage
*/
onRemoveItem: function () {
let [, host, ...path] = this.tree.selectedItem;
- let actor = this.getCurrentActor();
+ let front = this.getCurrentFront();
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
let name = data[this.table.uniqueId];
if (path.length > 0) {
name = JSON.stringify([...path, name]);
}
- actor.removeItem(host, name);
+ front.removeItem(host, name);
},
/**
* Handles removing all items from the storage
*/
onRemoveAll: function () {
- // Cannot use this.currentActor() if the handler is called from the
- // tree context menu: it returns correct value only after the table
- // data from server are successfully fetched (and that's async).
- let [type, host, ...path] = this.tree.selectedItem;
- let actor = this.storageTypes[type];
+ let [, host, ...path] = this.tree.selectedItem;
+ let front = this.getCurrentFront();
let name = path.length > 0 ? JSON.stringify(path) : undefined;
- actor.removeAll(host, name);
+ front.removeAll(host, name);
+ },
+
+ /**
+ * Handles removing all session cookies from the storage
+ */
+ onRemoveAllSessionCookies: function () {
+ let [, host, ...path] = this.tree.selectedItem;
+ let front = this.getCurrentFront();
+ let name = path.length > 0 ? JSON.stringify(path) : undefined;
+ front.removeAllSessionCookies(host, name);
},
/**
@@ -1026,11 +1177,11 @@ StorageUI.prototype = {
*/
onRemoveAllFrom: function () {
let [, host] = this.tree.selectedItem;
- let actor = this.getCurrentActor();
+ let front = this.getCurrentFront();
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
- actor.removeAll(host, data.host);
+ front.removeAll(host, data.host);
},
onRemoveTreeItem: function () {
@@ -1044,9 +1195,9 @@ StorageUI.prototype = {
},
removeDatabase: function (host, dbName) {
- let actor = this.storageTypes.indexedDB;
+ let front = this.getCurrentFront();
- actor.removeDatabase(host, dbName).then(result => {
+ front.removeDatabase(host, dbName).then(result => {
if (result.blocked) {
let notificationBox = this._toolbox.getNotificationBox();
notificationBox.appendNotification(
@@ -1066,8 +1217,17 @@ StorageUI.prototype = {
},
removeCache: function (host, cacheName) {
- let actor = this.storageTypes.Cache;
+ let front = this.getCurrentFront();
- actor.removeItem(host, JSON.stringify([ cacheName ]));
+ front.removeItem(host, JSON.stringify([ cacheName ]));
},
};
+
+// Helper Functions
+
+function createGUID() {
+ return "{cccccccc-cccc-4ccc-yccc-cccccccccccc}".replace(/[cy]/g, c => {
+ let r = Math.random() * 16 | 0, v = c == "c" ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ });
+}