From 390894c822f1b163f16744646372a28c0d93a89e Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 2 Mar 2018 13:36:16 +0100 Subject: Bug 1146194: Multiple cookies with the same name not shown Issue #31 --- devtools/client/locales/en-US/storage.properties | 1 + devtools/client/shared/widgets/TableWidget.js | 34 +++- devtools/client/storage/test/browser.ini | 4 +- .../client/storage/test/browser_storage_basic.js | 23 ++- .../test/browser_storage_cookies_delete_all.js | 44 ++++- .../storage/test/browser_storage_cookies_domain.js | 12 +- .../storage/test/browser_storage_cookies_edit.js | 21 ++- .../test/browser_storage_cookies_edit_keyboard.js | 5 +- .../test/browser_storage_cookies_tab_navigation.js | 3 +- .../client/storage/test/browser_storage_delete.js | 8 +- .../storage/test/browser_storage_delete_tree.js | 10 +- .../browser_storage_dynamic_updates_cookies.js | 188 +++++++++++++++++++++ ...browser_storage_dynamic_updates_localStorage.js | 70 ++++++++ ...owser_storage_dynamic_updates_sessionStorage.js | 83 +++++++++ .../client/storage/test/browser_storage_sidebar.js | 8 +- .../client/storage/test/browser_storage_values.js | 14 +- devtools/client/storage/test/head.js | 47 +++++- devtools/client/storage/test/storage-updates.html | 4 +- devtools/client/storage/ui.js | 32 ++-- 19 files changed, 553 insertions(+), 58 deletions(-) create mode 100644 devtools/client/storage/test/browser_storage_dynamic_updates_cookies.js create mode 100644 devtools/client/storage/test/browser_storage_dynamic_updates_localStorage.js create mode 100644 devtools/client/storage/test/browser_storage_dynamic_updates_sessionStorage.js (limited to 'devtools/client') diff --git a/devtools/client/locales/en-US/storage.properties b/devtools/client/locales/en-US/storage.properties index 1eeb88ff9..fd3b3ec52 100644 --- a/devtools/client/locales/en-US/storage.properties +++ b/devtools/client/locales/en-US/storage.properties @@ -35,6 +35,7 @@ tree.labels.Cache=Cache Storage # LOCALIZATION NOTE (table.headers.*.*): # These strings are the header names of the columns in the Storage Table for # each type of storage available through the Storage Tree to the side. +table.headers.cookies.uniqueKey=Unique key table.headers.cookies.name=Name table.headers.cookies.path=Path table.headers.cookies.host=Domain diff --git a/devtools/client/shared/widgets/TableWidget.js b/devtools/client/shared/widgets/TableWidget.js index 5dacd1b67..96c020230 100644 --- a/devtools/client/shared/widgets/TableWidget.js +++ b/devtools/client/shared/widgets/TableWidget.js @@ -615,8 +615,13 @@ TableWidget.prototype = { /** * Populates the header context menu with the names of the columns along with * displaying which columns are hidden or visible. + * + * @param {Array} privateColumns=[] + * An array of column names that should never appear in the table. This + * allows us to e.g. have an invisible compound primary key for a + * table's rows. */ - populateMenuPopup: function () { + populateMenuPopup: function (privateColumns = []) { if (!this.menupopup) { return; } @@ -626,6 +631,10 @@ TableWidget.prototype = { } for (let column of this.columns.values()) { + if (privateColumns.includes(column.id)) { + continue; + } + let menuitem = this.document.createElementNS(XUL_NS, "menuitem"); menuitem.setAttribute("label", column.header.getAttribute("value")); menuitem.setAttribute("data-id", column.id); @@ -663,16 +672,21 @@ TableWidget.prototype = { * Creates the columns in the table. Without calling this method, data cannot * be inserted into the table unless `initialColumns` was supplied. * - * @param {object} columns + * @param {Object} columns * A key value pair representing the columns of the table. Where the * key represents the id of the column and the value is the displayed * label in the header of the column. - * @param {string} sortOn + * @param {String} sortOn * The id of the column on which the table will be initially sorted on. - * @param {array} hiddenColumns + * @param {Array} hiddenColumns * Ids of all the columns that are hidden by default. + * @param {Array} privateColumns=[] + * An array of column names that should never appear in the table. This + * allows us to e.g. have an invisible compound primary key for a + * table's rows. */ - setColumns: function (columns, sortOn = this.sortedOn, hiddenColumns = []) { + setColumns: function (columns, sortOn = this.sortedOn, hiddenColumns = [], + privateColumns = []) { for (let column of this.columns.values()) { column.destroy(); } @@ -702,13 +716,14 @@ TableWidget.prototype = { } this.columns.set(id, new Column(this, id, columns[id])); - if (hiddenColumns.indexOf(id) > -1) { + if (hiddenColumns.includes(id) || privateColumns.includes(id)) { + // Hide the column. this.columns.get(id).toggleColumn(); } } this.sortedOn = sortOn; this.sortBy(this.sortedOn); - this.populateMenuPopup(); + this.populateMenuPopup(privateColumns); }, /** @@ -778,6 +793,11 @@ TableWidget.prototype = { return; } + if (this.editBookmark && !this.items.has(this.editBookmark)) { + // Key has been updated... update bookmark. + this.editBookmark = item[this.uniqueId]; + } + let index = this.columns.get(this.sortedOn).push(item); for (let [key, column] of this.columns) { if (key != this.sortedOn) { diff --git a/devtools/client/storage/test/browser.ini b/devtools/client/storage/test/browser.ini index dd7f48bd7..0ac28a92d 100644 --- a/devtools/client/storage/test/browser.ini +++ b/devtools/client/storage/test/browser.ini @@ -29,7 +29,9 @@ support-files = [browser_storage_delete.js] [browser_storage_delete_all.js] [browser_storage_delete_tree.js] -[browser_storage_dynamic_updates.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] diff --git a/devtools/client/storage/test/browser_storage_basic.js b/devtools/client/storage/test/browser_storage_basic.js index 343d46170..10eb8d0ca 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,23 @@ "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("uc1", ".example.org", "/") + ] + ], + [ + ["cookies", "sectest1.example.org"], + [ + getCookieId("uc1", ".example.org", "/"), + getCookieId("cs2", ".example.org", "/"), + getCookieId("sc1", "sectest1.example.org", "/browser/devtools/client/storage/test/") + ] + ], [["localStorage", "http://test1.example.org"], ["ls1", "ls2"]], [["localStorage", "http://sectest1.example.org"], 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..ba64014fd 100644 --- a/devtools/client/storage/test/browser_storage_cookies_delete_all.js +++ b/devtools/client/storage/test/browser_storage_cookies_delete_all.js @@ -21,8 +21,8 @@ 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) { @@ -43,24 +43,54 @@ 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("uc1", ".example.org", "/") + ] + ], + [ + ["cookies", "sectest1.example.org"], [ + getCookieId("cs2", ".example.org", "/"), + getCookieId("sc1", "sectest1.example.org", + "/browser/devtools/client/storage/test/"), + getCookieId("uc1", ".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, 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("uc1", ".example.org", "/") + ] + ], + [ + ["cookies", "sectest1.example.org"], + [ + getCookieId("cs2", ".example.org", "/"), + getCookieId("uc1", ".example.org", "/"), + getCookieId("sc1", "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("uc1", ".example.org", "/"); + yield performDelete(["cookies", "sectest1.example.org"], id, true); 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..d5cb59a10 100644 --- a/devtools/client/storage/test/browser_storage_delete.js +++ b/devtools/client/storage/test/browser_storage_delete.js @@ -13,8 +13,10 @@ const TEST_CASES = [ "ls1", "name"], [["sessionStorage", "http://test1.example.org"], "ss1", "name"], - [["cookies", "test1.example.org"], - "c1", "name"], + [ + ["cookies", "test1.example.org"], + getCookieId("c1", "test1.example.org", "/browser"), "name" + ], [["indexedDB", "http://test1.example.org", "idb1", "obj1"], 1, "name"], [["Cache", "http://test1.example.org", "plop"], @@ -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_tree.js b/devtools/client/storage/test/browser_storage_delete_tree.js index 867a1c8b6..3e866a2f5 100644 --- a/devtools/client/storage/test/browser_storage_delete_tree.js +++ b/devtools/client/storage/test/browser_storage_delete_tree.js @@ -17,7 +17,15 @@ 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("uc1", ".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]], 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_sidebar.js b/devtools/client/storage/test/browser_storage_sidebar.js index 9b60026a0..d1a71c667 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 }, diff --git a/devtools/client/storage/test/browser_storage_values.js b/devtools/client/storage/test/browser_storage_values.js index 920ce350e..122a867bb 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"}, diff --git a/devtools/client/storage/test/head.js b/devtools/client/storage/test/head.js index 9662393cf..894056c9e 100644 --- a/devtools/client/storage/test/head.js +++ b/devtools/client/storage/test/head.js @@ -24,6 +24,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); @@ -505,10 +510,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,21 +597,38 @@ 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. * @@ -798,9 +826,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 +875,7 @@ var focusSearchBoxUsingShortcut = Task.async(function* (panelWin, callback) { callback(); } }); + +function getCookieId(name, domain, path) { + return `${name}${SEPARATOR_GUID}${domain}${SEPARATOR_GUID}${path}`; +} 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..c4dd57c6e 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", @@ -786,6 +785,8 @@ StorageUI.prototype = { let uniqueKey = null; let columns = {}; let editableFields = []; + let hiddenFields = []; + let privateFields = []; let fields = yield this.getCurrentActor().getFields(subtype); fields.forEach(f => { @@ -797,6 +798,14 @@ 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 { @@ -812,7 +821,7 @@ StorageUI.prototype = { } }); - this.table.setColumns(columns, null, HIDDEN_COLUMNS); + this.table.setColumns(columns, null, hiddenFields, privateFields); this.hideSidebar(); yield this.makeFieldsEditable(editableFields); @@ -927,10 +936,13 @@ StorageUI.prototype = { let rowId = this.table.contextMenuRowId; let data = this.table.items.get(rowId); - let name = addEllipsis(data[this.table.uniqueId]); + let name = data[this.table.uniqueId]; + + let separatorRegex = new RegExp(SEPARATOR_GUID, "g"); + let label = addEllipsis((name + "").replace(separatorRegex, "-")); this._tablePopupDelete.setAttribute("label", - L10N.getFormatStr("storage.popupMenu.deleteLabel", name)); + L10N.getFormatStr("storage.popupMenu.deleteLabel", label)); if (type === "cookies") { let host = addEllipsis(data.host); -- cgit v1.2.3