mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
12
devtools/client/storage/moz.build
Normal file
12
devtools/client/storage/moz.build
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
||||
DevToolsModules(
|
||||
'panel.js',
|
||||
'ui.js'
|
||||
)
|
||||
87
devtools/client/storage/panel.js
Normal file
87
devtools/client/storage/panel.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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";
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
loader.lazyRequireGetter(this, "StorageFront",
|
||||
"devtools/shared/fronts/storage", true);
|
||||
loader.lazyRequireGetter(this, "StorageUI",
|
||||
"devtools/client/storage/ui", true);
|
||||
|
||||
var StoragePanel = this.StoragePanel =
|
||||
function StoragePanel(panelWin, toolbox) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._toolbox = toolbox;
|
||||
this._target = toolbox.target;
|
||||
this._panelWin = panelWin;
|
||||
|
||||
this.destroy = this.destroy.bind(this);
|
||||
};
|
||||
|
||||
exports.StoragePanel = StoragePanel;
|
||||
|
||||
StoragePanel.prototype = {
|
||||
get target() {
|
||||
return this._toolbox.target;
|
||||
},
|
||||
|
||||
get panelWindow() {
|
||||
return this._panelWin;
|
||||
},
|
||||
|
||||
/**
|
||||
* open is effectively an asynchronous constructor
|
||||
*/
|
||||
open: function () {
|
||||
let targetPromise;
|
||||
// We always interact with the target as if it were remote
|
||||
if (!this.target.isRemote) {
|
||||
targetPromise = this.target.makeRemote();
|
||||
} else {
|
||||
targetPromise = Promise.resolve(this.target);
|
||||
}
|
||||
|
||||
return targetPromise.then(() => {
|
||||
this.target.on("close", this.destroy);
|
||||
this._front = new StorageFront(this.target.client, this.target.form);
|
||||
|
||||
this.UI = new StorageUI(this._front, this._target,
|
||||
this._panelWin, this._toolbox);
|
||||
this.isReady = true;
|
||||
this.emit("ready");
|
||||
|
||||
return this;
|
||||
}).catch(e => {
|
||||
console.log("error while opening storage panel", e);
|
||||
this.destroy();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy the storage inspector.
|
||||
*/
|
||||
destroy: function () {
|
||||
if (!this._destroyed) {
|
||||
this.UI.destroy();
|
||||
this.UI = null;
|
||||
|
||||
// Destroy front to ensure packet handler is removed from client
|
||||
this._front.destroy();
|
||||
this._front = null;
|
||||
this._destroyed = true;
|
||||
|
||||
this._target.off("close", this.destroy);
|
||||
this._target = null;
|
||||
this._toolbox = null;
|
||||
this._panelWin = null;
|
||||
}
|
||||
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
};
|
||||
58
devtools/client/storage/storage.xul
Normal file
58
devtools/client/storage/storage.xul
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/storage.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % storageDTD SYSTEM "chrome://devtools/locale/storage.dtd">
|
||||
%storageDTD;
|
||||
]>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://devtools/content/shared/theme-switching.js"/>
|
||||
<script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
|
||||
|
||||
<commandset id="editMenuCommands"/>
|
||||
|
||||
<popupset id="storagePopupSet">
|
||||
<menupopup id="storage-tree-popup">
|
||||
<menuitem id="storage-tree-popup-delete-all"
|
||||
label="&storage.popupMenu.deleteAllLabel;"/>
|
||||
<menuitem id="storage-tree-popup-delete"/>
|
||||
</menupopup>
|
||||
<menupopup id="storage-table-popup">
|
||||
<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;"/>
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
<box flex="1" class="devtools-responsive-container theme-body">
|
||||
<vbox id="storage-tree"/>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox flex="1">
|
||||
<hbox id="storage-toolbar" class="devtools-toolbar">
|
||||
<textbox id="storage-searchbox"
|
||||
class="devtools-filterinput"
|
||||
type="search"
|
||||
timeout="200"
|
||||
placeholder="&searchBox.placeholder;"/>
|
||||
</hbox>
|
||||
<vbox id="storage-table" class="theme-sidebar" flex="1"/>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="storage-sidebar" class="devtools-sidebar-tabs" hidden="true">
|
||||
<vbox flex="1"/>
|
||||
</vbox>
|
||||
</box>
|
||||
|
||||
</window>
|
||||
6
devtools/client/storage/test/.eslintrc.js
Normal file
6
devtools/client/storage/test/.eslintrc.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
// Extend from the shared list of defined globals for mochitests.
|
||||
"extends": "../../../.eslintrc.mochitests.js"
|
||||
};
|
||||
44
devtools/client/storage/test/browser.ini
Normal file
44
devtools/client/storage/test/browser.ini
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
storage-cache-error.html
|
||||
storage-complex-values.html
|
||||
storage-cookies.html
|
||||
storage-empty-objectstores.html
|
||||
storage-idb-delete-blocked.html
|
||||
storage-listings.html
|
||||
storage-localstorage.html
|
||||
storage-overflow.html
|
||||
storage-search.html
|
||||
storage-secured-iframe.html
|
||||
storage-sessionstorage.html
|
||||
storage-unsecured-iframe.html
|
||||
storage-updates.html
|
||||
head.js
|
||||
!/devtools/client/framework/test/shared-head.js
|
||||
|
||||
[browser_storage_basic.js]
|
||||
[browser_storage_cache_delete.js]
|
||||
[browser_storage_cache_error.js]
|
||||
[browser_storage_cookies_delete_all.js]
|
||||
[browser_storage_cookies_domain.js]
|
||||
[browser_storage_cookies_edit.js]
|
||||
[browser_storage_cookies_edit_keyboard.js]
|
||||
[browser_storage_cookies_tab_navigation.js]
|
||||
[browser_storage_delete.js]
|
||||
[browser_storage_delete_all.js]
|
||||
[browser_storage_delete_tree.js]
|
||||
[browser_storage_dynamic_updates.js]
|
||||
[browser_storage_empty_objectstores.js]
|
||||
[browser_storage_indexeddb_delete.js]
|
||||
[browser_storage_indexeddb_delete_blocked.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_edit.js]
|
||||
[browser_storage_sidebar.js]
|
||||
[browser_storage_sidebar_update.js]
|
||||
[browser_storage_values.js]
|
||||
118
devtools/client/storage/test/browser_storage_basic.js
Normal file
118
devtools/client/storage/test/browser_storage_basic.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* 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 assert that the storage tree and table corresponding to each
|
||||
// item in the storage tree is correctly displayed
|
||||
|
||||
// Entries that should be present in the tree for this test
|
||||
// Format for each entry in the array :
|
||||
// [
|
||||
// ["path", "to", "tree", "item"], - The path to the tree item to click formed
|
||||
// by id of each item
|
||||
// ["key_value1", "key_value2", ...] - The value of the first (unique) column
|
||||
// for each row in the table corresponding
|
||||
// to the tree item selected.
|
||||
// ]
|
||||
// These entries are formed by the cookies, local storage, session storage and
|
||||
// indexedDB entries created in storage-listings.html,
|
||||
// storage-secured-iframe.html and storage-unsecured-iframe.html
|
||||
|
||||
"use strict";
|
||||
|
||||
const testCases = [
|
||||
[["cookies", "test1.example.org"],
|
||||
["c1", "cs2", "c3", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"],
|
||||
["uc1", "cs2", "sc1"]],
|
||||
[["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", "idb2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1"],
|
||||
["obj1", "obj2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2"],
|
||||
["obj3"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"],
|
||||
[1]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2", "obj3"],
|
||||
[]],
|
||||
[["indexedDB", "http://sectest1.example.org"],
|
||||
[]],
|
||||
[["indexedDB", "https://sectest1.example.org"],
|
||||
["idb-s1", "idb-s2"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1"],
|
||||
["obj-s1"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2"],
|
||||
["obj-s2"]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
|
||||
[6, 7]],
|
||||
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
|
||||
[16]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js",
|
||||
MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
];
|
||||
|
||||
/**
|
||||
* Test that the desired number of tree items are present
|
||||
*/
|
||||
function testTree() {
|
||||
let doc = gPanelWindow.document;
|
||||
for (let item of testCases) {
|
||||
ok(doc.querySelector("[data-id='" + JSON.stringify(item[0]) + "']"),
|
||||
"Tree item " + item[0] + " should be present in the storage tree");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that correct table entries are shown for each of the tree item
|
||||
*/
|
||||
function* testTables() {
|
||||
let doc = gPanelWindow.document;
|
||||
// Expand all nodes so that the synthesized click event actually works
|
||||
gUI.tree.expandAll();
|
||||
|
||||
// First tree item is already selected so no clicking and waiting for update
|
||||
for (let id of testCases[0][1]) {
|
||||
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
|
||||
"Table item " + id + " should be present");
|
||||
}
|
||||
|
||||
// Click rest of the tree items and wait for the table to be updated
|
||||
for (let item of testCases.slice(1)) {
|
||||
yield selectTreeItem(item[0]);
|
||||
|
||||
// Check whether correct number of items are present in the table
|
||||
is(doc.querySelectorAll(
|
||||
".table-widget-wrapper:first-of-type .table-widget-cell"
|
||||
).length, item[1].length, "Number of items in table is correct");
|
||||
|
||||
// Check if all the desired items are present in the table
|
||||
for (let id of item[1]) {
|
||||
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
|
||||
"Table item " + id + " should be present");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
testTree();
|
||||
yield testTables();
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
46
devtools/client/storage/test/browser_storage_cache_delete.js
Normal file
46
devtools/client/storage/test/browser_storage_cache_delete.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* 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 deleting a Cache object from the tree using context menu
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
|
||||
let menuDeleteItem = contextMenu.querySelector("#storage-tree-popup-delete");
|
||||
|
||||
let cacheToDelete = ["Cache", "http://test1.example.org", "plop"];
|
||||
|
||||
info("test state before delete");
|
||||
yield selectTreeItem(cacheToDelete);
|
||||
ok(gUI.tree.isSelected(cacheToDelete), "Cache item is present in the tree");
|
||||
|
||||
info("do the delete");
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
let selector = `[data-id='${JSON.stringify(cacheToDelete)}'] > .tree-widget-item`;
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, "Cache item's tree element is present");
|
||||
|
||||
yield waitForContextMenu(contextMenu, target, () => {
|
||||
info("Opened tree context menu");
|
||||
menuDeleteItem.click();
|
||||
|
||||
let cacheName = cacheToDelete[2];
|
||||
ok(menuDeleteItem.getAttribute("label").includes(cacheName),
|
||||
`Context menu item label contains '${cacheName}')`);
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
|
||||
info("test state after delete");
|
||||
yield selectTreeItem(cacheToDelete);
|
||||
ok(!gUI.tree.isSelected(cacheToDelete), "Cache item is no longer present in the tree");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
19
devtools/client/storage/test/browser_storage_cache_error.js
Normal file
19
devtools/client/storage/test/browser_storage_cache_error.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* 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 handling errors in CacheStorage
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cache-error.html");
|
||||
|
||||
const cacheItemId = ["Cache", "javascript:parent.frameContent"];
|
||||
|
||||
yield selectTreeItem(cacheItemId);
|
||||
ok(gUI.tree.isSelected(cacheItemId),
|
||||
`The item ${cacheItemId.join(" > ")} is present in the tree`);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* 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 deleting all cookies
|
||||
|
||||
function* performDelete(store, rowName, deleteAll) {
|
||||
let contextMenu = gPanelWindow.document.getElementById(
|
||||
"storage-table-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all");
|
||||
let menuDeleteAllFromItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all-from");
|
||||
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
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),
|
||||
`Context menu item label contains '${hostName}'`);
|
||||
}
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[["cookies", "sectest1.example.org"], ["cs2", "sc1", "uc1"]],
|
||||
]);
|
||||
|
||||
info("delete all from domain");
|
||||
// delete only cookies that match the host exactly
|
||||
yield performDelete(["cookies", "test1.example.org"], "c1", 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"]],
|
||||
]);
|
||||
|
||||
info("delete all");
|
||||
// delete all cookies for host, including domain cookies
|
||||
yield performDelete(["cookies", "sectest1.example.org"], "uc1", true);
|
||||
|
||||
info("test state after delete all");
|
||||
yield checkState([
|
||||
// Domain cookies (.example.org) are deleted too, so deleting in sectest1
|
||||
// also removes stuff from test1.
|
||||
[["cookies", "test1.example.org"], []],
|
||||
[["cookies", "sectest1.example.org"], []],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/* 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 that cookies with domain equal to full host name are listed.
|
||||
// E.g., ".example.org" vs. example.org). Bug 1149497.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"],
|
||||
["test1", "test2", "test3", "test4", "test5"]],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
22
devtools/client/storage/test/browser_storage_cookies_edit.js
Normal file
22
devtools/client/storage/test/browser_storage_cookies_edit.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* 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 editing of cookies.
|
||||
|
||||
"use strict";
|
||||
|
||||
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");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/* 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 editing of cookies with the keyboard.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
showAllColumns(true);
|
||||
|
||||
yield startCellEdit("test4", "name");
|
||||
yield typeWithTerminator("test6", "VK_TAB");
|
||||
yield typeWithTerminator("/", "VK_TAB");
|
||||
yield typeWithTerminator(".example.org", "VK_TAB");
|
||||
yield typeWithTerminator("Tue, 25 Dec 2040 12:00:00 GMT", "VK_TAB");
|
||||
yield typeWithTerminator("test6value", "VK_TAB");
|
||||
yield typeWithTerminator("false", "VK_TAB");
|
||||
yield typeWithTerminator("false", "VK_TAB");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* 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 cookie table tab navigation.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-cookies.html");
|
||||
showAllColumns(true);
|
||||
|
||||
yield startCellEdit("test1", "name");
|
||||
|
||||
PressKeyXTimes("VK_TAB", 18);
|
||||
is(getCurrentEditorValue(), "value3",
|
||||
"We have tabbed to the correct cell.");
|
||||
|
||||
PressKeyXTimes("VK_TAB", 18, {shiftKey: true});
|
||||
is(getCurrentEditorValue(), "test1",
|
||||
"We have shift-tabbed to the correct cell.");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
56
devtools/client/storage/test/browser_storage_delete.js
Normal file
56
devtools/client/storage/test/browser_storage_delete.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/* 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 deleting storage items
|
||||
|
||||
const TEST_CASES = [
|
||||
[["localStorage", "http://test1.example.org"],
|
||||
"ls1", "name"],
|
||||
[["sessionStorage", "http://test1.example.org"],
|
||||
"ss1", "name"],
|
||||
[["cookies", "test1.example.org"],
|
||||
"c1", "name"],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
1, "name"],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
MAIN_DOMAIN + "404_cached_file.js", "url"],
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-table-popup");
|
||||
let menuDeleteItem = contextMenu.querySelector("#storage-table-popup-delete");
|
||||
|
||||
for (let [ treeItem, rowName, cellToClick] of TEST_CASES) {
|
||||
let treeItemName = treeItem.join(" > ");
|
||||
|
||||
info(`Selecting tree item ${treeItemName}`);
|
||||
yield selectTreeItem(treeItem);
|
||||
|
||||
let row = getRowCells(rowName);
|
||||
ok(gUI.table.items.has(rowName), `There is a row '${rowName}' in ${treeItemName}`);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
yield waitForContextMenu(contextMenu, row[cellToClick], () => {
|
||||
info(`Opened context menu in ${treeItemName}, row '${rowName}'`);
|
||||
menuDeleteItem.click();
|
||||
let truncatedRowName = String(rowName).substr(0, 16);
|
||||
ok(menuDeleteItem.getAttribute("label").includes(truncatedRowName),
|
||||
`Context menu item label contains '${rowName}' (maybe truncated)`);
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
|
||||
ok(!gUI.table.items.has(rowName),
|
||||
`There is no row '${rowName}' in ${treeItemName} after deletion`);
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
90
devtools/client/storage/test/browser_storage_delete_all.js
Normal file
90
devtools/client/storage/test/browser_storage_delete_all.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* 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 deleting all storage items
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-table-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-table-popup-delete-all");
|
||||
|
||||
info("test state before delete");
|
||||
const beforeState = [
|
||||
[["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", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
];
|
||||
|
||||
yield checkState(beforeState);
|
||||
|
||||
info("do the delete");
|
||||
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"],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
MAIN_DOMAIN + "404_cached_file.js", "url"],
|
||||
];
|
||||
|
||||
for (let [store, rowName, cellToClick] of deleteHosts) {
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventWait = gUI.once("store-objects-cleared");
|
||||
|
||||
let cell = getRowCells(rowName)[cellToClick];
|
||||
yield waitForContextMenu(contextMenu, cell, () => {
|
||||
info(`Opened context menu in ${storeName}, row '${rowName}'`);
|
||||
menuDeleteAllItem.click();
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
info("test state after delete");
|
||||
const afterState = [
|
||||
// iframes from the same host, one secure, one unsecure, are independent
|
||||
// from each other. Delete all in one doesn't touch the other one.
|
||||
[["localStorage", "http://test1.example.org"],
|
||||
["ls1", "ls2"]],
|
||||
[["localStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ls1"]],
|
||||
[["localStorage", "https://sectest1.example.org"],
|
||||
[]],
|
||||
[["sessionStorage", "http://test1.example.org"],
|
||||
["ss1"]],
|
||||
[["sessionStorage", "http://sectest1.example.org"],
|
||||
["iframe-u-ss1", "iframe-u-ss2"]],
|
||||
[["sessionStorage", "https://sectest1.example.org"],
|
||||
[]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[]],
|
||||
];
|
||||
|
||||
yield checkState(afterState);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
67
devtools/client/storage/test/browser_storage_delete_tree.js
Normal file
67
devtools/client/storage/test/browser_storage_delete_tree.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* 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 deleting all storage items from the tree.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
|
||||
let menuDeleteAllItem = contextMenu.querySelector(
|
||||
"#storage-tree-popup-delete-all");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], ["c1", "c3", "cs2", "uc1"]],
|
||||
[["localStorage", "http://test1.example.org"], ["ls1", "ls2"]],
|
||||
[["sessionStorage", "http://test1.example.org"], ["ss1"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], [1, 2, 3]],
|
||||
[["Cache", "http://test1.example.org", "plop"],
|
||||
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
|
||||
]);
|
||||
|
||||
info("do the delete");
|
||||
const deleteHosts = [
|
||||
["cookies", "test1.example.org"],
|
||||
["localStorage", "http://test1.example.org"],
|
||||
["sessionStorage", "http://test1.example.org"],
|
||||
["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
["Cache", "http://test1.example.org", "plop"],
|
||||
];
|
||||
|
||||
for (let store of deleteHosts) {
|
||||
let storeName = store.join(" > ");
|
||||
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let eventName = "store-objects-" +
|
||||
(store[0] == "cookies" ? "updated" : "cleared");
|
||||
let eventWait = gUI.once(eventName);
|
||||
|
||||
let selector = `[data-id='${JSON.stringify(store)}'] > .tree-widget-item`;
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, `tree item found in ${storeName}`);
|
||||
yield waitForContextMenu(contextMenu, target, () => {
|
||||
info(`Opened tree context menu in ${storeName}`);
|
||||
menuDeleteAllItem.click();
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
}
|
||||
|
||||
info("test state after delete");
|
||||
yield checkState([
|
||||
[["cookies", "test1.example.org"], []],
|
||||
[["localStorage", "http://test1.example.org"], []],
|
||||
[["sessionStorage", "http://test1.example.org"], []],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"], []],
|
||||
[["Cache", "http://test1.example.org", "plop"], []],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
213
devtools/client/storage/test/browser_storage_dynamic_updates.js
Normal file
213
devtools/client/storage/test/browser_storage_dynamic_updates.js
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/* 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";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html");
|
||||
|
||||
let $ = id => gPanelWindow.document.querySelector(id);
|
||||
let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
|
||||
yield selectTableItem("c1");
|
||||
|
||||
// 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
|
||||
ok($("#value [data-id='c1'].table-widget-cell"), "cell is present");
|
||||
is($("#value [data-id='c1'].table-widget-cell").value, "1.2.3.4.5.6.7",
|
||||
"correct initial value in table");
|
||||
gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
yield findVariableViewProperties(finalValue[0], false);
|
||||
yield findVariableViewProperties(finalValue[1], true);
|
||||
ok($("#value [data-id='c1'].table-widget-cell"),
|
||||
"cell is present after update");
|
||||
is($("#value [data-id='c1'].table-widget-cell").value, '{"foo": 4,"bar":6}',
|
||||
"correct final value in table");
|
||||
|
||||
// Add a new entry
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows before update 0");
|
||||
|
||||
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");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows after update 1");
|
||||
|
||||
// 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");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 4,
|
||||
"Correct number of rows after update 2");
|
||||
|
||||
// Removing cookies
|
||||
gWindow.removeCookie("c1", "/browser");
|
||||
|
||||
yield gUI.once("sidebar-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows after delete update 3");
|
||||
|
||||
ok(!$("#c1"), "Correct row got deleted");
|
||||
|
||||
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");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows after delete update 4");
|
||||
|
||||
// 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 findVariableViewProperties([{name: "c4", value: "booyeah"}]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 1,
|
||||
"Correct number of rows after delete update 5");
|
||||
|
||||
gWindow.removeCookie("c4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 0,
|
||||
"Correct number of rows after delete update 6");
|
||||
ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
|
||||
|
||||
// Testing in local storage
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 7,
|
||||
"Correct number of rows after delete update 7");
|
||||
|
||||
ok($(".table-widget-cell[data-id='ls4']"), "ls4 exists before deleting");
|
||||
|
||||
gWindow.localStorage.removeItem("ls4");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 6,
|
||||
"Correct number of rows after delete update 8");
|
||||
ok(!$(".table-widget-cell[data-id='ls4']"),
|
||||
"ls4 does not exists after deleting");
|
||||
|
||||
gWindow.localStorage.setItem("ls4", "again");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 7,
|
||||
"Correct number of rows after delete update 9");
|
||||
ok($(".table-widget-cell[data-id='ls4']"),
|
||||
"ls4 came back after adding it again");
|
||||
|
||||
// Updating a row
|
||||
gWindow.localStorage.setItem("ls2", "ls2-changed");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($("#value [data-id='ls2']").value, "ls2-changed",
|
||||
"Value got updated for local storage");
|
||||
|
||||
// Testing in session storage
|
||||
yield selectTreeItem(["sessionStorage", "http://test1.example.org"]);
|
||||
|
||||
is($$("#value .table-widget-cell").length, 3,
|
||||
"Correct number of rows for session storage");
|
||||
|
||||
gWindow.sessionStorage.setItem("ss4", "new-item");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 4,
|
||||
"Correct number of rows after session storage update");
|
||||
|
||||
// deleting item
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss3");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
gWindow.sessionStorage.removeItem("ss1");
|
||||
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 2,
|
||||
"Correct number of rows after removing items from session storage");
|
||||
|
||||
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");
|
||||
|
||||
is($("#value [data-id='ss2']").value, "changed=ss2",
|
||||
"Value got updated for session storage in the table");
|
||||
|
||||
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");
|
||||
|
||||
is($$("#value .table-widget-cell").length, 0,
|
||||
"Table should be cleared");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
/* 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 assert that the storage tree and table corresponding to each
|
||||
// item in the storage tree is correctly displayed.
|
||||
|
||||
"use strict";
|
||||
|
||||
// Entries that should be present in the tree for this test
|
||||
// Format for each entry in the array:
|
||||
// [
|
||||
// ["path", "to", "tree", "item"],
|
||||
// - The path to the tree item to click formed by id of each item
|
||||
// ["key_value1", "key_value2", ...]
|
||||
// - The value of the first (unique) column for each row in the table
|
||||
// corresponding to the tree item selected.
|
||||
// ]
|
||||
// These entries are formed by the cookies, local storage, session storage and
|
||||
// indexedDB entries created in storage-listings.html,
|
||||
// storage-secured-iframe.html and storage-unsecured-iframe.html
|
||||
const storeItems = [
|
||||
[["indexedDB", "http://test1.example.org"],
|
||||
["idb1", "idb2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1"],
|
||||
["obj1", "obj2"]],
|
||||
[["indexedDB", "http://test1.example.org", "idb2"],
|
||||
[]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
|
||||
[1, 2, 3]],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"],
|
||||
[1]]
|
||||
];
|
||||
|
||||
/**
|
||||
* Test that the desired number of tree items are present
|
||||
*/
|
||||
function testTree() {
|
||||
let doc = gPanelWindow.document;
|
||||
for (let [item] of storeItems) {
|
||||
ok(doc.querySelector(`[data-id='${JSON.stringify(item)}']`),
|
||||
`Tree item ${item} should be present in the storage tree`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that correct table entries are shown for each of the tree item
|
||||
*/
|
||||
let testTables = function* () {
|
||||
let doc = gPanelWindow.document;
|
||||
// Expand all nodes so that the synthesized click event actually works
|
||||
gUI.tree.expandAll();
|
||||
|
||||
// Click the tree items and wait for the table to be updated
|
||||
for (let [item, ids] of storeItems) {
|
||||
yield selectTreeItem(item);
|
||||
|
||||
// Check whether correct number of items are present in the table
|
||||
is(doc.querySelectorAll(
|
||||
".table-widget-wrapper:first-of-type .table-widget-cell"
|
||||
).length, ids.length, "Number of items in table is correct");
|
||||
|
||||
// Check if all the desired items are present in the table
|
||||
for (let id of ids) {
|
||||
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
|
||||
`Table item ${id} should be present`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-empty-objectstores.html");
|
||||
|
||||
testTree();
|
||||
yield testTables();
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/* 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 deleting indexedDB database from the tree using context menu
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-empty-objectstores.html");
|
||||
|
||||
let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
|
||||
let menuDeleteDb = contextMenu.querySelector("#storage-tree-popup-delete");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb1", "idb2"]],
|
||||
]);
|
||||
|
||||
info("do the delete");
|
||||
const deletedDb = ["indexedDB", "http://test1.example.org", "idb1"];
|
||||
|
||||
yield selectTreeItem(deletedDb);
|
||||
|
||||
// Wait once for update and another time for value fetching
|
||||
let eventWait = gUI.once("store-objects-updated").then(
|
||||
() => gUI.once("store-objects-updated"));
|
||||
|
||||
let selector = `[data-id='${JSON.stringify(deletedDb)}'] > .tree-widget-item`;
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, `tree item found in ${deletedDb.join(" > ")}`);
|
||||
yield waitForContextMenu(contextMenu, target, () => {
|
||||
info(`Opened tree context menu in ${deletedDb.join(" > ")}`);
|
||||
menuDeleteDb.click();
|
||||
});
|
||||
|
||||
yield eventWait;
|
||||
|
||||
info("test state after delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb2"]],
|
||||
]);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/* 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 what happens when deleting indexedDB database is blocked
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-idb-delete-blocked.html");
|
||||
|
||||
info("test state before delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb"]]
|
||||
]);
|
||||
|
||||
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");
|
||||
|
||||
ok(result.blocked, "removeDatabase attempt is blocked");
|
||||
|
||||
info("test state after blocked delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], ["idb"]]
|
||||
]);
|
||||
|
||||
let eventWait = gUI.once("store-objects-updated");
|
||||
|
||||
info("telling content to close the db");
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
let win = content.wrappedJSObject;
|
||||
yield win.closeDb();
|
||||
});
|
||||
|
||||
info("waiting for store update events");
|
||||
yield eventWait;
|
||||
|
||||
info("test state after real delete");
|
||||
yield checkState([
|
||||
[["indexedDB", "http://test1.example.org"], []]
|
||||
]);
|
||||
|
||||
info("try to delete database from nonexistent host");
|
||||
let errorThrown = false;
|
||||
try {
|
||||
result = yield actor.removeDatabase("http://test2.example.org", "idb");
|
||||
} catch (ex) {
|
||||
errorThrown = true;
|
||||
}
|
||||
|
||||
ok(errorThrown, "error was reported when trying to delete");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* 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 editing of localStorage.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-localstorage.html");
|
||||
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
yield editCell("TestLS1", "name", "newTestLS1");
|
||||
yield editCell("newTestLS1", "value", "newValueLS1");
|
||||
|
||||
yield editCell("TestLS3", "name", "newTestLS3");
|
||||
yield editCell("newTestLS3", "value", "newValueLS3");
|
||||
|
||||
yield editCell("TestLS5", "name", "newTestLS5");
|
||||
yield editCell("newTestLS5", "value", "newValueLS5");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* 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 that for pages where local/sessionStorage is not available (like about:home),
|
||||
// the host still appears in the storage tree and no unhandled exception is thrown.
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage("about:home");
|
||||
|
||||
let itemsToOpen = [
|
||||
["localStorage", "about:home"],
|
||||
["sessionStorage", "about:home"]
|
||||
];
|
||||
|
||||
for (let item of itemsToOpen) {
|
||||
yield selectTreeItem(item);
|
||||
ok(gUI.tree.isSelected(item), `Item ${item.join(" > ")} is present in the tree`);
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
41
devtools/client/storage/test/browser_storage_overflow.js
Normal file
41
devtools/client/storage/test/browser_storage_overflow.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Test endless scrolling when a lot of items are present in the storage
|
||||
// inspector table.
|
||||
"use strict";
|
||||
|
||||
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"]);
|
||||
|
||||
let table = $("#storage-table .table-widget-body");
|
||||
let cellHeight = $(".table-widget-cell").getBoundingClientRect().height;
|
||||
|
||||
is($$("#value .table-widget-cell").length, 50,
|
||||
"Table should initially display 50 items");
|
||||
|
||||
let onStoresUpdate = gUI.once("store-objects-updated");
|
||||
table.scrollTop += cellHeight * 50;
|
||||
yield onStoresUpdate;
|
||||
|
||||
is($$("#value .table-widget-cell").length, 100,
|
||||
"Table should display 100 items after scrolling");
|
||||
|
||||
onStoresUpdate = gUI.once("store-objects-updated");
|
||||
table.scrollTop += cellHeight * 50;
|
||||
yield onStoresUpdate;
|
||||
|
||||
is($$("#value .table-widget-cell").length, 150,
|
||||
"Table should display 150 items after scrolling");
|
||||
|
||||
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();
|
||||
});
|
||||
87
devtools/client/storage/test/browser_storage_search.js
Normal file
87
devtools/client/storage/test/browser_storage_search.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Tests the filter search box in the storage inspector
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-search.html");
|
||||
|
||||
let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
|
||||
gUI.tree.expandAll();
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
// Results: 0=hidden, 1=visible
|
||||
let testcases = [
|
||||
// Test that search isn't case-sensitive
|
||||
{
|
||||
value: "FoO",
|
||||
results: [0, 0, 1, 1, 0, 1, 0]
|
||||
},
|
||||
{
|
||||
value: "OR",
|
||||
results: [0, 1, 0, 0, 0, 1, 0]
|
||||
},
|
||||
{
|
||||
value: "aNImAl",
|
||||
results: [0, 1, 0, 0, 0, 0, 0]
|
||||
},
|
||||
// Test numbers
|
||||
{
|
||||
value: "01",
|
||||
results: [1, 0, 0, 0, 0, 0, 1]
|
||||
},
|
||||
{
|
||||
value: "2016",
|
||||
results: [0, 0, 0, 0, 0, 0, 1]
|
||||
},
|
||||
{
|
||||
value: "56789",
|
||||
results: [1, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
// Test filtering by value
|
||||
{
|
||||
value: "horse",
|
||||
results: [0, 1, 0, 0, 0, 0, 0]
|
||||
},
|
||||
{
|
||||
value: "$$$",
|
||||
results: [0, 0, 0, 0, 1, 0, 0]
|
||||
},
|
||||
{
|
||||
value: "bar",
|
||||
results: [0, 0, 1, 1, 0, 0, 0]
|
||||
},
|
||||
// Test input with whitespace
|
||||
{
|
||||
value: "energy b",
|
||||
results: [0, 0, 0, 1, 0, 0, 0]
|
||||
},
|
||||
// Test no input at all
|
||||
{
|
||||
value: "",
|
||||
results: [1, 1, 1, 1, 1, 1, 1]
|
||||
},
|
||||
// Test input that matches nothing
|
||||
{
|
||||
value: "input that matches nothing",
|
||||
results: [0, 0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
let names = $$("#name .table-widget-cell");
|
||||
let rows = $$("#value .table-widget-cell");
|
||||
for (let testcase of testcases) {
|
||||
info(`Testing input: ${testcase.value}`);
|
||||
|
||||
gUI.searchBox.value = testcase.value;
|
||||
gUI.filterItems();
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
info(`Testing row ${i}`);
|
||||
info(`key: ${names[i].value}, value: ${rows[i].value}`);
|
||||
let state = testcase.results[i] ? "visible" : "hidden";
|
||||
is(rows[i].hasAttribute("hidden"), !testcase.results[i],
|
||||
`Row ${i} should be ${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Test ability to focus search field by using keyboard
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-search.html");
|
||||
|
||||
gUI.tree.expandAll();
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
yield focusSearchBoxUsingShortcut(gPanelWindow);
|
||||
ok(containsFocus(gPanelWindow.document, gUI.searchBox),
|
||||
"Focus is in a searchbox");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/* 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 editing of localStorage.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-sessionstorage.html");
|
||||
|
||||
yield selectTreeItem(["sessionStorage", "http://test1.example.org"]);
|
||||
|
||||
yield editCell("TestSS1", "name", "newTestSS1");
|
||||
yield editCell("newTestSS1", "value", "newValueSS1");
|
||||
|
||||
yield editCell("TestSS3", "name", "newTestSS3");
|
||||
yield editCell("newTestSS3", "value", "newValueSS3");
|
||||
|
||||
yield editCell("TestSS5", "name", "newTestSS5");
|
||||
yield editCell("newTestSS5", "value", "newValueSS5");
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
125
devtools/client/storage/test/browser_storage_sidebar.js
Normal file
125
devtools/client/storage/test/browser_storage_sidebar.js
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* 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 the sidebar opens, closes and updates
|
||||
// This test is not testing the values in the sidebar, being tested in _values
|
||||
|
||||
// Format: [
|
||||
// <id of the table item to click> or <id array for tree item to select> or
|
||||
// null to press Escape,
|
||||
// <do we wait for the async "sidebar-updated" event>,
|
||||
// <is the sidebar open>
|
||||
// ]
|
||||
|
||||
"use strict";
|
||||
|
||||
const testCases = [
|
||||
{
|
||||
location: ["cookies", "sectest1.example.org"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "cs2",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
sendEscape: true
|
||||
},
|
||||
{
|
||||
location: "cs2",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
location: "uc1",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
location: "uc1",
|
||||
sidebarHidden: false
|
||||
},
|
||||
|
||||
{
|
||||
location: ["localStorage", "http://sectest1.example.org"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "iframe-u-ls1",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
location: "iframe-u-ls1",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
sendEscape: true
|
||||
},
|
||||
|
||||
{
|
||||
location: ["sessionStorage", "http://test1.example.org"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "ss1",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
sendEscape: true
|
||||
},
|
||||
|
||||
{
|
||||
location: ["indexedDB", "http://test1.example.org"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "idb2",
|
||||
sidebarHidden: false
|
||||
},
|
||||
|
||||
{
|
||||
location: ["indexedDB", "http://test1.example.org", "idb2", "obj3"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
|
||||
{
|
||||
location: ["indexedDB", "https://sectest1.example.org", "idb-s2"],
|
||||
sidebarHidden: true
|
||||
},
|
||||
{
|
||||
location: "obj-s2",
|
||||
sidebarHidden: false
|
||||
},
|
||||
{
|
||||
sendEscape: true
|
||||
}, {
|
||||
location: "obj-s2",
|
||||
sidebarHidden: false
|
||||
}
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
|
||||
|
||||
for (let test of testCases) {
|
||||
let { location, sidebarHidden, sendEscape } = test;
|
||||
|
||||
info("running " + JSON.stringify(test));
|
||||
|
||||
if (Array.isArray(location)) {
|
||||
yield selectTreeItem(location);
|
||||
} else if (location) {
|
||||
yield selectTableItem(location);
|
||||
}
|
||||
|
||||
if (sendEscape) {
|
||||
EventUtils.sendKey("ESCAPE", gPanelWindow);
|
||||
} else {
|
||||
is(gUI.sidebar.hidden, sidebarHidden,
|
||||
"correct visibility state of sidebar.");
|
||||
}
|
||||
|
||||
info("-".repeat(80));
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/* 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 the sidebar is not broken when several updates
|
||||
// come in quick succession. See bug 1260380 - it could happen that the
|
||||
// "Parsed Value" section gets duplicated.
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
const ITEM_NAME = "ls1";
|
||||
const UPDATE_COUNT = 3;
|
||||
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-complex-values.html");
|
||||
|
||||
let updated = gUI.once("sidebar-updated");
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
yield selectTableItem(ITEM_NAME);
|
||||
yield updated;
|
||||
|
||||
is(gUI.sidebar.hidden, false, "sidebar is visible");
|
||||
|
||||
// do several updates in a row and wait for them to finish
|
||||
let updates = [];
|
||||
for (let i = 0; i < UPDATE_COUNT; i++) {
|
||||
info(`Performing update #${i}`);
|
||||
updates.push(gUI.once("sidebar-updated"));
|
||||
gUI.displayObjectSidebar();
|
||||
}
|
||||
yield promise.all(updates);
|
||||
|
||||
info("Updates performed, going to verify result");
|
||||
let parsedScope = gUI.view.getScopeAtIndex(1);
|
||||
let elements = parsedScope.target.querySelectorAll(
|
||||
`.name[value="${ITEM_NAME}"]`);
|
||||
is(elements.length, 1,
|
||||
`There is only one displayed variable named '${ITEM_NAME}'`);
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
165
devtools/client/storage/test/browser_storage_values.js
Normal file
165
devtools/client/storage/test/browser_storage_values.js
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/* 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 the values shown in sidebar are correct
|
||||
|
||||
// Format: [
|
||||
// <id of the table item to click> or <id array for tree item to select> or
|
||||
// null do click nothing,
|
||||
// null to skip checking value in variables view or a key value pair object
|
||||
// which will be asserted to exist in the storage sidebar,
|
||||
// true if the check is to be made in the parsed value section
|
||||
// ]
|
||||
|
||||
"use strict";
|
||||
|
||||
const LONG_WORD = "a".repeat(1000);
|
||||
|
||||
const testCases = [
|
||||
["cs2", [
|
||||
{name: "cs2", value: "sessionCookie"},
|
||||
{name: "cs2.Path", value: "/"},
|
||||
{name: "cs2.HostOnly", value: "false"},
|
||||
{name: "cs2.HttpOnly", value: "false"},
|
||||
{name: "cs2.Domain", value: ".example.org"},
|
||||
{name: "cs2.Expires", value: "Session"},
|
||||
{name: "cs2.Secure", value: "false"},
|
||||
]],
|
||||
["c1", [
|
||||
{name: "c1", value: JSON.stringify(["foo", "Bar", {foo: "Bar"}])},
|
||||
{name: "c1.Path", value: "/browser"},
|
||||
{name: "c1.HostOnly", value: "true"},
|
||||
{name: "c1.HttpOnly", value: "false"},
|
||||
{name: "c1.Domain", value: "test1.example.org"},
|
||||
{name: "c1.Expires", value: new Date(2000000000000).toUTCString()},
|
||||
{name: "c1.Secure", value: "false"},
|
||||
]],
|
||||
[null, [
|
||||
{name: "c1", value: "Array"},
|
||||
{name: "c1.0", value: "foo"},
|
||||
{name: "c1.1", value: "Bar"},
|
||||
{name: "c1.2", value: "Object"},
|
||||
{name: "c1.2.foo", value: "Bar"},
|
||||
], true],
|
||||
["c_encoded", [
|
||||
{name: "c_encoded", value: encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}))}
|
||||
]],
|
||||
[null, [
|
||||
{name: "c_encoded", value: "Object"},
|
||||
{name: "c_encoded.foo", value: "Object"},
|
||||
{name: "c_encoded.foo.foo1", value: "bar"}
|
||||
], true],
|
||||
[["localStorage", "http://test1.example.org"]],
|
||||
["ls2", [
|
||||
{name: "ls2", value: "foobar-2"}
|
||||
]],
|
||||
["ls1", [
|
||||
{name: "ls1", value: JSON.stringify({
|
||||
es6: "for", the: "win", baz: [0, 2, 3, {
|
||||
deep: "down",
|
||||
nobody: "cares"
|
||||
}]})}
|
||||
]],
|
||||
[null, [
|
||||
{name: "ls1", value: "Object"},
|
||||
{name: "ls1.es6", value: "for"},
|
||||
{name: "ls1.the", value: "win"},
|
||||
{name: "ls1.baz", value: "Array"},
|
||||
{name: "ls1.baz.0", value: "0"},
|
||||
{name: "ls1.baz.1", value: "2"},
|
||||
{name: "ls1.baz.2", value: "3"},
|
||||
{name: "ls1.baz.3", value: "Object"},
|
||||
{name: "ls1.baz.3.deep", value: "down"},
|
||||
{name: "ls1.baz.3.nobody", value: "cares"},
|
||||
], true],
|
||||
["ls3", [
|
||||
{name: "ls3", "value": "http://foobar.com/baz.php"}
|
||||
]],
|
||||
[null, [
|
||||
{name: "ls3", "value": "http://foobar.com/baz.php", dontMatch: true}
|
||||
], true],
|
||||
[["sessionStorage", "http://test1.example.org"]],
|
||||
["ss1", [
|
||||
{name: "ss1", value: "This#is#an#array"}
|
||||
]],
|
||||
[null, [
|
||||
{name: "ss1", value: "Array"},
|
||||
{name: "ss1.0", value: "This"},
|
||||
{name: "ss1.1", value: "is"},
|
||||
{name: "ss1.2", value: "an"},
|
||||
{name: "ss1.3", value: "array"},
|
||||
], true],
|
||||
["ss2", [
|
||||
{name: "ss2", value: "Array"},
|
||||
{name: "ss2.0", value: "This"},
|
||||
{name: "ss2.1", value: "is"},
|
||||
{name: "ss2.2", value: "another"},
|
||||
{name: "ss2.3", value: "array"},
|
||||
], true],
|
||||
["ss3", [
|
||||
{name: "ss3", value: "Object"},
|
||||
{name: "ss3.this", value: "is"},
|
||||
{name: "ss3.an", value: "object"},
|
||||
{name: "ss3.foo", value: "bar"},
|
||||
], true],
|
||||
["ss4", [
|
||||
{name: "ss4", value: "Array"},
|
||||
{name: "ss4.0", value: ""},
|
||||
{name: "ss4.1", value: "array"},
|
||||
{name: "ss4.2", value: ""},
|
||||
{name: "ss4.3", value: "with"},
|
||||
{name: "ss4.4", value: "empty"},
|
||||
{name: "ss4.5", value: "items"},
|
||||
], true],
|
||||
["ss5", [
|
||||
{name: "ss5", value: "Array"},
|
||||
{name: "ss5.0", value: LONG_WORD},
|
||||
{name: "ss5.1", value: LONG_WORD},
|
||||
{name: "ss5.2", value: LONG_WORD},
|
||||
{name: "ss5.3", value: `${LONG_WORD}&${LONG_WORD}`},
|
||||
{name: "ss5.4", value: `${LONG_WORD}&${LONG_WORD}`},
|
||||
], true],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj1"]],
|
||||
[1, [
|
||||
{name: 1, value: JSON.stringify({id: 1, name: "foo", email: "foo@bar.com"})}
|
||||
]],
|
||||
[null, [
|
||||
{name: "1.id", value: "1"},
|
||||
{name: "1.name", value: "foo"},
|
||||
{name: "1.email", value: "foo@bar.com"},
|
||||
], true],
|
||||
[["indexedDB", "http://test1.example.org", "idb1", "obj2"]],
|
||||
[1, [
|
||||
{name: 1, value: JSON.stringify({
|
||||
id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"
|
||||
})}
|
||||
]],
|
||||
[null, [
|
||||
{name: "1.id2", value: "1"},
|
||||
{name: "1.name", value: "foo"},
|
||||
{name: "1.email", value: "foo@bar.com"},
|
||||
{name: "1.extra", value: "baz"},
|
||||
], true]
|
||||
];
|
||||
|
||||
add_task(function* () {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-complex-values.html");
|
||||
|
||||
gUI.tree.expandAll();
|
||||
|
||||
for (let item of testCases) {
|
||||
info("clicking for item " + item);
|
||||
|
||||
if (Array.isArray(item[0])) {
|
||||
yield selectTreeItem(item[0]);
|
||||
continue;
|
||||
} else if (item[0]) {
|
||||
yield selectTableItem(item[0]);
|
||||
}
|
||||
|
||||
yield findVariableViewProperties(item[1], item[2]);
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
||||
840
devtools/client/storage/test/head.js
Normal file
840
devtools/client/storage/test/head.js
Normal file
|
|
@ -0,0 +1,840 @@
|
|||
/* 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";
|
||||
|
||||
/* eslint no-unused-vars: [2, {"vars": "local"}] */
|
||||
/* import-globals-from ../../framework/test/shared-head.js */
|
||||
|
||||
// shared-head.js handles imports, constants, and utility functions
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
|
||||
this);
|
||||
|
||||
const {TableWidget} = require("devtools/client/shared/widgets/TableWidget");
|
||||
const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
|
||||
const STORAGE_PREF = "devtools.storage.enabled";
|
||||
const DUMPEMIT_PREF = "devtools.dump.emit";
|
||||
const DEBUGGERLOG_PREF = "devtools.debugger.log";
|
||||
// Allows Cache API to be working on usage `http` test page
|
||||
const CACHES_ON_HTTP_PREF = "dom.caches.testing.enabled";
|
||||
const PATH = "browser/devtools/client/storage/test/";
|
||||
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;
|
||||
|
||||
var gToolbox, gPanelWindow, gWindow, gUI;
|
||||
|
||||
// Services.prefs.setBoolPref(DUMPEMIT_PREF, true);
|
||||
// Services.prefs.setBoolPref(DEBUGGERLOG_PREF, true);
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
/**
|
||||
* This generator function opens the given url in a new tab, then sets up the
|
||||
* page by waiting for all cookies, indexedDB items etc. to be created; Then
|
||||
* opens the storage inspector and waits for the storage tree and table to be
|
||||
* populated.
|
||||
*
|
||||
* @param url {String} The url to be opened in the new tab
|
||||
*
|
||||
* @return {Promise} A promise that resolves after storage inspector is ready
|
||||
*/
|
||||
function* openTabAndSetupStorage(url) {
|
||||
let tab = yield addTab(url);
|
||||
let content = tab.linkedBrowser.contentWindow;
|
||||
|
||||
gWindow = content.wrappedJSObject;
|
||||
|
||||
// Setup the async storages in main window and for all its iframes
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function* () {
|
||||
/**
|
||||
* Get all windows including frames recursively.
|
||||
*
|
||||
* @param {Window} [baseWindow]
|
||||
* The base window at which to start looking for child windows
|
||||
* (optional).
|
||||
* @return {Set}
|
||||
* A set of windows.
|
||||
*/
|
||||
function getAllWindows(baseWindow) {
|
||||
let windows = new Set();
|
||||
|
||||
let _getAllWindows = function (win) {
|
||||
windows.add(win.wrappedJSObject);
|
||||
|
||||
for (let i = 0; i < win.length; i++) {
|
||||
_getAllWindows(win[i]);
|
||||
}
|
||||
};
|
||||
_getAllWindows(baseWindow);
|
||||
|
||||
return windows;
|
||||
}
|
||||
|
||||
let windows = getAllWindows(content);
|
||||
for (let win of windows) {
|
||||
let readyState = win.document.readyState;
|
||||
info(`Found a window: ${readyState}`);
|
||||
if (readyState != "complete") {
|
||||
yield new Promise(resolve => {
|
||||
let onLoad = () => {
|
||||
win.removeEventListener("load", onLoad);
|
||||
resolve();
|
||||
};
|
||||
win.addEventListener("load", onLoad);
|
||||
});
|
||||
}
|
||||
if (win.setup) {
|
||||
yield win.setup();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// open storage inspector
|
||||
return yield openStoragePanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the toolbox, with the storage tool visible.
|
||||
*
|
||||
* @param cb {Function} Optional callback, if you don't want to use the returned
|
||||
* promise
|
||||
*
|
||||
* @return {Promise} a promise that resolves when the storage inspector is ready
|
||||
*/
|
||||
var openStoragePanel = Task.async(function* (cb) {
|
||||
info("Opening the storage inspector");
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
let storage, toolbox;
|
||||
|
||||
// Checking if the toolbox and the storage are already loaded
|
||||
// The storage-updated event should only be waited for if the storage
|
||||
// isn't loaded yet
|
||||
toolbox = gDevTools.getToolbox(target);
|
||||
if (toolbox) {
|
||||
storage = toolbox.getPanel("storage");
|
||||
if (storage) {
|
||||
gPanelWindow = storage.panelWindow;
|
||||
gUI = storage.UI;
|
||||
gToolbox = toolbox;
|
||||
info("Toolbox and storage already open");
|
||||
if (cb) {
|
||||
return cb(storage, toolbox);
|
||||
}
|
||||
|
||||
return {
|
||||
toolbox: toolbox,
|
||||
storage: storage
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
info("Opening the toolbox");
|
||||
toolbox = yield gDevTools.showToolbox(target, "storage");
|
||||
storage = toolbox.getPanel("storage");
|
||||
gPanelWindow = storage.panelWindow;
|
||||
gUI = storage.UI;
|
||||
gToolbox = toolbox;
|
||||
|
||||
// The table animation flash causes some timeouts on Linux debug tests,
|
||||
// so we disable it
|
||||
gUI.animationsEnabled = false;
|
||||
|
||||
info("Waiting for the stores to update");
|
||||
yield gUI.once("store-objects-updated");
|
||||
|
||||
yield waitForToolboxFrameFocus(toolbox);
|
||||
|
||||
if (cb) {
|
||||
return cb(storage, toolbox);
|
||||
}
|
||||
|
||||
return {
|
||||
toolbox: toolbox,
|
||||
storage: storage
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Wait for the toolbox frame to receive focus after it loads
|
||||
*
|
||||
* @param toolbox {Toolbox}
|
||||
*
|
||||
* @return a promise that resolves when focus has been received
|
||||
*/
|
||||
function waitForToolboxFrameFocus(toolbox) {
|
||||
info("Making sure that the toolbox's frame is focused");
|
||||
let def = promise.defer();
|
||||
waitForFocus(def.resolve, toolbox.win);
|
||||
return def.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces GC, CC and Shrinking GC to get rid of disconnected docshells and
|
||||
* windows.
|
||||
*/
|
||||
function forceCollections() {
|
||||
Cu.forceGC();
|
||||
Cu.forceCC();
|
||||
Cu.forceShrinkingGC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up and finishes the test
|
||||
*/
|
||||
function* finishTests() {
|
||||
// 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* () {
|
||||
/**
|
||||
* Get all windows including frames recursively.
|
||||
*
|
||||
* @param {Window} [baseWindow]
|
||||
* The base window at which to start looking for child windows
|
||||
* (optional).
|
||||
* @return {Set}
|
||||
* A set of windows.
|
||||
*/
|
||||
function getAllWindows(baseWindow) {
|
||||
let windows = new Set();
|
||||
|
||||
let _getAllWindows = function (win) {
|
||||
windows.add(win.wrappedJSObject);
|
||||
|
||||
for (let i = 0; i < win.length; i++) {
|
||||
_getAllWindows(win[i]);
|
||||
}
|
||||
};
|
||||
_getAllWindows(baseWindow);
|
||||
|
||||
return windows;
|
||||
}
|
||||
|
||||
let windows = getAllWindows(content);
|
||||
for (let win of windows) {
|
||||
// Some windows (e.g., about: URLs) don't have storage available
|
||||
try {
|
||||
win.localStorage.clear();
|
||||
win.sessionStorage.clear();
|
||||
} catch (ex) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (win.clear) {
|
||||
yield win.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Services.cookies.removeAll();
|
||||
forceCollections();
|
||||
finish();
|
||||
}
|
||||
|
||||
// Sends a click event on the passed DOM node in an async manner
|
||||
function* click(node) {
|
||||
let def = promise.defer();
|
||||
|
||||
node.scrollIntoView();
|
||||
|
||||
// We need setTimeout here to allow any scrolling to complete before clicking
|
||||
// the node.
|
||||
setTimeout(() => {
|
||||
node.click();
|
||||
def.resolve();
|
||||
}, 200);
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively expand the variables view up to a given property.
|
||||
*
|
||||
* @param options
|
||||
* Options for view expansion:
|
||||
* - rootVariable: start from the given scope/variable/property.
|
||||
* - expandTo: string made up of property names you want to expand.
|
||||
* For example: "body.firstChild.nextSibling" given |rootVariable:
|
||||
* document|.
|
||||
* @return object
|
||||
* A promise that is resolved only when the last property in |expandTo|
|
||||
* is found, and rejected otherwise. Resolution reason is always the
|
||||
* last property - |nextSibling| in the example above. Rejection is
|
||||
* always the last property that was found.
|
||||
*/
|
||||
function variablesViewExpandTo(options) {
|
||||
let root = options.rootVariable;
|
||||
let expandTo = options.expandTo.split(".");
|
||||
let lastDeferred = promise.defer();
|
||||
|
||||
function getNext(prop) {
|
||||
let name = expandTo.shift();
|
||||
let newProp = prop.get(name);
|
||||
|
||||
if (expandTo.length > 0) {
|
||||
ok(newProp, "found property " + name);
|
||||
if (newProp && newProp.expand) {
|
||||
newProp.expand();
|
||||
getNext(newProp);
|
||||
} else {
|
||||
lastDeferred.reject(prop);
|
||||
}
|
||||
} else if (newProp) {
|
||||
lastDeferred.resolve(newProp);
|
||||
} else {
|
||||
lastDeferred.reject(prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (root && root.expand) {
|
||||
root.expand();
|
||||
getNext(root);
|
||||
} else {
|
||||
lastDeferred.resolve(root);
|
||||
}
|
||||
|
||||
return lastDeferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find variables or properties in a VariablesView instance.
|
||||
*
|
||||
* @param array ruleArray
|
||||
* The array of rules you want to match. Each rule is an object with:
|
||||
* - name (string|regexp): property name to match.
|
||||
* - value (string|regexp): property value to match.
|
||||
* - dontMatch (boolean): make sure the rule doesn't match any property.
|
||||
* @param boolean parsed
|
||||
* true if we want to test the rules in the parse value section of the
|
||||
* storage sidebar
|
||||
* @return object
|
||||
* A promise object that is resolved when all the rules complete
|
||||
* matching. The resolved callback is given an array of all the rules
|
||||
* you wanted to check. Each rule has a new property: |matchedProp|
|
||||
* which holds a reference to the Property object instance from the
|
||||
* VariablesView. If the rule did not match, then |matchedProp| is
|
||||
* undefined.
|
||||
*/
|
||||
function findVariableViewProperties(ruleArray, parsed) {
|
||||
// Initialize the search.
|
||||
function init() {
|
||||
// If parsed is true, we are checking rules in the parsed value section of
|
||||
// the storage sidebar. That scope uses a blank variable as a placeholder
|
||||
// Thus, adding a blank parent to each name
|
||||
if (parsed) {
|
||||
ruleArray = ruleArray.map(({name, value, dontMatch}) => {
|
||||
return {name: "." + name, value, dontMatch};
|
||||
});
|
||||
}
|
||||
// Separate out the rules that require expanding properties throughout the
|
||||
// view.
|
||||
let expandRules = [];
|
||||
let rules = ruleArray.filter(rule => {
|
||||
if (typeof rule.name == "string" && rule.name.indexOf(".") > -1) {
|
||||
expandRules.push(rule);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Search through the view those rules that do not require any properties to
|
||||
// be expanded. Build the array of matchers, outstanding promises to be
|
||||
// resolved.
|
||||
let outstanding = [];
|
||||
|
||||
finder(rules, gUI.view, outstanding);
|
||||
|
||||
// Process the rules that need to expand properties.
|
||||
let lastStep = processExpandRules.bind(null, expandRules);
|
||||
|
||||
// Return the results - a promise resolved to hold the updated ruleArray.
|
||||
let returnResults = onAllRulesMatched.bind(null, ruleArray);
|
||||
|
||||
return promise.all(outstanding).then(lastStep).then(returnResults);
|
||||
}
|
||||
|
||||
function onMatch(prop, rule, matched) {
|
||||
if (matched && !rule.matchedProp) {
|
||||
rule.matchedProp = prop;
|
||||
}
|
||||
}
|
||||
|
||||
function finder(rules, view, promises) {
|
||||
for (let scope of view) {
|
||||
for (let [, prop] of scope) {
|
||||
for (let rule of rules) {
|
||||
let matcher = matchVariablesViewProperty(prop, rule);
|
||||
promises.push(matcher.then(onMatch.bind(null, prop, rule)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processExpandRules(rules) {
|
||||
let rule = rules.shift();
|
||||
if (!rule) {
|
||||
return promise.resolve(null);
|
||||
}
|
||||
|
||||
let deferred = promise.defer();
|
||||
let expandOptions = {
|
||||
rootVariable: gUI.view.getScopeAtIndex(parsed ? 1 : 0),
|
||||
expandTo: rule.name
|
||||
};
|
||||
|
||||
variablesViewExpandTo(expandOptions).then(function onSuccess(prop) {
|
||||
let name = rule.name;
|
||||
let lastName = name.split(".").pop();
|
||||
rule.name = lastName;
|
||||
|
||||
let matched = matchVariablesViewProperty(prop, rule);
|
||||
return matched.then(onMatch.bind(null, prop, rule)).then(function () {
|
||||
rule.name = name;
|
||||
});
|
||||
}, function onFailure() {
|
||||
return promise.resolve(null);
|
||||
}).then(processExpandRules.bind(null, rules)).then(function () {
|
||||
deferred.resolve(null);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function onAllRulesMatched(rules) {
|
||||
for (let rule of rules) {
|
||||
let matched = rule.matchedProp;
|
||||
if (matched && !rule.dontMatch) {
|
||||
ok(true, "rule " + rule.name + " matched for property " + matched.name);
|
||||
} else if (matched && rule.dontMatch) {
|
||||
ok(false, "rule " + rule.name + " should not match property " +
|
||||
matched.name);
|
||||
} else {
|
||||
ok(rule.dontMatch, "rule " + rule.name + " did not match any property");
|
||||
}
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
return init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given Property object from the variables view matches the given
|
||||
* rule.
|
||||
*
|
||||
* @param object prop
|
||||
* The variable's view Property instance.
|
||||
* @param object rule
|
||||
* Rules for matching the property. See findVariableViewProperties() for
|
||||
* details.
|
||||
* @return object
|
||||
* A promise that is resolved when all the checks complete. Resolution
|
||||
* result is a boolean that tells your promise callback the match
|
||||
* result: true or false.
|
||||
*/
|
||||
function matchVariablesViewProperty(prop, rule) {
|
||||
function resolve(result) {
|
||||
return promise.resolve(result);
|
||||
}
|
||||
|
||||
if (!prop) {
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
if (rule.name) {
|
||||
let match = rule.name instanceof RegExp ?
|
||||
rule.name.test(prop.name) :
|
||||
prop.name == rule.name;
|
||||
if (!match) {
|
||||
return resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
if ("value" in rule) {
|
||||
let displayValue = prop.displayValue;
|
||||
if (prop.displayValueClassName == "token-string") {
|
||||
displayValue = displayValue.substring(1, displayValue.length - 1);
|
||||
}
|
||||
|
||||
let match = rule.value instanceof RegExp ?
|
||||
rule.value.test(displayValue) :
|
||||
displayValue == rule.value;
|
||||
if (!match) {
|
||||
info("rule " + rule.name + " did not match value, expected '" +
|
||||
rule.value + "', found '" + displayValue + "'");
|
||||
return resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Click selects a row in the table.
|
||||
*
|
||||
* @param {[String]} ids
|
||||
* The array id of the item in the tree
|
||||
*/
|
||||
function* selectTreeItem(ids) {
|
||||
/* If this item is already selected, return */
|
||||
if (gUI.tree.isSelected(ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let updated = gUI.once("store-objects-updated");
|
||||
gUI.tree.selectedItem = ids;
|
||||
yield updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click selects a row in the table.
|
||||
*
|
||||
* @param {String} id
|
||||
* The id of the row in the table widget
|
||||
*/
|
||||
function* selectTableItem(id) {
|
||||
let selector = ".table-widget-cell[data-id='" + id + "']";
|
||||
let target = gPanelWindow.document.querySelector(selector);
|
||||
ok(target, "table item found with ids " + id);
|
||||
|
||||
yield click(target);
|
||||
yield gUI.once("sidebar-updated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for eventName on target.
|
||||
* @param {Object} target An observable object that either supports on/off or
|
||||
* addEventListener/removeEventListener
|
||||
* @param {String} eventName
|
||||
* @param {Boolean} [useCapture] for addEventListener/removeEventListener
|
||||
* @return A promise that resolves when the event has been handled
|
||||
*/
|
||||
function once(target, eventName, useCapture = false) {
|
||||
info("Waiting for event: '" + eventName + "' on " + target + ".");
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
for (let [add, remove] of [
|
||||
["addEventListener", "removeEventListener"],
|
||||
["addListener", "removeListener"],
|
||||
["on", "off"]
|
||||
]) {
|
||||
if ((add in target) && (remove in target)) {
|
||||
target[add](eventName, function onEvent(...aArgs) {
|
||||
target[remove](eventName, onEvent, useCapture);
|
||||
deferred.resolve.apply(deferred, aArgs);
|
||||
}, useCapture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get values for a row.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the given row.
|
||||
* @param {Boolean} includeHidden
|
||||
* Include hidden columns.
|
||||
*
|
||||
* @return {Object}
|
||||
* An object of column names to values for the given row.
|
||||
*/
|
||||
function getRowValues(id, includeHidden = false) {
|
||||
let cells = getRowCells(id, includeHidden);
|
||||
let values = {};
|
||||
|
||||
for (let name in cells) {
|
||||
let cell = cells[name];
|
||||
|
||||
values[name] = cell.value;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cells for a row.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the given row.
|
||||
* @param {Boolean} includeHidden
|
||||
* Include hidden columns.
|
||||
*
|
||||
* @return {Object}
|
||||
* An object of column names to cells for the given row.
|
||||
*/
|
||||
function getRowCells(id, includeHidden = false) {
|
||||
let doc = gPanelWindow.document;
|
||||
let table = gUI.table;
|
||||
let item = doc.querySelector(".table-widget-column#" + table.uniqueId +
|
||||
" .table-widget-cell[value='" + id + "']");
|
||||
|
||||
if (!item) {
|
||||
ok(false, "Row id '" + id + "' exists");
|
||||
}
|
||||
|
||||
let index = table.columns.get(table.uniqueId).visibleCellNodes.indexOf(item);
|
||||
let cells = {};
|
||||
|
||||
for (let [name, column] of [...table.columns]) {
|
||||
if (!includeHidden && column.column.parentNode.hidden) {
|
||||
continue;
|
||||
}
|
||||
cells[name] = column.visibleCellNodes[index];
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cell value.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the row.
|
||||
* @param {String} column
|
||||
* The id of the column
|
||||
*
|
||||
* @yield {String}
|
||||
* The cell value.
|
||||
*/
|
||||
function getCellValue(id, column) {
|
||||
let row = getRowValues(id, true);
|
||||
|
||||
return row[column];
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a cell value. The cell is assumed to be in edit mode, see startCellEdit.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the row.
|
||||
* @param {String} column
|
||||
* The id of the column
|
||||
* @param {String} newValue
|
||||
* Replacement value.
|
||||
* @param {Boolean} validate
|
||||
* Validate result? Default true.
|
||||
*
|
||||
* @yield {String}
|
||||
* The uniqueId of the changed row.
|
||||
*/
|
||||
function* editCell(id, column, newValue, validate = true) {
|
||||
let row = getRowCells(id, true);
|
||||
let editableFieldsEngine = gUI.table._editableFieldsEngine;
|
||||
|
||||
editableFieldsEngine.edit(row[column]);
|
||||
|
||||
yield typeWithTerminator(newValue, "VK_RETURN", validate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin edit mode for a cell.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the row.
|
||||
* @param {String} column
|
||||
* The id of the column
|
||||
* @param {Boolean} selectText
|
||||
* Select text? Default true.
|
||||
*/
|
||||
function* startCellEdit(id, column, selectText = true) {
|
||||
let row = getRowCells(id, true);
|
||||
let editableFieldsEngine = gUI.table._editableFieldsEngine;
|
||||
let cell = row[column];
|
||||
|
||||
info("Selecting row " + id);
|
||||
gUI.table.selectedRow = id;
|
||||
|
||||
info("Starting cell edit (" + id + ", " + column + ")");
|
||||
editableFieldsEngine.edit(cell);
|
||||
|
||||
if (!selectText) {
|
||||
let textbox = gUI.table._editableFieldsEngine.textbox;
|
||||
textbox.selectionEnd = textbox.selectionStart;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a cell value.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the row.
|
||||
* @param {String} column
|
||||
* The id of the column
|
||||
* @param {String} expected
|
||||
* Expected value.
|
||||
*/
|
||||
function checkCell(id, column, expected) {
|
||||
is(getCellValue(id, column), expected,
|
||||
column + " column has the right value for " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide a column.
|
||||
*
|
||||
* @param {String} id
|
||||
* The uniqueId of the given column.
|
||||
* @param {Boolean} state
|
||||
* true = show, false = hide
|
||||
*/
|
||||
function showColumn(id, state) {
|
||||
let columns = gUI.table.columns;
|
||||
let column = columns.get(id);
|
||||
|
||||
if (state) {
|
||||
column.wrapper.removeAttribute("hidden");
|
||||
} else {
|
||||
column.wrapper.setAttribute("hidden", true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide all columns.
|
||||
*
|
||||
* @param {Boolean} state
|
||||
* true = show, false = hide
|
||||
*/
|
||||
function showAllColumns(state) {
|
||||
let columns = gUI.table.columns;
|
||||
|
||||
for (let [id] of columns) {
|
||||
showColumn(id, state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type a string in the currently selected editor and then wait for the row to
|
||||
* be updated.
|
||||
*
|
||||
* @param {String} str
|
||||
* The string to type.
|
||||
* @param {String} terminator
|
||||
* The terminating key e.g. VK_RETURN or VK_TAB
|
||||
* @param {Boolean} validate
|
||||
* Validate result? Default true.
|
||||
*/
|
||||
function* typeWithTerminator(str, terminator, validate = true) {
|
||||
let editableFieldsEngine = gUI.table._editableFieldsEngine;
|
||||
let textbox = editableFieldsEngine.textbox;
|
||||
let colName = textbox.closest(".table-widget-column").id;
|
||||
|
||||
let changeExpected = str !== textbox.value;
|
||||
|
||||
if (!changeExpected) {
|
||||
return editableFieldsEngine.currentTarget.getAttribute("data-id");
|
||||
}
|
||||
|
||||
info("Typing " + str);
|
||||
EventUtils.sendString(str);
|
||||
|
||||
info("Pressing " + terminator);
|
||||
EventUtils.synthesizeKey(terminator, {});
|
||||
|
||||
if (validate) {
|
||||
info("Validating results... waiting for ROW_EDIT event.");
|
||||
let uniqueId = yield gUI.table.once(TableWidget.EVENTS.ROW_EDIT);
|
||||
|
||||
checkCell(uniqueId, colName, str);
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
return yield gUI.table.once(TableWidget.EVENTS.ROW_EDIT);
|
||||
}
|
||||
|
||||
function getCurrentEditorValue() {
|
||||
let editableFieldsEngine = gUI.table._editableFieldsEngine;
|
||||
let textbox = editableFieldsEngine.textbox;
|
||||
|
||||
return textbox.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Press a key x times.
|
||||
*
|
||||
* @param {String} key
|
||||
* The key to press e.g. VK_RETURN or VK_TAB
|
||||
* @param {Number} x
|
||||
* The number of times to press the key.
|
||||
* @param {Object} modifiers
|
||||
* The event modifier e.g. {shiftKey: true}
|
||||
*/
|
||||
function PressKeyXTimes(key, x, modifiers = {}) {
|
||||
for (let i = 0; i < x; i++) {
|
||||
EventUtils.synthesizeKey(key, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the storage inspector state: check that given type/host exists
|
||||
* in the tree, and that the table contains rows with specified names.
|
||||
*
|
||||
* @param {Array} state Array of state specifications. For example,
|
||||
* [["cookies", "example.com"], ["c1", "c2"]] means to select the
|
||||
* "example.com" host in cookies and then verify there are "c1" and "c2"
|
||||
* cookies (and no other ones).
|
||||
*/
|
||||
function* checkState(state) {
|
||||
for (let [store, names] of state) {
|
||||
let storeName = store.join(" > ");
|
||||
info(`Selecting tree item ${storeName}`);
|
||||
yield selectTreeItem(store);
|
||||
|
||||
let items = gUI.table.items;
|
||||
|
||||
is(items.size, names.length,
|
||||
`There is correct number of rows in ${storeName}`);
|
||||
for (let name of names) {
|
||||
ok(items.has(name),
|
||||
`There is item with name '${name}' in ${storeName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if document's active element is within the given element.
|
||||
* @param {HTMLDocument} doc document with active element in question
|
||||
* @param {DOMNode} container element tested on focus containment
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function containsFocus(doc, container) {
|
||||
let elm = doc.activeElement;
|
||||
while (elm) {
|
||||
if (elm === container) {
|
||||
return true;
|
||||
}
|
||||
elm = elm.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var focusSearchBoxUsingShortcut = Task.async(function* (panelWin, callback) {
|
||||
info("Focusing search box");
|
||||
let searchBox = panelWin.document.getElementById("storage-searchbox");
|
||||
let focused = once(searchBox, "focus");
|
||||
|
||||
panelWin.focus();
|
||||
let strings = Services.strings.createBundle(
|
||||
"chrome://devtools/locale/storage.properties");
|
||||
synthesizeKeyShortcut(strings.GetStringFromName("storage.filter.key"));
|
||||
|
||||
yield focused;
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
20
devtools/client/storage/test/storage-cache-error.html
Normal file
20
devtools/client/storage/test/storage-cache-error.html
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector test for handling errors in CacheStorage</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
// Create an iframe with a javascript: source URL. Such iframes are
|
||||
// considered untrusted by the CacheStorage.
|
||||
let frameEl = document.createElement("iframe");
|
||||
document.body.appendChild(frameEl);
|
||||
|
||||
window.frameContent = 'Hello World';
|
||||
frameEl.contentWindow.location.href = "javascript:parent.frameContent";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
123
devtools/client/storage/test/storage-complex-values.html
Normal file
123
devtools/client/storage/test/storage-complex-values.html
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 970517 - Storage inspector front end - tests
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector test for correct values in the sidebar</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
|
||||
let cookieExpiresTime = 2000000000000;
|
||||
// Setting up some cookies to eat.
|
||||
document.cookie = "c1=" + JSON.stringify([
|
||||
"foo", "Bar", {
|
||||
foo: "Bar"
|
||||
}]) + "; expires=" + new Date(cookieExpiresTime).toGMTString() +
|
||||
"; path=/browser";
|
||||
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
|
||||
// URLEncoded cookie
|
||||
document.cookie = "c_encoded=" + encodeURIComponent(JSON.stringify({foo: {foo1: "bar"}}));
|
||||
|
||||
// ... and some local storage items ..
|
||||
const es6 = "for";
|
||||
localStorage.setItem("ls1", JSON.stringify({
|
||||
es6, the: "win", baz: [0, 2, 3, {
|
||||
deep: "down",
|
||||
nobody: "cares"
|
||||
}]}));
|
||||
localStorage.setItem("ls2", "foobar-2");
|
||||
localStorage.setItem("ls3", "http://foobar.com/baz.php");
|
||||
// ... and finally some session storage items too
|
||||
sessionStorage.setItem("ss1", "This#is#an#array");
|
||||
sessionStorage.setItem("ss2", "This~is~another~array");
|
||||
sessionStorage.setItem("ss3", "this#is~an#object~foo#bar");
|
||||
sessionStorage.setItem("ss4", "#array##with#empty#items");
|
||||
// long string that is almost an object and might trigger exponential
|
||||
// regexp backtracking
|
||||
let s = "a".repeat(1000);
|
||||
sessionStorage.setItem("ss5", `${s}=${s}=${s}=${s}&${s}=${s}&${s}`);
|
||||
console.log("added cookies and stuff from main page");
|
||||
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb1", 1);
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
// Prevents AbortError
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj1");
|
||||
let store2 = transaction.objectStore("obj2");
|
||||
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
|
||||
store2.add({
|
||||
id2: 1,
|
||||
name: "foo",
|
||||
email: "foo@bar.com",
|
||||
extra: "baz"});
|
||||
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb2", 1);
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
db2.close();
|
||||
console.log("added cookies and stuff from main page");
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
return new Promise(resolve => {
|
||||
dump("removing database " + dbName + " from " + document.location + "\n");
|
||||
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
yield deleteDB("idb1");
|
||||
yield deleteDB("idb2");
|
||||
|
||||
dump("removed indexedDB data from " + document.location + "\n");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
devtools/client/storage/test/storage-cookies.html
Normal file
24
devtools/client/storage/test/storage-cookies.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 970517 - Storage inspector front end - tests
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector cookie test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
let expiresIn24Hours = new Date(Date.now() + 60 * 60 * 24 * 1000).toUTCString();
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
let cookieString = "test" + i + "=value" + i +
|
||||
";expires=" + expiresIn24Hours + ";path=/browser";
|
||||
if (i % 2) {
|
||||
cookieString += ";domain=test1.example.org";
|
||||
}
|
||||
document.cookie = cookieString;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
62
devtools/client/storage/test/storage-empty-objectstores.html
Normal file
62
devtools/client/storage/test/storage-empty-objectstores.html
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for proper listing indexedDB databases with no object stores</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
window.setup = function* () {
|
||||
let request = indexedDB.open("idb1", 1);
|
||||
let db = yield new Promise((resolve, reject) => {
|
||||
request.onerror = e => reject(Error("error opening db connection"));
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
store1.transaction.oncomplete = () => resolve(db);
|
||||
};
|
||||
});
|
||||
|
||||
yield new Promise(resolve => request.onsuccess = resolve);
|
||||
|
||||
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj1");
|
||||
let store2 = transaction.objectStore("obj2");
|
||||
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
|
||||
store2.add({id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"});
|
||||
|
||||
yield new Promise(resolve => transaction.oncomplete = resolve);
|
||||
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb2", 1);
|
||||
let db2 = yield new Promise((resolve, reject) => {
|
||||
request.onerror = e => reject(Error("error opening db2 connection"));
|
||||
request.onupgradeneeded = event => resolve(event.target.result);
|
||||
});
|
||||
|
||||
yield new Promise(resolve => request.onsuccess = resolve);
|
||||
|
||||
db2.close();
|
||||
dump("added indexedDB items from main page\n");
|
||||
};
|
||||
|
||||
window.clear = function* () {
|
||||
for (let dbName of ["idb1", "idb2"]) {
|
||||
yield new Promise(resolve => {
|
||||
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
dump("removed indexedDB items from main page\n");
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
52
devtools/client/storage/test/storage-idb-delete-blocked.html
Normal file
52
devtools/client/storage/test/storage-idb-delete-blocked.html
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for proper listing indexedDB databases with no object stores</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
let db;
|
||||
|
||||
window.setup = function* () {
|
||||
db = yield new Promise((resolve, reject) => {
|
||||
let request = indexedDB.open("idb", 1);
|
||||
|
||||
request.onsuccess = e => resolve(e.target.result);
|
||||
request.onerror = e => reject(new Error("error opening db connection"));
|
||||
|
||||
request.onupgradeneeded = e => {
|
||||
let db = e.target.result;
|
||||
let store = db.createObjectStore("obj", { keyPath: "id" });
|
||||
};
|
||||
});
|
||||
|
||||
dump("opened indexedDB\n");
|
||||
};
|
||||
|
||||
window.closeDb = function* () {
|
||||
db.close();
|
||||
};
|
||||
|
||||
window.deleteDb = function* () {
|
||||
yield new Promise((resolve, reject) => {
|
||||
let request = indexedDB.deleteDatabase("idb");
|
||||
|
||||
request.onsuccess = resolve;
|
||||
request.onerror = e => reject(new Error("error deleting db"));
|
||||
});
|
||||
};
|
||||
|
||||
window.clear = function* () {
|
||||
for (let dbName of ["idb1", "idb2"]) {
|
||||
yield new Promise(resolve => {
|
||||
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
dump("removed indexedDB items from main page\n");
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
126
devtools/client/storage/test/storage-listings.html
Normal file
126
devtools/client/storage/test/storage-listings.html
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 970517 - Storage inspector front end - tests
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector test for listing hosts and storages</title>
|
||||
</head>
|
||||
<body>
|
||||
<iframe src="http://sectest1.example.org/browser/devtools/client/storage/test/storage-unsecured-iframe.html"></iframe>
|
||||
<iframe src="https://sectest1.example.org:443/browser/devtools/client/storage/test/storage-secured-iframe.html"></iframe>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
|
||||
let cookieExpiresTime1 = 2000000000000;
|
||||
let cookieExpiresTime2 = 2000000001000;
|
||||
// Setting up some cookies to eat.
|
||||
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=/";
|
||||
// ... and some local storage items ..
|
||||
localStorage.setItem("ls1", "foobar");
|
||||
localStorage.setItem("ls2", "foobar-2");
|
||||
// ... and finally some session storage items too
|
||||
sessionStorage.setItem("ss1", "foobar-3");
|
||||
dump("added cookies and storage from main page\n");
|
||||
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb1", 1);
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
|
||||
store1.createIndex("name", "name", { unique: false });
|
||||
store1.createIndex("email", "email", { unique: true });
|
||||
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
// Prevents AbortError
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj1");
|
||||
let store2 = transaction.objectStore("obj2");
|
||||
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
|
||||
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
|
||||
store2.add({
|
||||
id2: 1,
|
||||
name: "foo",
|
||||
email: "foo@bar.com",
|
||||
extra: "baz"
|
||||
});
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(success => {
|
||||
transaction.oncomplete = success;
|
||||
});
|
||||
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb2", 1);
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
}
|
||||
};
|
||||
});
|
||||
// Prevents AbortError during close()
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
db2.close();
|
||||
|
||||
dump("added indexedDB from main page\n");
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
return new Promise(resolve => {
|
||||
dump("removing database " + dbName + " from " + document.location + "\n");
|
||||
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
function fetchPut(cache, url) {
|
||||
let response = yield fetch(url);
|
||||
yield cache.put(url, response);
|
||||
}
|
||||
|
||||
let cacheGenerator = function*() {
|
||||
let cache = yield caches.open("plop");
|
||||
yield fetchPut(cache, "404_cached_file.js");
|
||||
yield fetchPut(cache, "browser_storage_basic.js");
|
||||
};
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
yield cacheGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
yield deleteDB("idb1");
|
||||
yield deleteDB("idb2");
|
||||
|
||||
yield caches.delete("plop");
|
||||
|
||||
dump("removed indexedDB and cache data from " + document.location + "\n");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
23
devtools/client/storage/test/storage-localstorage.html
Normal file
23
devtools/client/storage/test/storage-localstorage.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1231155 - Storage inspector front end - tests
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Storage inspector localStorage test</title>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
function setup() {
|
||||
localStorage.setItem("TestLS1", "ValueLS1");
|
||||
localStorage.setItem("TestLS2", "ValueLS2");
|
||||
localStorage.setItem("TestLS3", "ValueLS3");
|
||||
localStorage.setItem("TestLS4", "ValueLS4");
|
||||
localStorage.setItem("TestLS5", "ValueLS5");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setup()">
|
||||
</body>
|
||||
</html>
|
||||
19
devtools/client/storage/test/storage-overflow.html
Normal file
19
devtools/client/storage/test/storage-overflow.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1171903 - Storage Inspector endless scrolling
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector endless scrolling test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
for (let i = 0; i < 160; i++) {
|
||||
localStorage.setItem(`item-${i}`, `value-${i}`);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
23
devtools/client/storage/test/storage-search.html
Normal file
23
devtools/client/storage/test/storage-search.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1224115 - Storage Inspector table filtering
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector table filtering test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
localStorage.setItem("01234", "56789");
|
||||
localStorage.setItem("ANIMAL", "hOrSe");
|
||||
localStorage.setItem("FOO", "bArBaz");
|
||||
localStorage.setItem("food", "energy bar");
|
||||
localStorage.setItem("money", "##$$$**");
|
||||
localStorage.setItem("sport", "football");
|
||||
localStorage.setItem("year", "2016");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
91
devtools/client/storage/test/storage-secured-iframe.html
Normal file
91
devtools/client/storage/test/storage-secured-iframe.html
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Iframe for testing multiple host detetion in storage actor
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
document.cookie = "sc1=foobar;";
|
||||
localStorage.setItem("iframe-s-ls1", "foobar");
|
||||
sessionStorage.setItem("iframe-s-ss1", "foobar-2");
|
||||
dump("added cookies and storage from secured iframe\n");
|
||||
|
||||
let idbGenerator = function*() {
|
||||
let request = indexedDB.open("idb-s1", 1);
|
||||
request.onerror = function() {
|
||||
throw new Error("error opening db connection");
|
||||
};
|
||||
let db = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db = event.target.result;
|
||||
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
|
||||
store1.transaction.oncomplete = () => {
|
||||
done(db);
|
||||
};
|
||||
};
|
||||
});
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
let transaction = db.transaction(["obj-s1"], "readwrite");
|
||||
let store1 = transaction.objectStore("obj-s1");
|
||||
store1.add({id: 6, name: "foo", email: "foo@bar.com"});
|
||||
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"});
|
||||
yield new Promise(success => {
|
||||
transaction.oncomplete = success;
|
||||
});
|
||||
|
||||
db.close();
|
||||
|
||||
request = indexedDB.open("idb-s2", 1);
|
||||
let db2 = yield new Promise(done => {
|
||||
request.onupgradeneeded = event => {
|
||||
let db2 = event.target.result;
|
||||
let store3 =
|
||||
db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
|
||||
store3.createIndex("name2", "name2", { unique: true });
|
||||
store3.transaction.oncomplete = () => {
|
||||
done(db2);
|
||||
};
|
||||
};
|
||||
});
|
||||
yield new Promise(done => {
|
||||
request.onsuccess = done;
|
||||
});
|
||||
|
||||
transaction = db2.transaction(["obj-s2"], "readwrite");
|
||||
let store3 = transaction.objectStore("obj-s2");
|
||||
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"});
|
||||
yield new Promise(success => {
|
||||
transaction.oncomplete = success;
|
||||
});
|
||||
|
||||
db2.close();
|
||||
dump("added indexedDB from secured iframe\n");
|
||||
};
|
||||
|
||||
function deleteDB(dbName) {
|
||||
return new Promise(resolve => {
|
||||
dump("removing database " + dbName + " from " + document.location + "\n");
|
||||
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
|
||||
});
|
||||
}
|
||||
|
||||
window.setup = function*() {
|
||||
yield idbGenerator();
|
||||
};
|
||||
|
||||
window.clear = function*() {
|
||||
yield deleteDB("idb-s1");
|
||||
yield deleteDB("idb-s2");
|
||||
|
||||
dump("removed indexedDB data from " + document.location + "\n");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
23
devtools/client/storage/test/storage-sessionstorage.html
Normal file
23
devtools/client/storage/test/storage-sessionstorage.html
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1231179 - Storage inspector front end - tests
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Storage inspector sessionStorage test</title>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
function setup() {
|
||||
sessionStorage.setItem("TestSS1", "ValueSS1");
|
||||
sessionStorage.setItem("TestSS2", "ValueSS2");
|
||||
sessionStorage.setItem("TestSS3", "ValueSS3");
|
||||
sessionStorage.setItem("TestSS4", "ValueSS4");
|
||||
sessionStorage.setItem("TestSS5", "ValueSS5");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="setup()">
|
||||
</body>
|
||||
</html>
|
||||
19
devtools/client/storage/test/storage-unsecured-iframe.html
Normal file
19
devtools/client/storage/test/storage-unsecured-iframe.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Iframe for testing multiple host detetion in storage actor
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
document.cookie = "uc1=foobar; domain=.example.org; path=/";
|
||||
localStorage.setItem("iframe-u-ls1", "foobar");
|
||||
sessionStorage.setItem("iframe-u-ss1", "foobar1");
|
||||
sessionStorage.setItem("iframe-u-ss2", "foobar2");
|
||||
dump("added cookies and storage from unsecured iframe\n");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
64
devtools/client/storage/test/storage-updates.html
Normal file
64
devtools/client/storage/test/storage-updates.html
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 965872 - Storage inspector actor with cookies, local storage and session storage.
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector blank html for tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
window.addCookie = function(name, value, path, domain, expires, secure) {
|
||||
let cookieString = name + "=" + value + ";";
|
||||
if (path) {
|
||||
cookieString += "path=" + path + ";";
|
||||
}
|
||||
if (domain) {
|
||||
cookieString += "domain=" + domain + ";";
|
||||
}
|
||||
if (expires) {
|
||||
cookieString += "expires=" + expires + ";";
|
||||
}
|
||||
if (secure) {
|
||||
cookieString += "secure=true;";
|
||||
}
|
||||
document.cookie = cookieString;
|
||||
};
|
||||
|
||||
window.removeCookie = function(name, path) {
|
||||
document.cookie =
|
||||
name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=" + path;
|
||||
};
|
||||
|
||||
/**
|
||||
* We keep this method here even though these items are automatically cleared
|
||||
* after the test is complete. this is so that the store-objects-cleared event
|
||||
* can be tested.
|
||||
*/
|
||||
window.clear = function*() {
|
||||
sessionStorage.clear();
|
||||
|
||||
dump("removed sessionStorage from " + document.location + "\n");
|
||||
};
|
||||
|
||||
window.onload = function() {
|
||||
addCookie("c1", "1.2.3.4.5.6.7", "/browser");
|
||||
addCookie("c2", "foobar", "/browser");
|
||||
|
||||
localStorage.setItem("ls1", "testing");
|
||||
localStorage.setItem("ls2", "testing");
|
||||
localStorage.setItem("ls3", "testing");
|
||||
localStorage.setItem("ls4", "testing");
|
||||
localStorage.setItem("ls5", "testing");
|
||||
localStorage.setItem("ls6", "testing");
|
||||
localStorage.setItem("ls7", "testing");
|
||||
|
||||
sessionStorage.setItem("ss1", "foobar");
|
||||
sessionStorage.setItem("ss2", "foobar");
|
||||
sessionStorage.setItem("ss3", "foobar");
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1073
devtools/client/storage/ui.js
Normal file
1073
devtools/client/storage/ui.js
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue