summaryrefslogtreecommitdiffstats
path: root/devtools/client/webide/test
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/webide/test')
-rw-r--r--devtools/client/webide/test/.eslintrc.js6
-rw-r--r--devtools/client/webide/test/addons/adbhelper-linux.xpibin0 -> 1293 bytes
-rw-r--r--devtools/client/webide/test/addons/adbhelper-linux64.xpibin0 -> 1293 bytes
-rw-r--r--devtools/client/webide/test/addons/adbhelper-mac64.xpibin0 -> 1293 bytes
-rw-r--r--devtools/client/webide/test/addons/adbhelper-win32.xpibin0 -> 1293 bytes
-rw-r--r--devtools/client/webide/test/addons/fxdt-adapters-linux32.xpibin0 -> 1156 bytes
-rw-r--r--devtools/client/webide/test/addons/fxdt-adapters-linux64.xpibin0 -> 1156 bytes
-rw-r--r--devtools/client/webide/test/addons/fxdt-adapters-mac64.xpibin0 -> 1156 bytes
-rw-r--r--devtools/client/webide/test/addons/fxdt-adapters-win32.xpibin0 -> 1156 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpibin0 -> 5046 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpibin0 -> 5046 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpibin0 -> 5044 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpibin0 -> 5046 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpibin0 -> 5046 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpibin0 -> 5046 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpibin0 -> 5043 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpibin0 -> 5045 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpibin0 -> 5045 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpibin0 -> 5048 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpibin0 -> 5048 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpibin0 -> 5044 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpibin0 -> 5052 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpibin0 -> 5055 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpibin0 -> 5051 bytes
-rw-r--r--devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpibin0 -> 5051 bytes
-rw-r--r--devtools/client/webide/test/addons/simulators.json4
-rw-r--r--devtools/client/webide/test/app.zipbin0 -> 480 bytes
-rw-r--r--devtools/client/webide/test/app/index.html6
-rw-r--r--devtools/client/webide/test/app/manifest.webapp5
-rw-r--r--devtools/client/webide/test/browser.ini12
-rw-r--r--devtools/client/webide/test/browser_tabs.js84
-rw-r--r--devtools/client/webide/test/browser_widget.js15
-rw-r--r--devtools/client/webide/test/build_app1/package.json5
-rw-r--r--devtools/client/webide/test/build_app2/manifest.webapp1
-rw-r--r--devtools/client/webide/test/build_app2/package.json10
-rw-r--r--devtools/client/webide/test/build_app2/stage/empty-directory0
-rw-r--r--devtools/client/webide/test/build_app_windows1/package.json5
-rw-r--r--devtools/client/webide/test/build_app_windows2/manifest.webapp1
-rw-r--r--devtools/client/webide/test/build_app_windows2/package.json10
-rw-r--r--devtools/client/webide/test/build_app_windows2/stage/empty-directory0
-rw-r--r--devtools/client/webide/test/chrome.ini71
-rw-r--r--devtools/client/webide/test/device_front_shared.js219
-rw-r--r--devtools/client/webide/test/doc_tabs.html15
-rw-r--r--devtools/client/webide/test/head.js248
-rw-r--r--devtools/client/webide/test/hosted_app.manifest3
-rw-r--r--devtools/client/webide/test/templates.json14
-rw-r--r--devtools/client/webide/test/test_addons.html176
-rw-r--r--devtools/client/webide/test/test_app_validator.html205
-rw-r--r--devtools/client/webide/test/test_autoconnect_runtime.html94
-rw-r--r--devtools/client/webide/test/test_autoselect_project.html110
-rw-r--r--devtools/client/webide/test/test_basic.html55
-rw-r--r--devtools/client/webide/test/test_build.html128
-rw-r--r--devtools/client/webide/test/test_device_permissions.html81
-rw-r--r--devtools/client/webide/test/test_device_preferences.html87
-rw-r--r--devtools/client/webide/test/test_device_runtime.html81
-rw-r--r--devtools/client/webide/test/test_device_settings.html87
-rw-r--r--devtools/client/webide/test/test_duplicate_import.html77
-rw-r--r--devtools/client/webide/test/test_fullscreenToolbox.html67
-rw-r--r--devtools/client/webide/test/test_import.html82
-rw-r--r--devtools/client/webide/test/test_manifestUpdate.html98
-rw-r--r--devtools/client/webide/test/test_newapp.html46
-rw-r--r--devtools/client/webide/test/test_runtime.html203
-rw-r--r--devtools/client/webide/test/test_simulators.html426
-rw-r--r--devtools/client/webide/test/test_telemetry.html325
-rw-r--r--devtools/client/webide/test/test_toolbox.html93
-rw-r--r--devtools/client/webide/test/test_zoom.html77
-rw-r--r--devtools/client/webide/test/validator/no-name-or-icon/home.html0
-rw-r--r--devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp3
-rw-r--r--devtools/client/webide/test/validator/non-absolute-path/manifest.webapp7
-rw-r--r--devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp7
-rw-r--r--devtools/client/webide/test/validator/valid/home.html0
-rw-r--r--devtools/client/webide/test/validator/valid/icon.png0
-rw-r--r--devtools/client/webide/test/validator/valid/manifest.webapp7
-rw-r--r--devtools/client/webide/test/validator/wrong-launch-path/icon.png0
-rw-r--r--devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp7
75 files changed, 3363 insertions, 0 deletions
diff --git a/devtools/client/webide/test/.eslintrc.js b/devtools/client/webide/test/.eslintrc.js
new file mode 100644
index 000000000..8d15a76d9
--- /dev/null
+++ b/devtools/client/webide/test/.eslintrc.js
@@ -0,0 +1,6 @@
+"use strict";
+
+module.exports = {
+ // Extend from the shared list of defined globals for mochitests.
+ "extends": "../../../.eslintrc.mochitests.js"
+};
diff --git a/devtools/client/webide/test/addons/adbhelper-linux.xpi b/devtools/client/webide/test/addons/adbhelper-linux.xpi
new file mode 100644
index 000000000..b56cc03e3
--- /dev/null
+++ b/devtools/client/webide/test/addons/adbhelper-linux.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/adbhelper-linux64.xpi b/devtools/client/webide/test/addons/adbhelper-linux64.xpi
new file mode 100644
index 000000000..b56cc03e3
--- /dev/null
+++ b/devtools/client/webide/test/addons/adbhelper-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/adbhelper-mac64.xpi b/devtools/client/webide/test/addons/adbhelper-mac64.xpi
new file mode 100644
index 000000000..b56cc03e3
--- /dev/null
+++ b/devtools/client/webide/test/addons/adbhelper-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/adbhelper-win32.xpi b/devtools/client/webide/test/addons/adbhelper-win32.xpi
new file mode 100644
index 000000000..b56cc03e3
--- /dev/null
+++ b/devtools/client/webide/test/addons/adbhelper-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi b/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi
new file mode 100644
index 000000000..5a512ae3d
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxdt-adapters-linux32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi b/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi
new file mode 100644
index 000000000..5a512ae3d
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxdt-adapters-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi b/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi
new file mode 100644
index 000000000..5a512ae3d
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxdt-adapters-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi b/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi
new file mode 100644
index 000000000..5a512ae3d
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxdt-adapters-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi
new file mode 100644
index 000000000..238c97562
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi
new file mode 100644
index 000000000..2f86c4d4d
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_1_0_simulator-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi
new file mode 100644
index 000000000..6da2fcbad
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_1_0_simulator-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi
new file mode 100644
index 000000000..546deacaf
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_1_0_simulator-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi
new file mode 100644
index 000000000..e2335e3a0
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi
new file mode 100644
index 000000000..75fe209ea
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_2_0_simulator-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi
new file mode 100644
index 000000000..58749f724
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_2_0_simulator-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi
new file mode 100644
index 000000000..60cffd46e
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_2_0_simulator-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi
new file mode 100644
index 000000000..c54cae3aa
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi
new file mode 100644
index 000000000..9a650a888
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_simulator-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi
new file mode 100644
index 000000000..d13dd78de
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_simulator-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi
new file mode 100644
index 000000000..92d5cc394
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_simulator-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi
new file mode 100644
index 000000000..7a2a432ff
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi
new file mode 100644
index 000000000..d38932195
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-linux64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi
new file mode 100644
index 000000000..48e271d54
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-mac64.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi
new file mode 100644
index 000000000..4c8bb2f10
--- /dev/null
+++ b/devtools/client/webide/test/addons/fxos_3_0_tv_simulator-win32.xpi
Binary files differ
diff --git a/devtools/client/webide/test/addons/simulators.json b/devtools/client/webide/test/addons/simulators.json
new file mode 100644
index 000000000..31d71b4da
--- /dev/null
+++ b/devtools/client/webide/test/addons/simulators.json
@@ -0,0 +1,4 @@
+{
+ "stable": ["1.0", "2.0"],
+ "unstable": ["3.0", "3.0_tv"]
+}
diff --git a/devtools/client/webide/test/app.zip b/devtools/client/webide/test/app.zip
new file mode 100644
index 000000000..8a706a3c9
--- /dev/null
+++ b/devtools/client/webide/test/app.zip
Binary files differ
diff --git a/devtools/client/webide/test/app/index.html b/devtools/client/webide/test/app/index.html
new file mode 100644
index 000000000..3ef4a25e2
--- /dev/null
+++ b/devtools/client/webide/test/app/index.html
@@ -0,0 +1,6 @@
+<!doctype html>
+<html>
+<head><title></title></head>
+<body>
+</body>
+</html>
diff --git a/devtools/client/webide/test/app/manifest.webapp b/devtools/client/webide/test/app/manifest.webapp
new file mode 100644
index 000000000..4a198b1ca
--- /dev/null
+++ b/devtools/client/webide/test/app/manifest.webapp
@@ -0,0 +1,5 @@
+{
+ "name": "A name (in app directory)",
+ "description": "desc",
+ "launch_path": "/index.html"
+}
diff --git a/devtools/client/webide/test/browser.ini b/devtools/client/webide/test/browser.ini
new file mode 100644
index 000000000..7d6e2de72
--- /dev/null
+++ b/devtools/client/webide/test/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+tags = devtools
+subsuite = devtools
+support-files =
+ addons/simulators.json
+ doc_tabs.html
+ head.js
+ templates.json
+
+[browser_tabs.js]
+skip-if = e10s # Bug 1072167 - browser_tabs.js test fails under e10s
+[browser_widget.js]
diff --git a/devtools/client/webide/test/browser_tabs.js b/devtools/client/webide/test/browser_tabs.js
new file mode 100644
index 000000000..541c6b363
--- /dev/null
+++ b/devtools/client/webide/test/browser_tabs.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const TEST_URI = "http://example.com/browser/devtools/client/webide/test/doc_tabs.html";
+
+function test() {
+ waitForExplicitFinish();
+ requestCompleteLog();
+
+ Task.spawn(function* () {
+ // Since we test the connections set below, destroy the server in case it
+ // was left open.
+ DebuggerServer.destroy();
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+
+ let tab = yield addTab(TEST_URI);
+
+ let win = yield openWebIDE();
+ let docProject = getProjectDocument(win);
+ let docRuntime = getRuntimeDocument(win);
+
+ yield connectToLocal(win, docRuntime);
+
+ is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
+
+ yield selectTabProject(win, docProject);
+
+ ok(win.UI.toolboxPromise, "Toolbox promise exists");
+ yield win.UI.toolboxPromise;
+
+ let project = win.AppManager.selectedProject;
+ is(project.location, TEST_URI, "Location is correct");
+ is(project.name, "example.com: Test Tab", "Name is correct");
+
+ // Ensure tab list changes are noticed
+ let tabsNode = docProject.querySelector("#project-panel-tabs");
+ is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
+ yield removeTab(tab);
+ yield waitForUpdate(win, "project");
+ yield waitForUpdate(win, "runtime-targets");
+ is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");
+
+ tab = yield addTab(TEST_URI);
+
+ is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
+
+ yield removeTab(tab);
+
+ is(tabsNode.querySelectorAll(".panel-item").length, 2, "2 tabs available");
+
+ docProject.querySelector("#refresh-tabs").click();
+
+ yield waitForUpdate(win, "runtime-targets");
+
+ is(tabsNode.querySelectorAll(".panel-item").length, 1, "1 tab available");
+
+ yield win.Cmds.disconnectRuntime();
+ yield closeWebIDE(win);
+
+ DebuggerServer.destroy();
+ }).then(finish, handleError);
+}
+
+function connectToLocal(win, docRuntime) {
+ let deferred = promise.defer();
+ win.AppManager.connection.once(
+ win.Connection.Events.CONNECTED,
+ () => deferred.resolve());
+ docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+ return deferred.promise;
+}
+
+function selectTabProject(win, docProject) {
+ return Task.spawn(function* () {
+ yield waitForUpdate(win, "runtime-targets");
+ let tabsNode = docProject.querySelector("#project-panel-tabs");
+ let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
+ let project = waitForUpdate(win, "project");
+ tabNode.click();
+ yield project;
+ });
+}
diff --git a/devtools/client/webide/test/browser_widget.js b/devtools/client/webide/test/browser_widget.js
new file mode 100644
index 000000000..7cfb2782b
--- /dev/null
+++ b/devtools/client/webide/test/browser_widget.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+function test() {
+ waitForExplicitFinish();
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ ok(document.querySelector("#webide-button"), "Found WebIDE button");
+ Services.prefs.setBoolPref("devtools.webide.widget.enabled", false);
+ ok(!document.querySelector("#webide-button"), "WebIDE button uninstalled");
+ yield closeWebIDE(win);
+ Services.prefs.clearUserPref("devtools.webide.widget.enabled");
+ }).then(finish, handleError);
+}
diff --git a/devtools/client/webide/test/build_app1/package.json b/devtools/client/webide/test/build_app1/package.json
new file mode 100644
index 000000000..c6ae833e1
--- /dev/null
+++ b/devtools/client/webide/test/build_app1/package.json
@@ -0,0 +1,5 @@
+{
+ "webide": {
+ "prepackage": "echo \"{\\\"name\\\":\\\"hello\\\"}\" > manifest.webapp"
+ }
+}
diff --git a/devtools/client/webide/test/build_app2/manifest.webapp b/devtools/client/webide/test/build_app2/manifest.webapp
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/devtools/client/webide/test/build_app2/manifest.webapp
@@ -0,0 +1 @@
+{}
diff --git a/devtools/client/webide/test/build_app2/package.json b/devtools/client/webide/test/build_app2/package.json
new file mode 100644
index 000000000..5b7101620
--- /dev/null
+++ b/devtools/client/webide/test/build_app2/package.json
@@ -0,0 +1,10 @@
+{
+ "webide": {
+ "prepackage": {
+ "command": "echo \"{\\\"name\\\":\\\"$NAME\\\"}\" > manifest.webapp",
+ "cwd": "./stage",
+ "env": ["NAME=world"]
+ },
+ "packageDir": "./stage"
+ }
+}
diff --git a/devtools/client/webide/test/build_app2/stage/empty-directory b/devtools/client/webide/test/build_app2/stage/empty-directory
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/build_app2/stage/empty-directory
diff --git a/devtools/client/webide/test/build_app_windows1/package.json b/devtools/client/webide/test/build_app_windows1/package.json
new file mode 100644
index 000000000..036d2d767
--- /dev/null
+++ b/devtools/client/webide/test/build_app_windows1/package.json
@@ -0,0 +1,5 @@
+{
+ "webide": {
+ "prepackage": "echo {\"name\":\"hello\"} > manifest.webapp"
+ }
+}
diff --git a/devtools/client/webide/test/build_app_windows2/manifest.webapp b/devtools/client/webide/test/build_app_windows2/manifest.webapp
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/devtools/client/webide/test/build_app_windows2/manifest.webapp
@@ -0,0 +1 @@
+{}
diff --git a/devtools/client/webide/test/build_app_windows2/package.json b/devtools/client/webide/test/build_app_windows2/package.json
new file mode 100644
index 000000000..83caf82ab
--- /dev/null
+++ b/devtools/client/webide/test/build_app_windows2/package.json
@@ -0,0 +1,10 @@
+{
+ "webide": {
+ "prepackage": {
+ "command": "echo {\"name\":\"%NAME%\"} > manifest.webapp",
+ "cwd": "./stage",
+ "env": ["NAME=world"]
+ },
+ "packageDir": "./stage"
+ }
+}
diff --git a/devtools/client/webide/test/build_app_windows2/stage/empty-directory b/devtools/client/webide/test/build_app_windows2/stage/empty-directory
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/build_app_windows2/stage/empty-directory
diff --git a/devtools/client/webide/test/chrome.ini b/devtools/client/webide/test/chrome.ini
new file mode 100644
index 000000000..b492ccd9b
--- /dev/null
+++ b/devtools/client/webide/test/chrome.ini
@@ -0,0 +1,71 @@
+[DEFAULT]
+tags = devtools
+support-files =
+ app/index.html
+ app/manifest.webapp
+ app.zip
+ addons/simulators.json
+ addons/fxos_1_0_simulator-linux.xpi
+ addons/fxos_1_0_simulator-linux64.xpi
+ addons/fxos_1_0_simulator-win32.xpi
+ addons/fxos_1_0_simulator-mac64.xpi
+ addons/fxos_2_0_simulator-linux.xpi
+ addons/fxos_2_0_simulator-linux64.xpi
+ addons/fxos_2_0_simulator-win32.xpi
+ addons/fxos_2_0_simulator-mac64.xpi
+ addons/fxos_3_0_simulator-linux.xpi
+ addons/fxos_3_0_simulator-linux64.xpi
+ addons/fxos_3_0_simulator-win32.xpi
+ addons/fxos_3_0_simulator-mac64.xpi
+ addons/fxos_3_0_tv_simulator-linux.xpi
+ addons/fxos_3_0_tv_simulator-linux64.xpi
+ addons/fxos_3_0_tv_simulator-win32.xpi
+ addons/fxos_3_0_tv_simulator-mac64.xpi
+ addons/adbhelper-linux.xpi
+ addons/adbhelper-linux64.xpi
+ addons/adbhelper-win32.xpi
+ addons/adbhelper-mac64.xpi
+ addons/fxdt-adapters-linux32.xpi
+ addons/fxdt-adapters-linux64.xpi
+ addons/fxdt-adapters-win32.xpi
+ addons/fxdt-adapters-mac64.xpi
+ build_app1/package.json
+ build_app2/manifest.webapp
+ build_app2/package.json
+ build_app2/stage/empty-directory
+ build_app_windows1/package.json
+ build_app_windows2/manifest.webapp
+ build_app_windows2/package.json
+ build_app_windows2/stage/empty-directory
+ device_front_shared.js
+ head.js
+ hosted_app.manifest
+ templates.json
+ ../../shared/test/browser_devices.json
+ validator/*
+
+[test_basic.html]
+[test_newapp.html]
+skip-if = (os == "win" && os_version == "10.0") # Bug 1197053
+[test_import.html]
+skip-if = (os == "linux") # Bug 1024734
+[test_duplicate_import.html]
+[test_runtime.html]
+[test_manifestUpdate.html]
+[test_addons.html]
+skip-if = true # Bug 1201392 - Update add-ons after migration
+[test_device_runtime.html]
+[test_device_permissions.html]
+[test_autoconnect_runtime.html]
+[test_autoselect_project.html]
+[test_telemetry.html]
+skip-if = true # Bug 1201392 - Update add-ons after migration
+[test_device_preferences.html]
+[test_device_settings.html]
+[test_fullscreenToolbox.html]
+[test_zoom.html]
+[test_build.html]
+[test_simulators.html]
+skip-if = true # Bug 1281138 - intermittent failures
+[test_toolbox.html]
+[test_app_validator.html]
diff --git a/devtools/client/webide/test/device_front_shared.js b/devtools/client/webide/test/device_front_shared.js
new file mode 100644
index 000000000..0ddb5df21
--- /dev/null
+++ b/devtools/client/webide/test/device_front_shared.js
@@ -0,0 +1,219 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var customName;
+var customValue;
+var customValueType;
+var customBtn;
+var newField;
+var change;
+var doc;
+var iframe;
+var resetBtn;
+var found = false;
+
+function setDocument(frame) {
+ iframe = frame;
+ doc = iframe.contentWindow.document;
+}
+
+function fieldChange(fields, id) {
+ // Trigger existing field change
+ for (let field of fields) {
+ if (field.id == id) {
+ let button = doc.getElementById("btn-" + id);
+ found = true;
+ ok(button.classList.contains("hide"), "Default field detected");
+ field.value = "custom";
+ field.click();
+ ok(!button.classList.contains("hide"), "Custom field detected");
+ break;
+ }
+ }
+ ok(found, "Found " + id + " line");
+}
+
+function addNewField() {
+ found = false;
+ customName = doc.querySelector("#custom-value-name");
+ customValue = doc.querySelector("#custom-value-text");
+ customValueType = doc.querySelector("#custom-value-type");
+ customBtn = doc.querySelector("#custom-value");
+ change = doc.createEvent("HTMLEvents");
+ change.initEvent("change", false, true);
+
+ // Add a new custom string
+ customValueType.value = "string";
+ customValueType.dispatchEvent(change);
+ customName.value = "new-string-field!";
+ customValue.value = "test";
+ customBtn.click();
+ let newField = doc.querySelector("#new-string-field");
+ if (newField) {
+ found = true;
+ is(newField.type, "text", "Custom type is a string");
+ is(newField.value, "test", "Custom string new value is correct");
+ }
+ ok(found, "Found new string field line");
+ is(customName.value, "", "Custom string name reset");
+ is(customValue.value, "", "Custom string value reset");
+}
+
+function addNewFieldWithEnter() {
+ // Add a new custom value with the <enter> key
+ found = false;
+ customName.value = "new-string-field-two";
+ customValue.value = "test";
+ let newAddField = doc.querySelector("#add-custom-field");
+ let enter = doc.createEvent("KeyboardEvent");
+ enter.initKeyEvent(
+ "keyup", true, true, null, false, false, false, false, 13, 0);
+ newAddField.dispatchEvent(enter);
+ newField = doc.querySelector("#new-string-field-two");
+ if (newField) {
+ found = true;
+ is(newField.type, "text", "Custom type is a string");
+ is(newField.value, "test", "Custom string new value is correct");
+ }
+ ok(found, "Found new string field line");
+ is(customName.value, "", "Custom string name reset");
+ is(customValue.value, "", "Custom string value reset");
+}
+
+function editExistingField() {
+ // Edit existing custom string preference
+ newField.value = "test2";
+ newField.click();
+ is(newField.value, "test2", "Custom string existing value is correct");
+}
+
+function addNewFieldInteger() {
+ // Add a new custom integer preference with a valid integer
+ customValueType.value = "number";
+ customValueType.dispatchEvent(change);
+ customName.value = "new-integer-field";
+ customValue.value = 1;
+ found = false;
+
+ customBtn.click();
+ newField = doc.querySelector("#new-integer-field");
+ if (newField) {
+ found = true;
+ is(newField.type, "number", "Custom type is a number");
+ is(newField.value, "1", "Custom integer value is correct");
+ }
+ ok(found, "Found new integer field line");
+ is(customName.value, "", "Custom integer name reset");
+ is(customValue.value, "", "Custom integer value reset");
+}
+
+var editFieldInteger = Task.async(function* () {
+ // Edit existing custom integer preference
+ newField.value = 3;
+ newField.click();
+ is(newField.value, "3", "Custom integer existing value is correct");
+
+ // Reset a custom field
+ let resetBtn = doc.querySelector("#btn-new-integer-field");
+ resetBtn.click();
+
+ try {
+ yield iframe.contentWindow.configView._defaultField;
+ } catch (err) {
+ let fieldRow = doc.querySelector("#row-new-integer-field");
+ if (!fieldRow) {
+ found = false;
+ }
+ ok(!found, "Custom field removed");
+ }
+});
+
+var resetExistingField = Task.async(function* (id) {
+ let existing = doc.getElementById(id);
+ existing.click();
+ is(existing.checked, true, "Existing boolean value is correct");
+ resetBtn = doc.getElementById("btn-" + id);
+ resetBtn.click();
+
+ yield iframe.contentWindow.configView._defaultField;
+
+ ok(resetBtn.classList.contains("hide"), true, "Reset button hidden");
+ is(existing.checked, true, "Existing field reset");
+});
+
+var resetNewField = Task.async(function* (id) {
+ let custom = doc.getElementById(id);
+ custom.click();
+ is(custom.value, "test", "New string value is correct");
+ resetBtn = doc.getElementById("btn-" + id);
+ resetBtn.click();
+
+ yield iframe.contentWindow.configView._defaultField;
+
+ ok(resetBtn.classList.contains("hide"), true, "Reset button hidden");
+});
+
+function addNewFieldBoolean() {
+ customValueType.value = "boolean";
+ customValueType.dispatchEvent(change);
+ customName.value = "new-boolean-field";
+ customValue.checked = true;
+ found = false;
+ customBtn.click();
+ newField = doc.querySelector("#new-boolean-field");
+ if (newField) {
+ found = true;
+ is(newField.type, "checkbox", "Custom type is a checkbox");
+ is(newField.checked, true, "Custom boolean value is correctly true");
+ }
+ ok(found, "Found new boolean field line");
+
+ // Mouse event trigger
+ var mouseClick = new MouseEvent("click", {
+ canBubble: true,
+ cancelable: true,
+ view: doc.parent,
+ });
+
+ found = false;
+ customValueType.value = "boolean";
+ customValueType.dispatchEvent(change);
+ customName.value = "new-boolean-field2";
+ customValue.dispatchEvent(mouseClick);
+ customBtn.dispatchEvent(mouseClick);
+ newField = doc.querySelector("#new-boolean-field2");
+ if (newField) {
+ found = true;
+ is(newField.checked, true, "Custom boolean value is correctly false");
+ }
+ ok(found, "Found new second boolean field line");
+
+ is(customName.value, "", "Custom boolean name reset");
+ is(customValue.checked, false, "Custom boolean value reset");
+
+ newField.click();
+ is(newField.checked, false, "Custom boolean existing value is correct");
+}
+
+function searchFields(deck, keyword) {
+ // Search for a non-existent field
+ let searchField = doc.querySelector("#search-bar");
+ searchField.value = "![o_O]!";
+ searchField.click();
+
+ let fieldsTotal = doc.querySelectorAll("tr.edit-row").length;
+ let hiddenFields = doc.querySelectorAll("tr.hide");
+ is(hiddenFields.length, fieldsTotal, "Search keyword not found");
+
+ // Search for existing fields
+ searchField.value = keyword;
+ searchField.click();
+ hiddenFields = doc.querySelectorAll("tr.hide");
+ isnot(hiddenFields.length, fieldsTotal, "Search keyword found");
+
+ doc.querySelector("#close").click();
+
+ ok(!deck.selectedPanel, "No panel selected");
+}
diff --git a/devtools/client/webide/test/doc_tabs.html b/devtools/client/webide/test/doc_tabs.html
new file mode 100644
index 000000000..4901289fc
--- /dev/null
+++ b/devtools/client/webide/test/doc_tabs.html
@@ -0,0 +1,15 @@
+<!-- Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!doctype html>
+
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Test Tab</title>
+ </head>
+
+ <body>
+ Test Tab
+ </body>
+
+</html>
diff --git a/devtools/client/webide/test/head.js b/devtools/client/webide/test/head.js
new file mode 100644
index 000000000..c0171c730
--- /dev/null
+++ b/devtools/client/webide/test/head.js
@@ -0,0 +1,248 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
+
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const { FileUtils } = require("resource://gre/modules/FileUtils.jsm");
+const { gDevTools } = require("devtools/client/framework/devtools");
+const promise = require("promise");
+const Services = require("Services");
+const { Task } = require("devtools/shared/task");
+const { AppProjects } = require("devtools/client/webide/modules/app-projects");
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+const { DebuggerServer } = require("devtools/server/main");
+const flags = require("devtools/shared/flags");
+flags.testing = true;
+
+var TEST_BASE;
+if (window.location === "chrome://browser/content/browser.xul") {
+ TEST_BASE = "chrome://mochitests/content/browser/devtools/client/webide/test/";
+} else {
+ TEST_BASE = "chrome://mochitests/content/chrome/devtools/client/webide/test/";
+}
+
+Services.prefs.setBoolPref("devtools.webide.enabled", true);
+Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
+
+Services.prefs.setCharPref("devtools.webide.addonsURL", TEST_BASE + "addons/simulators.json");
+Services.prefs.setCharPref("devtools.webide.simulatorAddonsURL", TEST_BASE + "addons/fxos_#SLASHED_VERSION#_simulator-#OS#.xpi");
+Services.prefs.setCharPref("devtools.webide.adbAddonURL", TEST_BASE + "addons/adbhelper-#OS#.xpi");
+Services.prefs.setCharPref("devtools.webide.adaptersAddonURL", TEST_BASE + "addons/fxdt-adapters-#OS#.xpi");
+Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "templates.json");
+Services.prefs.setCharPref("devtools.devices.url", TEST_BASE + "browser_devices.json");
+
+var registerCleanupFunction = registerCleanupFunction ||
+ SimpleTest.registerCleanupFunction;
+registerCleanupFunction(() => {
+ flags.testing = false;
+ Services.prefs.clearUserPref("devtools.webide.enabled");
+ Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
+ Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
+ Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
+ Services.prefs.clearUserPref("devtools.webide.busyTimeout");
+ Services.prefs.clearUserPref("devtools.webide.lastSelectedProject");
+ Services.prefs.clearUserPref("devtools.webide.lastConnectedRuntime");
+});
+
+var openWebIDE = Task.async(function* (autoInstallAddons) {
+ info("opening WebIDE");
+
+ Services.prefs.setBoolPref("devtools.webide.autoinstallADBHelper", !!autoInstallAddons);
+ Services.prefs.setBoolPref("devtools.webide.autoinstallFxdtAdapters", !!autoInstallAddons);
+
+ let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(Ci.nsIWindowWatcher);
+ let win = ww.openWindow(null, "chrome://webide/content/", "webide", "chrome,centerscreen,resizable", null);
+
+ yield new Promise(resolve => {
+ win.addEventListener("load", function onLoad() {
+ win.removeEventListener("load", onLoad);
+ SimpleTest.requestCompleteLog();
+ SimpleTest.executeSoon(resolve);
+ });
+ });
+
+ info("WebIDE open");
+
+ return win;
+});
+
+function closeWebIDE(win) {
+ info("Closing WebIDE");
+
+ let deferred = promise.defer();
+
+ Services.prefs.clearUserPref("devtools.webide.widget.enabled");
+
+ win.addEventListener("unload", function onUnload() {
+ win.removeEventListener("unload", onUnload);
+ info("WebIDE closed");
+ SimpleTest.executeSoon(() => {
+ deferred.resolve();
+ });
+ });
+
+ win.close();
+
+ return deferred.promise;
+}
+
+function removeAllProjects() {
+ return Task.spawn(function* () {
+ yield AppProjects.load();
+ // use a new array so we're not iterating over the same
+ // underlying array that's being modified by AppProjects
+ let projects = AppProjects.projects.map(p => p.location);
+ for (let i = 0; i < projects.length; i++) {
+ yield AppProjects.remove(projects[i]);
+ }
+ });
+}
+
+function nextTick() {
+ let deferred = promise.defer();
+ SimpleTest.executeSoon(() => {
+ deferred.resolve();
+ });
+
+ return deferred.promise;
+}
+
+function waitForUpdate(win, update) {
+ info("Wait: " + update);
+ let deferred = promise.defer();
+ win.AppManager.on("app-manager-update", function onUpdate(e, what) {
+ info("Got: " + what);
+ if (what !== update) {
+ return;
+ }
+ win.AppManager.off("app-manager-update", onUpdate);
+ deferred.resolve(win.UI._updatePromise);
+ });
+ return deferred.promise;
+}
+
+function waitForTime(time) {
+ let deferred = promise.defer();
+ setTimeout(() => {
+ deferred.resolve();
+ }, time);
+ return deferred.promise;
+}
+
+function documentIsLoaded(doc) {
+ let deferred = promise.defer();
+ if (doc.readyState == "complete") {
+ deferred.resolve();
+ } else {
+ doc.addEventListener("readystatechange", function onChange() {
+ if (doc.readyState == "complete") {
+ doc.removeEventListener("readystatechange", onChange);
+ deferred.resolve();
+ }
+ });
+ }
+ return deferred.promise;
+}
+
+function lazyIframeIsLoaded(iframe) {
+ let deferred = promise.defer();
+ iframe.addEventListener("load", function onLoad() {
+ iframe.removeEventListener("load", onLoad, true);
+ deferred.resolve(nextTick());
+ }, true);
+ return deferred.promise;
+}
+
+function addTab(aUrl, aWindow) {
+ info("Adding tab: " + aUrl);
+
+ let deferred = promise.defer();
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+
+ targetWindow.focus();
+ let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+ let linkedBrowser = tab.linkedBrowser;
+
+ BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
+ info("Tab added and finished loading: " + aUrl);
+ deferred.resolve(tab);
+ });
+
+ return deferred.promise;
+}
+
+function removeTab(aTab, aWindow) {
+ info("Removing tab.");
+
+ let deferred = promise.defer();
+ let targetWindow = aWindow || window;
+ let targetBrowser = targetWindow.gBrowser;
+ let tabContainer = targetBrowser.tabContainer;
+
+ tabContainer.addEventListener("TabClose", function onClose(aEvent) {
+ tabContainer.removeEventListener("TabClose", onClose, false);
+ info("Tab removed and finished closing.");
+ deferred.resolve();
+ }, false);
+
+ targetBrowser.removeTab(aTab);
+ return deferred.promise;
+}
+
+function getRuntimeDocument(win) {
+ return win.document.querySelector("#runtime-listing-panel-details").contentDocument;
+}
+
+function getProjectDocument(win) {
+ return win.document.querySelector("#project-listing-panel-details").contentDocument;
+}
+
+function getRuntimeWindow(win) {
+ return win.document.querySelector("#runtime-listing-panel-details").contentWindow;
+}
+
+function getProjectWindow(win) {
+ return win.document.querySelector("#project-listing-panel-details").contentWindow;
+}
+
+function connectToLocalRuntime(win) {
+ info("Loading local runtime.");
+
+ let panelNode;
+ let runtimePanel;
+
+ runtimePanel = getRuntimeDocument(win);
+
+ panelNode = runtimePanel.querySelector("#runtime-panel");
+ let items = panelNode.querySelectorAll(".runtime-panel-item-other");
+ is(items.length, 2, "Found 2 custom runtime buttons");
+
+ let updated = waitForUpdate(win, "runtime-global-actors");
+ items[1].click();
+ return updated;
+}
+
+function handleError(aError) {
+ ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
+ finish();
+}
+
+function waitForConnectionChange(expectedState, count = 1) {
+ return new Promise(resolve => {
+ let onConnectionChange = (_, state) => {
+ if (state != expectedState) {
+ return;
+ }
+ if (--count != 0) {
+ return;
+ }
+ DebuggerServer.off("connectionchange", onConnectionChange);
+ resolve();
+ };
+ DebuggerServer.on("connectionchange", onConnectionChange);
+ });
+}
diff --git a/devtools/client/webide/test/hosted_app.manifest b/devtools/client/webide/test/hosted_app.manifest
new file mode 100644
index 000000000..ab5069978
--- /dev/null
+++ b/devtools/client/webide/test/hosted_app.manifest
@@ -0,0 +1,3 @@
+{
+ "name": "hosted manifest name property"
+}
diff --git a/devtools/client/webide/test/templates.json b/devtools/client/webide/test/templates.json
new file mode 100644
index 000000000..e6ffa3efe
--- /dev/null
+++ b/devtools/client/webide/test/templates.json
@@ -0,0 +1,14 @@
+[
+ {
+ "file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?1",
+ "icon": "ximgx1",
+ "name": "app name 1",
+ "description": "app description 1"
+ },
+ {
+ "file": "chrome://mochitests/content/chrome/devtools/client/webide/test/app.zip?2",
+ "icon": "ximgx2",
+ "name": "app name 2",
+ "description": "app description 2"
+ }
+]
diff --git a/devtools/client/webide/test/test_addons.html b/devtools/client/webide/test/test_addons.html
new file mode 100644
index 000000000..5a1bc7504
--- /dev/null
+++ b/devtools/client/webide/test/test_addons.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ const {GetAvailableAddons} = require("devtools/client/webide/modules/addons");
+ const {Devices} = Cu.import("resource://devtools/shared/apps/Devices.jsm");
+ const {Simulators} = require("devtools/client/webide/modules/simulators");
+
+ let adbAddonsInstalled = promise.defer();
+ Devices.on("addon-status-updated", function onUpdate1() {
+ Devices.off("addon-status-updated", onUpdate1);
+ adbAddonsInstalled.resolve();
+ });
+
+ function getVersion(name) {
+ return name.match(/(\d+\.\d+)/)[0];
+ }
+
+ function onSimulatorInstalled(name) {
+ let deferred = promise.defer();
+ Simulators.on("updated", function onUpdate() {
+ Simulators.findSimulatorAddons().then(addons => {
+ for (let addon of addons) {
+ if (name == addon.name.replace(" Simulator", "")) {
+ Simulators.off("updated", onUpdate);
+ nextTick().then(deferred.resolve);
+ return;
+ }
+ }
+ });
+ });
+ return deferred.promise;
+ }
+
+ function installSimulatorFromUI(doc, name) {
+ let li = doc.querySelector('[addon="simulator-' + getVersion(name) + '"]');
+ li.querySelector(".install-button").click();
+ return onSimulatorInstalled(name);
+ }
+
+ function uninstallSimulatorFromUI(doc, name) {
+ let deferred = promise.defer();
+ Simulators.on("updated", function onUpdate() {
+ nextTick().then(() => {
+ let li = doc.querySelector('[status="uninstalled"][addon="simulator-' + getVersion(name) + '"]');
+ if (li) {
+ Simulators.off("updated", onUpdate);
+ deferred.resolve();
+ } else {
+ deferred.reject("Can't find item");
+ }
+ });
+ });
+ let li = doc.querySelector('[status="installed"][addon="simulator-' + getVersion(name) + '"]');
+ li.querySelector(".uninstall-button").click();
+ return deferred.promise;
+ }
+
+ function uninstallADBFromUI(doc) {
+ let deferred = promise.defer();
+ Devices.on("addon-status-updated", function onUpdate() {
+ nextTick().then(() => {
+ let li = doc.querySelector('[status="uninstalled"][addon="adb"]');
+ if (li) {
+ Devices.off("addon-status-updated", onUpdate);
+ deferred.resolve();
+ } else {
+ deferred.reject("Can't find item");
+ }
+ })
+ });
+ let li = doc.querySelector('[status="installed"][addon="adb"]');
+ li.querySelector(".uninstall-button").click();
+ return deferred.promise;
+ }
+
+ Task.spawn(function*() {
+
+ ok(!Devices.helperAddonInstalled, "Helper not installed");
+
+ let win = yield openWebIDE(true);
+ let docRuntime = getRuntimeDocument(win);
+
+ yield adbAddonsInstalled.promise;
+
+ ok(Devices.helperAddonInstalled, "Helper has been auto-installed");
+
+ yield nextTick();
+
+ let addons = yield GetAvailableAddons();
+
+ is(addons.simulators.length, 3, "3 simulator addons to install");
+
+ let sim10 = addons.simulators.filter(a => a.version == "1.0")[0];
+ sim10.install();
+
+ yield onSimulatorInstalled("Firefox OS 1.0");
+
+ win.Cmds.showAddons();
+
+ let frame = win.document.querySelector("#deck-panel-addons");
+ let addonDoc = frame.contentWindow.document;
+ let lis;
+
+ lis = addonDoc.querySelectorAll("li");
+ is(lis.length, 5, "5 addons listed");
+
+ lis = addonDoc.querySelectorAll('li[status="installed"]');
+ is(lis.length, 3, "3 addons installed");
+
+ lis = addonDoc.querySelectorAll('li[status="uninstalled"]');
+ is(lis.length, 2, "2 addons uninstalled");
+
+ info("Uninstalling Simulator 2.0");
+
+ yield installSimulatorFromUI(addonDoc, "Firefox OS 2.0");
+
+ info("Uninstalling Simulator 3.0");
+
+ yield installSimulatorFromUI(addonDoc, "Firefox OS 3.0");
+
+ yield nextTick();
+
+ let panelNode = docRuntime.querySelector("#runtime-panel");
+ let items;
+
+ items = panelNode.querySelectorAll(".runtime-panel-item-usb");
+ is(items.length, 1, "Found one runtime button");
+
+ items = panelNode.querySelectorAll(".runtime-panel-item-simulator");
+ is(items.length, 3, "Found 3 simulators button");
+
+ yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 1.0");
+ yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 2.0");
+ yield uninstallSimulatorFromUI(addonDoc, "Firefox OS 3.0");
+
+ items = panelNode.querySelectorAll(".runtime-panel-item-simulator");
+ is(items.length, 0, "No simulator listed");
+
+ let w = addonDoc.querySelector(".warning");
+ let display = addonDoc.defaultView.getComputedStyle(w).display
+ is(display, "none", "Warning about missing ADB hidden");
+
+ yield uninstallADBFromUI(addonDoc, "adb");
+
+ items = panelNode.querySelectorAll(".runtime-panel-item-usb");
+ is(items.length, 0, "No usb runtime listed");
+
+ display = addonDoc.defaultView.getComputedStyle(w).display
+ is(display, "block", "Warning about missing ADB present");
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_app_validator.html b/devtools/client/webide/test/test_app_validator.html
new file mode 100644
index 000000000..60ed29aac
--- /dev/null
+++ b/devtools/client/webide/test/test_app_validator.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ const Cu = Components.utils;
+ const Cc = Components.classes;
+ const Ci = Components.interfaces;
+ Cu.import("resource://testing-common/httpd.js");
+ const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
+
+ const {AppValidator} = require("devtools/client/webide/modules/app-validator");
+ const Services = require("Services");
+ const nsFile = Components.Constructor("@mozilla.org/file/local;1",
+ "nsILocalFile", "initWithPath");
+ const cr = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIChromeRegistry);
+ const strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties");
+ let httpserver, origin;
+
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ httpserver = new HttpServer();
+ httpserver.start(-1);
+ origin = "http://localhost:" + httpserver.identity.primaryPort + "/";
+
+ next();
+ }
+
+ function createHosted(path, manifestFile="/manifest.webapp") {
+ let dirPath = getTestFilePath("validator/" + path);
+ httpserver.registerDirectory("/", nsFile(dirPath));
+ return new AppValidator({
+ type: "hosted",
+ location: origin + manifestFile
+ });
+ }
+
+ function createPackaged(path) {
+ let dirPath = getTestFilePath("validator/" + path);
+ return new AppValidator({
+ type: "packaged",
+ location: dirPath
+ });
+ }
+
+ function next() {
+ let test = tests.shift();
+ if (test) {
+ try {
+ test();
+ } catch(e) {
+ console.error("exception", String(e), e, e.stack);
+ }
+ } else {
+ httpserver.stop(function() {
+ SimpleTest.finish();
+ });
+ }
+ }
+
+ let tests = [
+ // Test a 100% valid example
+ function () {
+ let validator = createHosted("valid");
+ validator.validate().then(() => {
+ is(validator.errors.length, 0, "valid app got no error");
+ is(validator.warnings.length, 0, "valid app got no warning");
+
+ next();
+ });
+ },
+
+ function () {
+ let validator = createPackaged("valid");
+ validator.validate().then(() => {
+ is(validator.errors.length, 0, "valid packaged app got no error");
+ is(validator.warnings.length, 0, "valid packaged app got no warning");
+
+ next();
+ });
+ },
+
+ // Test a launch path that returns a 404
+ function () {
+ let validator = createHosted("wrong-launch-path");
+ validator.validate().then(() => {
+ is(validator.errors.length, 1, "app with non-existant launch path got an error");
+ is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [origin + "wrong-path.html", 404], 2),
+ "with the right error message");
+ is(validator.warnings.length, 0, "but no warning");
+ next();
+ });
+ },
+ function () {
+ let validator = createPackaged("wrong-launch-path");
+ validator.validate().then(() => {
+ is(validator.errors.length, 1, "app with wrong path got an error");
+ let file = nsFile(validator.location);
+ file.append("wrong-path.html");
+ let url = Services.io.newFileURI(file);
+ is(validator.errors[0], strings.formatStringFromName("validator.accessFailedLaunchPath", [url.spec], 1),
+ "with the expected message");
+ is(validator.warnings.length, 0, "but no warning");
+
+ next();
+ });
+ },
+
+ // Test when using a non-absolute path for launch_path
+ function () {
+ let validator = createHosted("non-absolute-path");
+ validator.validate().then(() => {
+ is(validator.errors.length, 1, "app with non absolute path got an error");
+ is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"], 1),
+ "with expected message");
+ is(validator.warnings.length, 0, "but no warning");
+ next();
+ });
+ },
+ function () {
+ let validator = createPackaged("non-absolute-path");
+ validator.validate().then(() => {
+ is(validator.errors.length, 1, "app with non absolute path got an error");
+ is(validator.errors[0], strings.formatStringFromName("validator.nonAbsoluteLaunchPath", ["non-absolute.html"], 1),
+ "with expected message");
+ is(validator.warnings.length, 0, "but no warning");
+ next();
+ });
+ },
+
+ // Test multiple failures (missing name [error] and icon [warning])
+ function () {
+ let validator = createHosted("no-name-or-icon");
+ validator.validate().then(() => {
+ checkNoNameOrIcon(validator);
+ });
+ },
+ function () {
+ let validator = createPackaged("no-name-or-icon");
+ validator.validate().then(() => {
+ checkNoNameOrIcon(validator);
+ });
+ },
+
+ // Test a regular URL instead of a direct link to the manifest
+ function () {
+ let validator = createHosted("valid", "/");
+ validator.validate().then(() => {
+ is(validator.warnings.length, 0, "manifest found got no warning");
+ is(validator.errors.length, 0, "manifest found got no error");
+
+ next();
+ });
+ },
+
+ // Test finding a manifest at origin's root
+ function () {
+ let validator = createHosted("valid", "/unexisting-dir");
+ validator.validate().then(() => {
+ is(validator.warnings.length, 0, "manifest found at origin root got no warning");
+ is(validator.errors.length, 0, "manifest found at origin root got no error");
+
+ next();
+ });
+ },
+
+ // Test priorization of manifest.webapp at provided location instead of a manifest located at origin's root
+ function() {
+ let validator = createHosted("valid", "/alsoValid");
+ validator.validate().then(() => {
+ is(validator.manifest.name, "valid at subfolder", "manifest at subfolder was used");
+
+ next();
+ });
+ }
+ ];
+
+ function checkNoNameOrIcon(validator) {
+ is(validator.errors.length, 1, "app with no name has an error");
+ is(validator.errors[0],
+ strings.GetStringFromName("validator.missNameManifestProperty"),
+ "with expected message");
+ is(validator.warnings.length, 1, "app with no icon has a warning");
+ is(validator.warnings[0],
+ strings.GetStringFromName("validator.missIconsManifestProperty"),
+ "with expected message");
+ next();
+ }
+
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_autoconnect_runtime.html b/devtools/client/webide/test/test_autoconnect_runtime.html
new file mode 100644
index 000000000..3de00473a
--- /dev/null
+++ b/devtools/client/webide/test/test_autoconnect_runtime.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function*() {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+ let docRuntime = getRuntimeDocument(win);
+
+ let fakeRuntime = {
+ type: "USB",
+ connect: function(connection) {
+ is(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ },
+
+ get id() {
+ return "fakeRuntime";
+ },
+
+ get name() {
+ return "fakeRuntime";
+ }
+ };
+ win.AppManager.runtimeList.usb.push(fakeRuntime);
+ win.AppManager.update("runtime-list");
+
+ let panelNode = docRuntime.querySelector("#runtime-panel");
+ let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
+ is(items.length, 1, "Found one runtime button");
+
+ let connectionsChanged = waitForConnectionChange("opened", 2);
+ items[0].click();
+
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+ yield win.UI._busyPromise;
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Connected");
+
+ connectionsChanged = waitForConnectionChange("closed", 2);
+
+ yield nextTick();
+ yield closeWebIDE(win);
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
+
+ connectionsChanged = waitForConnectionChange("opened", 2);
+
+ win = yield openWebIDE();
+
+ win.AppManager.runtimeList.usb.push(fakeRuntime);
+ win.AppManager.update("runtime-list");
+
+ yield waitForUpdate(win, "runtime-targets");
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Automatically reconnected");
+
+ yield win.Cmds.disconnectRuntime();
+
+ yield closeWebIDE(win);
+
+ DebuggerServer.destroy();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_autoselect_project.html b/devtools/client/webide/test/test_autoselect_project.html
new file mode 100644
index 000000000..cd5793559
--- /dev/null
+++ b/devtools/client/webide/test/test_autoselect_project.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+ let docRuntime = getRuntimeDocument(win);
+ let docProject = getProjectDocument(win);
+
+ let panelNode = docRuntime.querySelector("#runtime-panel");
+ let items = panelNode.querySelectorAll(".runtime-panel-item-other");
+ is(items.length, 2, "Found 2 runtime buttons");
+
+ // Connect to local runtime
+ let connectionsChanged = waitForConnectionChange("opened", 2);
+ items[1].click();
+
+ yield waitForUpdate(win, "runtime-targets");
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected");
+
+ ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
+
+ // Select main process
+ yield win.Cmds.showProjectPanel();
+ yield waitForUpdate(win, "runtime-targets");
+ SimpleTest.executeSoon(() => {
+ docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
+ });
+
+ yield waitForUpdate(win, "project");
+
+ let lastProject = Services.prefs.getCharPref("devtools.webide.lastSelectedProject");
+ is(lastProject, "mainProcess:", "Last project is main process");
+
+ connectionsChanged = waitForConnectionChange("closed", 2);
+
+ yield nextTick();
+ yield closeWebIDE(win);
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
+
+ connectionsChanged = waitForConnectionChange("opened", 2);
+
+ // Re-open, should reselect main process after connection
+ win = yield openWebIDE();
+
+ docRuntime = getRuntimeDocument(win);
+
+ panelNode = docRuntime.querySelector("#runtime-panel");
+ items = panelNode.querySelectorAll(".runtime-panel-item-other");
+ is(items.length, 2, "Found 2 runtime buttons");
+
+ // Connect to local runtime
+ items[1].click();
+
+ yield waitForUpdate(win, "runtime-targets");
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected");
+ ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
+ is(win.AppManager.selectedProject.type, "mainProcess", "Main process reselected");
+
+ // Wait for the toolbox to be fully loaded
+ yield win.UI.toolboxPromise;
+
+ // If we happen to pass a project object targeting the same context,
+ // here, the main process, the `selectedProject` attribute shouldn't be updated
+ // so that no `project` event would fire.
+ let oldProject = win.AppManager.selectedProject;
+ win.AppManager.selectedProject = {
+ type: "mainProcess"
+ };
+ is(win.AppManager.selectedProject, oldProject, "AppManager.selectedProject shouldn't be updated if we selected the same project");
+
+ yield win.Cmds.disconnectRuntime();
+
+ yield closeWebIDE(win);
+
+ DebuggerServer.destroy();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_basic.html b/devtools/client/webide/test/test_basic.html
new file mode 100644
index 000000000..e619a0f06
--- /dev/null
+++ b/devtools/client/webide/test/test_basic.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+
+ const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
+ yield gDevToolsBrowser.isWebIDEInitialized.promise;
+ ok(true, "WebIDE was initialized");
+
+ ok(win, "Found a window");
+ ok(win.AppManager, "App Manager accessible");
+ let appmgr = win.AppManager;
+ ok(appmgr.connection, "App Manager connection ready");
+ ok(appmgr.runtimeList, "Runtime list ready");
+
+ // test error reporting
+ let nbox = win.document.querySelector("#notificationbox");
+ let notification = nbox.getNotificationWithValue("webide:errornotification");
+ ok(!notification, "No notification yet");
+ let deferred = promise.defer();
+ nextTick().then(() => {
+ deferred.reject("BOOM!");
+ });
+ try {
+ yield win.UI.busyUntil(deferred.promise, "xx");
+ } catch(e) {/* This *will* fail */}
+ notification = nbox.getNotificationWithValue("webide:errornotification");
+ ok(notification, "Error has been reported");
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_build.html b/devtools/client/webide/test/test_build.html
new file mode 100644
index 000000000..ffb01998c
--- /dev/null
+++ b/devtools/client/webide/test/test_build.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
+ let {ProjectBuilding} = require("devtools/client/webide/modules/build");
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ let winProject = getProjectWindow(win);
+ let AppManager = win.AppManager;
+
+ function isProjectMarkedAsValid() {
+ let details = win.frames[0];
+ return !details.document.body.classList.contains("error");
+ }
+
+ // # Test first package.json like this: `{webide: {prepackage: "command line string"}}`
+ let platform = Services.appShell.hiddenDOMWindow.navigator.platform;
+ let testSuffix = "";
+ if (platform.indexOf("Win") != -1) {
+ testSuffix = "_windows";
+ }
+
+ let packagedAppLocation = getTestFilePath("build_app" + testSuffix + "1");
+
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ let project = win.AppManager.selectedProject;
+
+ ok(!project.manifest, "manifest includes name");
+ is(project.name, "--", "Display name uses manifest name");
+
+ let loggedMessages = [];
+ let logger = function (msg) {
+ loggedMessages.push(msg);
+ }
+
+ yield ProjectBuilding.build({
+ project,
+ logger
+ });
+ let packageDir = yield ProjectBuilding.getPackageDir(project);
+ is(packageDir, packagedAppLocation, "no custom packagedir");
+ is(loggedMessages[0], "start", "log messages are correct");
+ ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct");
+ is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct");
+ is(loggedMessages[3], "succeed", "log messages are correct");
+
+ // Trigger validation
+ yield AppManager.validateAndUpdateProject(AppManager.selectedProject);
+ yield nextTick();
+
+ ok("name" in project.manifest, "manifest includes name");
+ is(project.name, "hello", "Display name uses manifest name");
+ is(project.manifest.name, project.name, "Display name uses manifest name");
+
+ yield OS.File.remove(OS.Path.join(packagedAppLocation, "manifest.webapp"));
+
+ // # Now test a full featured package.json
+ packagedAppLocation = getTestFilePath("build_app" + testSuffix + "2");
+
+ onValidated = waitForUpdate(win, "project-validated");
+ onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ project = win.AppManager.selectedProject;
+
+ loggedMessages = [];
+ yield ProjectBuilding.build({
+ project,
+ logger
+ });
+ packageDir = yield ProjectBuilding.getPackageDir(project);
+ is(OS.Path.normalize(packageDir),
+ OS.Path.join(packagedAppLocation, "stage"), "custom packagedir");
+ is(loggedMessages[0], "start", "log messages are correct");
+ ok(loggedMessages[1].indexOf("Running pre-package hook") != -1, "log messages are correct");
+ is(loggedMessages[2], "Terminated with error code: 0", "log messages are correct");
+ is(loggedMessages[3], "succeed", "log messages are correct");
+
+ // Switch to the package dir in order to verify the generated webapp.manifest
+ onValidated = waitForUpdate(win, "project-validated");
+ onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packageDir);
+ yield onValidated;
+ yield onDetails;
+
+ project = win.AppManager.selectedProject;
+
+ ok("name" in project.manifest, "manifest includes name");
+ is(project.name, "world", "Display name uses manifest name");
+ is(project.manifest.name, project.name, "Display name uses manifest name");
+
+ yield closeWebIDE(win);
+
+ yield removeAllProjects();
+
+ SimpleTest.finish();
+ });
+ }
+
+
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_device_permissions.html b/devtools/client/webide/test/test_device_permissions.html
new file mode 100644
index 000000000..eadd9f595
--- /dev/null
+++ b/devtools/client/webide/test/test_device_permissions.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+
+ let permIframe = win.document.querySelector("#deck-panel-permissionstable");
+ let docRuntime = getRuntimeDocument(win);
+ let winRuntime = getRuntimeWindow(win);
+
+ yield connectToLocalRuntime(win);
+
+ let perm = docRuntime.querySelector("#runtime-permissions");
+
+ ok(!perm.hasAttribute("disabled"), "perm cmd enabled");
+
+ let deck = win.document.querySelector("#deck");
+
+ winRuntime.runtimeList.showPermissionsTable();
+ is(deck.selectedPanel, permIframe, "permission iframe selected");
+
+ yield nextTick();
+
+ yield lazyIframeIsLoaded(permIframe);
+
+ yield permIframe.contentWindow.getRawPermissionsTablePromise;
+
+ doc = permIframe.contentWindow.document;
+ trs = doc.querySelectorAll(".line");
+ found = false;
+ for (let tr of trs) {
+ let [name,v1,v2,v3] = tr.querySelectorAll("td");
+ if (name.textContent == "geolocation") {
+ found = true;
+ is(v1.className, "permprompt", "geolocation perm is valid");
+ is(v2.className, "permprompt", "geolocation perm is valid");
+ is(v3.className, "permprompt", "geolocation perm is valid");
+ break;
+ }
+ }
+ ok(found, "Found geolocation line");
+
+ doc.querySelector("#close").click();
+
+ ok(!deck.selectedPanel, "No panel selected");
+
+ DebuggerServer.destroy();
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_device_preferences.html b/devtools/client/webide/test/test_device_preferences.html
new file mode 100644
index 000000000..c79db7f79
--- /dev/null
+++ b/devtools/client/webide/test/test_device_preferences.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <script type="application/javascript;version=1.8" src="device_front_shared.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+
+ let prefIframe = win.document.querySelector("#deck-panel-devicepreferences");
+ let docRuntime = getRuntimeDocument(win);
+
+ win.AppManager.update("runtime-list");
+
+ yield connectToLocalRuntime(win);
+
+ let prefs = docRuntime.querySelector("#runtime-preferences");
+
+ ok(!prefs.hasAttribute("disabled"), "device prefs cmd enabled");
+
+ let deck = win.document.querySelector("#deck");
+
+ win.Cmds.showDevicePrefs();
+ is(deck.selectedPanel, prefIframe, "device preferences iframe selected");
+
+ yield nextTick();
+
+ yield lazyIframeIsLoaded(prefIframe);
+
+ yield prefIframe.contentWindow.getAllPrefs;
+
+ setDocument(prefIframe);
+
+ let fields = doc.querySelectorAll(".editable");
+
+ addNewField();
+
+ let preference = "accessibility.accesskeycausesactivation";
+
+ fieldChange(fields, preference);
+
+ addNewFieldWithEnter();
+
+ editExistingField();
+
+ addNewFieldInteger();
+
+ yield editFieldInteger();
+
+ yield resetExistingField("accessibility.accesskeycausesactivation");
+
+ addNewFieldBoolean();
+
+ searchFields(deck, "debugger");
+
+ DebuggerServer.destroy();
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_device_runtime.html b/devtools/client/webide/test/test_device_runtime.html
new file mode 100644
index 000000000..0ac42b472
--- /dev/null
+++ b/devtools/client/webide/test/test_device_runtime.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+
+ let detailsIframe = win.document.querySelector("#deck-panel-runtimedetails");
+
+ yield connectToLocalRuntime(win);
+
+ let details = win.document.querySelector("#cmd_showRuntimeDetails");
+
+ ok(!details.hasAttribute("disabled"), "info cmd enabled");
+
+ let deck = win.document.querySelector("#deck");
+
+ win.Cmds.showRuntimeDetails();
+ is(deck.selectedPanel, detailsIframe, "info iframe selected");
+
+ yield nextTick();
+
+ yield lazyIframeIsLoaded(detailsIframe);
+
+ yield detailsIframe.contentWindow.getDescriptionPromise;
+
+ // device info and permissions content is checked in other tests
+ // We just test one value to make sure we get something
+
+ let doc = detailsIframe.contentWindow.document;
+ let trs = doc.querySelectorAll("tr");
+ let found = false;
+
+ for (let tr of trs) {
+ let [name,val] = tr.querySelectorAll("td");
+ if (name.textContent == "appid") {
+ found = true;
+ is(val.textContent, Services.appinfo.ID, "appid has the right value");
+ break;
+ }
+ }
+ ok(found, "Found appid line");
+
+ doc.querySelector("#close").click();
+
+ ok(!deck.selectedPanel, "No panel selected");
+
+ DebuggerServer.destroy();
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_device_settings.html b/devtools/client/webide/test/test_device_settings.html
new file mode 100644
index 000000000..ec8e7943b
--- /dev/null
+++ b/devtools/client/webide/test/test_device_settings.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <script type="application/javascript;version=1.8" src="device_front_shared.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function*() {
+ if (SpecialPowers.isMainProcess()) {
+ Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
+ }
+
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ let win = yield openWebIDE();
+
+ let settingIframe = win.document.querySelector("#deck-panel-devicesettings");
+ let docRuntime = getRuntimeDocument(win);
+
+ win.AppManager.update("runtime-list");
+
+ yield connectToLocalRuntime(win);
+
+ let settings = docRuntime.querySelector("#runtime-settings");
+
+ ok(!settings.hasAttribute("disabled"), "device settings cmd enabled");
+
+ let deck = win.document.querySelector("#deck");
+
+ win.Cmds.showSettings();
+ is(deck.selectedPanel, settingIframe, "device settings iframe selected");
+
+ yield nextTick();
+
+ yield lazyIframeIsLoaded(settingIframe);
+
+ yield settingIframe.contentWindow.getAllSettings;
+
+ setDocument(settingIframe);
+
+ let fields = doc.querySelectorAll(".editable");
+
+ addNewField();
+
+ addNewFieldWithEnter();
+
+ editExistingField();
+
+ addNewFieldInteger();
+
+ yield editFieldInteger();
+
+ yield resetNewField("new-string-field");
+
+ addNewFieldBoolean();
+
+ searchFields(deck, "new-boolean-field2");
+
+ DebuggerServer.destroy();
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_duplicate_import.html b/devtools/client/webide/test/test_duplicate_import.html
new file mode 100644
index 000000000..ef01e23e4
--- /dev/null
+++ b/devtools/client/webide/test/test_duplicate_import.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function*() {
+ let win = yield openWebIDE();
+ let docProject = getProjectDocument(win);
+ let winProject = getProjectWindow(win);
+ let packagedAppLocation = getTestFilePath("app");
+ let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
+
+ yield win.AppProjects.load();
+ is(win.AppProjects.projects.length, 0, "IDB is empty");
+
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ yield winProject.projectList.importHostedApp(hostedAppManifest);
+ yield waitForUpdate(win, "project-validated");
+ yield nextTick();
+
+ onValidated = waitForUpdate(win, "project-validated");
+ onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ let project = win.AppManager.selectedProject;
+ is(project.location, packagedAppLocation, "Correctly reselected existing packaged app.");
+ yield nextTick();
+
+ info("to call importHostedApp(" + hostedAppManifest + ") again");
+ yield winProject.projectList.importHostedApp(hostedAppManifest);
+ yield waitForUpdate(win, "project-validated");
+ project = win.AppManager.selectedProject;
+ is(project.location, hostedAppManifest, "Correctly reselected existing hosted app.");
+ yield nextTick();
+
+ let panelNode = docProject.querySelector("#project-panel");
+ let items = panelNode.querySelectorAll(".panel-item");
+ // 3 controls, + 2 projects
+ is(items.length, 5, "5 projects in panel");
+ is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
+ is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
+
+ yield closeWebIDE(win);
+
+ yield removeAllProjects();
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
+
diff --git a/devtools/client/webide/test/test_fullscreenToolbox.html b/devtools/client/webide/test/test_fullscreenToolbox.html
new file mode 100644
index 000000000..6ae0c4446
--- /dev/null
+++ b/devtools/client/webide/test/test_fullscreenToolbox.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ function connectToLocal(win, docRuntime) {
+ let deferred = promise.defer();
+ win.AppManager.connection.once(
+ win.Connection.Events.CONNECTED,
+ () => deferred.resolve());
+ docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+ return deferred.promise;
+ }
+
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ let docProject = getProjectDocument(win);
+ let docRuntime = getRuntimeDocument(win);
+ win.AppManager.update("runtime-list");
+
+ yield connectToLocal(win, docRuntime);
+
+ // Select main process
+ yield waitForUpdate(win, "runtime-targets");
+ SimpleTest.executeSoon(() => {
+ docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
+ });
+
+ yield waitForUpdate(win, "project");
+
+ ok(win.UI.toolboxPromise, "Toolbox promise exists");
+ yield win.UI.toolboxPromise;
+
+ let nbox = win.document.querySelector("#notificationbox");
+ ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen");
+
+ win.Cmds.showRuntimeDetails();
+
+ ok(!nbox.hasAttribute("toolboxfullscreen"), "Toolbox is not fullscreen");
+
+ yield win.Cmds.disconnectRuntime();
+
+ yield closeWebIDE(win);
+
+ DebuggerServer.destroy();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_import.html b/devtools/client/webide/test/test_import.html
new file mode 100644
index 000000000..830198cca
--- /dev/null
+++ b/devtools/client/webide/test/test_import.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function*() {
+ let win = yield openWebIDE();
+ let docProject = getProjectDocument(win);
+ let winProject = getProjectWindow(win);
+ let packagedAppLocation = getTestFilePath("app");
+
+ yield win.AppProjects.load();
+ is(win.AppProjects.projects.length, 0, "IDB is empty");
+
+ info("to call importPackagedApp(" + packagedAppLocation + ")");
+ ok(!win.UI._busyPromise, "UI is not busy");
+
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ let project = win.AppManager.selectedProject;
+ is(project.location, packagedAppLocation, "Location is valid");
+ is(project.name, "A name (in app directory)", "name field has been updated");
+ is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
+ is(project.manifest.description, "desc", "manifest found. description valid");
+
+ yield nextTick();
+
+ let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
+ yield winProject.projectList.importHostedApp(hostedAppManifest);
+ yield waitForUpdate(win, "project-validated");
+
+ project = win.AppManager.selectedProject;
+ is(project.location, hostedAppManifest, "Location is valid");
+ is(project.name, "hosted manifest name property", "name field has been updated");
+
+ yield nextTick();
+
+ hostedAppManifest = TEST_BASE + "/app";
+ yield winProject.projectList.importHostedApp(hostedAppManifest);
+ yield waitForUpdate(win, "project-validated");
+
+ project = win.AppManager.selectedProject;
+ ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated");
+
+ let panelNode = docProject.querySelector("#project-panel");
+ let items = panelNode.querySelectorAll(".panel-item");
+ // 4 controls, + 2 projects
+ is(items.length, 6, "6 projects in panel");
+ is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
+ is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
+
+ yield closeWebIDE(win);
+
+ yield removeAllProjects();
+
+ SimpleTest.finish();
+ }).then(null, e => {
+ ok(false, "Exception: " + e);
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_manifestUpdate.html b/devtools/client/webide/test/test_manifestUpdate.html
new file mode 100644
index 000000000..66f9affd0
--- /dev/null
+++ b/devtools/client/webide/test/test_manifestUpdate.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ let {TextDecoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ let winProject = getProjectWindow(win);
+ let AppManager = win.AppManager;
+
+ function isProjectMarkedAsValid() {
+ let details = win.frames[1];
+ return !details.document.body.classList.contains("error");
+ }
+
+ let packagedAppLocation = getTestFilePath("app");
+
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ let project = win.AppManager.selectedProject;
+
+ ok("name" in project.manifest, "manifest includes name");
+ is(project.name, project.manifest.name, "Display name uses manifest name");
+ ok(isProjectMarkedAsValid(), "project is marked as valid");
+
+ // Change the name
+ let originalName = project.manifest.name;
+
+ project.manifest.name = "xxx";
+
+ // Write to disk
+ yield AppManager.writeManifest(project);
+
+ // Read file
+ let manifestPath = OS.Path.join(packagedAppLocation, "manifest.webapp");
+ let Decoder = new TextDecoder();
+ let data = yield OS.File.read(manifestPath);
+ data = new TextDecoder().decode(data);
+ let json = JSON.parse(data);
+ is(json.name, "xxx", "manifest written on disc");
+
+ // Make the manifest invalid on disk
+ delete json.name;
+ let Encoder = new TextEncoder();
+ data = Encoder.encode(JSON.stringify(json));
+ yield OS.File.writeAtomic(manifestPath, data , {tmpPath: manifestPath + ".tmp"});
+
+ // Trigger validation
+ yield AppManager.validateAndUpdateProject(AppManager.selectedProject);
+ yield nextTick();
+
+ ok(!("name" in project.manifest), "manifest has been updated");
+ is(project.name, "--", "Placeholder is used for display name");
+ ok(!isProjectMarkedAsValid(), "project is marked as invalid");
+
+ // Make the manifest valid on disk
+ project.manifest.name = originalName;
+ yield AppManager.writeManifest(project);
+
+ // Trigger validation
+ yield AppManager.validateAndUpdateProject(AppManager.selectedProject);
+ yield nextTick();
+
+ ok("name" in project.manifest, "manifest includes name");
+ is(project.name, originalName, "Display name uses original manifest name");
+ ok(isProjectMarkedAsValid(), "project is marked as valid");
+
+ yield closeWebIDE(win);
+
+ yield removeAllProjects();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_newapp.html b/devtools/client/webide/test/test_newapp.html
new file mode 100644
index 000000000..45374f268
--- /dev/null
+++ b/devtools/client/webide/test/test_newapp.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ let winProject = getProjectWindow(win);
+ let tmpDir = FileUtils.getDir("TmpD", []);
+ yield winProject.projectList.newApp({
+ index: 0,
+ name: "webideTmpApp",
+ folder: tmpDir
+ });
+
+ let project = win.AppManager.selectedProject;
+ tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]);
+ ok(tmpDir.isDirectory(), "Directory created");
+ is(project.location, tmpDir.path, "Location is valid (and lowercase)");
+ is(project.name, "webideTmpApp", "name field has been updated");
+
+ // Clean up
+ tmpDir.remove(true);
+ yield closeWebIDE(win);
+ yield removeAllProjects();
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_runtime.html b/devtools/client/webide/test/test_runtime.html
new file mode 100644
index 000000000..9b16ef82d
--- /dev/null
+++ b/devtools/client/webide/test/test_runtime.html
@@ -0,0 +1,203 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ let win;
+
+ SimpleTest.registerCleanupFunction(() => {
+ Task.spawn(function*() {
+ if (win) {
+ yield closeWebIDE(win);
+ }
+ DebuggerServer.destroy();
+ yield removeAllProjects();
+ });
+ });
+
+ Task.spawn(function*() {
+ function isPlayActive() {
+ return !win.document.querySelector("#cmd_play").hasAttribute("disabled");
+ }
+
+ function isStopActive() {
+ return !win.document.querySelector("#cmd_stop").hasAttribute("disabled");
+ }
+
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ win = yield openWebIDE();
+ let docRuntime = getRuntimeDocument(win);
+ let docProject = getProjectDocument(win);
+ let winProject = getProjectWindow(win);
+
+ let packagedAppLocation = getTestFilePath("app");
+
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+
+ win.AppManager.runtimeList.usb.push({
+ connect: function(connection) {
+ is(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ },
+
+ get name() {
+ return "fakeRuntime";
+ }
+ });
+
+ win.AppManager.runtimeList.usb.push({
+ connect: function(connection) {
+ let deferred = promise.defer();
+ return deferred.promise;
+ },
+
+ get name() {
+ return "infiniteRuntime";
+ }
+ });
+
+ win.AppManager.runtimeList.usb.push({
+ connect: function(connection) {
+ let deferred = promise.defer();
+ return deferred.promise;
+ },
+
+ prolongedConnection: true,
+
+ get name() {
+ return "prolongedRuntime";
+ }
+ });
+
+ win.AppManager.update("runtime-list");
+
+ let panelNode = docRuntime.querySelector("#runtime-panel");
+ let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
+ is(items.length, 3, "Found 3 runtime buttons");
+
+ let connectionsChanged = waitForConnectionChange("opened", 2);
+ items[0].click();
+
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+ yield win.UI._busyPromise;
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Connected");
+
+ yield waitForUpdate(win, "runtime-global-actors");
+
+ // Play button always disabled now, webapps actor removed
+ ok(!isPlayActive(), "play button is disabled");
+ ok(!isStopActive(), "stop button is disabled");
+ let oldProject = win.AppManager.selectedProject;
+ win.AppManager.selectedProject = null;
+
+ yield nextTick();
+
+ ok(!isPlayActive(), "play button is disabled");
+ ok(!isStopActive(), "stop button is disabled");
+ win.AppManager._selectedProject = oldProject;
+ win.UI.updateCommands();
+
+ yield nextTick();
+
+ ok(!isPlayActive(), "play button is enabled");
+ ok(!isStopActive(), "stop button is disabled");
+
+ connectionsChanged = waitForConnectionChange("closed", 2);
+ yield win.Cmds.disconnectRuntime();
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
+
+ ok(win.AppManager.selectedProject, "A project is still selected");
+ ok(!isPlayActive(), "play button is disabled");
+ ok(!isStopActive(), "stop button is disabled");
+
+ connectionsChanged = waitForConnectionChange("opened", 2);
+ docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+
+ yield waitForUpdate(win, "runtime-targets");
+
+ yield connectionsChanged;
+ is(Object.keys(DebuggerServer._connections).length, 2, "Locally connected");
+
+ ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
+
+ // Select main process
+ SimpleTest.executeSoon(() => {
+ docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
+ });
+
+ yield waitForUpdate(win, "project");
+
+ // Toolbox opens automatically for main process / runtime apps
+ ok(win.UI.toolboxPromise, "Toolbox promise exists");
+ yield win.UI.toolboxPromise;
+
+ yield win.Cmds.disconnectRuntime();
+
+ Services.prefs.setIntPref("devtools.webide.busyTimeout", 100);
+
+ // Wait for error message since connection never completes
+ let errorDeferred = promise.defer();
+ win.UI.reportError = errorName => {
+ if (errorName === "error_operationTimeout") {
+ errorDeferred.resolve();
+ }
+ };
+
+ // Click the infinite runtime
+ items[1].click();
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+ yield errorDeferred.promise;
+
+ // Check for unexpected error message since this is prolonged
+ let noErrorDeferred = promise.defer();
+ win.UI.reportError = errorName => {
+ if (errorName === "error_operationTimeout") {
+ noErrorDeferred.reject();
+ }
+ };
+
+ // Click the prolonged runtime
+ items[2].click();
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+
+ setTimeout(() => {
+ noErrorDeferred.resolve();
+ }, 1000);
+
+ yield noErrorDeferred.promise;
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_simulators.html b/devtools/client/webide/test/test_simulators.html
new file mode 100644
index 000000000..204881512
--- /dev/null
+++ b/devtools/client/webide/test/test_simulators.html
@@ -0,0 +1,426 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ const asyncStorage = require("devtools/shared/async-storage");
+ const EventEmitter = require("devtools/shared/event-emitter");
+ const { GetAvailableAddons } = require("devtools/client/webide/modules/addons");
+ const { getDevices } = require("devtools/client/shared/devices");
+ const { Simulator, Simulators } = require("devtools/client/webide/modules/simulators");
+ const { AddonSimulatorProcess,
+ OldAddonSimulatorProcess,
+ CustomSimulatorProcess } = require("devtools/client/webide/modules/simulator-process");
+
+ function addonStatus(addon, status) {
+ if (addon.status == status) {
+ return promise.resolve();
+ }
+ let deferred = promise.defer();
+ addon.on("update", function onUpdate() {
+ if (addon.status == status) {
+ addon.off("update", onUpdate);
+ nextTick().then(() => deferred.resolve());
+ }
+ });
+ return deferred.promise;
+ }
+
+ function waitForUpdate(length) {
+ info(`Wait for update with length ${length}`);
+ let deferred = promise.defer();
+ let handler = (_, data) => {
+ if (data.length != length) {
+ return;
+ }
+ info(`Got update with length ${length}`);
+ Simulators.off("updated", handler);
+ deferred.resolve();
+ };
+ Simulators.on("updated", handler);
+ return deferred.promise;
+ }
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE(false);
+
+ yield Simulators._load();
+
+ let docRuntime = getRuntimeDocument(win);
+ let find = win.document.querySelector.bind(docRuntime);
+ let findAll = win.document.querySelectorAll.bind(docRuntime);
+
+ let simulatorList = find("#runtime-panel-simulator");
+ let simulatorPanel = win.document.querySelector("#deck-panel-simulator");
+
+ // Hack SimulatorProcesses to spy on simulation parameters.
+
+ let runPromise;
+ function fakeRun() {
+ runPromise.resolve({
+ path: this.b2gBinary.path,
+ args: this.args
+ });
+ // Don't actually try to connect to the fake simulator.
+ throw new Error("Aborting on purpose before connection.");
+ }
+
+ AddonSimulatorProcess.prototype.run = fakeRun;
+ OldAddonSimulatorProcess.prototype.run = fakeRun;
+ CustomSimulatorProcess.prototype.run = fakeRun;
+
+ function runSimulator(i) {
+ runPromise = promise.defer();
+ findAll(".runtime-panel-item-simulator")[i].click();
+ return runPromise.promise;
+ }
+
+ // Install fake "Firefox OS 1.0" simulator addon.
+
+ let addons = yield GetAvailableAddons();
+
+ let sim10 = addons.simulators.filter(a => a.version == "1.0")[0];
+
+ sim10.install();
+
+ let updated = waitForUpdate(1);
+ yield addonStatus(sim10, "installed");
+ yield updated;
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ is(findAll(".runtime-panel-item-simulator").length, 1, "One simulator in runtime panel");
+
+ // Install fake "Firefox OS 2.0" simulator addon.
+
+ let sim20 = addons.simulators.filter(a => a.version == "2.0")[0];
+
+ sim20.install();
+
+ updated = waitForUpdate(2);
+ yield addonStatus(sim20, "installed");
+ yield updated;
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ is(findAll(".runtime-panel-item-simulator").length, 2, "Two simulators in runtime panel");
+
+ // Dry run a simulator to verify that its parameters look right.
+
+ let params = yield runSimulator(0);
+
+ ok(params.path.includes(sim10.addonID) && params.path.includes("b2g-bin"), "Simulator binary path looks right");
+
+ let pid = params.args.indexOf("-profile");
+ ok(pid > -1, "Simulator process arguments have --profile");
+
+ let profilePath = params.args[pid + 1];
+ ok(profilePath.includes(sim10.addonID) && profilePath.includes("profile"), "Simulator profile path looks right");
+
+ ok(params.args.indexOf("-dbgport") > -1 || params.args.indexOf("-start-debugger-server") > -1, "Simulator process arguments have a debugger port");
+
+ ok(params.args.indexOf("-no-remote") > -1, "Simulator process arguments have --no-remote");
+
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ // Configure the fake 1.0 simulator.
+
+ simulatorList.querySelectorAll(".configure-button")[0].click();
+ is(win.document.querySelector("#deck").selectedPanel, simulatorPanel, "Simulator deck panel is selected");
+
+ yield lazyIframeIsLoaded(simulatorPanel);
+
+ let doc = simulatorPanel.contentWindow.document;
+ let form = doc.querySelector("#simulator-editor");
+
+ let formReady = new Promise((resolve, reject) => {
+ form.addEventListener("change", () => {
+ resolve();
+ });
+ });
+
+ let change = doc.createEvent("HTMLEvents");
+ change.initEvent("change", true, true);
+
+ function set(input, value) {
+ input.value = value;
+ input.dispatchEvent(change);
+ return nextTick();
+ }
+
+ let MockFilePicker = SpecialPowers.MockFilePicker;
+ MockFilePicker.init(simulatorPanel.contentWindow);
+
+ yield formReady;
+
+ // Test `name`.
+
+ is(form.name.value, find(".runtime-panel-item-simulator").textContent, "Original simulator name");
+
+ let customName = "CustomFox ";
+ yield set(form.name, customName + "1.0");
+
+ is(find(".runtime-panel-item-simulator").textContent, form.name.value, "Updated simulator name");
+
+ // Test `version`.
+
+ is(form.version.value, sim10.addonID, "Original simulator version");
+ ok(!form.version.classList.contains("custom"), "Version selector is not customized");
+
+ yield set(form.version, sim20.addonID);
+
+ ok(!form.version.classList.contains("custom"), "Version selector is not customized after addon change");
+ is(form.name.value, customName + "2.0", "Simulator name was updated to new version");
+
+ // Pick custom binary, but act like the user aborted the file picker.
+
+ MockFilePicker.returnFiles = [];
+ yield set(form.version, "pick");
+
+ is(form.version.value, sim20.addonID, "Version selector reverted to last valid choice after customization abort");
+ ok(!form.version.classList.contains("custom"), "Version selector is not customized after customization abort");
+
+ // Pick custom binary, and actually follow through. (success, verify value = "custom" and textContent = custom path)
+
+ MockFilePicker.useAnyFile();
+ yield set(form.version, "pick");
+
+ let fakeBinary = MockFilePicker.returnFiles[0];
+
+ ok(form.version.value == "custom", "Version selector was set to a new custom binary");
+ ok(form.version.classList.contains("custom"), "Version selector is now customized");
+ is(form.version.selectedOptions[0].textContent, fakeBinary.path, "Custom option textContent is correct");
+
+ yield set(form.version, sim10.addonID);
+
+ ok(form.version.classList.contains("custom"), "Version selector remains customized after change back to addon");
+ is(form.name.value, customName + "1.0", "Simulator name was updated to new version");
+
+ yield set(form.version, "custom");
+
+ ok(form.version.value == "custom", "Version selector is back to custom");
+
+ // Test `profile`.
+
+ is(form.profile.value, "default", "Default simulator profile");
+ ok(!form.profile.classList.contains("custom"), "Profile selector is not customized");
+
+ MockFilePicker.returnFiles = [];
+ yield set(form.profile, "pick");
+
+ is(form.profile.value, "default", "Profile selector reverted to last valid choice after customization abort");
+ ok(!form.profile.classList.contains("custom"), "Profile selector is not customized after customization abort");
+
+ let fakeProfile = FileUtils.getDir("TmpD", []);
+
+ MockFilePicker.returnFiles = [ fakeProfile ];
+ yield set(form.profile, "pick");
+
+ ok(form.profile.value == "custom", "Profile selector was set to a new custom directory");
+ ok(form.profile.classList.contains("custom"), "Profile selector is now customized");
+ is(form.profile.selectedOptions[0].textContent, fakeProfile.path, "Custom option textContent is correct");
+
+ yield set(form.profile, "default");
+
+ is(form.profile.value, "default", "Profile selector back to default");
+ ok(form.profile.classList.contains("custom"), "Profile selector remains customized after change back to default");
+
+ yield set(form.profile, "custom");
+
+ is(form.profile.value, "custom", "Profile selector back to custom");
+
+ params = yield runSimulator(0);
+
+ is(params.path, fakeBinary.path, "Simulator process uses custom binary path");
+
+ pid = params.args.indexOf("-profile");
+ is(params.args[pid + 1], fakeProfile.path, "Simulator process uses custom profile directory");
+
+ yield set(form.version, sim10.addonID);
+
+ is(form.name.value, customName + "1.0", "Simulator restored to 1.0");
+
+ params = yield runSimulator(0);
+
+ pid = params.args.indexOf("-profile");
+ is(params.args[pid + 1], fakeProfile.path, "Simulator process still uses custom profile directory");
+
+ yield set(form.version, "custom");
+
+ // Test `device`.
+
+ let defaults = Simulator.prototype._defaults;
+
+ for (let param in defaults.phone) {
+ is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param);
+ }
+
+ let width = 5000, height = 4000;
+ yield set(form.width, width);
+ yield set(form.height, height);
+
+ is(form.device.value, "custom", "Device selector is custom");
+
+ params = yield runSimulator(0);
+
+ let sid = params.args.indexOf("-screen");
+ ok(sid > -1, "Simulator process arguments have --screen");
+ ok(params.args[sid + 1].includes(width + "x" + height), "Simulator screen resolution looks right");
+
+ yield set(form.version, sim10.addonID);
+
+ // Configure the fake 2.0 simulator.
+
+ simulatorList.querySelectorAll(".configure-button")[1].click();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ // Test `name`.
+
+ is(form.name.value, findAll(".runtime-panel-item-simulator")[1].textContent, "Original simulator name");
+
+ yield set(form.name, customName + "2.0");
+
+ is(findAll(".runtime-panel-item-simulator")[1].textContent, form.name.value, "Updated simulator name");
+
+ yield set(form.version, sim10.addonID);
+
+ ok(form.name.value !== customName + "1.0", "Conflicting simulator name was deduplicated");
+
+ is(form.name.value, findAll(".runtime-panel-item-simulator")[1].textContent, "Deduplicated simulator name stayed consistent");
+
+ yield set(form.version, sim20.addonID);
+
+ is(form.name.value, customName + "2.0", "Name deduplication was undone when possible");
+
+ // Test `device`.
+
+ for (let param in defaults.phone) {
+ is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param);
+ }
+
+ let devices = yield getDevices();
+ devices = devices[devices.TYPES[0]];
+ let device = devices[devices.length - 1];
+
+ yield set(form.device, device.name);
+
+ is(form.device.value, device.name, "Device selector was changed");
+ is(form.width.value, String(device.width), "New device width is correct");
+ is(form.height.value, String(device.height), "New device height is correct");
+
+ params = yield runSimulator(1);
+
+ sid = params.args.indexOf("-screen");
+ ok(params.args[sid + 1].includes(device.width + "x" + device.height), "Simulator screen resolution looks right");
+
+ // Test Simulator Menu.
+ is(doc.querySelector("#tv_simulator_menu").style.visibility, "hidden", "OpenTVDummyDirectory Button is not hidden");
+
+ // Restore default simulator options.
+
+ doc.querySelector("#reset").click();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ for (let param in defaults.phone) {
+ is(form[param].value, String(defaults.phone[param]), "Default phone value for device " + param);
+ }
+
+ // Install and configure the fake "Firefox OS 3.0 TV" simulator addon.
+
+ let sim30tv = addons.simulators.filter(a => a.version == "3.0_tv")[0];
+
+ sim30tv.install();
+
+ updated = waitForUpdate(3);
+ yield addonStatus(sim30tv, "installed");
+ yield updated;
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ is(findAll(".runtime-panel-item-simulator").length, 3, "Three simulators in runtime panel");
+
+ simulatorList.querySelectorAll(".configure-button")[2].click();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ for (let param in defaults.television) {
+ is(form[param].value, String(defaults.television[param]), "Default TV value for device " + param);
+ }
+
+ // Test Simulator Menu
+ is(doc.querySelector("#tv_simulator_menu").style.visibility, "visible", "OpenTVDummyDirectory Button is not visible");
+
+ // Force reload the list of simulators.
+
+ Simulators._loadingPromise = null;
+ Simulators._simulators = [];
+ yield Simulators._load();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ is(findAll(".runtime-panel-item-simulator").length, 3, "Three simulators saved and reloaded " + Simulators._simulators.map(s => s.name).join(','));
+
+ // Uninstall the 3.0 TV and 2.0 addons, and watch their Simulator objects disappear.
+
+ sim30tv.uninstall();
+
+ yield addonStatus(sim30tv, "uninstalled");
+
+ is(findAll(".runtime-panel-item-simulator").length, 2, "Two simulators left in runtime panel");
+
+ sim20.uninstall();
+
+ yield addonStatus(sim20, "uninstalled");
+
+ is(findAll(".runtime-panel-item-simulator").length, 1, "One simulator left in runtime panel");
+
+ // Remove 1.0 simulator.
+
+ simulatorList.querySelectorAll(".configure-button")[0].click();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ doc.querySelector("#remove").click();
+ // Wait for next tick to ensure UI elements are updated
+ yield nextTick();
+
+ is(findAll(".runtime-panel-item-simulator").length, 0, "Last simulator was removed");
+
+ yield asyncStorage.removeItem("simulators");
+
+ sim10.uninstall();
+
+ MockFilePicker.cleanup();
+
+ doc.querySelector("#close").click();
+
+ ok(!win.document.querySelector("#deck").selectedPanel, "No panel selected");
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+
+ });
+ }
+
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_telemetry.html b/devtools/client/webide/test/test_telemetry.html
new file mode 100644
index 000000000..225ddb89b
--- /dev/null
+++ b/devtools/client/webide/test/test_telemetry.html
@@ -0,0 +1,325 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ const Telemetry = require("devtools/client/shared/telemetry");
+ const { _DeprecatedUSBRuntime, _WiFiRuntime, _SimulatorRuntime,
+ _gRemoteRuntime, _gLocalRuntime, RuntimeTypes }
+ = require("devtools/client/webide/modules/runtimes");
+
+ // Because we need to gather stats for the period of time that a tool has
+ // been opened we make use of setTimeout() to create tool active times.
+ const TOOL_DELAY = 200;
+
+ function patchTelemetry() {
+ Telemetry.prototype.telemetryInfo = {};
+ Telemetry.prototype._oldlog = Telemetry.prototype.log;
+ Telemetry.prototype.log = function(histogramId, value) {
+ if (histogramId) {
+ if (!this.telemetryInfo[histogramId]) {
+ this.telemetryInfo[histogramId] = [];
+ }
+ this.telemetryInfo[histogramId].push(value);
+ }
+ }
+ Telemetry.prototype._oldlogKeyed = Telemetry.prototype.logKeyed;
+ Telemetry.prototype.logKeyed = function(histogramId, key, value) {
+ // This simple reduction is enough to test WebIDE's usage
+ this.log(`${histogramId}|${key}`, value);
+ }
+ }
+
+ function resetTelemetry() {
+ Telemetry.prototype.log = Telemetry.prototype._oldlog;
+ Telemetry.prototype.logKeyed = Telemetry.prototype._oldlogKeyed;
+ delete Telemetry.prototype._oldlog;
+ delete Telemetry.prototype._oldlogKeyed;
+ delete Telemetry.prototype.telemetryInfo;
+ }
+
+ function cycleWebIDE() {
+ return Task.spawn(function*() {
+ let win = yield openWebIDE();
+ // Wait a bit, so we're open for a non-zero time
+ yield waitForTime(TOOL_DELAY);
+ yield closeWebIDE(win);
+ });
+ }
+
+ function addFakeRuntimes(win) {
+ // We use the real runtimes here (and switch out some functionality)
+ // so we can ensure that logging happens as it would in real use.
+
+ let usb = new _DeprecatedUSBRuntime("fakeUSB");
+ // Use local pipe instead
+ usb.connect = function(connection) {
+ ok(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ };
+ win.AppManager.runtimeList.usb.push(usb);
+
+ let wifi = new _WiFiRuntime("fakeWiFi");
+ // Use local pipe instead
+ wifi.connect = function(connection) {
+ ok(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ };
+ win.AppManager.runtimeList.wifi.push(wifi);
+
+ let sim = new _SimulatorRuntime({ id: "fakeSimulator" });
+ // Use local pipe instead
+ sim.connect = function(connection) {
+ ok(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ };
+ Object.defineProperty(sim, "name", {
+ get() {
+ return this.version;
+ }
+ });
+ win.AppManager.runtimeList.simulator.push(sim);
+
+ let remote = _gRemoteRuntime;
+ // Use local pipe instead
+ remote.connect = function(connection) {
+ ok(connection, win.AppManager.connection, "connection is valid");
+ connection.host = null; // force connectPipe
+ connection.connect();
+ return promise.resolve();
+ };
+ let local = _gLocalRuntime;
+
+ let other = Object.create(_gLocalRuntime);
+ other.type = RuntimeTypes.OTHER;
+
+ win.AppManager.runtimeList.other = [remote, local, other];
+
+ win.AppManager.update("runtime-list");
+ }
+
+ function addTestApp(win) {
+ return Task.spawn(function*() {
+ let packagedAppLocation = getTestFilePath("../app");
+ let winProject = getProjectWindow(win);
+ let onValidated = waitForUpdate(win, "project-validated");
+ let onDetails = waitForUpdate(win, "details");
+ yield winProject.projectList.importPackagedApp(packagedAppLocation);
+ yield onValidated;
+ yield onDetails;
+ });
+ }
+
+ function startConnection(win, docRuntime, type, index) {
+ let panelNode = docRuntime.querySelector("#runtime-panel");
+ let items = panelNode.querySelectorAll(".runtime-panel-item-" + type);
+ if (index === undefined) {
+ is(items.length, 1, "Found one runtime button");
+ }
+
+ let deferred = promise.defer();
+ win.AppManager.connection.once(
+ win.Connection.Events.CONNECTED,
+ () => deferred.resolve());
+
+ items[index || 0].click();
+
+ return deferred.promise;
+ }
+
+ function waitUntilConnected(win) {
+ return Task.spawn(function*() {
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+ yield win.UI._busyPromise;
+ is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
+ // Logging runtime info needs to use the device actor
+ yield waitForUpdate(win, "runtime-global-actors");
+ // Ensure detailed telemetry is recorded
+ yield waitForUpdate(win, "runtime-telemetry");
+ });
+ }
+
+ function connectToRuntime(win, docRuntime, type, index) {
+ return Task.spawn(function*() {
+ startConnection(win, docRuntime, type, index);
+ yield waitUntilConnected(win);
+ });
+ }
+
+ function checkResults() {
+ let result = Telemetry.prototype.telemetryInfo;
+ for (let [histId, value] of Iterator(result)) {
+ if (histId === "DEVTOOLS_WEBIDE_IMPORT_PROJECT_BOOLEAN") {
+ ok(value.length === 1 && !!value[0],
+ histId + " has 1 successful entry");
+ } else if (histId ===
+ "DEVTOOLS_WEBIDE_PROJECT_EDITOR_OPENED_COUNT") {
+ ok(value.length === 1 && !!value[0],
+ histId + " has 1 successful entry");
+ } else if (histId === "DEVTOOLS_WEBIDE_OPENED_COUNT") {
+ ok(value.length > 1, histId + " has more than one entry");
+
+ let okay = value.every(function(element) {
+ return !!element;
+ });
+
+ ok(okay, "All " + histId + " entries are true");
+ } else if (histId.endsWith("WEBIDE_TIME_ACTIVE_SECONDS")) {
+ ok(value.length > 1, histId + " has more than one entry");
+
+ let okay = value.every(function(element) {
+ return element > 0;
+ });
+
+ ok(okay, "All " + histId + " entries have time > 0");
+ } else if (histId.endsWith("EDITOR_TIME_ACTIVE_SECONDS")) {
+ ok(value.length === 1 && value[0] > 0,
+ histId + " has 1 entry with time > 0");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
+ ok(value.length === 6, histId + " has 6 connection results");
+
+ let okay = value.every(function(element) {
+ return !!element;
+ });
+
+ ok(okay, "All " + histId + " connections succeeded");
+ } else if (histId.endsWith("CONNECTION_RESULT")) {
+ ok(value.length === 1 && !!value[0],
+ histId + " has 1 successful connection");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS") {
+ ok(value.length === 6, histId + " has 6 connection results");
+
+ let okay = value.every(function(element) {
+ return element > 0;
+ });
+
+ ok(okay, "All " + histId + " connections have time > 0");
+ } else if (histId.endsWith("USED")) {
+ ok(value.length === 6, histId + " has 6 connection actions");
+
+ let okay = value.every(function(element) {
+ return !element;
+ });
+
+ ok(okay, "All " + histId + " actions were skipped");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|USB") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|WIFI") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|SIMULATOR") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|REMOTE") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|LOCAL") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_TYPE|OTHER") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeUSB") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeWiFi") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|fakeSimulator") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|unknown") {
+ is(value.length, 1, histId + " has 1 connection results");
+ } else if (histId === "DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_ID|local") {
+ is(value.length, 2, histId + " has 2 connection results");
+ } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PROCESSOR")) {
+ let processor = histId.split("|")[1];
+ is(processor, Services.appinfo.XPCOMABI.split("-")[0], "Found runtime processor");
+ is(value.length, 6, histId + " has 6 connection results");
+ } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_OS")) {
+ let os = histId.split("|")[1];
+ is(os, Services.appinfo.OS, "Found runtime OS");
+ is(value.length, 6, histId + " has 6 connection results");
+ } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_PLATFORM_VERSION")) {
+ let platformversion = histId.split("|")[1];
+ is(platformversion, Services.appinfo.platformVersion, "Found runtime platform version");
+ is(value.length, 6, histId + " has 6 connection results");
+ } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_APP_TYPE")) {
+ let apptype = histId.split("|")[1];
+ is(apptype, "firefox", "Found runtime app type");
+ is(value.length, 6, histId + " has 6 connection results");
+ } else if (histId.startsWith("DEVTOOLS_WEBIDE_CONNECTED_RUNTIME_VERSION")) {
+ let version = histId.split("|")[1];
+ is(version, Services.appinfo.version, "Found runtime version");
+ is(value.length, 6, histId + " has 6 connection results");
+ } else {
+ ok(false, "Unexpected " + histId + " was logged");
+ }
+ }
+ }
+
+ window.onload = function() {
+ SimpleTest.testInChaosMode();
+ SimpleTest.waitForExplicitFinish();
+
+ let win;
+
+ SimpleTest.registerCleanupFunction(() => {
+ return Task.spawn(function*() {
+ if (win) {
+ yield closeWebIDE(win);
+ }
+ DebuggerServer.destroy();
+ yield removeAllProjects();
+ resetTelemetry();
+ });
+ });
+
+ Task.spawn(function*() {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ patchTelemetry();
+
+ // Cycle once, so we can test for multiple opens
+ yield cycleWebIDE();
+
+ win = yield openWebIDE();
+ let docRuntime = getRuntimeDocument(win);
+
+ // Wait a bit, so we're open for a non-zero time
+ yield waitForTime(TOOL_DELAY);
+ addFakeRuntimes(win);
+ yield addTestApp(win);
+
+ // Each one should log a connection result and non-zero connection
+ // time
+ yield connectToRuntime(win, docRuntime, "usb");
+ yield connectToRuntime(win, docRuntime, "wifi");
+ yield connectToRuntime(win, docRuntime, "simulator");
+ yield connectToRuntime(win, docRuntime, "other", 0 /* remote */);
+ yield connectToRuntime(win, docRuntime, "other", 1 /* local */);
+ yield connectToRuntime(win, docRuntime, "other", 2 /* other */);
+ yield closeWebIDE(win);
+ win = null;
+
+ checkResults();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_toolbox.html b/devtools/client/webide/test/test_toolbox.html
new file mode 100644
index 000000000..71ac2706c
--- /dev/null
+++ b/devtools/client/webide/test/test_toolbox.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ let win;
+
+ SimpleTest.registerCleanupFunction(() => {
+ Task.spawn(function*() {
+ if (win) {
+ yield closeWebIDE(win);
+ }
+ DebuggerServer.destroy();
+ yield removeAllProjects();
+ });
+ });
+
+ Task.spawn(function*() {
+ if (!DebuggerServer.initialized) {
+ DebuggerServer.init();
+ DebuggerServer.addBrowserActors();
+ }
+
+ win = yield openWebIDE();
+ let docRuntime = getRuntimeDocument(win);
+ let docProject = getProjectDocument(win);
+
+ win.AppManager.update("runtime-list");
+
+ let deferred = promise.defer();
+ win.AppManager.connection.once(
+ win.Connection.Events.CONNECTED,
+ () => deferred.resolve());
+
+ docRuntime.querySelectorAll(".runtime-panel-item-other")[1].click();
+
+ ok(win.document.querySelector("window").className, "busy", "UI is busy");
+ yield win.UI._busyPromise;
+
+ is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
+
+ yield waitForUpdate(win, "runtime-global-actors");
+
+ ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
+
+ // Select main process
+ SimpleTest.executeSoon(() => {
+ docProject.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
+ });
+
+ yield waitForUpdate(win, "project");
+
+ // Toolbox opens automatically for main process / runtime apps
+ ok(win.UI.toolboxPromise, "Toolbox promise exists");
+ let toolbox = yield win.UI.toolboxPromise;
+
+ yield toolbox.destroy();
+
+ ok(!win.UI.toolboxPromise, "Toolbox promise should be unset once toolbox.destroy()'s promise resolves");
+
+ // Reopen the toolbox right after to check races and also
+ // opening a toolbox more than just once against the same target
+ yield win.Cmds.toggleToolbox();
+
+ ok(win.UI.toolboxPromise, "Toolbox promise exists");
+
+ yield win.UI.destroyToolbox();
+
+ ok(!win.UI.toolboxPromise, "Toolbox promise is also nullified the second times");
+
+ yield win.Cmds.disconnectRuntime();
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/test_zoom.html b/devtools/client/webide/test/test_zoom.html
new file mode 100644
index 000000000..4ad3885d2
--- /dev/null
+++ b/devtools/client/webide/test/test_zoom.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<html>
+
+ <head>
+ <meta charset="utf8">
+ <title></title>
+
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
+ <script type="application/javascript;version=1.8" src="head.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+ </head>
+
+ <body>
+
+ <script type="application/javascript;version=1.8">
+ window.onload = function() {
+ SimpleTest.waitForExplicitFinish();
+
+ Task.spawn(function* () {
+ let win = yield openWebIDE();
+ let viewer = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .contentViewer;
+
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+ win.Cmds.zoomOut();
+
+ let roundZoom = Math.round(10 * viewer.fullZoom) / 10;
+ is(roundZoom, 0.6, "Reach min zoom");
+
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+ win.Cmds.zoomIn();
+
+ roundZoom = Math.round(10 * viewer.fullZoom) / 10;
+ is(roundZoom, 1.4, "Reach max zoom");
+
+ yield closeWebIDE(win);
+
+ win = yield openWebIDE();
+ viewer = win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell)
+ .contentViewer;
+
+ roundZoom = Math.round(10 * viewer.fullZoom) / 10;
+ is(roundZoom, 1.4, "Zoom restored");
+
+ win.Cmds.resetZoom();
+
+ is(viewer.fullZoom, 1, "Zoom reset");
+
+ yield closeWebIDE(win);
+
+ SimpleTest.finish();
+ });
+ }
+ </script>
+ </body>
+</html>
diff --git a/devtools/client/webide/test/validator/no-name-or-icon/home.html b/devtools/client/webide/test/validator/no-name-or-icon/home.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/validator/no-name-or-icon/home.html
diff --git a/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp b/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp
new file mode 100644
index 000000000..149e3fb79
--- /dev/null
+++ b/devtools/client/webide/test/validator/no-name-or-icon/manifest.webapp
@@ -0,0 +1,3 @@
+{
+ "launch_path": "/home.html"
+}
diff --git a/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp b/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp
new file mode 100644
index 000000000..64744067f
--- /dev/null
+++ b/devtools/client/webide/test/validator/non-absolute-path/manifest.webapp
@@ -0,0 +1,7 @@
+{
+ "name": "non-absolute path",
+ "icons": {
+ "128": "/icon.png"
+ },
+ "launch_path": "non-absolute.html"
+}
diff --git a/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp b/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp
new file mode 100644
index 000000000..20bd97bba
--- /dev/null
+++ b/devtools/client/webide/test/validator/valid/alsoValid/manifest.webapp
@@ -0,0 +1,7 @@
+{
+ "name": "valid at subfolder",
+ "launch_path": "/home.html",
+ "icons": {
+ "128": "/icon.png"
+ }
+}
diff --git a/devtools/client/webide/test/validator/valid/home.html b/devtools/client/webide/test/validator/valid/home.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/validator/valid/home.html
diff --git a/devtools/client/webide/test/validator/valid/icon.png b/devtools/client/webide/test/validator/valid/icon.png
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/validator/valid/icon.png
diff --git a/devtools/client/webide/test/validator/valid/manifest.webapp b/devtools/client/webide/test/validator/valid/manifest.webapp
new file mode 100644
index 000000000..2c22a1567
--- /dev/null
+++ b/devtools/client/webide/test/validator/valid/manifest.webapp
@@ -0,0 +1,7 @@
+{
+ "name": "valid",
+ "launch_path": "/home.html",
+ "icons": {
+ "128": "/icon.png"
+ }
+}
diff --git a/devtools/client/webide/test/validator/wrong-launch-path/icon.png b/devtools/client/webide/test/validator/wrong-launch-path/icon.png
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/devtools/client/webide/test/validator/wrong-launch-path/icon.png
diff --git a/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp b/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp
new file mode 100644
index 000000000..08057bae1
--- /dev/null
+++ b/devtools/client/webide/test/validator/wrong-launch-path/manifest.webapp
@@ -0,0 +1,7 @@
+{
+ "name": "valid",
+ "launch_path": "/wrong-path.html",
+ "icons": {
+ "128": "/icon.png"
+ }
+}