summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/webextensions/test/browser
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/webextensions/test/browser')
-rw-r--r--toolkit/mozapps/webextensions/test/browser/.eslintrc.js7
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addon_about.xul6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addon_prefs.xul6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpibin0 -> 4426 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpibin0 -> 4425 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpibin0 -> 4427 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpibin0 -> 4425 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpibin0 -> 4432 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpibin0 -> 4427 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpibin0 -> 4424 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpibin0 -> 4424 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpibin0 -> 4427 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpibin0 -> 4421 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpibin0 -> 4425 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpibin0 -> 4427 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpibin0 -> 4449 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpibin0 -> 4440 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpibin0 -> 4424 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpibin0 -> 4420 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpibin0 -> 4328 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1/install.rdf16
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpibin0 -> 5811 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/bootstrap.js8
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/chrome.manifest1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/install.rdf27
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/options.xul23
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/settings.dtd1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpibin0 -> 6155 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml19
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js8
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest2
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf27
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/options.xul5
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpibin0 -> 5279 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js8
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/install.rdf28
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/options.xul19
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpibin0 -> 4489 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1/install.rdf32
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpibin0 -> 4415 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpibin0 -> 4430 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_installssl/install.rdf30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpibin0 -> 4808 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_searching/bootstrap.js9
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_searching/install.rdf25
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpibin0 -> 5479 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/bootstrap.js12
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/chrome.manifest1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/frame-script.js6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpibin0 -> 5481 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/bootstrap.js12
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/chrome.manifest1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/frame-script.js6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/install.rdf31
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpibin0 -> 4782 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/bootstrap.js9
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/install.rdf29
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpibin0 -> 4560 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/options_signed/manifest.json11
-rw-r--r--toolkit/mozapps/webextensions/test/browser/addons/options_signed/options.html9
-rw-r--r--toolkit/mozapps/webextensions/test/browser/blockNoPlugins.xml7
-rw-r--r--toolkit/mozapps/webextensions/test/browser/blockPluginHard.xml11
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser-common.ini67
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser-window.ini52
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser.ini75
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_CTP_plugins.js172
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_about.js84
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_addonrepository_performance.js99
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug523784.js120
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557943.js80
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557956.js524
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557956.rdf310
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557956.xml20
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpibin0 -> 4438 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpibin0 -> 4426 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug562797.js975
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug562854.js129
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug562890.js78
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug562899.js88
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug562992.js70
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug567127.js136
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug567137.js40
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug570760.js44
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug572561.js99
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug573062.js116
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug577990.js132
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug580298.js98
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug581076.js132
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug586574.js286
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug587970.js180
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug590347.js121
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug591465.js512
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug591465.xml35
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug591663.js161
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug593535.js119
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug593535.xml34
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug596336.js156
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug608316.js65
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug610764.js34
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug616841.js21
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug618502.js44
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug679604.js29
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_bug714593.js140
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_cancelCompatCheck.js462
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_checkAddonCompatibility.js34
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_details.js1053
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_discovery.js651
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_discovery_install.js133
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_dragdrop.js234
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_eula.js85
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_eula.xml35
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_experiments.js654
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_globalwarnings.js63
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_gmpProvider.js418
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_hotfix.js171
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_inlinesettings.js680
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_browser.js207
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_custom.js92
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_info.js574
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_install.js312
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_install.rdf27
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_install.rdf^headers^1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_install.xml34
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpibin0 -> 4419 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_installssl.js374
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_list.js956
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_manualupdates.js246
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_metadataTimeout.js114
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_newaddon.js232
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_openDialog.js173
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_plugin_enabled_state_locked.js124
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_pluginprefs.js61
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_purchase.js197
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_purchase.xml180
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_recentupdates.js125
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_searching.js698
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_searching.xml277
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_searching_empty.xml3
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_sorting.js372
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_sorting_plugins.js95
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_system_addons_are_e10s.js13
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_tabsettings.js100
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_task_next_test.js17
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_types.js473
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_uninstalling.js1098
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_update.js53
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_updateid.js84
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_updatessl.js370
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf25
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf^headers^1
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi.js106
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi_access.js127
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi_addon_listener.js174
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi_enable.js62
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi_install.js311
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webapi_uninstall.js51
-rw-r--r--toolkit/mozapps/webextensions/test/browser/browser_webext_options.js70
-rw-r--r--toolkit/mozapps/webextensions/test/browser/cancelCompatCheck.sjs43
-rw-r--r--toolkit/mozapps/webextensions/test/browser/discovery.html10
-rw-r--r--toolkit/mozapps/webextensions/test/browser/discovery_frame.html6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/discovery_install.html19
-rw-r--r--toolkit/mozapps/webextensions/test/browser/head.js1468
-rw-r--r--toolkit/mozapps/webextensions/test/browser/more_options.xul32
-rw-r--r--toolkit/mozapps/webextensions/test/browser/moz.build10
-rw-r--r--toolkit/mozapps/webextensions/test/browser/options.xul12
-rw-r--r--toolkit/mozapps/webextensions/test/browser/plugin_test.html7
-rw-r--r--toolkit/mozapps/webextensions/test/browser/redirect.sjs5
-rw-r--r--toolkit/mozapps/webextensions/test/browser/releaseNotes.xhtml15
-rw-r--r--toolkit/mozapps/webextensions/test/browser/signed_hotfix.rdf26
-rw-r--r--toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpibin0 -> 2745 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.rdf26
-rw-r--r--toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpibin0 -> 560 bytes
-rw-r--r--toolkit/mozapps/webextensions/test/browser/webapi_addon_listener.html30
-rw-r--r--toolkit/mozapps/webextensions/test/browser/webapi_checkavailable.html13
-rw-r--r--toolkit/mozapps/webextensions/test/browser/webapi_checkchromeframe.xul6
-rw-r--r--toolkit/mozapps/webextensions/test/browser/webapi_checkframed.html7
-rw-r--r--toolkit/mozapps/webextensions/test/browser/webapi_checknavigatedwindow.html28
196 files changed, 21728 insertions, 0 deletions
diff --git a/toolkit/mozapps/webextensions/test/browser/.eslintrc.js b/toolkit/mozapps/webextensions/test/browser/.eslintrc.js
new file mode 100644
index 000000000..2852eb81d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = { // eslint-disable-line no-undef
+ "extends": [
+ "../../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/toolkit/mozapps/webextensions/test/browser/addon_about.xul b/toolkit/mozapps/webextensions/test/browser/addon_about.xul
new file mode 100644
index 000000000..c2b8b935e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addon_about.xul
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ id="addon-test-about-window">
+ <label value="Oh hai!"/>
+</window>
diff --git a/toolkit/mozapps/webextensions/test/browser/addon_prefs.xul b/toolkit/mozapps/webextensions/test/browser/addon_prefs.xul
new file mode 100644
index 000000000..85cfe6b2d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addon_prefs.xul
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ id="addon-test-pref-window">
+ <label value="Oh hai!"/>
+</window>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpi
new file mode 100644
index 000000000..d13e5d66e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1/install.rdf
new file mode 100644
index 000000000..5199c2f3f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon1</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpi
new file mode 100644
index 000000000..e1d6ac586
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10/install.rdf
new file mode 100644
index 000000000..c061814b6
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-10@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon10</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpi
new file mode 100644
index 000000000..1380e7b5b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2/install.rdf
new file mode 100644
index 000000000..1be5422b2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-2@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon2</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpi
new file mode 100644
index 000000000..46326b04c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3/install.rdf
new file mode 100644
index 000000000..54887a30e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-3@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon3</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpi
new file mode 100644
index 000000000..95de79b79
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4/install.rdf
new file mode 100644
index 000000000..79946b0f0
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-4@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>1.0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>1</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon4</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpi
new file mode 100644
index 000000000..005d7ef21
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5/install.rdf
new file mode 100644
index 000000000..067af1ba1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-5@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon5</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpi
new file mode 100644
index 000000000..89f751a03
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6/install.rdf
new file mode 100644
index 000000000..37d7e6a7c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-6@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon6</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpi
new file mode 100644
index 000000000..77de37c2a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7/install.rdf
new file mode 100644
index 000000000..461facbb2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-7@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon7</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpi
new file mode 100644
index 000000000..666ae0910
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1/install.rdf
new file mode 100644
index 000000000..2111b9c64
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-8@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon8</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpi
new file mode 100644
index 000000000..ad9367dc1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1/install.rdf
new file mode 100644
index 000000000..032e9adaf
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug557956-9@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>0.3</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Addon9</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpi
new file mode 100644
index 000000000..20ae35539
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1/install.rdf
new file mode 100644
index 000000000..d9f0ca745
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug567127_1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>browser_bug567127 #1</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpi
new file mode 100644
index 000000000..3c99022cf
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2/install.rdf
new file mode 100644
index 000000000..8809ffb58
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug567127_2@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>browser_bug567127 #2</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpi
new file mode 100644
index 000000000..c438cbd0b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1/install.rdf
new file mode 100644
index 000000000..c768d7881
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug596336-1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Bootstrap upgrade test</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpi
new file mode 100644
index 000000000..a87191efe
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2/install.rdf
new file mode 100644
index 000000000..bed489c3e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>bug596336-1@tests.mozilla.org</em:id>
+ <em:version>2.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Bootstrap upgrade test</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpi
new file mode 100644
index 000000000..d8b4d083c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1/install.rdf
new file mode 100644
index 000000000..9bcd43e87
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>dragdrop1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Drag Drop test 1</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpi
new file mode 100644
index 000000000..e4441cb19
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2/install.rdf
new file mode 100644
index 000000000..4789abfaf
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>dragdrop2@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Drag Drop test 2</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpi
new file mode 100644
index 000000000..1c2b793f1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1/install.rdf
new file mode 100644
index 000000000..92f20a4ef
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1/install.rdf
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>test-experiment1@experiments.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:type>128</em:type>
+
+ <!-- Front End MetaData -->
+ <em:name>Test Experiment 1</em:name>
+ <em:description>Test Description</em:description>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpi
new file mode 100644
index 000000000..be453ce9c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/bootstrap.js
new file mode 100644
index 000000000..7871af738
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/bootstrap.js
@@ -0,0 +1,8 @@
+function install (params, aReason) {
+}
+function uninstall (params, aReason) {
+}
+function startup (params, aReason) {
+}
+function shutdown (params, aReason) {
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/chrome.manifest b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/chrome.manifest
new file mode 100644
index 000000000..8884e3974
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/chrome.manifest
@@ -0,0 +1 @@
+locale inlinesettings en-US ./
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/install.rdf
new file mode 100644
index 000000000..18fcec167
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/install.rdf
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>inlinesettings1@tests.mozilla.org</em:id>
+ <em:name>Inline Settings (Bootstrap)</em:name>
+ <em:version>1</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/options.xul b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/options.xul
new file mode 100644
index 000000000..cd4f72387
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/options.xul
@@ -0,0 +1,23 @@
+<?xml version="1.0" ?>
+
+<!DOCTYPE vbox SYSTEM "chrome://inlinesettings/locale/settings.dtd">
+
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting pref="extensions.inlinesettings1.bool" type="bool" title="Bool" checkboxlabel="&checkbox;"/>
+ <setting pref="extensions.inlinesettings1.boolint" type="boolint" on="1" off="2" title="BoolInt"/>
+ <setting pref="extensions.inlinesettings1.integer" type="integer" title="Integer"/>
+ <setting pref="extensions.inlinesettings1.string" type="string" title="String"/>
+ <setting type="control" title="Menulist">
+ <menulist sizetopopup="always" oncommand="window._testValue = this.value;">
+ <menupopup>
+ <menuitem label="Alpha" value="1" />
+ <menuitem label="Bravo" value="2" />
+ <menuitem label="Charlie" value="3" />
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting pref="extensions.inlinesettings1.color" type="color" title="Color"/>
+ <setting pref="extensions.inlinesettings1.file" type="file" title="File"/>
+ <setting pref="extensions.inlinesettings1.directory" type="directory" title="Directory"/>
+ <setting pref="extensions.inlinesettings1.integer-size" type="integer" title="Integer with size" size="1" />
+</vbox>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/settings.dtd b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/settings.dtd
new file mode 100644
index 000000000..6864a3d5a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1/settings.dtd
@@ -0,0 +1 @@
+<!ENTITY checkbox "Check box label">
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpi
new file mode 100644
index 000000000..6e937c5cc
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml
new file mode 100644
index 000000000..6ac72a03c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/binding.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<bindings xmlns="http://www.mozilla.org/xbl"
+ xmlns:xbl="http://www.mozilla.org/xbl"
+ xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <binding id="custom"
+ extends="chrome://mozapps/content/extensions/setting.xml#setting-base">
+ <content>
+ <xul:vbox>
+ <xul:hbox class="preferences-alignment">
+ <xul:label anonid="label" class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/>
+ </xul:hbox>
+ <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/>
+ </xul:vbox>
+ <xul:hbox class="preferences-alignment">
+ <xul:label anonid="input" value="Woah!"/>
+ </xul:hbox>
+ </content>
+ </binding>
+</bindings>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js
new file mode 100644
index 000000000..7871af738
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/bootstrap.js
@@ -0,0 +1,8 @@
+function install (params, aReason) {
+}
+function uninstall (params, aReason) {
+}
+function startup (params, aReason) {
+}
+function shutdown (params, aReason) {
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest
new file mode 100644
index 000000000..f1eaef1d0
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/chrome.manifest
@@ -0,0 +1,2 @@
+content inlinesettings ./ contentaccessible=yes
+locale inlinesettings en-US ./
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf
new file mode 100644
index 000000000..a04046a74
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/install.rdf
@@ -0,0 +1,27 @@
+<?xml version="1.0" ?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>inlinesettings1@tests.mozilla.org</em:id>
+ <em:name>Inline Settings (Bootstrap)</em:name>
+ <em:version>2</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/options.xul b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/options.xul
new file mode 100644
index 000000000..148fb9856
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/options.xul
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<!DOCTYPE vbox SYSTEM "chrome://inlinesettings/locale/string.dtd">
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting type="custom" title="&custom.title;" style="background-color: blue; display: -moz-grid-line; -moz-binding: url('chrome://inlinesettings/content/binding.xml#custom');"/>
+</vbox>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd
new file mode 100644
index 000000000..0b2dcc8fe
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom/string.dtd
@@ -0,0 +1 @@
+<!ENTITY custom.title "Custom">
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpi
new file mode 100644
index 000000000..4c939c05b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js
new file mode 100644
index 000000000..7871af738
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/bootstrap.js
@@ -0,0 +1,8 @@
+function install (params, aReason) {
+}
+function uninstall (params, aReason) {
+}
+function startup (params, aReason) {
+}
+function shutdown (params, aReason) {
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/install.rdf
new file mode 100644
index 000000000..ba90bd57b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/install.rdf
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>inlinesettings1@tests.mozilla.org</em:id>
+ <em:name>Inline Settings (Bootstrap)</em:name>
+ <em:version>3</em:version>
+ <em:bootstrap>true</em:bootstrap>
+ <em:optionsType>4</em:optionsType>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/options.xul b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/options.xul
new file mode 100644
index 000000000..095d3bcef
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info/options.xul
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting pref="extensions.inlinesettings1.bool" type="bool" title="Bool" checkboxlabel="Check box label"/>
+ <setting pref="extensions.inlinesettings1.boolint" type="boolint" on="1" off="2" title="BoolInt"/>
+ <setting pref="extensions.inlinesettings1.integer" type="integer" title="Integer"/>
+ <setting pref="extensions.inlinesettings1.string" type="string" title="String"/>
+ <setting type="control" title="Menulist">
+ <menulist sizetopopup="always" oncommand="window._testValue = this.value;">
+ <menupopup>
+ <menuitem label="Alpha" value="1" />
+ <menuitem label="Bravo" value="2" />
+ <menuitem label="Charlie" value="3" />
+ </menupopup>
+ </menulist>
+ </setting>
+ <setting pref="extensions.inlinesettings1.color" type="color" title="Color"/>
+ <setting pref="extensions.inlinesettings1.file" type="file" title="File"/>
+ <setting pref="extensions.inlinesettings1.directory" type="directory" title="Directory"/>
+</vbox>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpi
new file mode 100644
index 000000000..d6df8f9d0
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1/install.rdf
new file mode 100644
index 000000000..b11b6d7e4
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1/install.rdf
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>install1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+ <em:updateURL>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_install.rdf</em:updateURL>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Install Tests</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpi
new file mode 100644
index 000000000..5468e6cb0
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2/install.rdf
new file mode 100644
index 000000000..81898b24d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>install1@tests.mozilla.org</em:id>
+ <em:version>2.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Install Tests</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpi
new file mode 100644
index 000000000..999535a97
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl/install.rdf
new file mode 100644
index 000000000..7ce6cd09a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl/install.rdf
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>sslinstall@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>SSL Install Tests</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpi
new file mode 100644
index 000000000..efef815aa
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/bootstrap.js
new file mode 100644
index 000000000..7b86e419a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/bootstrap.js
@@ -0,0 +1,9 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function install(data, reason) {}
+function startup(data, reason) {}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
+
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/install.rdf
new file mode 100644
index 000000000..02cc935ea
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching/install.rdf
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>remote1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:type>2</em:type>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>PASS - b - installed</em:name>
+ <em:description>Test sumary - SEARCH SEARCH</em:description>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpi
new file mode 100644
index 000000000..956812aaa
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/bootstrap.js
new file mode 100644
index 000000000..ff5b80ae8
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/bootstrap.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function install(data, reason) {}
+function startup(data, reason) {
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.ppmm.loadProcessScript(
+ "resource://my-addon/frame-script.js", false);
+}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/chrome.manifest b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/chrome.manifest
new file mode 100644
index 000000000..f1a7ccee1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/chrome.manifest
@@ -0,0 +1 @@
+resource my-addon .
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/frame-script.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/frame-script.js
new file mode 100644
index 000000000..f4674b840
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/frame-script.js
@@ -0,0 +1,6 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Services.cpmm.sendAsyncMessage("my-addon-1");
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/install.rdf
new file mode 100644
index 000000000..c52307b4a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>update1@tests.mozilla.org</em:id>
+ <em:version>1.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Update Tests</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpi
new file mode 100644
index 000000000..7ef3db940
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/bootstrap.js
new file mode 100644
index 000000000..ff5b80ae8
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/bootstrap.js
@@ -0,0 +1,12 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function install(data, reason) {}
+function startup(data, reason) {
+ Components.utils.import("resource://gre/modules/Services.jsm");
+ Services.ppmm.loadProcessScript(
+ "resource://my-addon/frame-script.js", false);
+}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/chrome.manifest b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/chrome.manifest
new file mode 100644
index 000000000..f1a7ccee1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/chrome.manifest
@@ -0,0 +1 @@
+resource my-addon .
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/frame-script.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/frame-script.js
new file mode 100644
index 000000000..e35092a55
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/frame-script.js
@@ -0,0 +1,6 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Services.cpmm.sendAsyncMessage("my-addon-2");
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/install.rdf
new file mode 100644
index 000000000..2fae190b4
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2/install.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>update1@tests.mozilla.org</em:id>
+ <em:version>2.0</em:version>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Update Tests</em:name>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpi b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpi
new file mode 100644
index 000000000..4fa7b8bfa
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/bootstrap.js b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/bootstrap.js
new file mode 100644
index 000000000..bd11077c2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/bootstrap.js
@@ -0,0 +1,9 @@
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+function startup(data, reason) {
+ Services.prefs.setIntPref("webapitest.active_version", 1);
+}
+
+function shutdown(data, reason) {
+ Services.prefs.setIntPref("webapitest.active_version", 0);
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/install.rdf b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/install.rdf
new file mode 100644
index 000000000..2cae124e1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install/install.rdf
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>webapi_install@tests.mozilla.org</em:id>
+ <em:version>1.1</em:version>
+ <em:name>AddonManger web API test</em:name>
+ <em:bootstrap>true</em:bootstrap>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0.3</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ </Description>
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpi b/toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpi
new file mode 100644
index 000000000..a063fd1c4
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/options_signed/manifest.json b/toolkit/mozapps/webextensions/test/browser/addons/options_signed/manifest.json
new file mode 100644
index 000000000..e808cd5ab
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/options_signed/manifest.json
@@ -0,0 +1,11 @@
+{
+ "manifest_version": 2,
+
+ "name": "Test options_ui",
+ "description": "Test add-ons manager handling options_ui with no id in manifest.json",
+ "version": "1.2",
+
+ "options_ui": {
+ "page": "options.html"
+ }
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/addons/options_signed/options.html b/toolkit/mozapps/webextensions/test/browser/addons/options_signed/options.html
new file mode 100644
index 000000000..ea804601b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/addons/options_signed/options.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ </head>
+ <body>
+ <div id="options-test-panel" />
+ </body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/blockNoPlugins.xml b/toolkit/mozapps/webextensions/test/browser/blockNoPlugins.xml
new file mode 100644
index 000000000..e4e191b37
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/blockNoPlugins.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310001">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ </pluginItems>
+</blocklist>
diff --git a/toolkit/mozapps/webextensions/test/browser/blockPluginHard.xml b/toolkit/mozapps/webextensions/test/browser/blockPluginHard.xml
new file mode 100644
index 000000000..24eb5bc6f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/blockPluginHard.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1336406310000">
+ <emItems>
+ </emItems>
+ <pluginItems>
+ <pluginItem blockID="p9999">
+ <match name="filename" exp="libnptest\.so|nptest\.dll|Test\.plugin" />
+ <versionRange severity="2"></versionRange>
+ </pluginItem>
+ </pluginItems>
+</blocklist>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser-common.ini b/toolkit/mozapps/webextensions/test/browser/browser-common.ini
new file mode 100644
index 000000000..eda266e2f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser-common.ini
@@ -0,0 +1,67 @@
+[browser_about.js]
+skip-if = os == 'linux' || os == 'win' # bug 632290
+[browser_bug523784.js]
+[browser_bug557943.js]
+[browser_bug562797.js]
+[browser_bug562854.js]
+[browser_bug562890.js]
+skip-if = os == 'win' && !debug # Disabled on Windows opt/PGO builds due to intermittent failures (bug 1135866)
+[browser_bug562899.js]
+skip-if = buildapp == 'mulet'
+[browser_bug562992.js]
+[browser_bug567127.js]
+[browser_bug567137.js]
+[browser_bug570760.js]
+[browser_bug572561.js]
+[browser_bug573062.js]
+[browser_bug577990.js]
+[browser_bug580298.js]
+[browser_bug581076.js]
+[browser_bug586574.js]
+[browser_bug587970.js]
+[browser_bug591465.js]
+[browser_bug591663.js]
+[browser_bug593535.js]
+skip-if = true # Bug 1093190 - Disabled due to leak
+[browser_bug596336.js]
+[browser_bug608316.js]
+[browser_bug610764.js]
+[browser_bug618502.js]
+[browser_bug679604.js]
+[browser_bug714593.js]
+[browser_bug590347.js]
+[browser_details.js]
+[browser_discovery.js]
+[browser_dragdrop.js]
+skip-if = buildapp == 'mulet'
+[browser_experiments.js]
+[browser_list.js]
+[browser_metadataTimeout.js]
+[browser_searching.js]
+[browser_sorting.js]
+[browser_sorting_plugins.js]
+[browser_plugin_enabled_state_locked.js]
+[browser_uninstalling.js]
+[browser_install.js]
+[browser_recentupdates.js]
+[browser_manualupdates.js]
+[browser_globalwarnings.js]
+[browser_eula.js]
+skip-if = buildapp == 'mulet'
+[browser_updateid.js]
+[browser_purchase.js]
+[browser_openDialog.js]
+tags = openwindow
+skip-if = os == 'win' # Disabled on Windows due to intermittent failures (bug 1135866)
+[browser_types.js]
+[browser_inlinesettings.js]
+[browser_inlinesettings_browser.js]
+[browser_inlinesettings_custom.js]
+[browser_inlinesettings_info.js]
+[browser_tabsettings.js]
+[browser_pluginprefs.js]
+skip-if = buildapp == 'mulet'
+[browser_CTP_plugins.js]
+skip-if = buildapp == 'mulet'
+[browser_webext_options.js]
+tags = webextensions
diff --git a/toolkit/mozapps/webextensions/test/browser/browser-window.ini b/toolkit/mozapps/webextensions/test/browser/browser-window.ini
new file mode 100644
index 000000000..fcda90fc6
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser-window.ini
@@ -0,0 +1,52 @@
+[DEFAULT]
+install-to-subdir = test-window
+support-files =
+ addons/*
+ addon_about.xul
+ addon_prefs.xul
+ cancelCompatCheck.sjs
+ discovery.html
+ discovery_frame.html
+ discovery_install.html
+ head.js
+ signed_hotfix.rdf
+ signed_hotfix.xpi
+ unsigned_hotfix.rdf
+ unsigned_hotfix.xpi
+ more_options.xul
+ options.xul
+ plugin_test.html
+ redirect.sjs
+ releaseNotes.xhtml
+ blockNoPlugins.xml
+ blockPluginHard.xml
+ browser_bug557956.rdf
+ browser_bug557956_8_2.xpi
+ browser_bug557956_9_2.xpi
+ browser_bug557956.xml
+ browser_bug591465.xml
+ browser_bug593535.xml
+ browser_searching.xml
+ browser_searching_empty.xml
+ browser_updatessl.rdf
+ browser_updatessl.rdf^headers^
+ browser_install.rdf
+ browser_install.rdf^headers^
+ browser_install.xml
+ browser_install1_3.xpi
+ browser_eula.xml
+ browser_purchase.xml
+ webapi_addon_listener.html
+ webapi_checkavailable.html
+ webapi_checkchromeframe.xul
+ webapi_checkframed.html
+ webapi_checknavigatedwindow.html
+ !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
+ !/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/theme.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
+
+[include:browser-common.ini]
diff --git a/toolkit/mozapps/webextensions/test/browser/browser.ini b/toolkit/mozapps/webextensions/test/browser/browser.ini
new file mode 100644
index 000000000..a23841d33
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser.ini
@@ -0,0 +1,75 @@
+[DEFAULT]
+tags = addons
+support-files =
+ addons/*
+ addon_about.xul
+ addon_prefs.xul
+ cancelCompatCheck.sjs
+ discovery.html
+ discovery_frame.html
+ discovery_install.html
+ head.js
+ signed_hotfix.rdf
+ signed_hotfix.xpi
+ unsigned_hotfix.rdf
+ unsigned_hotfix.xpi
+ more_options.xul
+ options.xul
+ plugin_test.html
+ redirect.sjs
+ releaseNotes.xhtml
+ blockNoPlugins.xml
+ blockPluginHard.xml
+ browser_bug557956.rdf
+ browser_bug557956_8_2.xpi
+ browser_bug557956_9_2.xpi
+ browser_bug557956.xml
+ browser_bug591465.xml
+ browser_bug593535.xml
+ browser_searching.xml
+ browser_searching_empty.xml
+ browser_updatessl.rdf
+ browser_updatessl.rdf^headers^
+ browser_install.rdf
+ browser_install.rdf^headers^
+ browser_install.xml
+ browser_install1_3.xpi
+ browser_eula.xml
+ browser_purchase.xml
+ webapi_addon_listener.html
+ webapi_checkavailable.html
+ webapi_checkchromeframe.xul
+ webapi_checkframed.html
+ webapi_checknavigatedwindow.html
+ !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
+ !/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/theme.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi
+ !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
+
+[browser_addonrepository_performance.js]
+[browser_bug557956.js]
+[browser_bug616841.js]
+[browser_cancelCompatCheck.js]
+[browser_checkAddonCompatibility.js]
+[browser_gmpProvider.js]
+[browser_hotfix.js]
+# Verifies the old style of signing hotfixes
+skip-if = require_signing
+[browser_installssl.js]
+[browser_newaddon.js]
+[browser_updatessl.js]
+[browser_system_addons_are_e10s.js]
+[browser_task_next_test.js]
+[browser_discovery_install.js]
+[browser_update.js]
+[browser_webapi.js]
+[browser_webapi_access.js]
+[browser_webapi_addon_listener.js]
+[browser_webapi_enable.js]
+[browser_webapi_install.js]
+[browser_webapi_uninstall.js]
+
+[include:browser-common.ini]
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_CTP_plugins.js b/toolkit/mozapps/webextensions/test/browser/browser_CTP_plugins.js
new file mode 100644
index 000000000..dd2992f81
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_CTP_plugins.js
@@ -0,0 +1,172 @@
+const gHttpTestRoot = "http://127.0.0.1:8888/" + RELATIVE_DIR + "/";
+
+function updateBlocklist(aCallback) {
+ var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
+ .getService(Ci.nsITimerCallback);
+ var observer = function() {
+ Services.obs.removeObserver(observer, "blocklist-updated");
+ SimpleTest.executeSoon(aCallback);
+ };
+ Services.obs.addObserver(observer, "blocklist-updated", false);
+ blocklistNotifier.notify(null);
+}
+
+var _originalBlocklistURL = null;
+function setAndUpdateBlocklist(aURL, aCallback) {
+ if (!_originalBlocklistURL) {
+ _originalBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
+ }
+ Services.prefs.setCharPref("extensions.blocklist.url", aURL);
+ updateBlocklist(aCallback);
+}
+
+function resetBlocklist(aCallback) {
+ Services.prefs.setCharPref("extensions.blocklist.url", _originalBlocklistURL);
+}
+
+add_task(function*() {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["plugins.click_to_play", true],
+ ["extensions.blocklist.suppressUI", true]
+ ]});
+ registerCleanupFunction(function*() {
+ let pluginTag = getTestPluginTag();
+ pluginTag.enabledState = Ci.nsIPluginTag.STATE_ENABLED;
+ yield new Promise(resolve => {
+ setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", resolve);
+ });
+ resetBlocklist();
+ });
+
+ let pluginTag = getTestPluginTag();
+ pluginTag.enabledState = Ci.nsIPluginTag.STATE_CLICKTOPLAY;
+ let managerWindow = yield new Promise(resolve => open_manager("addons://list/plugin", resolve));
+
+ let plugins = yield new Promise(resolve => AddonManager.getAddonsByTypes(["plugin"], resolve));
+
+ let testPluginId;
+ for (let plugin of plugins) {
+ if (plugin.name == "Test Plug-in") {
+ testPluginId = plugin.id;
+ break;
+ }
+ }
+ ok(testPluginId, "part2: Test Plug-in should exist");
+
+ let testPlugin = yield new Promise(resolve => AddonManager.getAddonByID(testPluginId, resolve));
+
+ let pluginEl = get_addon_element(managerWindow, testPluginId);
+ pluginEl.parentNode.ensureElementIsVisible(pluginEl);
+ let enableButton = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "enable-btn");
+ is_element_hidden(enableButton, "part3: enable button should not be visible");
+ let disableButton = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "enable-btn");
+ is_element_hidden(disableButton, "part3: disable button should not be visible");
+ let menu = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
+ is_element_visible(menu, "part3: state menu should be visible");
+ let askToActivateItem = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "ask-to-activate-menuitem");
+ is(menu.selectedItem, askToActivateItem, "part3: state menu should have 'Ask To Activate' selected");
+
+ let pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
+ let pluginBrowser = pluginTab.linkedBrowser;
+
+ let condition = () => PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
+ yield BrowserTestUtils.waitForCondition(condition, "part4: should have a click-to-play notification");
+
+ yield BrowserTestUtils.removeTab(pluginTab);
+
+ let alwaysActivateItem = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "always-activate-menuitem");
+ menu.selectedItem = alwaysActivateItem;
+ alwaysActivateItem.doCommand();
+
+ pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
+
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let testPlugin = content.document.getElementById("test");
+ ok(testPlugin, "part5: should have a plugin element in the page");
+ let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let condition = () => objLoadingContent.activated;
+ yield ContentTaskUtils.waitForCondition(condition, "part5: waited too long for plugin to activate");
+ ok(objLoadingContent.activated, "part6: plugin should be activated");
+ });
+
+ yield BrowserTestUtils.removeTab(pluginTab);
+
+ let neverActivateItem = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "never-activate-menuitem");
+ menu.selectedItem = neverActivateItem;
+ neverActivateItem.doCommand();
+
+ pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
+ pluginBrowser = pluginTab.linkedBrowser;
+
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let testPlugin = content.document.getElementById("test");
+ ok(testPlugin, "part7: should have a plugin element in the page");
+ let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ ok(!objLoadingContent.activated, "part7: plugin should not be activated");
+ });
+
+ yield BrowserTestUtils.removeTab(pluginTab);
+
+ let details = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
+ is_element_visible(details, "part7: details link should be visible");
+ EventUtils.synthesizeMouseAtCenter(details, {}, managerWindow);
+ yield BrowserTestUtils.waitForEvent(managerWindow.document, "ViewChanged");
+
+ is_element_hidden(enableButton, "part8: detail enable button should be hidden");
+ is_element_hidden(disableButton, "part8: detail disable button should be hidden");
+ is_element_visible(menu, "part8: detail state menu should be visible");
+ is(menu.selectedItem, neverActivateItem, "part8: state menu should have 'Never Activate' selected");
+
+ menu.selectedItem = alwaysActivateItem;
+ alwaysActivateItem.doCommand();
+
+ pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
+ pluginBrowser = pluginTab.linkedBrowser;
+
+ yield ContentTask.spawn(pluginTab.linkedBrowser, null, function*() {
+ let testPlugin = content.document.getElementById("test");
+ ok(testPlugin, "part9: should have a plugin element in the page");
+ let objLoadingContent = testPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
+ let condition = () => objLoadingContent.activated;
+ yield ContentTaskUtils.waitForCondition(condition, "part9: waited too long for plugin to activate");
+ ok(objLoadingContent.activated, "part10: plugin should be activated");
+ });
+
+ yield BrowserTestUtils.removeTab(pluginTab);
+
+ menu.selectedItem = askToActivateItem;
+ askToActivateItem.doCommand();
+
+ pluginTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, gHttpTestRoot + "plugin_test.html");
+ pluginBrowser = pluginTab.linkedBrowser;
+
+ condition = () => PopupNotifications.getNotification("click-to-play-plugins", pluginBrowser);
+ yield BrowserTestUtils.waitForCondition(condition, "part11: should have a click-to-play notification");
+
+ yield BrowserTestUtils.removeTab(pluginTab);
+
+ // causes appDisabled to be set
+ managerWindow = yield new Promise(resolve => {
+ setAndUpdateBlocklist(gHttpTestRoot + "blockPluginHard.xml",
+ () => {
+ close_manager(managerWindow, function() {
+ open_manager("addons://list/plugin", resolve);
+ });
+ }
+ );
+ });
+
+ pluginEl = get_addon_element(managerWindow, testPluginId);
+ pluginEl.parentNode.ensureElementIsVisible(pluginEl);
+ menu = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
+ is(menu.disabled, true, "part12: state menu should be disabled");
+
+ details = managerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(details, {}, managerWindow);
+ yield BrowserTestUtils.waitForEvent(managerWindow.document, "ViewChanged");
+
+ menu = managerWindow.document.getElementById("detail-state-menulist");
+ is(menu.disabled, true, "part13: detail state menu should be disabled");
+
+ managerWindow.close();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_about.js b/toolkit/mozapps/webextensions/test/browser/browser_about.js
new file mode 100644
index 000000000..f781cf146
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_about.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Tests the default and custom "about" dialogs of add-ons.
+ *
+ * Test for bug 610661 <https://bugzilla.mozilla.org/show_bug.cgi?id=610661>:
+ * Addon object not passed to custom about dialogs.
+ */
+
+var gManagerWindow;
+
+const URI_ABOUT_DEFAULT = "chrome://mozapps/content/extensions/about.xul";
+const URI_ABOUT_CUSTOM = CHROMEROOT + "addon_about.xul";
+
+function test() {
+ requestLongerTimeout(2);
+
+ waitForExplicitFinish();
+
+ var gProvider = new MockProvider();
+ gProvider.createAddons([{
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on 1",
+ description: "foo"
+ },
+ {
+ id: "test2@tests.mozilla.org",
+ name: "Test add-on 2",
+ description: "bar",
+ aboutURL: URI_ABOUT_CUSTOM
+ }]);
+
+ open_manager("addons://list/extension", function(aManager) {
+ gManagerWindow = aManager;
+
+ test_about_window("Test add-on 1", URI_ABOUT_DEFAULT, function() {
+ test_about_window("Test add-on 2", URI_ABOUT_CUSTOM, function() {
+ close_manager(gManagerWindow, finish);
+ });
+ });
+ });
+}
+
+function test_about_window(aAddonItemName, aExpectedAboutUri, aCallback) {
+ var addonList = gManagerWindow.document.getElementById("addon-list");
+ for (var addonItem of addonList.childNodes) {
+ if (addonItem.hasAttribute("name") &&
+ addonItem.getAttribute("name") === aAddonItemName)
+ break;
+ }
+
+ info("Waiting for about dialog");
+ Services.ww.registerNotification(function TEST_ww_observer(aSubject, aTopic,
+ aData) {
+ if (aTopic == "domwindowclosed") {
+ Services.ww.unregisterNotification(TEST_ww_observer);
+
+ info("About dialog closed, waiting for focus on browser window");
+ waitForFocus(() => executeSoon(aCallback));
+ } else if (aTopic == "domwindowopened") {
+ info("About dialog opened, waiting for focus");
+
+ let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
+ waitForFocus(function() {
+ info("Saw about dialog");
+
+ is(win.location,
+ aExpectedAboutUri,
+ "The correct add-on about window should have opened");
+
+ is(win.arguments && win.arguments[0] && win.arguments[0].name,
+ aAddonItemName,
+ "window.arguments[0] should refer to the add-on object");
+
+ executeSoon(() => win.close());
+ }, win);
+ }
+ });
+
+ gManagerWindow.gViewController.doCommand("cmd_showItemAbout",
+ addonItem.mAddon);
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_addonrepository_performance.js b/toolkit/mozapps/webextensions/test/browser/browser_addonrepository_performance.js
new file mode 100644
index 000000000..879d7331e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_addonrepository_performance.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the metadata request includes startup time measurements
+
+var tmp = {};
+Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", tmp);
+var AddonRepository = tmp.AddonRepository;
+
+var gTelemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
+var gManagerWindow;
+var gProvider;
+
+function parseParams(aQuery) {
+ let params = {};
+
+ for (let param of aQuery.split("&")) {
+ let [key, value] = param.split("=");
+ params[key] = value;
+ }
+
+ return params;
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ var gSeenRequest = false;
+
+ gProvider = new MockProvider();
+ gProvider.createAddons([{
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on"
+ }]);
+
+ function observe(aSubject, aTopic, aData) {
+ aSubject.QueryInterface(Ci.nsIChannel);
+ let url = aSubject.URI.QueryInterface(Ci.nsIURL);
+ if (url.filePath != "/extensions-dummy/metadata") {
+ return;
+ }
+ info(url.query);
+
+ // Check if we encountered telemetry errors and turn the tests for which
+ // we don't have valid data into known failures.
+ let snapshot = gTelemetry.getHistogramById("STARTUP_MEASUREMENT_ERRORS")
+ .snapshot();
+
+ let tProcessValid = (snapshot.counts[0] == 0);
+ let tMainValid = tProcessValid && (snapshot.counts[2] == 0);
+ let tFirstPaintValid = tProcessValid && (snapshot.counts[5] == 0);
+ let tSessionRestoredValid = tProcessValid && (snapshot.counts[6] == 0);
+
+ let params = parseParams(url.query);
+
+ is(params.appOS, Services.appinfo.OS, "OS should be correct");
+ is(params.appVersion, Services.appinfo.version, "Version should be correct");
+
+ if (tMainValid) {
+ ok(params.tMain >= 0, "Should be a sensible tMain");
+ } else {
+ todo(false, "An error occurred while recording the startup timestamps, skipping this test");
+ }
+
+ if (tFirstPaintValid) {
+ ok(params.tFirstPaint >= 0, "Should be a sensible tFirstPaint");
+ } else {
+ todo(false, "An error occurred while recording the startup timestamps, skipping this test");
+ }
+
+ if (tSessionRestoredValid) {
+ ok(params.tSessionRestored >= 0, "Should be a sensible tSessionRestored");
+ } else {
+ todo(false, "An error occurred while recording the startup timestamps, skipping this test");
+ }
+
+ gSeenRequest = true;
+ }
+
+ const PREF = "extensions.getAddons.getWithPerformance.url";
+
+ // Watch HTTP requests
+ Services.obs.addObserver(observe, "http-on-modify-request", false);
+ Services.prefs.setCharPref(PREF,
+ "http://127.0.0.1:8888/extensions-dummy/metadata?appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
+
+ registerCleanupFunction(function() {
+ Services.obs.removeObserver(observe, "http-on-modify-request");
+ });
+
+ AddonRepository._beginGetAddons(["test1@tests.mozilla.org"], {
+ searchFailed: function() {
+ ok(gSeenRequest, "Should have seen metadata request");
+ finish();
+ }
+ }, true);
+}
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug523784.js b/toolkit/mozapps/webextensions/test/browser/browser_bug523784.js
new file mode 100644
index 000000000..e61fafd6b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug523784.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const URI_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
+
+// This tests that the blocklist dialog still affects soft-blocked add-ons
+// if the user clicks the "Restart Later" button. It also ensures that the
+// "Cancel" button is correctly renamed (to "Restart Later").
+var args = {
+ restart: false,
+ list: [{
+ name: "Bug 523784 softblocked addon",
+ version: "1",
+ icon: "chrome://mozapps/skin/plugins/pluginGeneric.png",
+ disable: false,
+ blocked: false,
+ url: 'http://example.com/bug523784_1',
+ }],
+};
+
+function test() {
+ waitForExplicitFinish();
+
+ let windowObserver = function(aSubject, aTopic, aData) {
+ if (aTopic != "domwindowopened")
+ return;
+
+ Services.ww.unregisterNotification(windowObserver);
+
+ let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
+ win.addEventListener("load", function() {
+ win.removeEventListener("load", arguments.callee, false);
+
+ executeSoon(() => bug523784_test1(win));
+ }, false);
+ };
+ Services.ww.registerNotification(windowObserver);
+
+ args.wrappedJSObject = args;
+ Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
+ "chrome,centerscreen,dialog,titlebar", args);
+}
+
+function bug523784_test1(win) {
+ let bundle = Services.strings.
+ createBundle("chrome://mozapps/locale/update/updates.properties");
+ let cancelButton = win.document.documentElement.getButton("cancel");
+ let moreInfoLink = win.document.getElementById("moreInfo");
+
+ is(cancelButton.getAttribute("label"),
+ bundle.GetStringFromName("restartLaterButton"),
+ "Text should be changed on Cancel button");
+ is(cancelButton.getAttribute("accesskey"),
+ bundle.GetStringFromName("restartLaterButton.accesskey"),
+ "Accesskey should also be changed on Cancel button");
+ is(moreInfoLink.getAttribute("href"),
+ 'http://example.com/bug523784_1',
+ "More Info link should link to a detailed blocklist page.");
+ let windowObserver = function(aSubject, aTopic, aData) {
+ if (aTopic != "domwindowclosed")
+ return;
+
+ Services.ww.unregisterNotification(windowObserver);
+
+ ok(args.list[0].disable, "Should be blocking add-on");
+ ok(!args.restart, "Should not restart browser immediately");
+
+ executeSoon(bug523784_test2);
+ };
+ Services.ww.registerNotification(windowObserver);
+
+ cancelButton.doCommand();
+}
+
+function bug523784_test2(win) {
+ let windowObserver = function(aSubject, aTopic, aData) {
+ if (aTopic != "domwindowopened")
+ return;
+
+ Services.ww.unregisterNotification(windowObserver);
+ let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
+ win.addEventListener("load", function() {
+ win.removeEventListener("load", arguments.callee, false);
+
+ executeSoon(function() {
+ let moreInfoLink = win.document.getElementById("moreInfo");
+ let cancelButton = win.document.documentElement.getButton("cancel");
+ is(moreInfoLink.getAttribute("href"),
+ Services.urlFormatter.formatURLPref("extensions.blocklist.detailsURL"),
+ "More Info link should link to the general blocklist page.");
+ cancelButton.doCommand();
+ executeSoon(finish);
+ })
+ }, false);
+ };
+ Services.ww.registerNotification(windowObserver);
+
+ // Add 2 more addons to the blocked list to check that the more info link
+ // points to the general blocked list page.
+ args.list.push({
+ name: "Bug 523784 softblocked addon 2",
+ version: "2",
+ icon: "chrome://mozapps/skin/plugins/pluginGeneric.png",
+ disable: false,
+ blocked: false,
+ url: 'http://example.com/bug523784_2'
+ });
+ args.list.push({
+ name: "Bug 523784 softblocked addon 3",
+ version: "4",
+ icon: "chrome://mozapps/skin/plugins/pluginGeneric.png",
+ disable: false,
+ blocked: false,
+ url: 'http://example.com/bug523784_3'
+ });
+
+ args.wrappedJSObject = args;
+ Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
+ "chrome,centerscreen,dialog,titlebar", args);
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557943.js b/toolkit/mozapps/webextensions/test/browser/browser_bug557943.js
new file mode 100644
index 000000000..94a8b6f49
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557943.js
@@ -0,0 +1,80 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 557943 - Searching for addons can result in wrong results
+
+var gManagerWindow;
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Microsoft .NET Framework Assistant",
+ description: "",
+ version: "6.66"
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "AwesomeNet Addon",
+ description: ""
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "Dictionnaire MySpell en Francais (réforme 1990)",
+ description: ""
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+
+function perform_search(aQuery, aCallback) {
+ waitForFocus(function() {
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = aQuery;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+ aCallback(rows);
+ });
+ }, gManagerWindow);
+}
+
+
+add_test(function() {
+ perform_search(".net", function(aRows) {
+ is(aRows.length, 1, "Should only get one result");
+ is(aRows[0].mAddon.id, "addon1@tests.mozilla.org", "Should get expected addon as only result");
+ run_next_test();
+ });
+});
+
+add_test(function() {
+ perform_search("réf", function(aRows) {
+ is(aRows.length, 1, "Should only get one result");
+ is(aRows[0].mAddon.id, "addon3@tests.mozilla.org", "Should get expected addon as only result");
+ run_next_test();
+ });
+});
+
+add_test(function() {
+ perform_search("javascript:void()", function(aRows) {
+ is(aRows.length, 0, "Should not get any results");
+ run_next_test();
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956.js b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.js
new file mode 100644
index 000000000..136e7cb74
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.js
@@ -0,0 +1,524 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test the compatibility dialog that displays during startup when the browser
+// version changes.
+
+const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul";
+
+const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
+const PREF_MIN_APP_COMPAT = "extensions.minCompatibleAppVersion";
+const PREF_MIN_PLATFORM_COMPAT = "extensions.minCompatiblePlatformVersion";
+
+Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+// avoid the 'leaked window property' check
+var scope = {};
+Components.utils.import("resource://gre/modules/TelemetrySession.jsm", scope);
+var TelemetrySession = scope.TelemetrySession;
+
+/**
+ * Test add-ons:
+ *
+ * Addon minVersion maxVersion Notes
+ * addon1 0 *
+ * addon2 0 0
+ * addon3 0 0
+ * addon4 1 *
+ * addon5 0 0 Made compatible by update check
+ * addon6 0 0 Made compatible by update check
+ * addon7 0 0 Has a broken update available
+ * addon8 0 0 Has an update available
+ * addon9 0 0 Has an update available
+ */
+
+function test() {
+ requestLongerTimeout(2);
+ waitForExplicitFinish();
+
+ run_next_test();
+}
+
+function end_test() {
+ // Test generates a lot of available installs so just cancel them all
+ AddonManager.getAllInstalls(function(aInstalls) {
+ for (let install of aInstalls)
+ install.cancel();
+
+ Services.prefs.clearUserPref(PREF_MIN_APP_COMPAT);
+ Services.prefs.clearUserPref(PREF_MIN_PLATFORM_COMPAT);
+
+ finish();
+ });
+}
+
+function install_test_addons(aCallback) {
+ var installs = [];
+
+ // Use a blank update URL
+ Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
+
+ let names = ["browser_bug557956_1",
+ "browser_bug557956_2",
+ "browser_bug557956_3",
+ "browser_bug557956_4",
+ "browser_bug557956_5",
+ "browser_bug557956_6",
+ "browser_bug557956_7",
+ "browser_bug557956_8_1",
+ "browser_bug557956_9_1",
+ "browser_bug557956_10"];
+ for (let name of names) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/" + name + ".xpi", function(aInstall) {
+ installs.push(aInstall);
+ }, "application/x-xpinstall");
+ }
+
+ var listener = {
+ installCount: 0,
+
+ onInstallEnded: function() {
+ this.installCount++;
+ if (this.installCount == installs.length) {
+ // Switch to the test update URL
+ Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "browser_bug557956.rdf");
+
+ executeSoon(aCallback);
+ }
+ }
+ };
+
+ for (let install of installs) {
+ install.addListener(listener);
+ install.install();
+ }
+}
+
+function uninstall_test_addons(aCallback) {
+ AddonManager.getAddonsByIDs(["bug557956-1@tests.mozilla.org",
+ "bug557956-2@tests.mozilla.org",
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-4@tests.mozilla.org",
+ "bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org",
+ "bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org",
+ "bug557956-10@tests.mozilla.org"],
+ function(aAddons) {
+ for (let addon of aAddons) {
+ if (addon)
+ addon.uninstall();
+ }
+ aCallback();
+ });
+}
+
+// Open the compatibility dialog, with the list of addon IDs
+// that were disabled by this "update"
+function open_compatibility_window(aDisabledAddons, aCallback) {
+ // This will reset the longer timeout multiplier to 2 which will give each
+ // test that calls open_compatibility_window a minimum of 60 seconds to
+ // complete.
+ requestLongerTimeout(2);
+
+ var variant = Cc["@mozilla.org/variant;1"].
+ createInstance(Ci.nsIWritableVariant);
+ variant.setFromVariant(aDisabledAddons);
+
+ // Cannot be modal as we want to interact with it, shouldn't cause problems
+ // with testing though.
+ var features = "chrome,centerscreen,dialog,titlebar";
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+ getService(Ci.nsIWindowWatcher);
+ var win = ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
+
+ win.addEventListener("load", function() {
+ win.removeEventListener("load", arguments.callee, false);
+
+ info("Compatibility dialog opened");
+
+ function page_shown(aEvent) {
+ if (aEvent.target.pageid)
+ info("Page " + aEvent.target.pageid + " shown");
+ }
+
+ win.addEventListener("pageshow", page_shown, false);
+ win.addEventListener("unload", function() {
+ win.removeEventListener("unload", arguments.callee, false);
+ win.removeEventListener("pageshow", page_shown, false);
+ info("Compatibility dialog closed");
+ }, false);
+
+ aCallback(win);
+ }, false);
+}
+
+function wait_for_window_close(aWindow, aCallback) {
+ aWindow.addEventListener("unload", function() {
+ aWindow.removeEventListener("unload", arguments.callee, false);
+ aCallback();
+ }, false);
+}
+
+function wait_for_page(aWindow, aPageId, aCallback) {
+ var page = aWindow.document.getElementById(aPageId);
+ page.addEventListener("pageshow", function() {
+ page.removeEventListener("pageshow", arguments.callee, false);
+ executeSoon(function() {
+ aCallback(aWindow);
+ });
+ }, false);
+}
+
+function get_list_names(aList) {
+ var items = [];
+ for (let listItem of aList.childNodes)
+ items.push(listItem.label);
+ items.sort();
+ return items;
+}
+
+function check_telemetry({disabled, metaenabled, metadisabled, upgraded, failed, declined}) {
+ let ping = TelemetrySession.getPayload();
+ // info(JSON.stringify(ping));
+ let am = ping.simpleMeasurements.addonManager;
+ if (disabled !== undefined)
+ is(am.appUpdate_disabled, disabled, disabled + " add-ons disabled by version change");
+ if (metaenabled !== undefined)
+ is(am.appUpdate_metadata_enabled, metaenabled, metaenabled + " add-ons enabled by metadata");
+ if (metadisabled !== undefined)
+ is(am.appUpdate_metadata_disabled, metadisabled, metadisabled + " add-ons disabled by metadata");
+ if (upgraded !== undefined)
+ is(am.appUpdate_upgraded, upgraded, upgraded + " add-ons upgraded");
+ if (failed !== undefined)
+ is(am.appUpdate_upgradeFailed, failed, failed + " upgrades failed");
+ if (declined !== undefined)
+ is(am.appUpdate_upgradeDeclined, declined, declined + " upgrades declined");
+}
+
+add_test(function test_setup() {
+ let oldCanRecord = Services.telemetry.canRecordExtended;
+ Services.telemetry.canRecordExtended = true;
+ registerCleanupFunction(function () {
+ Services.telemetry.canRecordExtended = oldCanRecord;
+ });
+ run_next_test();
+});
+
+// Tests that the right add-ons show up in the mismatch dialog and updates can
+// be installed
+add_test(function basic_mismatch() {
+ install_test_addons(function() {
+ // These add-ons become disabled
+ var disabledAddonIds = [
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org",
+ "bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org"
+ ];
+
+ AddonManager.getAddonsByIDs(["bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org"],
+ function([a5, a6]) {
+ // Check starting (pre-update) conditions
+ ok(!a5.isCompatible, "bug557956-5 should not be compatible");
+ ok(!a6.isCompatible, "bug557956-6 should not be compatible");
+
+ open_compatibility_window(disabledAddonIds, function(aWindow) {
+ var doc = aWindow.document;
+ wait_for_page(aWindow, "mismatch", function(aWindow) {
+ var items = get_list_names(doc.getElementById("mismatch.incompatible"));
+ // Check that compatibility updates from individual add-on update checks were applied.
+ is(items.length, 4, "Should have seen 4 still incompatible items");
+ is(items[0], "Addon3 1.0", "Should have seen addon3 still incompatible");
+ is(items[1], "Addon7 1.0", "Should have seen addon7 still incompatible");
+ is(items[2], "Addon8 1.0", "Should have seen addon8 still incompatible");
+ is(items[3], "Addon9 1.0", "Should have seen addon9 still incompatible");
+
+ // If it wasn't disabled by this run, we don't try to enable it
+ ok(!a5.isCompatible, "bug557956-5 should not be compatible");
+ ok(a6.isCompatible, "bug557956-6 should be compatible");
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "found", function(aWindow) {
+ ok(doc.getElementById("xpinstallDisabledAlert").hidden,
+ "Install should be allowed");
+
+ var list = doc.getElementById("found.updates");
+ var items = get_list_names(list);
+ is(items.length, 3, "Should have seen 3 updates available");
+ is(items[0], "Addon7 2.0", "Should have seen update for addon7");
+ is(items[1], "Addon8 2.0", "Should have seen update for addon8");
+ is(items[2], "Addon9 2.0", "Should have seen update for addon9");
+
+ ok(!doc.documentElement.getButton("next").disabled,
+ "Next button should be enabled");
+
+ // Uncheck all
+ for (let listItem of list.childNodes)
+ EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
+
+ ok(doc.documentElement.getButton("next").disabled,
+ "Next button should not be enabled");
+
+ // Check the ones we want to install
+ for (let listItem of list.childNodes) {
+ if (listItem.label != "Addon7 2.0")
+ EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
+ }
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "finished", function(aWindow) {
+ var button = doc.documentElement.getButton("finish");
+ ok(!button.hidden, "Finish button should not be hidden");
+ ok(!button.disabled, "Finish button should not be disabled");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_window_close(aWindow, function() {
+ AddonManager.getAddonsByIDs(["bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org"],
+ function([a8, a9]) {
+ is(a8.version, "2.0", "bug557956-8 should have updated");
+ is(a9.version, "2.0", "bug557956-9 should have updated");
+
+ check_telemetry({disabled: 5, metaenabled: 1, metadisabled: 0,
+ upgraded: 2, failed: 0, declined: 1});
+
+ uninstall_test_addons(run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that the install failures show the install failed page and disabling
+// xpinstall shows the right UI.
+add_test(function failure_page() {
+ install_test_addons(function() {
+ // These add-ons become disabled
+ var disabledAddonIds = [
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org",
+ "bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org"
+ ];
+
+ Services.prefs.setBoolPref("xpinstall.enabled", false);
+
+ open_compatibility_window(disabledAddonIds, function(aWindow) {
+ var doc = aWindow.document;
+ wait_for_page(aWindow, "mismatch", function(aWindow) {
+ var items = get_list_names(doc.getElementById("mismatch.incompatible"));
+ is(items.length, 4, "Should have seen 4 still incompatible items");
+ is(items[0], "Addon3 1.0", "Should have seen addon3 still incompatible");
+ is(items[1], "Addon7 1.0", "Should have seen addon7 still incompatible");
+ is(items[2], "Addon8 1.0", "Should have seen addon8 still incompatible");
+ is(items[3], "Addon9 1.0", "Should have seen addon9 still incompatible");
+
+ // Check that compatibility updates were applied.
+ AddonManager.getAddonsByIDs(["bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org"],
+ function([a5, a6]) {
+ ok(!a5.isCompatible, "bug557956-5 should not be compatible");
+ ok(a6.isCompatible, "bug557956-6 should be compatible");
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "found", function(aWindow) {
+ ok(!doc.getElementById("xpinstallDisabledAlert").hidden,
+ "Install should not be allowed");
+
+ ok(doc.documentElement.getButton("next").disabled,
+ "Next button should be disabled");
+
+ var checkbox = doc.getElementById("enableXPInstall");
+ EventUtils.synthesizeMouse(checkbox, 2, 2, { }, aWindow);
+
+ ok(!doc.documentElement.getButton("next").disabled,
+ "Next button should be enabled");
+
+ var list = doc.getElementById("found.updates");
+ var items = get_list_names(list);
+ is(items.length, 3, "Should have seen 3 updates available");
+ is(items[0], "Addon7 2.0", "Should have seen update for addon7");
+ is(items[1], "Addon8 2.0", "Should have seen update for addon8");
+ is(items[2], "Addon9 2.0", "Should have seen update for addon9");
+
+ // Unheck the ones we don't want to install
+ for (let listItem of list.childNodes) {
+ if (listItem.label != "Addon7 2.0")
+ EventUtils.synthesizeMouse(listItem, 2, 2, { }, aWindow);
+ }
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "installerrors", function(aWindow) {
+ var button = doc.documentElement.getButton("finish");
+ ok(!button.hidden, "Finish button should not be hidden");
+ ok(!button.disabled, "Finish button should not be disabled");
+
+ wait_for_window_close(aWindow, function() {
+ uninstall_test_addons(run_next_test);
+ });
+
+ check_telemetry({disabled: 5, metaenabled: 1, metadisabled: 0,
+ upgraded: 0, failed: 1, declined: 2});
+
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that no add-ons show up in the mismatch dialog when they are all disabled
+add_test(function all_disabled() {
+ install_test_addons(function() {
+ AddonManager.getAddonsByIDs(["bug557956-1@tests.mozilla.org",
+ "bug557956-2@tests.mozilla.org",
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-4@tests.mozilla.org",
+ "bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org",
+ "bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org",
+ "bug557956-10@tests.mozilla.org"],
+ function(aAddons) {
+ for (let addon of aAddons)
+ addon.userDisabled = true;
+
+ open_compatibility_window([], function(aWindow) {
+ // Should close immediately on its own
+ wait_for_window_close(aWindow, function() {
+ uninstall_test_addons(run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Tests that the right UI shows for when no updates are available
+add_test(function no_updates() {
+ install_test_addons(function() {
+ AddonManager.getAddonsByIDs(["bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org",
+ "bug557956-10@tests.mozilla.org"],
+ function(aAddons) {
+ for (let addon of aAddons)
+ addon.uninstall();
+
+ // These add-ons were disabled by the upgrade
+ var inactiveAddonIds = [
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org"
+ ];
+
+ open_compatibility_window(inactiveAddonIds, function(aWindow) {
+ var doc = aWindow.document;
+ wait_for_page(aWindow, "mismatch", function(aWindow) {
+ var items = get_list_names(doc.getElementById("mismatch.incompatible"));
+ is(items.length, 1, "Should have seen 1 still incompatible items");
+ is(items[0], "Addon3 1.0", "Should have seen addon3 still incompatible");
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "noupdates", function(aWindow) {
+ var button = doc.documentElement.getButton("finish");
+ ok(!button.hidden, "Finish button should not be hidden");
+ ok(!button.disabled, "Finish button should not be disabled");
+
+ wait_for_window_close(aWindow, function() {
+ uninstall_test_addons(run_next_test);
+ });
+
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that compatibility overrides are retrieved and affect addon
+// compatibility.
+add_test(function overrides_retrieved() {
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
+ Services.prefs.setCharPref(PREF_MIN_APP_COMPAT, "0");
+ Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
+ is(AddonManager.strictCompatibility, false, "Strict compatibility should be disabled");
+
+ // Use a blank update URL
+ Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
+
+ install_test_addons(function() {
+
+ AddonManager.getAddonsByIDs(["bug557956-1@tests.mozilla.org",
+ "bug557956-2@tests.mozilla.org",
+ "bug557956-3@tests.mozilla.org",
+ "bug557956-4@tests.mozilla.org",
+ "bug557956-5@tests.mozilla.org",
+ "bug557956-6@tests.mozilla.org",
+ "bug557956-7@tests.mozilla.org",
+ "bug557956-8@tests.mozilla.org",
+ "bug557956-9@tests.mozilla.org",
+ "bug557956-10@tests.mozilla.org"],
+ function(aAddons) {
+
+ for (let addon of aAddons) {
+ if (addon.id == "bug557956-10@tests.mozilla.org")
+ is(addon.isCompatible, true, "Addon10 should be compatible before compat overrides are refreshed");
+ else
+ addon.uninstall();
+ }
+
+ Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, TESTROOT + "browser_bug557956.xml");
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+
+ open_compatibility_window([], function(aWindow) {
+ var doc = aWindow.document;
+ wait_for_page(aWindow, "mismatch", function(aWindow) {
+ var items = get_list_names(doc.getElementById("mismatch.incompatible"));
+ is(items.length, 1, "Should have seen 1 incompatible item");
+ is(items[0], "Addon10 1.0", "Should have seen addon10 as incompatible");
+
+ var button = doc.documentElement.getButton("next");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+
+ wait_for_page(aWindow, "noupdates", function(aWindow) {
+ var button = doc.documentElement.getButton("finish");
+ ok(!button.hidden, "Finish button should not be hidden");
+ ok(!button.disabled, "Finish button should not be disabled");
+
+ wait_for_window_close(aWindow, function() {
+ uninstall_test_addons(run_next_test);
+ });
+
+ check_telemetry({disabled: 0, metaenabled: 0, metadisabled: 1,
+ upgraded: 0, failed: 0, declined: 0});
+
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956.rdf b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.rdf
new file mode 100644
index 000000000..c72eb9363
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.rdf
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-1@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-2@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-3@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-4@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>1</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>1</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-5@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-6@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-7@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>2.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_7_2.xpi</em:updateLink>
+ <em:updateHash>sha1:18674cf7ad76664e0ead6280a43cc0c681180505</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_7_2.xpi</em:updateLink>
+ <em:updateHash>sha1:18674cf7ad76664e0ead6280a43cc0c681180505</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-8@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>2.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_8_2.xpi</em:updateLink>
+ <em:updateHash>sha1:5691c398e55ddf93aa1076b9820619d21d40acbc</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_8_2.xpi</em:updateLink>
+ <em:updateHash>sha1:5691c398e55ddf93aa1076b9820619d21d40acbc</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+ <RDF:Description about="urn:mozilla:extension:bug557956-9@tests.mozilla.org">
+ <em:updates>
+ <RDF:Seq>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>0</em:maxVersion>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ <RDF:li>
+ <RDF:Description>
+ <em:version>2.0</em:version>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_9_2.xpi</em:updateLink>
+ <em:updateHash>sha1:1ae63bfc6f67a4503a1ff1bd02402c98fef19ae3</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ <em:targetApplication>
+ <RDF:Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>http://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_bug557956_9_2.xpi</em:updateLink>
+ <em:updateHash>sha1:1ae63bfc6f67a4503a1ff1bd02402c98fef19ae3</em:updateHash>
+ </RDF:Description>
+ </em:targetApplication>
+ </RDF:Description>
+ </RDF:li>
+ </RDF:Seq>
+ </em:updates>
+ </RDF:Description>
+
+</RDF:RDF>
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956.xml b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.xml
new file mode 100644
index 000000000..c32ed3062
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="1">
+ <addon_compatibility hosted="false">
+ <guid>bug557956-10@tests.mozilla.org</guid>
+ <name>Addon10</name>
+ <version_ranges>
+ <version_range type="incompatible">
+ <min_version>1.0</min_version>
+ <max_version>2.0</max_version>
+ <compatible_applications>
+ <application>
+ <min_version>0.1</min_version>
+ <max_version>999.0</max_version>
+ <appID>toolkit@mozilla.org</appID>
+ </application>
+ </compatible_applications>
+ </version_range>
+ </version_ranges>
+ </addon_compatibility>
+</searchresults>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpi b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpi
new file mode 100644
index 000000000..e99f3c3bd
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi
new file mode 100644
index 000000000..23686b608
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug562797.js b/toolkit/mozapps/webextensions/test/browser/browser_bug562797.js
new file mode 100644
index 000000000..55e882a05
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug562797.js
@@ -0,0 +1,975 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Tests that history navigation works for the add-ons manager.
+ */
+
+const MAIN_URL = "https://example.com/" + RELATIVE_DIR + "discovery.html";
+const SECOND_URL = "https://example.com/" + RELATIVE_DIR + "releaseNotes.xhtml";
+
+var gLoadCompleteCallback = null;
+
+var gProgressListener = {
+ onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+ // Only care about the network stop status events
+ if (!(aStateFlags & (Ci.nsIWebProgressListener.STATE_IS_NETWORK)) ||
+ !(aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP)))
+ return;
+
+ if (gLoadCompleteCallback)
+ executeSoon(gLoadCompleteCallback);
+ gLoadCompleteCallback = null;
+ },
+
+ onLocationChange: function() { },
+ onSecurityChange: function() { },
+ onProgressChange: function() { },
+ onStatusChange: function() { },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+ Ci.nsISupportsWeakReference]),
+};
+
+function waitForLoad(aManager, aCallback) {
+ var browser = aManager.document.getElementById("discover-browser");
+ browser.addProgressListener(gProgressListener);
+
+ gLoadCompleteCallback = function() {
+ browser.removeProgressListener(gProgressListener);
+ aCallback();
+ };
+}
+
+function clickLink(aManager, aId, aCallback) {
+ waitForLoad(aManager, aCallback);
+
+ var browser = aManager.document.getElementById("discover-browser");
+
+ var link = browser.contentDocument.getElementById(aId);
+ EventUtils.sendMouseEvent({type: "click"}, link);
+}
+
+function test() {
+ requestLongerTimeout(2);
+
+ waitForExplicitFinish();
+
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
+
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.ipc.processCount", 1],
+ ]}, () => {
+ var gProvider = new MockProvider();
+ gProvider.createAddons([{
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on 1",
+ description: "foo"
+ },
+ {
+ id: "test2@tests.mozilla.org",
+ name: "Test add-on 2",
+ description: "bar"
+ },
+ {
+ id: "test3@tests.mozilla.org",
+ name: "Test add-on 3",
+ type: "theme",
+ description: "bar"
+ }]);
+ });
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+function go_back(aManager) {
+ if (gUseInContentUI) {
+ gBrowser.goBack();
+ } else {
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("back-btn"),
+ { }, aManager);
+ }
+}
+
+function go_back_backspace(aManager) {
+ EventUtils.synthesizeKey("VK_BACK_SPACE", {});
+}
+
+function go_forward_backspace(aManager) {
+ EventUtils.synthesizeKey("VK_BACK_SPACE", {shiftKey: true});
+}
+
+function go_forward(aManager) {
+ if (gUseInContentUI) {
+ gBrowser.goForward();
+ } else {
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("forward-btn"),
+ { }, aManager);
+ }
+}
+
+function check_state(aManager, canGoBack, canGoForward) {
+ var doc = aManager.document;
+
+ if (gUseInContentUI) {
+ is(gBrowser.canGoBack, canGoBack, "canGoBack should be correct");
+ is(gBrowser.canGoForward, canGoForward, "canGoForward should be correct");
+ }
+
+ if (!is_hidden(doc.getElementById("back-btn"))) {
+ is(!doc.getElementById("back-btn").disabled, canGoBack, "Back button should have the right state");
+ is(!doc.getElementById("forward-btn").disabled, canGoForward, "Forward button should have the right state");
+ }
+}
+
+function is_in_list(aManager, view, canGoBack, canGoForward) {
+ var doc = aManager.document;
+
+ is(doc.getElementById("categories").selectedItem.value, view, "Should be on the right category");
+ is(get_current_view(aManager).id, "list-view", "Should be on the right view");
+
+ check_state(aManager, canGoBack, canGoForward);
+}
+
+function is_in_search(aManager, query, canGoBack, canGoForward) {
+ var doc = aManager.document;
+
+ is(doc.getElementById("categories").selectedItem.value, "addons://search/", "Should be on the right category");
+ is(get_current_view(aManager).id, "search-view", "Should be on the right view");
+ is(doc.getElementById("header-search").value, query, "Should have used the right query");
+
+ check_state(aManager, canGoBack, canGoForward);
+}
+
+function is_in_detail(aManager, view, canGoBack, canGoForward) {
+ var doc = aManager.document;
+
+ is(doc.getElementById("categories").selectedItem.value, view, "Should be on the right category");
+ is(get_current_view(aManager).id, "detail-view", "Should be on the right view");
+
+ check_state(aManager, canGoBack, canGoForward);
+}
+
+function is_in_discovery(aManager, url, canGoBack, canGoForward) {
+ var browser = aManager.document.getElementById("discover-browser");
+
+ is(aManager.document.getElementById("discover-view").selectedPanel, browser,
+ "Browser should be visible");
+
+ var spec = browser.currentURI.spec;
+ var pos = spec.indexOf("#");
+ if (pos != -1)
+ spec = spec.substring(0, pos);
+
+ is(spec, url, "Should have loaded the right url");
+
+ check_state(aManager, canGoBack, canGoForward);
+}
+
+function double_click_addon_element(aManager, aId) {
+ var addon = get_addon_element(aManager, aId);
+ addon.parentNode.ensureElementIsVisible(addon);
+ EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 1 }, aManager);
+ EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 2 }, aManager);
+}
+
+// Tests simple forward and back navigation and that the right heading and
+// category is selected
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-plugin"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ go_forward(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 5");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ double_click_addon_element(aManager, "test1@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 6");
+ is_in_detail(aManager, "addons://list/extension", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 7");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that browsing to the add-ons manager from a website and going back works
+// Only relevant for in-content UI
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ function promiseViewLoad(manager) {
+ return new Promise(resolve => {
+ wait_for_view_load(manager, resolve);
+ });
+ }
+
+ function promiseManagerLoaded(manager) {
+ return new Promise(resolve => {
+ wait_for_manager_load(manager, resolve);
+ });
+ }
+
+ Task.spawn(function*() {
+ info("Part 1");
+ yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com/", true, true);
+
+ info("Part 2");
+ ok(!gBrowser.canGoBack, "Should not be able to go back");
+ ok(!gBrowser.canGoForward, "Should not be able to go forward");
+
+ yield BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:addons");
+ yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+
+ let manager = yield promiseManagerLoaded(gBrowser.contentWindow.wrappedJSObject);
+
+ info("Part 3");
+ is_in_list(manager, "addons://list/extension", true, false);
+
+ // XXX: This is less than ideal, as it's currently difficult to deal with
+ // the browser frame switching between remote/non-remote in e10s mode.
+ let promiseLoaded;
+ if (gMultiProcessBrowser) {
+ promiseLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ } else {
+ promiseLoaded = BrowserTestUtils.waitForEvent(gBrowser.selectedBrowser, "pageshow");
+ }
+
+ go_back(manager);
+ yield promiseLoaded;
+
+ info("Part 4");
+ is(gBrowser.currentURI.spec, "http://example.com/", "Should be showing the webpage");
+ ok(!gBrowser.canGoBack, "Should not be able to go back");
+ ok(gBrowser.canGoForward, "Should be able to go forward");
+
+ promiseLoaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
+ go_forward(manager);
+ yield promiseLoaded;
+
+ manager = yield promiseManagerLoaded(gBrowser.contentWindow.wrappedJSObject);
+ info("Part 5");
+ is_in_list(manager, "addons://list/extension", true, false);
+
+ close_manager(manager, run_next_test);
+ });
+});
+
+// Tests simple forward and back navigation and that the right heading and
+// category is selected -- Keyboard navigation [Bug 565359]
+// Only add the test if the backspace key navigates back and addon-manager
+// loaded in a tab
+add_test(function() {
+
+ if (!gUseInContentUI || (Services.prefs.getIntPref("browser.backspace_action") != 0)) {
+ run_next_test();
+ return;
+ }
+
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-plugin"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back_backspace(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ go_forward_backspace(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back_backspace(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 5");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ double_click_addon_element(aManager, "test1@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 6");
+ is_in_detail(aManager, "addons://list/extension", true, false);
+
+ go_back_backspace(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 7");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+
+// Tests that opening a custom first view only stores a single history entry
+add_test(function() {
+ open_manager("addons://list/plugin", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-extension"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/extension", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/plugin", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+});
+
+
+// Tests that opening a view while the manager is already open adds a new
+// history entry
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ aManager.loadView("addons://list/plugin");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ go_forward(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Tests than navigating to a website and then going back returns to the
+// previous view
+// Only relevant for in-content UI
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ open_manager("addons://list/plugin", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ gBrowser.loadURI("http://example.com/");
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "http://example.com/")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+ info("Part 2");
+
+ executeSoon(function() {
+ ok(gBrowser.canGoBack, "Should be able to go back");
+ ok(!gBrowser.canGoForward, "Should not be able to go forward");
+
+ go_back(aManager);
+
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "about:addons")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+
+ wait_for_view_load(gBrowser.contentWindow.wrappedJSObject, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/plugin", false, true);
+
+ executeSoon(() => go_forward(aManager));
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "http://example.com/")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+ info("Part 4");
+
+ executeSoon(function() {
+ ok(gBrowser.canGoBack, "Should be able to go back");
+ ok(!gBrowser.canGoForward, "Should not be able to go forward");
+
+ go_back(aManager);
+
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "about:addons")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+ wait_for_view_load(gBrowser.contentWindow.wrappedJSObject, function(aManager) {
+ info("Part 5");
+ is_in_list(aManager, "addons://list/plugin", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ }, false);
+ });
+ }, false);
+ });
+ }, false);
+ });
+ }, false);
+ });
+});
+
+// Tests that going back to search results works
+add_test(function() {
+ // Before we open the add-ons manager, we should make sure that no filter
+ // has been set. If one is set, we remove it.
+ // This is for the check below, from bug 611459.
+ let store = Cc["@mozilla.org/xul/xulstore;1"].getService(Ci.nsIXULStore);
+ store.removeValue("about:addons", "search-filter-radiogroup", "value");
+
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ var search = aManager.document.getElementById("header-search");
+ search.focus();
+ search.value = "bar";
+ EventUtils.synthesizeKey("VK_RETURN", {}, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ // Remote search is meant to be checked by default (bug 611459), so we
+ // confirm that and then switch to a local search.
+ var localFilter = aManager.document.getElementById("search-filter-local");
+ var remoteFilter = aManager.document.getElementById("search-filter-remote");
+
+ is(remoteFilter.selected, true, "Remote filter should be set by default");
+
+ var list = aManager.document.getElementById("search-list");
+ list.ensureElementIsVisible(localFilter);
+ EventUtils.synthesizeMouseAtCenter(localFilter, { }, aManager);
+
+ is(localFilter.selected, true, "Should have changed to local filter");
+
+ // Now we continue with the normal test.
+
+ info("Part 2");
+ is_in_search(aManager, "bar", true, false);
+ check_all_in_list(aManager, ["test2@tests.mozilla.org", "test3@tests.mozilla.org"]);
+
+ double_click_addon_element(aManager, "test2@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_detail(aManager, "addons://search/", true, false);
+
+ go_back(aManager);
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_search(aManager, "bar", true, true);
+ check_all_in_list(aManager, ["test2@tests.mozilla.org", "test3@tests.mozilla.org"]);
+
+ go_forward(aManager);
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 5");
+ is_in_detail(aManager, "addons://search/", true, false);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that going back from a webpage to a detail view loaded from a search
+// result works
+// Only relevant for in-content UI
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ var search = aManager.document.getElementById("header-search");
+ search.focus();
+ search.value = "bar";
+ EventUtils.synthesizeKey("VK_RETURN", {});
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_search(aManager, "bar", true, false);
+ check_all_in_list(aManager, ["test2@tests.mozilla.org", "test3@tests.mozilla.org"]);
+
+ double_click_addon_element(aManager, "test2@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 3");
+ is_in_detail(aManager, "addons://search/", true, false);
+
+ gBrowser.loadURI("http://example.com/");
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "http://example.com/")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+
+ info("Part 4");
+ executeSoon(function() {
+ ok(gBrowser.canGoBack, "Should be able to go back");
+ ok(!gBrowser.canGoForward, "Should not be able to go forward");
+
+ go_back(aManager);
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "about:addons")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+
+ wait_for_view_load(gBrowser.contentWindow.wrappedJSObject, function(aManager) {
+ info("Part 5");
+ is_in_detail(aManager, "addons://search/", true, true);
+
+ go_back(aManager);
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 6");
+ is_in_search(aManager, "bar", true, true);
+ check_all_in_list(aManager, ["test2@tests.mozilla.org", "test3@tests.mozilla.org"]);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ }, false);
+ });
+ }, false);
+ });
+ });
+ });
+});
+
+// Tests that refreshing a list view does not affect the history
+// Only relevant for in-content UI
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-plugin"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ gBrowser.reload();
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "about:addons")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+
+ wait_for_view_load(gBrowser.contentWindow.wrappedJSObject, function(aManager) {
+ info("Part 3");
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ }, false);
+ });
+ });
+});
+
+// Tests that refreshing a detail view does not affect the history
+// Only relevant for in-content UI
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ open_manager(null, function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ double_click_addon_element(aManager, "test1@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_detail(aManager, "addons://list/extension", true, false);
+
+ gBrowser.reload();
+ gBrowser.addEventListener("pageshow", function(event) {
+ if (event.target.location != "about:addons")
+ return;
+ gBrowser.removeEventListener("pageshow", arguments.callee, false);
+
+ wait_for_view_load(gBrowser.contentWindow.wrappedJSObject, function(aManager) {
+ info("Part 3");
+ is_in_detail(aManager, "addons://list/extension", true, false);
+
+ go_back(aManager);
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 4");
+ is_in_list(aManager, "addons://list/extension", false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ }, false);
+ });
+ });
+});
+
+// Tests that removing an extension from the detail view goes back and doesn't
+// allow you to go forward again.
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension", false, false);
+
+ double_click_addon_element(aManager, "test1@tests.mozilla.org");
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_detail(aManager, "addons://list/extension", true, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("detail-uninstall-btn"),
+ { }, aManager);
+
+ wait_for_view_load(aManager, function() {
+ if (gUseInContentUI) {
+ // TODO until bug 590661 is fixed the back button will be enabled
+ // when displaying in content
+ is_in_list(aManager, "addons://list/extension", true, false);
+ } else {
+ is_in_list(aManager, "addons://list/extension", false, false);
+ }
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+});
+
+// Tests that the back and forward buttons only show up for windowed mode
+add_test(function() {
+ open_manager(null, function(aManager) {
+ var doc = aManager.document;
+
+ if (gUseInContentUI) {
+ var btn = document.getElementById("back-button");
+ if (!btn || is_hidden(btn)) {
+ is_element_visible(doc.getElementById("back-btn"), "Back button should not be hidden");
+ is_element_visible(doc.getElementById("forward-btn"), "Forward button should not be hidden");
+ } else {
+ is_element_hidden(doc.getElementById("back-btn"), "Back button should be hidden");
+ is_element_hidden(doc.getElementById("forward-btn"), "Forward button should be hidden");
+ }
+ } else {
+ is_element_visible(doc.getElementById("back-btn"), "Back button should not be hidden");
+ is_element_visible(doc.getElementById("forward-btn"), "Forward button should not be hidden");
+ }
+
+ close_manager(aManager, run_next_test);
+ });
+});
+
+// Tests that opening the manager opens the last view
+add_test(function() {
+ open_manager("addons://list/plugin", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ close_manager(aManager, function() {
+ open_manager(null, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+});
+
+// Tests that navigating the discovery page works when that was the first view
+add_test(function() {
+ open_manager("addons://discover/", function(aManager) {
+ info("1");
+ is_in_discovery(aManager, MAIN_URL, false, false);
+
+ clickLink(aManager, "link-good", function() {
+ info("2");
+ is_in_discovery(aManager, SECOND_URL, true, false);
+
+ waitForLoad(aManager, function() {
+ info("3");
+ is_in_discovery(aManager, MAIN_URL, false, true);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, SECOND_URL, true, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-plugin"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, SECOND_URL, true, true);
+
+ go_back(aManager);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, false, true);
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ });
+ });
+
+ go_forward(aManager);
+ });
+
+ go_back(aManager);
+ });
+ });
+});
+
+// Tests that navigating the discovery page works when that was the second view
+add_test(function() {
+ open_manager("addons://list/plugin", function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-discover"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, MAIN_URL, true, false);
+
+ clickLink(aManager, "link-good", function() {
+ is_in_discovery(aManager, SECOND_URL, true, false);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, true, true);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, SECOND_URL, true, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-plugin"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", true, false);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, SECOND_URL, true, true);
+
+ go_back(aManager);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, true, true);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", false, true);
+
+ go_forward(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, MAIN_URL, true, true);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, SECOND_URL, true, true);
+
+ close_manager(aManager, run_next_test);
+ });
+
+ go_forward(aManager);
+ });
+ });
+ });
+ });
+ });
+ });
+
+ go_forward(aManager);
+ });
+
+ go_back(aManager);
+ });
+ });
+ });
+});
+
+// Tests that when displaying in-content and opened in the background the back
+// and forward buttons still appear when switching tabs
+add_test(function() {
+ if (!gUseInContentUI) {
+ run_next_test();
+ return;
+ }
+
+ var tab = gBrowser.addTab("about:addons");
+ var browser = gBrowser.getBrowserForTab(tab);
+
+ browser.addEventListener("pageshow", function(event) {
+ if (event.target.location.href != "about:addons")
+ return;
+ browser.removeEventListener("pageshow", arguments.callee, true);
+
+ wait_for_manager_load(browser.contentWindow.wrappedJSObject, function() {
+ wait_for_view_load(browser.contentWindow.wrappedJSObject, function(aManager) {
+ gBrowser.selectedTab = tab;
+
+ var doc = aManager.document;
+ var btn = document.getElementById("back-button");
+ if (!btn || is_hidden(btn)) {
+ is_element_visible(doc.getElementById("back-btn"), "Back button should not be hidden");
+ is_element_visible(doc.getElementById("forward-btn"), "Forward button should not be hidden");
+ } else {
+ is_element_hidden(doc.getElementById("back-btn"), "Back button should be hidden");
+ is_element_hidden(doc.getElementById("forward-btn"), "Forward button should be hidden");
+ }
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+ }, true);
+});
+
+// Tests that refreshing the disicovery pane integrates properly with history
+add_test(function() {
+ open_manager("addons://list/plugin", function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", false, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-discover"), { }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, MAIN_URL, true, false);
+
+ clickLink(aManager, "link-good", function() {
+ is_in_discovery(aManager, SECOND_URL, true, false);
+
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-discover"), { }, aManager);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, true, false);
+
+ go_back(aManager);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, SECOND_URL, true, true);
+
+ go_back(aManager);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, true, true);
+
+ go_back(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_list(aManager, "addons://list/plugin", false, true);
+
+ go_forward(aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ is_in_discovery(aManager, MAIN_URL, true, true);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, SECOND_URL, true, true);
+
+ waitForLoad(aManager, function() {
+ is_in_discovery(aManager, MAIN_URL, true, false);
+
+ close_manager(aManager, run_next_test);
+ });
+ go_forward(aManager);
+ });
+
+ go_forward(aManager);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug562854.js b/toolkit/mozapps/webextensions/test/browser/browser_bug562854.js
new file mode 100644
index 000000000..53e890b71
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug562854.js
@@ -0,0 +1,129 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Tests that double-click does not go to detail view if the target is a link or button.
+ */
+
+function test() {
+ requestLongerTimeout(2);
+
+ waitForExplicitFinish();
+
+ var gProvider = new MockProvider();
+ gProvider.createAddons([{
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on 1",
+ description: "foo",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }]);
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+function is_in_list(aManager, view) {
+ var doc = aManager.document;
+
+ is(doc.getElementById("categories").selectedItem.value, view, "Should be on the right category");
+ is(get_current_view(aManager).id, "list-view", "Should be on the right view");
+}
+
+function is_in_detail(aManager, view) {
+ var doc = aManager.document;
+
+ is(doc.getElementById("categories").selectedItem.value, view, "Should be on the right category");
+ is(get_current_view(aManager).id, "detail-view", "Should be on the right view");
+}
+
+// Check that double-click does something.
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension");
+
+ var addon = get_addon_element(aManager, "test1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+ EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 1 }, aManager);
+ EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 2 }, aManager);
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_detail(aManager, "addons://list/extension");
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+});
+
+// Check that double-click does nothing when over the disable button.
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension");
+
+ var addon = get_addon_element(aManager, "test1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+ EventUtils.synthesizeMouseAtCenter(
+ aManager.document.getAnonymousElementByAttribute(addon, "anonid", "disable-btn"),
+ { clickCount: 1 },
+ aManager
+ );
+ // The disable button is replaced by the enable button when clicked on.
+ EventUtils.synthesizeMouseAtCenter(
+ aManager.document.getAnonymousElementByAttribute(addon, "anonid", "enable-btn"),
+ { clickCount: 2 },
+ aManager
+ );
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/extension");
+
+ close_manager(aManager, run_next_test);
+ });
+ });
+});
+
+// Check that double-click does nothing when over the undo button.
+add_test(function() {
+ open_manager("addons://list/extension", function(aManager) {
+ info("Part 1");
+ is_in_list(aManager, "addons://list/extension");
+
+ var addon = get_addon_element(aManager, "test1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+ EventUtils.synthesizeMouseAtCenter(
+ aManager.document.getAnonymousElementByAttribute(addon, "anonid", "remove-btn"),
+ { clickCount: 1 },
+ aManager
+ );
+
+ // The undo button is removed when clicked on.
+ // We need to wait for the UI to catch up.
+ setTimeout(function() {
+ var target = aManager.document.getAnonymousElementByAttribute(addon, "anonid", "undo-btn");
+ var rect = target.getBoundingClientRect();
+ var addonRect = addon.getBoundingClientRect();
+
+ EventUtils.synthesizeMouse(target, rect.width / 2, rect.height / 2, { clickCount: 1 }, aManager);
+ EventUtils.synthesizeMouse(addon,
+ rect.left - addonRect.left + rect.width / 2,
+ rect.top - addonRect.top + rect.height / 2,
+ { clickCount: 2 },
+ aManager
+ );
+
+ wait_for_view_load(aManager, function(aManager) {
+ info("Part 2");
+ is_in_list(aManager, "addons://list/extension");
+
+ close_manager(aManager, run_next_test);
+ });
+ }, 0);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug562890.js b/toolkit/mozapps/webextensions/test/browser/browser_bug562890.js
new file mode 100644
index 000000000..ccb12c489
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug562890.js
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Tests the Preferences button for addons in list view
+ */
+
+function test() {
+ requestLongerTimeout(2);
+
+ waitForExplicitFinish();
+
+ var addonPrefsURI = CHROMEROOT + "addon_prefs.xul";
+
+ var gProvider = new MockProvider();
+ gProvider.createAddons([{
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on 1",
+ description: "foo"
+ },
+ {
+ id: "test2@tests.mozilla.org",
+ name: "Test add-on 2",
+ description: "bar",
+ optionsURL: addonPrefsURI
+ }]);
+
+ open_manager("addons://list/extension", function(aManager) {
+ var addonList = aManager.document.getElementById("addon-list");
+ for (var addonItem of addonList.childNodes) {
+ if (addonItem.hasAttribute("name") &&
+ addonItem.getAttribute("name") == "Test add-on 1")
+ break;
+ }
+ var prefsBtn = aManager.document.getAnonymousElementByAttribute(addonItem,
+ "anonid",
+ "preferences-btn");
+ is(prefsBtn.hidden, true, "Prefs button should be hidden for addon with no optionsURL set")
+
+ for (addonItem of addonList.childNodes) {
+ if (addonItem.hasAttribute("name") &&
+ addonItem.getAttribute("name") == "Test add-on 2")
+ break;
+ }
+ prefsBtn = aManager.document.getAnonymousElementByAttribute(addonItem,
+ "anonid",
+ "preferences-btn");
+ is(prefsBtn.hidden, false, "Prefs button should be shown for addon with a optionsURL set")
+
+ Services.ww.registerNotification(function TEST_ww_observer(aSubject, aTopic, aData) {
+ if (aTopic == "domwindowclosed") {
+ Services.ww.unregisterNotification(TEST_ww_observer);
+ // Give the preference window a chance to finish closing before closing
+ // the add-ons manager.
+ executeSoon(function() {
+ close_manager(aManager, finish);
+ });
+ } else if (aTopic == "domwindowopened") {
+ let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
+ win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
+ win.addEventListener("load", function TEST_ww_onLoad() {
+ if (win.location != addonPrefsURI)
+ return;
+
+ win.removeEventListener("load", TEST_ww_onLoad, false);
+ is(win.location, addonPrefsURI,
+ "The correct addon pref window should have opened");
+ win.close();
+ }, false);
+ }
+ });
+
+ addonList.ensureElementIsVisible(addonItem);
+ EventUtils.synthesizeMouseAtCenter(prefsBtn, { }, aManager);
+ });
+
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug562899.js b/toolkit/mozapps/webextensions/test/browser/browser_bug562899.js
new file mode 100644
index 000000000..9807be98f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug562899.js
@@ -0,0 +1,88 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Simulates quickly switching between different list views to verify that only
+// the last selected is displayed
+
+var tempScope = {};
+Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
+var LightweightThemeManager = tempScope.LightweightThemeManager;
+
+const xpi = "browser/toolkit/mozapps/extensions/test/browser/browser_installssl.xpi";
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+function test() {
+ waitForExplicitFinish();
+
+ // Add a lightweight theme so at least one theme exists
+ LightweightThemeManager.currentTheme = {
+ id: "test",
+ name: "Test lightweight theme",
+ headerURL: "http://example.com/header.png"
+ };
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ LightweightThemeManager.forgetUsedTheme("test");
+ finish();
+ });
+}
+
+// Tests that loading a second view before the first has not finished loading
+// does not merge the results
+add_test(function() {
+ var themeCount = null;
+ var pluginCount = null;
+ var themeItem = gCategoryUtilities.get("theme");
+ var pluginItem = gCategoryUtilities.get("plugin");
+ var list = gManagerWindow.document.getElementById("addon-list");
+
+ gCategoryUtilities.open(themeItem, function() {
+ themeCount = list.childNodes.length;
+ ok(themeCount > 0, "Test is useless if there are no themes");
+
+ gCategoryUtilities.open(pluginItem, function() {
+ pluginCount = list.childNodes.length;
+ ok(pluginCount > 0, "Test is useless if there are no plugins");
+
+ gCategoryUtilities.open(themeItem);
+
+ gCategoryUtilities.open(pluginItem, function() {
+ is(list.childNodes.length, pluginCount, "Should only see the plugins");
+
+ var item = list.firstChild;
+ while (item) {
+ is(item.getAttribute("type"), "plugin", "All items should be plugins");
+ item = item.nextSibling;
+ }
+
+ // Tests that switching to, from, to the same pane in quick succession
+ // still only shows the right number of results
+
+ gCategoryUtilities.open(themeItem);
+ gCategoryUtilities.open(pluginItem);
+ gCategoryUtilities.open(themeItem, function() {
+ is(list.childNodes.length, themeCount, "Should only see the theme");
+
+ var item = list.firstChild;
+ while (item) {
+ is(item.getAttribute("type"), "theme", "All items should be theme");
+ item = item.nextSibling;
+ }
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug562992.js b/toolkit/mozapps/webextensions/test/browser/browser_bug562992.js
new file mode 100644
index 000000000..1cd4d90cd
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug562992.js
@@ -0,0 +1,70 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * This test ensures that when the extension manager UI is open and a
+ * restartless extension is installed from the web, its correct name appears
+ * when the download and installation complete. See bug 562992.
+ */
+
+var gManagerWindow;
+var gProvider;
+var gInstall;
+
+const EXTENSION_NAME = "Wunderbar";
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ open_manager("addons://list/extension", function (aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function () {
+ finish();
+ });
+}
+
+// Create a MockInstall with a MockAddon payload and add it to the provider,
+// causing the onNewInstall event to fire, which in turn will cause a new
+// "installing" item to appear in the list of extensions.
+add_test(function () {
+ let addon = new MockAddon(undefined, EXTENSION_NAME, "extension", true);
+ gInstall = new MockInstall(undefined, undefined, addon);
+ gInstall.addTestListener({
+ onNewInstall: run_next_test
+ });
+ gProvider.addInstall(gInstall);
+});
+
+// Finish the install, which will cause the "installing" item to be converted
+// to an "installed" item, which should have the correct add-on name.
+add_test(function () {
+ gInstall.addTestListener({
+ onInstallEnded: function () {
+ let list = gManagerWindow.document.getElementById("addon-list");
+
+ // To help prevent future breakage, don't assume the item is the only one
+ // in the list, or that it's first in the list. Find it by name.
+ for (let i = 0; i < list.itemCount; i++) {
+ let item = list.getItemAtIndex(i);
+ if (item.getAttribute("name") === EXTENSION_NAME) {
+ ok(true, "Item with correct name found");
+ run_next_test();
+ return;
+ }
+ }
+ ok(false, "Item with correct name was not found");
+ run_next_test();
+ }
+ });
+ gInstall.install();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug567127.js b/toolkit/mozapps/webextensions/test/browser/browser_bug567127.js
new file mode 100644
index 000000000..1d9a75416
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug567127.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests bug 567127 - Add install button to the add-ons manager
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+var gManagerWindow;
+var gSawInstallNotification = false;
+
+// This listens for the next opened window and checks it is of the right url.
+// opencallback is called when the new window is fully loaded
+// closecallback is called when the window is closed
+function WindowOpenListener(url, opencallback, closecallback) {
+ this.url = url;
+ this.opencallback = opencallback;
+ this.closecallback = closecallback;
+
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ wm.addListener(this);
+}
+
+WindowOpenListener.prototype = {
+ url: null,
+ opencallback: null,
+ closecallback: null,
+ window: null,
+ domwindow: null,
+
+ handleEvent: function(event) {
+ is(this.domwindow.document.location.href, this.url, "Should have opened the correct window");
+
+ this.domwindow.removeEventListener("load", this, false);
+ // Allow any other load handlers to execute
+ var self = this;
+ executeSoon(function() { self.opencallback(self.domwindow); } );
+ },
+
+ onWindowTitleChange: function(window, title) {
+ },
+
+ onOpenWindow: function(window) {
+ if (this.window)
+ return;
+
+ this.window = window;
+ this.domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindow);
+ this.domwindow.addEventListener("load", this, false);
+ },
+
+ onCloseWindow: function(window) {
+ if (this.window != window)
+ return;
+
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ wm.removeListener(this);
+ this.opencallback = null;
+ this.window = null;
+ this.domwindow = null;
+
+ // Let the window close complete
+ executeSoon(this.closecallback);
+ this.closecallback = null;
+ }
+};
+
+
+var gInstallNotificationObserver = {
+ observe: function(aSubject, aTopic, aData) {
+ var installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
+ if (gTestInWindow)
+ is(installInfo.browser, null, "Notification should have a null browser");
+ else
+ isnot(installInfo.browser, null, "Notification should have non-null browser");
+ gSawInstallNotification = true;
+ Services.obs.removeObserver(this, "addon-install-started");
+ }
+};
+
+
+function test_confirmation(aWindow, aExpectedURLs) {
+ var list = aWindow.document.getElementById("itemList");
+ is(list.childNodes.length, aExpectedURLs.length, "Should be the right number of installs");
+
+ for (let url of aExpectedURLs) {
+ let found = false;
+ for (let node of list.children) {
+ if (node.url == url) {
+ found = true;
+ break;
+ }
+ }
+ ok(found, "Should have seen " + url + " in the list");
+ }
+
+ aWindow.document.documentElement.cancelDialog();
+}
+
+add_task(function* test_install_from_file() {
+ gManagerWindow = yield open_manager("addons://list/extension");
+
+ var filePaths = [
+ get_addon_file_url("browser_bug567127_1.xpi"),
+ get_addon_file_url("browser_bug567127_2.xpi")
+ ];
+ MockFilePicker.returnFiles = filePaths.map(aPath => aPath.file);
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ // Set handler that executes the core test after the window opens,
+ // and resolves the promise when the window closes
+ let pInstallURIClosed = new Promise((resolve, reject) => {
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ try {
+ test_confirmation(aWindow, filePaths.map(aPath => aPath.spec));
+ } catch (e) {
+ reject(e);
+ }
+ }, resolve);
+ });
+
+ gManagerWindow.gViewController.doCommand("cmd_installFromFile");
+
+ yield pInstallURIClosed;
+
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+
+ MockFilePicker.cleanup();
+ yield close_manager(gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug567137.js b/toolkit/mozapps/webextensions/test/browser/browser_bug567137.js
new file mode 100644
index 000000000..bb9b9a894
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug567137.js
@@ -0,0 +1,40 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that the selected category is persisted across loads of the manager
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager(null, function(aWindow) {
+ let utils = new CategoryUtilities(aWindow);
+
+ // Open the plugins category
+ utils.openType("plugin", function() {
+
+ // Re-open the manager
+ close_manager(aWindow, function() {
+ open_manager(null, function(aWindow) {
+ utils = new CategoryUtilities(aWindow);
+
+ is(utils.selectedCategory, "plugin", "Should have shown the plugins category");
+
+ // Open the extensions category
+ utils.openType("extension", function() {
+
+ // Re-open the manager
+ close_manager(aWindow, function() {
+ open_manager(null, function(aWindow) {
+ utils = new CategoryUtilities(aWindow);
+
+ is(utils.selectedCategory, "extension", "Should have shown the extensions category");
+ close_manager(aWindow, finish);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug570760.js b/toolkit/mozapps/webextensions/test/browser/browser_bug570760.js
new file mode 100644
index 000000000..0606a9a31
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug570760.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("");
+
+// Bug 570760 - Make ctrl-f and / focus the search box in the add-ons manager
+
+var gManagerWindow;
+var focusCount = 0;
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ function focusHandler() {
+ searchBox.blur();
+ focusCount++;
+ }
+ searchBox.addEventListener("focus", focusHandler);
+ f_key_test();
+ slash_key_test();
+ searchBox.removeEventListener("focus", focusHandler);
+ end_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+function f_key_test() {
+ EventUtils.synthesizeKey("f", { accelKey: true }, gManagerWindow);
+ is(focusCount, 1, "Search box should have been focused due to the f key");
+}
+
+function slash_key_test() {
+ EventUtils.synthesizeKey("/", { }, gManagerWindow);
+ is(focusCount, 2, "Search box should have been focused due to the / key");
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug572561.js b/toolkit/mozapps/webextensions/test/browser/browser_bug572561.js
new file mode 100644
index 000000000..69102060e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug572561.js
@@ -0,0 +1,99 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the locale category is shown if there are no locale packs
+// installed but some are pending install
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+var gInstallProperties = [{
+ name: "Locale Category Test",
+ type: "locale"
+}];
+var gInstall;
+var gExpectedCancel = false;
+var gTestInstallListener = {
+ onInstallStarted: function(aInstall) {
+ check_hidden(false);
+ },
+
+ onInstallEnded: function(aInstall) {
+ check_hidden(false);
+ run_next_test();
+ },
+
+ onInstallCancelled: function(aInstall) {
+ ok(gExpectedCancel, "Should expect install cancel");
+ check_hidden(false);
+ run_next_test();
+ },
+
+ onInstallFailed: function(aInstall) {
+ ok(false, "Did not expect onInstallFailed");
+ run_next_test();
+ }
+};
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+function check_hidden(aExpectedHidden) {
+ var hidden = !gCategoryUtilities.isTypeVisible("locale");
+ is(hidden, aExpectedHidden, "Should have correct hidden state");
+}
+
+// Tests that a non-active install does not make the locale category show
+add_test(function() {
+ check_hidden(true);
+ gInstall = gProvider.createInstalls(gInstallProperties)[0];
+ gInstall.addTestListener(gTestInstallListener);
+ check_hidden(true);
+ run_next_test();
+});
+
+// Test that restarting the add-on manager with a non-active install
+// does not cause the locale category to show
+add_test(function() {
+ restart_manager(gManagerWindow, null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_hidden(true);
+ run_next_test();
+ });
+});
+
+// Test that installing the install shows the locale category
+add_test(function() {
+ gInstall.install();
+});
+
+// Test that restarting the add-on manager does not cause the locale category
+// to become hidden
+add_test(function() {
+ restart_manager(gManagerWindow, null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_hidden(false);
+
+ gExpectedCancel = true;
+ gInstall.cancel();
+ });
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug573062.js b/toolkit/mozapps/webextensions/test/browser/browser_bug573062.js
new file mode 100644
index 000000000..6554451fb
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug573062.js
@@ -0,0 +1,116 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+ waitForExplicitFinish();
+
+ var gProvider = new MockProvider();
+ let perms = AddonManager.PERM_CAN_UNINSTALL |
+ AddonManager.PERM_CAN_ENABLE | AddonManager.PERM_CAN_DISABLE;
+
+ gProvider.createAddons([{
+ id: "restart-enable-disable@tests.mozilla.org",
+ name: "restart-enable-disable",
+ description: "foo",
+ permissions: perms,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_ENABLE |
+ AddonManager.OP_NEEDS_RESTART_DISABLE
+ },
+ {
+ id: "restart-uninstall@tests.mozilla.org",
+ name: "restart-uninstall",
+ description: "foo",
+ permissions: perms,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_UNINSTALL
+ },
+ {
+ id: "no-restart-required@tests.mozilla.org",
+ name: "no-restart-required",
+ description: "bar",
+ permissions: perms,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ let addonList = aWindow.document.getElementById("addon-list");
+ let ed_r_Item, un_r_Item, no_r_Item;
+ for (let addonItem of addonList.childNodes) {
+ let name = addonItem.getAttribute("name");
+ switch (name) {
+ case "restart-enable-disable":
+ ed_r_Item = addonItem;
+ break;
+ case "restart-uninstall":
+ un_r_Item = addonItem;
+ break;
+ case "no-restart-required":
+ no_r_Item = addonItem;
+ break;
+ }
+ }
+
+ // Check the buttons in the list view.
+ function checkTooltips(aItem, aEnable, aDisable, aRemove) {
+ is(aItem._enableBtn.getAttribute("tooltiptext"), aEnable);
+ is(aItem._disableBtn.getAttribute("tooltiptext"), aDisable);
+ is(aItem._removeBtn.getAttribute("tooltiptext"), aRemove);
+ }
+
+ let strs = aWindow.gStrings.ext;
+ addonList.selectedItem = ed_r_Item;
+ let ed_args = [ed_r_Item,
+ strs.GetStringFromName("enableAddonRestartRequiredTooltip"),
+ strs.GetStringFromName("disableAddonRestartRequiredTooltip"),
+ strs.GetStringFromName("uninstallAddonTooltip")];
+ checkTooltips.apply(null, ed_args);
+
+ addonList.selectedItem = un_r_Item;
+ let un_args = [un_r_Item,
+ strs.GetStringFromName("enableAddonTooltip"),
+ strs.GetStringFromName("disableAddonTooltip"),
+ strs.GetStringFromName("uninstallAddonRestartRequiredTooltip")];
+ checkTooltips.apply(null, un_args);
+
+ addonList.selectedItem = no_r_Item;
+ let no_args = [no_r_Item,
+ strs.GetStringFromName("enableAddonTooltip"),
+ strs.GetStringFromName("disableAddonTooltip"),
+ strs.GetStringFromName("uninstallAddonTooltip")];
+ checkTooltips.apply(null, no_args);
+
+ // Check the buttons in the details view.
+ function checkTooltips2(aItem, aEnable, aDisable, aRemove) {
+ let detailEnable = aWindow.document.getElementById("detail-enable-btn");
+ let detailDisable = aWindow.document.getElementById("detail-disable-btn");
+ let detailUninstall = aWindow.document.getElementById("detail-uninstall-btn");
+ ok(detailEnable.getAttribute("tooltiptext") == aEnable);
+ ok(detailDisable.getAttribute("tooltiptext") == aDisable);
+ ok(detailUninstall.getAttribute("tooltiptext") == aRemove);
+ }
+
+ function showInDetailView(aAddonId) {
+ aWindow.gViewController.loadView("addons://detail/" +
+ aWindow.encodeURIComponent(aAddonId));
+ }
+
+ // enable-disable:
+ showInDetailView("restart-enable-disable@tests.mozilla.org");
+ wait_for_view_load(aWindow, function() {
+ checkTooltips2.apply(null, ed_args);
+ // uninstall:
+ showInDetailView("restart-uninstall@tests.mozilla.org");
+ wait_for_view_load(aWindow, function() {
+ checkTooltips2.apply(null, un_args);
+ // no restart:
+ showInDetailView("no-restart-required@tests.mozilla.org");
+ wait_for_view_load(aWindow, function() {
+ checkTooltips2.apply(null, no_args);
+ aWindow.close();
+ finish();
+ });
+ });
+ });
+
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug577990.js b/toolkit/mozapps/webextensions/test/browser/browser_bug577990.js
new file mode 100644
index 000000000..913b3b954
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug577990.js
@@ -0,0 +1,132 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the visible delay in showing the "Language" category occurs
+// very minimally
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+var gInstall;
+var gInstallProperties = [{
+ name: "Locale Category Test",
+ type: "locale"
+}];
+
+function test() {
+ try {
+ if (Components.classes["@mozilla.org/gfx/info;1"].getService(Components.interfaces.nsIGfxInfo).D2DEnabled) {
+ requestLongerTimeout(2);
+ }
+ } catch (e) {}
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+function install_locale(aCallback) {
+ gInstall = gProvider.createInstalls(gInstallProperties)[0];
+ gInstall.addTestListener({
+ onInstallEnded: function(aInstall) {
+ gInstall.removeTestListener(this);
+ executeSoon(aCallback);
+ }
+ });
+ gInstall.install();
+}
+
+function check_hidden(aExpectedHidden) {
+ var hidden = !gCategoryUtilities.isTypeVisible("locale");
+ is(hidden, !!aExpectedHidden, "Should have correct hidden state");
+}
+
+function run_open_test(aTestSetup, aLoadHidden, aInitializedHidden, aSelected) {
+ function loadCallback(aManagerWindow) {
+ gManagerWindow = aManagerWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_hidden(aLoadHidden);
+ }
+
+ function run() {
+ open_manager(null, function() {
+ check_hidden(aInitializedHidden);
+ var selected = (gCategoryUtilities.selectedCategory == "locale");
+ is(selected, !!aSelected, "Should have correct selected state");
+
+ run_next_test();
+ }, loadCallback);
+ }
+
+ close_manager(gManagerWindow, function() {
+ // Allow for asynchronous functions to run before the manager opens
+ aTestSetup ? aTestSetup(run) : run();
+ });
+}
+
+
+// Tests that the locale category is hidden when there are no locales installed
+add_test(function() {
+ run_open_test(null, true, true);
+});
+
+// Tests that installing a locale while the Add-on Manager is open shows the
+// locale category
+add_test(function() {
+ check_hidden(true);
+ install_locale(function() {
+ check_hidden(false);
+ run_next_test();
+ });
+});
+
+// Tests that the locale category is shown with no delay when restarting
+// Add-on Manager
+add_test(function() {
+ run_open_test(null, false, false);
+});
+
+// Tests that cancelling the locale install and restarting the Add-on Manager
+// causes the locale category to be hidden with an acceptable delay
+add_test(function() {
+ gInstall.cancel();
+ run_open_test(null, false, true)
+});
+
+// Tests that the locale category is hidden with no delay when restarting
+// Add-on Manager
+add_test(function() {
+ run_open_test(null, true, true);
+});
+
+// Tests that installing a locale when the Add-on Manager is closed, and then
+// opening the Add-on Manager causes the locale category to be shown with an
+// acceptable delay
+add_test(function() {
+ run_open_test(install_locale, true, false);
+});
+
+// Tests that selection of the locale category persists
+add_test(function() {
+ gCategoryUtilities.openType("locale", function() {
+ run_open_test(null, false, false, true);
+ });
+});
+
+// Tests that cancelling the locale install and restarting the Add-on Manager
+// causes the locale category to be hidden and not selected
+add_test(function() {
+ gInstall.cancel();
+ run_open_test(null, false, true);
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug580298.js b/toolkit/mozapps/webextensions/test/browser/browser_bug580298.js
new file mode 100644
index 000000000..d3d338203
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug580298.js
@@ -0,0 +1,98 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that certain types of addons do not have their version number
+// displayed. This currently only includes lightweight themes.
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+add_task(function* test() {
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "extension@tests.mozilla.org",
+ name: "Extension 1",
+ type: "extension",
+ version: "123"
+ }, {
+ id: "theme@tests.mozilla.org",
+ name: "Theme 2",
+ type: "theme",
+ version: "456"
+ }, {
+ id: "lwtheme@personas.mozilla.org",
+ name: "Persona 3",
+ type: "theme",
+ version: "789"
+ }]);
+
+ gManagerWindow = yield open_manager();
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+});
+
+function get(aId) {
+ return gManagerWindow.document.getElementById(aId);
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function open_details(aList, aItem, aCallback) {
+ aList.ensureElementIsVisible(aItem);
+ EventUtils.synthesizeMouseAtCenter(aItem, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(aItem, { clickCount: 2 }, gManagerWindow);
+ return new Promise(resolve => wait_for_view_load(gManagerWindow, resolve));
+}
+
+var check_addon_has_version = Task.async(function*(aList, aName, aVersion) {
+ for (let i = 0; i < aList.itemCount; i++) {
+ let item = aList.getItemAtIndex(i);
+ if (get_node(item, "name").value === aName) {
+ ok(true, "Item with correct name found");
+ let { version } = yield get_tooltip_info(item);
+ is(version, aVersion, "Item has correct version");
+ return item;
+ }
+ }
+ ok(false, "Item with correct name was not found");
+ return null;
+});
+
+add_task(function*() {
+ yield gCategoryUtilities.openType("extension");
+ info("Extension");
+ let list = gManagerWindow.document.getElementById("addon-list");
+ let item = yield check_addon_has_version(list, "Extension 1", "123");
+ yield open_details(list, item);
+ is_element_visible(get("detail-version"), "Details view has version visible");
+ is(get("detail-version").value, "123", "Details view has correct version");
+});
+
+add_task(function*() {
+ yield gCategoryUtilities.openType("theme");
+ info("Normal theme");
+ let list = gManagerWindow.document.getElementById("addon-list");
+ let item = yield check_addon_has_version(list, "Theme 2", "456");
+ yield open_details(list, item);
+ is_element_visible(get("detail-version"), "Details view has version visible");
+ is(get("detail-version").value, "456", "Details view has correct version");
+});
+
+add_task(function*() {
+ yield gCategoryUtilities.openType("theme");
+ info("Lightweight theme");
+ let list = gManagerWindow.document.getElementById("addon-list");
+ // See that the version isn't displayed
+ let item = yield check_addon_has_version(list, "Persona 3", undefined);
+ yield open_details(list, item);
+ is_element_hidden(get("detail-version"), "Details view has version hidden");
+ // If the version element is hidden then we don't care about its value
+});
+
+add_task(function end_test() {
+ close_manager(gManagerWindow, finish);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug581076.js b/toolkit/mozapps/webextensions/test/browser/browser_bug581076.js
new file mode 100644
index 000000000..b02a6cc3e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug581076.js
@@ -0,0 +1,132 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 581076 - No "See all results" link present when searching for add-ons and not all are displayed (extensions.getAddons.maxResults)
+
+const PREF_GETADDONS_BROWSESEARCHRESULTS = "extensions.getAddons.search.browseURL";
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const PREF_GETADDONS_MAXRESULTS = "extensions.getAddons.maxResults";
+const SEARCH_URL = TESTROOT + "browser_searching.xml";
+const SEARCH_EXPECTED_TOTAL = 100;
+const SEARCH_QUERY = "search";
+
+const SEARCHABLE_PAGE = "addons://list/extension";
+
+var gManagerWindow;
+
+
+function test() {
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+
+ waitForExplicitFinish();
+
+ open_manager(SEARCHABLE_PAGE, function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ // Test generates a lot of available installs so just cancel them all
+ AddonManager.getAllInstalls(function(aInstalls) {
+ for (let install of aInstalls)
+ install.cancel();
+
+ close_manager(gManagerWindow, finish);
+ });
+}
+
+function search(aRemoteSearch, aCallback) {
+ waitForFocus(function() {
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = SEARCH_QUERY;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ let filter;
+ if (aRemoteSearch)
+ filter = gManagerWindow.document.getElementById("search-filter-remote");
+ else
+ filter = gManagerWindow.document.getElementById("search-filter-local");
+ EventUtils.synthesizeMouseAtCenter(filter, { }, gManagerWindow);
+
+ executeSoon(aCallback);
+ });
+ }, gManagerWindow);
+}
+
+function check_allresultslink(aShouldShow) {
+ var list = gManagerWindow.document.getElementById("search-list");
+ var link = gManagerWindow.document.getElementById("search-allresults-link");
+ is(link.parentNode, list.lastChild, "Footer should be at the end of the richlistbox");
+ if (aShouldShow) {
+ is_element_visible(link, "All Results link should be visible");
+ is(link.value, "See all " + SEARCH_EXPECTED_TOTAL + " results", "All Results link should show the correct message");
+ var scope = {};
+ Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", scope);
+ is(link.href, scope.AddonRepository.getSearchURL(SEARCH_QUERY), "All Results link should have the correct href");
+ } else {
+ is_element_hidden(link, "All Results link should be hidden");
+ }
+}
+
+add_test(function() {
+ info("Searching locally");
+ search(false, function() {
+ check_allresultslink(false);
+ restart_manager(gManagerWindow, SEARCHABLE_PAGE, function(aManager) {
+ gManagerWindow = aManager;
+ run_next_test();
+ });
+ });
+});
+
+add_test(function() {
+ debugger;
+ info("Searching remotely - more results than cap");
+ Services.prefs.setIntPref(PREF_GETADDONS_MAXRESULTS, 3);
+ search(true, function() {
+ check_allresultslink(true);
+ restart_manager(gManagerWindow, SEARCHABLE_PAGE, function(aManager) {
+ gManagerWindow = aManager;
+ run_next_test();
+ });
+ });
+});
+
+add_test(function() {
+ info("Searching remotely - less results than cap");
+ Services.prefs.setIntPref(PREF_GETADDONS_MAXRESULTS, 200);
+ search(true, function() {
+ check_allresultslink(false);
+ restart_manager(gManagerWindow, SEARCHABLE_PAGE, function(aManager) {
+ gManagerWindow = aManager;
+ run_next_test();
+ });
+ });
+});
+
+add_test(function() {
+ info("Searching remotely - more results than cap");
+ Services.prefs.setIntPref(PREF_GETADDONS_MAXRESULTS, 3);
+ search(true, function() {
+ check_allresultslink(true);
+ run_next_test();
+ });
+});
+
+add_test(function() {
+ info("Switching views");
+ gManagerWindow.loadView("addons://list/extension");
+ wait_for_view_load(gManagerWindow, function() {
+ info("Re-loading previous search");
+ search(true, function() {
+ check_allresultslink(true);
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug586574.js b/toolkit/mozapps/webextensions/test/browser/browser_bug586574.js
new file mode 100644
index 000000000..fb5ebf01b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug586574.js
@@ -0,0 +1,286 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 586574 - Provide way to set a default for automatic updates
+// Bug 710064 - Make the "Update Add-ons Automatically" checkbox state
+// also depend on the extensions.update.enabled pref
+
+// TEST_PATH=toolkit/mozapps/extensions/test/browser/browser_bug586574.js make -C obj-ff mochitest-browser-chrome
+
+const PREF_UPDATE_ENABLED = "extensions.update.enabled";
+const PREF_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault";
+
+var gManagerWindow;
+var gProvider;
+
+var gUtilsBtn;
+var gUtilsMenu;
+var gDropdownMenu;
+var gSetDefault;
+var gResetToAutomatic;
+var gResetToManual;
+
+// Make sure we don't accidentally start a background update while the prefs
+// are enabled.
+disableBackgroundUpdateTimer();
+registerCleanupFunction(() => {
+ enableBackgroundUpdateTimer();
+});
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "addon 1",
+ version: "1.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+
+ gUtilsBtn = gManagerWindow.document.getElementById("header-utils-btn");
+ gUtilsMenu = gManagerWindow.document.getElementById("utils-menu");
+
+ run_next_test();
+ });
+}
+
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+
+function wait_for_popup(aCallback) {
+ if (gUtilsMenu.state == "open") {
+ aCallback();
+ return;
+ }
+
+ gUtilsMenu.addEventListener("popupshown", function() {
+ gUtilsMenu.removeEventListener("popupshown", arguments.callee, false);
+ info("Utilities menu shown");
+ aCallback();
+ }, false);
+}
+
+function wait_for_hide(aCallback) {
+ if (gUtilsMenu.state == "closed") {
+ aCallback();
+ return;
+ }
+
+ gUtilsMenu.addEventListener("popuphidden", function() {
+ gUtilsMenu.removeEventListener("popuphidden", arguments.callee, false);
+ info("Utilities menu hidden");
+ aCallback();
+ }, false);
+}
+
+add_test(function() {
+ gSetDefault = gManagerWindow.document.getElementById("utils-autoUpdateDefault");
+ gResetToAutomatic = gManagerWindow.document.getElementById("utils-resetAddonUpdatesToAutomatic");
+ gResetToManual = gManagerWindow.document.getElementById("utils-resetAddonUpdatesToManual");
+
+ info("Ensuring default prefs are set to true");
+ Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, true);
+ Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, true);
+
+ wait_for_popup(function() {
+ is(gSetDefault.getAttribute("checked"), "true",
+ "#1 Set Default menuitem should be checked");
+ is_element_visible(gResetToAutomatic,
+ "#1 Reset to Automatic menuitem should be visible");
+ is_element_hidden(gResetToManual,
+ "#1 Reset to Manual menuitem should be hidden");
+
+ var listener = {
+ onPropertyChanged: function(aAddon, aProperties) {
+ AddonManager.removeAddonListener(listener);
+ is(aAddon.id, gProvider.addons[0].id,
+ "Should get onPropertyChanged event for correct addon");
+ ok(!("applyBackgroundUpdates" in aProperties),
+ "Should have gotten applyBackgroundUpdates in properties array");
+ is(aAddon.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT,
+ "Addon.applyBackgroundUpdates should have been reset to default");
+
+ info("Setting Addon.applyBackgroundUpdates back to disabled");
+ aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
+
+ wait_for_hide(run_next_test);
+ }
+ };
+ AddonManager.addAddonListener(listener);
+
+ info("Clicking Reset to Automatic menuitem");
+ EventUtils.synthesizeMouseAtCenter(gResetToAutomatic, { }, gManagerWindow);
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ info("Disabling extensions.update.enabled");
+ Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, false);
+
+ wait_for_popup(function() {
+ isnot(gSetDefault.getAttribute("checked"), "true",
+ "#2 Set Default menuitem should not be checked");
+ is_element_visible(gResetToAutomatic,
+ "#2 Reset to Automatic menuitem should be visible");
+ is_element_hidden(gResetToManual,
+ "#2 Reset to Manual menuitem should be hidden");
+
+ wait_for_hide(run_next_test);
+
+ info("Clicking Set Default menuitem to reenable");
+ EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
+ "extensions.update.enabled should be true after the previous test");
+ ok(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
+ "extensions.update.autoUpdateDefault should be true after the previous test");
+
+ info("Disabling both extensions.update.enabled and extensions.update.autoUpdateDefault");
+ Services.prefs.setBoolPref(PREF_UPDATE_ENABLED, false);
+ Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, false);
+
+ wait_for_popup(function() {
+ isnot(gSetDefault.getAttribute("checked"), "true",
+ "#3 Set Default menuitem should not be checked");
+ is_element_hidden(gResetToAutomatic,
+ "#3 Reset to automatic menuitem should be hidden");
+ is_element_visible(gResetToManual,
+ "#3 Reset to manual menuitem should be visible");
+
+ wait_for_hide(run_next_test);
+
+ info("Clicking Set Default menuitem to reenable");
+ EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
+ "extensions.update.enabled should be true after the previous test");
+ ok(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT),
+ "extensions.update.autoUpdateDefault should be true after the previous test");
+
+ info("clicking the button to disable extensions.update.autoUpdateDefault");
+ wait_for_popup(function() {
+ is(gSetDefault.getAttribute("checked"), "true",
+ "#4 Set Default menuitem should be checked");
+ is_element_visible(gResetToAutomatic,
+ "#4 Reset to Automatic menuitem should be visible");
+ is_element_hidden(gResetToManual,
+ "#4 Reset to Manual menuitem should be hidden");
+
+ wait_for_hide(run_next_test);
+
+ info("Clicking Set Default menuitem to disable");
+ EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ ok(Services.prefs.getBoolPref(PREF_UPDATE_ENABLED),
+ "extensions.update.enabled should be true after the previous test");
+ is(Services.prefs.getBoolPref(PREF_AUTOUPDATE_DEFAULT), false,
+ "extensions.update.autoUpdateDefault should be false after the previous test");
+
+ wait_for_popup(function() {
+ isnot(gSetDefault.getAttribute("checked"), "true",
+ "#5 Set Default menuitem should not be checked");
+ is_element_hidden(gResetToAutomatic,
+ "#5 Reset to automatic menuitem should be hidden");
+ is_element_visible(gResetToManual,
+ "#5 Reset to manual menuitem should be visible");
+
+ var listener = {
+ onPropertyChanged: function(aAddon, aProperties) {
+ AddonManager.removeAddonListener(listener);
+ is(aAddon.id, gProvider.addons[0].id,
+ "Should get onPropertyChanged event for correct addon");
+ ok(!("applyBackgroundUpdates" in aProperties),
+ "Should have gotten applyBackgroundUpdates in properties array");
+ is(aAddon.applyBackgroundUpdates, AddonManager.AUTOUPDATE_DEFAULT,
+ "Addon.applyBackgroundUpdates should have been reset to default");
+
+ info("Setting Addon.applyBackgroundUpdates back to disabled");
+ aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
+
+ wait_for_hide(run_next_test);
+ }
+ };
+ AddonManager.addAddonListener(listener);
+
+ info("Clicking Reset to Manual menuitem");
+ EventUtils.synthesizeMouseAtCenter(gResetToManual, { }, gManagerWindow);
+
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ wait_for_popup(function() {
+ isnot(gSetDefault.getAttribute("checked"), "true",
+ "#6 Set Default menuitem should not be checked");
+ is_element_hidden(gResetToAutomatic,
+ "#6 Reset to automatic menuitem should be hidden");
+ is_element_visible(gResetToManual,
+ "#6 Reset to manual menuitem should be visible");
+
+ wait_for_hide(run_next_test);
+
+ info("Clicking Set Default menuitem");
+ EventUtils.synthesizeMouseAtCenter(gSetDefault, { }, gManagerWindow);
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ wait_for_popup(function() {
+ is(gSetDefault.getAttribute("checked"), "true",
+ "#7 Set Default menuitem should be checked");
+ is_element_visible(gResetToAutomatic,
+ "#7 Reset to Automatic menuitem should be visible");
+ is_element_hidden(gResetToManual,
+ "#7 Reset to Manual menuitem should be hidden");
+
+ wait_for_hide(run_next_test);
+
+ gUtilsMenu.hidePopup();
+ });
+
+ info("Opening utilities menu");
+ EventUtils.synthesizeMouseAtCenter(gUtilsBtn, { }, gManagerWindow);
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug587970.js b/toolkit/mozapps/webextensions/test/browser/browser_bug587970.js
new file mode 100644
index 000000000..ef05ba4ea
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug587970.js
@@ -0,0 +1,180 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 587970 - Provide ability "Update all now" within 'Available Updates' screen
+
+var gManagerWindow;
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "addon 1",
+ version: "1.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "addon 2",
+ version: "2.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "addon 3",
+ version: "3.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }]);
+
+
+ open_manager("addons://updates/available", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("updates-list");
+ is(list.childNodes.length, 0, "Available updates list should be empty");
+
+ var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
+ is_element_visible(emptyNotice, "Empty notice should be visible");
+
+ var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
+ is_element_hidden(updateSelected, "Update Selected button should be hidden");
+
+ info("Adding updates");
+ gProvider.createInstalls([{
+ name: "addon 1",
+ version: "1.1",
+ existingAddon: gProvider.addons[0]
+ }, {
+ name: "addon 2",
+ version: "2.1",
+ existingAddon: gProvider.addons[1]
+ }, {
+ name: "addon 3",
+ version: "3.1",
+ existingAddon: gProvider.addons[2]
+ }]);
+
+ function wait_for_refresh() {
+ if (list.childNodes.length == 3 &&
+ list.childNodes[0].mManualUpdate &&
+ list.childNodes[1].mManualUpdate &&
+ list.childNodes[2].mManualUpdate) {
+ run_next_test();
+ } else {
+ info("Waiting for pane to refresh");
+ setTimeout(wait_for_refresh, 10);
+ }
+ }
+ info("Waiting for pane to refresh");
+ setTimeout(wait_for_refresh, 10);
+});
+
+
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("updates-list");
+ is(list.childNodes.length, 3, "Available updates list should have 2 items");
+
+ var item1 = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ isnot(item1, null, "Item for addon1@tests.mozilla.org should be in list");
+ var item2 = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+ isnot(item2, null, "Item for addon2@tests.mozilla.org should be in list");
+ var item3 = get_addon_element(gManagerWindow, "addon3@tests.mozilla.org");
+ isnot(item3, null, "Item for addon3@tests.mozilla.org should be in list");
+
+ var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
+ is_element_hidden(emptyNotice, "Empty notice should be hidden");
+
+ var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
+ is_element_visible(updateSelected, "Update Selected button should be visible");
+ is(updateSelected.disabled, false, "Update Selected button should be enabled by default");
+
+ is(item1._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon1");
+ is(item2._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon2");
+ is(item3._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon3");
+
+ info("Unchecking Include Update checkbox for addon1");
+ EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item1._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon1");
+ is(updateSelected.disabled, false, "Update Selected button should still be enabled");
+
+ info("Unchecking Include Update checkbox for addon2");
+ EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item2._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon2");
+ is(updateSelected.disabled, false, "Update Selected button should still be enabled");
+
+ info("Unchecking Include Update checkbox for addon3");
+ EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item3._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon3");
+ is(updateSelected.disabled, true, "Update Selected button should now be disabled");
+
+ info("Checking Include Update checkbox for addon2");
+ EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item2._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon2");
+ is(updateSelected.disabled, false, "Update Selected button should now be enabled");
+
+ info("Checking Include Update checkbox for addon3");
+ EventUtils.synthesizeMouse(item3._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item3._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon3");
+ is(updateSelected.disabled, false, "Update Selected button should now be enabled");
+
+ var installCount = 0;
+ var listener = {
+ onDownloadStarted: function(aInstall) {
+ isnot(aInstall.existingAddon.id, "addon1@tests.mozilla.org", "Should not have seen a download start for addon1");
+ },
+
+ onInstallEnded: function(aInstall) {
+ if (++installCount < 2)
+ return;
+
+ gProvider.installs[0].removeTestListener(listener);
+ gProvider.installs[1].removeTestListener(listener);
+ gProvider.installs[2].removeTestListener(listener);
+
+ // Installs are started synchronously so by the time an executeSoon is
+ // executed all installs that are going to start will have started
+ executeSoon(function() {
+ is(gProvider.installs[0].state, AddonManager.STATE_AVAILABLE, "addon1 should not have been upgraded");
+ is(gProvider.installs[1].state, AddonManager.STATE_INSTALLED, "addon2 should have been upgraded");
+ is(gProvider.installs[2].state, AddonManager.STATE_INSTALLED, "addon3 should have been upgraded");
+
+ run_next_test();
+ });
+ }
+ }
+ gProvider.installs[0].addTestListener(listener);
+ gProvider.installs[1].addTestListener(listener);
+ gProvider.installs[2].addTestListener(listener);
+ info("Clicking Update Selected button");
+ EventUtils.synthesizeMouseAtCenter(updateSelected, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ var updateSelected = gManagerWindow.document.getElementById("update-selected-btn");
+ is(updateSelected.disabled, true, "Update Selected button should be disabled");
+
+ var item1 = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ isnot(item1, null, "Item for addon1@tests.mozilla.org should be in list");
+ is(item1._includeUpdate.checked, false, "Include Update checkbox should not have changed");
+
+ info("Checking Include Update checkbox for addon1");
+ EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
+ is(item1._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon1");
+ is(updateSelected.disabled, false, "Update Selected button should now not be disabled");
+
+ run_next_test();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug590347.js b/toolkit/mozapps/webextensions/test/browser/browser_bug590347.js
new file mode 100644
index 000000000..f805f0e19
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug590347.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 590347
+// Tests if softblock notifications are exposed in preference to incompatible
+// notifications when compatibility checking is disabled
+
+var gProvider;
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+var gVersion = Services.appinfo.version;
+
+// Opens the details view of an add-on
+function open_details(aId, aType, aCallback) {
+ requestLongerTimeout(2);
+
+ gCategoryUtilities.openType(aType, function() {
+ var list = gManagerWindow.document.getElementById("addon-list");
+ var item = list.firstChild;
+ while (item) {
+ if ("mAddon" in item && item.mAddon.id == aId) {
+ list.ensureElementIsVisible(item);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, aCallback);
+ return;
+ }
+ item = item.nextSibling;
+ }
+ ok(false, "Should have found the add-on in the list");
+ });
+}
+
+function get_list_view_warning_node() {
+ let item = gManagerWindow.document.getElementById("addon-list").firstChild;
+ let found = false;
+ while (item) {
+ if (item.mAddon.name == "Test add-on") {
+ found = true;
+ break;
+ }
+ item = item.nextSibling;
+ }
+ ok(found, "Test add-on node should have been found.");
+ return item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
+}
+
+function get_detail_view_warning_node(aManagerWindow) {
+ if (aManagerWindow)
+ return aManagerWindow.document.getElementById("detail-warning");
+ return undefined;
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on",
+ description: "A test add-on",
+ isCompatible: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
+ }]);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+// Check with compatibility checking enabled
+add_test(function() {
+ gCategoryUtilities.openType("extension", function() {
+ Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, true);
+ let warning_node = get_list_view_warning_node();
+ is_element_visible(warning_node, "Warning message should be visible");
+ is(warning_node.textContent, "Test add-on is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ run_next_test();
+ });
+});
+
+add_test(function() {
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ let warning_node = get_detail_view_warning_node(gManagerWindow);
+ is_element_visible(warning_node, "Warning message should be visible");
+ is(warning_node.textContent, "Test add-on is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, false);
+ run_next_test();
+ });
+});
+
+// Check with compatibility checking disabled
+add_test(function() {
+ gCategoryUtilities.openType("extension", function() {
+ let warning_node = get_list_view_warning_node();
+ is_element_visible(warning_node, "Warning message should be visible");
+ is(warning_node.textContent, "Test add-on is known to cause security or stability issues.", "Warning message should be correct");
+ run_next_test();
+ });
+});
+
+add_test(function() {
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ let warning_node = get_detail_view_warning_node(gManagerWindow);
+ is_element_visible(warning_node, "Warning message should be visible");
+ is(warning_node.textContent, "Test add-on is known to cause security or stability issues.", "Warning message should be correct");
+ run_next_test();
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug591465.js b/toolkit/mozapps/webextensions/test/browser/browser_bug591465.js
new file mode 100644
index 000000000..f759ffc1f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug591465.js
@@ -0,0 +1,512 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 591465 - Context menu of add-ons miss context related state change entries
+
+
+var tempScope = {};
+Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
+var LightweightThemeManager = tempScope.LightweightThemeManager;
+
+
+const PREF_GETADDONS_MAXRESULTS = "extensions.getAddons.maxResults";
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const SEARCH_URL = TESTROOT + "browser_bug591465.xml";
+const SEARCH_QUERY = "SEARCH";
+
+var gManagerWindow;
+var gProvider;
+var gContextMenu;
+var gLWTheme = {
+ id: "4",
+ version: "1",
+ name: "Bling",
+ description: "SO MUCH BLING!",
+ author: "Pixel Pusher",
+ homepageURL: "http://mochi.test:8888/data/index.html",
+ headerURL: "http://mochi.test:8888/data/header.png",
+ footerURL: "http://mochi.test:8888/data/footer.png",
+ previewURL: "http://mochi.test:8888/data/preview.png",
+ iconURL: "http://mochi.test:8888/data/icon.png"
+ };
+
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "addon 1",
+ version: "1.0"
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "addon 2",
+ version: "1.0",
+ _userDisabled: true
+ }, {
+ id: "theme1@tests.mozilla.org",
+ name: "theme 1",
+ version: "1.0",
+ type: "theme"
+ }, {
+ id: "theme2@tests.mozilla.org",
+ name: "theme 2",
+ version: "1.0",
+ type: "theme",
+ _userDisabled: true
+ }, {
+ id: "theme3@tests.mozilla.org",
+ name: "theme 3",
+ version: "1.0",
+ type: "theme",
+ permissions: 0
+ }]);
+
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gContextMenu = aWindow.document.getElementById("addonitem-popup");
+ run_next_test();
+ });
+}
+
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+
+function check_contextmenu(aIsTheme, aIsEnabled, aIsRemote, aIsDetails, aIsSingleItemCase) {
+ if (aIsTheme || aIsEnabled || aIsRemote)
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_enableItem"),
+ "'Enable' should be hidden");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_enableItem"),
+ "'Enable' should be visible");
+
+ if (aIsTheme || !aIsEnabled || aIsRemote)
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_disableItem"),
+ "'Disable' should be hidden");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_disableItem"),
+ "'Disable' should be visible");
+
+ if (!aIsTheme || aIsEnabled || aIsRemote || aIsSingleItemCase)
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_enableTheme"),
+ "'Wear Theme' should be hidden");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_enableTheme"),
+ "'Wear Theme' should be visible");
+
+ if (!aIsTheme || !aIsEnabled || aIsRemote || aIsSingleItemCase)
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_disableTheme"),
+ "'Stop Wearing Theme' should be hidden");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_disableTheme"),
+ "'Stop Wearing Theme' should be visible");
+
+ if (aIsRemote)
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_installItem"),
+ "'Install' should be visible");
+ else
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_installItem"),
+ "'Install' should be hidden");
+
+ if (aIsDetails)
+ is_element_hidden(gManagerWindow.document.getElementById("menuitem_showDetails"),
+ "'Show More Information' should be hidden in details view");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("menuitem_showDetails"),
+ "'Show More Information' should be visible in list view");
+
+ if (aIsSingleItemCase)
+ is_element_hidden(gManagerWindow.document.getElementById("addonitem-menuseparator"),
+ "Menu separator should be hidden with only one menu item");
+ else
+ is_element_visible(gManagerWindow.document.getElementById("addonitem-menuseparator"),
+ "Menu separator should be visible with multiple menu items");
+
+}
+
+
+add_test(function() {
+ var el = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ isnot(el, null, "Should have found addon element");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, true, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled extension item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+add_test(function() {
+ var el = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ isnot(el, null, "Should have found addon element");
+ el.mAddon.userDisabled = true;
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, false, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on newly disabled extension item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+add_test(function() {
+ var el = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ isnot(el, null, "Should have found addon element");
+ el.mAddon.userDisabled = false;
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, true, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on newly enabled extension item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+add_test(function() {
+ var el = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, false, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on disabled extension item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://list/theme");
+ wait_for_view_load(gManagerWindow, function() {
+ var el = get_addon_element(gManagerWindow, "theme1@tests.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, true, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled theme item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ var el = get_addon_element(gManagerWindow, "theme2@tests.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, false, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on disabled theme item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+
+add_test(function() {
+ LightweightThemeManager.currentTheme = gLWTheme;
+
+ var el = get_addon_element(gManagerWindow, "4@personas.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, true, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled LW theme item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+
+add_test(function() {
+ LightweightThemeManager.currentTheme = null;
+
+ var el = get_addon_element(gManagerWindow, "4@personas.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, false, false, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on disabled LW theme item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+});
+
+
+add_test(function() {
+ LightweightThemeManager.currentTheme = gLWTheme;
+
+ gManagerWindow.loadView("addons://detail/4@personas.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, true, false, true, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled LW theme, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ LightweightThemeManager.currentTheme = null;
+
+ gManagerWindow.loadView("addons://detail/4@personas.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, false, false, true, false);
+
+ gContextMenu.hidePopup();
+
+ AddonManager.getAddonByID("4@personas.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+ run_next_test();
+ });
+ }, false);
+
+ info("Opening context menu on disabled LW theme, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/addon1@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, true, false, true, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled extension, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/addon2@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, false, false, true, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on disabled extension, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/theme1@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, true, false, true, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on enabled theme, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/theme2@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, false, false, true, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on disabled theme, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/theme3@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(true, true, false, true, true);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu with single menu item on enabled theme, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
+
+add_test(function() {
+ info("Searching for remote addons");
+
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = SEARCH_QUERY;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var filter = gManagerWindow.document.getElementById("search-filter-remote");
+ EventUtils.synthesizeMouseAtCenter(filter, { }, gManagerWindow);
+ executeSoon(function() {
+
+ var el = get_addon_element(gManagerWindow, "remote1@tests.mozilla.org");
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, false, true, false, false);
+
+ gContextMenu.hidePopup();
+ run_next_test();
+ }, false);
+
+ info("Opening context menu on remote extension item");
+ el.parentNode.ensureElementIsVisible(el);
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+
+ });
+ });
+});
+
+
+add_test(function() {
+ gManagerWindow.loadView("addons://detail/remote1@tests.mozilla.org");
+ wait_for_view_load(gManagerWindow, function() {
+
+ gContextMenu.addEventListener("popupshown", function() {
+ gContextMenu.removeEventListener("popupshown", arguments.callee, false);
+
+ check_contextmenu(false, false, true, true, false);
+
+ gContextMenu.hidePopup();
+
+ // Delete the created install
+ AddonManager.getAllInstalls(function(aInstalls) {
+ is(aInstalls.length, 1, "Should be one available install");
+ aInstalls[0].cancel();
+
+ run_next_test();
+ });
+ }, false);
+
+ info("Opening context menu on remote extension, in detail view");
+ var el = gManagerWindow.document.querySelector("#detail-view .detail-view-container");
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug591465.xml b/toolkit/mozapps/webextensions/test/browser/browser_bug591465.xml
new file mode 100644
index 000000000..9c2e102e7
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug591465.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="100">
+ <addon>
+ <name>MAGICAL SEARCH RESULT</name>
+ <type id='1'>Extension</type>
+ <guid>remote1@tests.mozilla.org</guid>
+ <version>3.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary - SEARCH SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="2">http://example.com/browser/toolkit/mozapps/extensions/test/browser/addons/browser_searching.xpi</install>
+ </addon>
+</searchresults>
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug591663.js b/toolkit/mozapps/webextensions/test/browser/browser_bug591663.js
new file mode 100644
index 000000000..4a4f735af
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug591663.js
@@ -0,0 +1,161 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that the empty notice in the list view disappears as it should
+
+// Don't use a standard list view (e.g. "extension") to ensure that the list is
+// initially empty. Don't need to worry about the list of categories displayed
+// since only the list view itself is tested.
+var VIEW_ID = "addons://list/mock-addon";
+
+var LIST_ID = "addon-list";
+var EMPTY_ID = "addon-list-empty";
+
+var gManagerWindow;
+var gProvider;
+var gItem;
+
+var gInstallProperties = {
+ name: "Bug 591663 Mock Install",
+ type: "mock-addon"
+};
+var gAddonProperties = {
+ id: "test1@tests.mozilla.org",
+ name: "Bug 591663 Mock Add-on",
+ type: "mock-addon"
+};
+var gExtensionProperties = {
+ name: "Bug 591663 Extension Install",
+ type: "extension"
+};
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider(true, [{
+ id: "mock-addon",
+ name: "Mock Add-ons",
+ uiPriority: 4500,
+ flags: AddonManager.TYPE_UI_VIEW_LIST
+ }]);
+
+ open_manager(VIEW_ID, function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+/**
+ * Check that the list view is as expected
+ *
+ * @param aItem
+ * The expected item in the list, or null if list should be empty
+ */
+function check_list(aItem) {
+ // Check state of the empty notice
+ let emptyNotice = gManagerWindow.document.getElementById(EMPTY_ID);
+ ok(emptyNotice != null, "Should have found the empty notice");
+ is(!emptyNotice.hidden, (aItem == null), "Empty notice should be showing if list empty");
+
+ // Check the children of the list
+ let list = gManagerWindow.document.getElementById(LIST_ID);
+ is(list.childNodes.length, aItem ? 1 : 0, "Should get expected number of items in list");
+ if (aItem != null) {
+ let itemName = list.firstChild.getAttribute("name");
+ is(itemName, aItem.name, "List item should have correct name");
+ }
+}
+
+
+// Test that the empty notice is showing and no items are showing in list
+add_test(function() {
+ check_list(null);
+ run_next_test();
+});
+
+// Test that a new, non-active, install does not affect the list view
+add_test(function() {
+ gItem = gProvider.createInstalls([gInstallProperties])[0];
+ check_list(null);
+ run_next_test();
+});
+
+// Test that onInstallStarted properly hides empty notice and adds install to list
+add_test(function() {
+ gItem.addTestListener({
+ onDownloadStarted: function() {
+ // Install type unknown until download complete
+ check_list(null);
+ },
+ onInstallStarted: function() {
+ check_list(gItem);
+ },
+ onInstallEnded: function() {
+ check_list(gItem);
+ run_next_test();
+ }
+ });
+
+ gItem.install();
+});
+
+// Test that restarting the manager does not change list
+add_test(function() {
+ restart_manager(gManagerWindow, VIEW_ID, function(aManagerWindow) {
+ gManagerWindow = aManagerWindow;
+ check_list(gItem);
+ run_next_test();
+ });
+});
+
+// Test that onInstallCancelled removes install and shows empty notice
+add_test(function() {
+ gItem.cancel();
+ gItem = null;
+ check_list(null);
+ run_next_test();
+});
+
+// Test that add-ons of a different type do not show up in the list view
+add_test(function() {
+ let extension = gProvider.createInstalls([gExtensionProperties])[0];
+ check_list(null);
+
+ extension.addTestListener({
+ onDownloadStarted: function() {
+ check_list(null);
+ },
+ onInstallStarted: function() {
+ check_list(null);
+ },
+ onInstallEnded: function() {
+ check_list(null);
+ extension.cancel();
+ run_next_test();
+ }
+ });
+
+ extension.install();
+});
+
+// Test that onExternalInstall properly hides empty notice and adds install to list
+add_test(function() {
+ gItem = gProvider.createAddons([gAddonProperties])[0];
+ check_list(gItem);
+ run_next_test();
+});
+
+// Test that restarting the manager does not change list
+add_test(function() {
+ restart_manager(gManagerWindow, VIEW_ID, function(aManagerWindow) {
+ gManagerWindow = aManagerWindow;
+ check_list(gItem);
+ run_next_test();
+ });
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug593535.js b/toolkit/mozapps/webextensions/test/browser/browser_bug593535.js
new file mode 100644
index 000000000..fd23d0036
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug593535.js
@@ -0,0 +1,119 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 593535 - Failure to download extension causes about:addons to list the
+// addon with no way to restart the download
+
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const SEARCH_URL = TESTROOT + "browser_bug593535.xml";
+const QUERY = "NOTFOUND";
+
+var gProvider;
+var gManagerWindow;
+
+function test() {
+ waitForExplicitFinish();
+
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ AddonManager.getAllInstalls(function(aInstallsList) {
+ for (var install of aInstallsList) {
+ var sourceURI = install.sourceURI.spec;
+ if (sourceURI.match(/^http:\/\/example\.com\/(.+)\.xpi$/) != null)
+ install.cancel();
+ }
+
+ finish();
+ });
+ });
+}
+
+function search(aQuery, aCallback) {
+ // Point search to the correct xml test file
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = aQuery;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var remoteFilter = gManagerWindow.document.getElementById("search-filter-remote");
+ EventUtils.synthesizeMouseAtCenter(remoteFilter, { }, gManagerWindow);
+
+ aCallback();
+ });
+}
+
+function get_addon_item(aName) {
+ var id = aName + "@tests.mozilla.org";
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+ for (let row of rows) {
+ if (row.mAddon && row.mAddon.id == id)
+ return row;
+ }
+
+ return null;
+}
+
+function get_install_button(aItem) {
+ isnot(aItem, null, "Item should not be null when checking state of install button");
+ var installStatus = getAnonymousElementByAttribute(aItem, "anonid", "install-status");
+ return getAnonymousElementByAttribute(installStatus, "anonid", "install-remote-btn");
+}
+
+
+function getAnonymousElementByAttribute(aElement, aName, aValue) {
+ return gManagerWindow.document.getAnonymousElementByAttribute(aElement,
+ aName,
+ aValue);
+}
+
+
+
+// Tests that a failed install for a remote add-on will ask to retry the install
+add_test(function() {
+ var remoteItem;
+
+ var listener = {
+ onDownloadFailed: function(aInstall) {
+ aInstall.removeListener(this);
+ ok(true, "Install failed as expected");
+
+ executeSoon(function() {
+ is(remoteItem.getAttribute("notification"), "warning", "Item should have notification attribute set to 'warning'");
+ is_element_visible(remoteItem._warning, "Warning text should be visible");
+ is(remoteItem._warning.textContent, "There was an error downloading NOTFOUND.", "Warning should show correct message");
+ is_element_visible(remoteItem._warningLink, "Retry button should be visible");
+ run_next_test();
+ });
+ },
+
+ onInstallEnded: function() {
+ ok(false, "Install should have failed");
+ }
+ }
+
+ search(QUERY, function() {
+ var list = gManagerWindow.document.getElementById("search-list");
+ remoteItem = get_addon_item("notfound1");
+ list.ensureElementIsVisible(remoteItem);
+
+ remoteItem.mAddon.install.addListener(listener);
+
+ var installBtn = get_install_button(remoteItem);
+ EventUtils.synthesizeMouseAtCenter(installBtn, { }, gManagerWindow);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug593535.xml b/toolkit/mozapps/webextensions/test/browser/browser_bug593535.xml
new file mode 100644
index 000000000..411d9f383
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug593535.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="100">
+ <addon>
+ <name>NOTFOUND</name>
+ <type id='1'>Extension</type>
+ <guid>notfound1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Install file not found - NOTFOUND</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/file_not_found.xpi</install>
+ </addon>
+</searchresults>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug596336.js b/toolkit/mozapps/webextensions/test/browser/browser_bug596336.js
new file mode 100644
index 000000000..ec32e376f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug596336.js
@@ -0,0 +1,156 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that upgrading bootstrapped add-ons behaves correctly while the
+// manager is open
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+add_task(function* test() {
+ waitForExplicitFinish();
+
+ gManagerWindow = yield open_manager("addons://list/extension");
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+});
+
+function get_list_item_count() {
+ return get_test_items_in_list(gManagerWindow).length;
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function get_class_node(parent, cls) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "class", cls);
+}
+
+function install_addon(aXpi) {
+ return new Promise(resolve => {
+ AddonManager.getInstallForURL(TESTROOT + "addons/" + aXpi + ".xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: function(aInstall) {
+ resolve();
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+ });
+}
+
+var check_addon = Task.async(function*(aAddon, aVersion) {
+ is(get_list_item_count(), 1, "Should be one item in the list");
+ is(aAddon.version, aVersion, "Add-on should have the right version");
+
+ let item = get_addon_element(gManagerWindow, "bug596336-1@tests.mozilla.org");
+ ok(!!item, "Should see the add-on in the list");
+
+ // Force XBL to apply
+ item.clientTop;
+
+ let { version } = yield get_tooltip_info(item);
+ is(version, aVersion, "Version should be correct");
+
+ if (aAddon.userDisabled)
+ is_element_visible(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
+ else
+ is_element_hidden(get_class_node(item, "disabled-postfix"), "Disabled postfix should be hidden");
+});
+
+// Install version 1 then upgrade to version 2 with the manager open
+add_task(function*() {
+ yield install_addon("browser_bug596336_1");
+ let [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "1.0");
+ ok(!aAddon.userDisabled, "Add-on should not be disabled");
+
+ yield install_addon("browser_bug596336_2");
+ [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "2.0");
+ ok(!aAddon.userDisabled, "Add-on should not be disabled");
+
+ aAddon.uninstall();
+
+ is(get_list_item_count(), 0, "Should be no items in the list");
+});
+
+// Install version 1 mark it as disabled then upgrade to version 2 with the
+// manager open
+add_task(function*() {
+ yield install_addon("browser_bug596336_1");
+ let [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ aAddon.userDisabled = true;
+ yield check_addon(aAddon, "1.0");
+ ok(aAddon.userDisabled, "Add-on should be disabled");
+
+ yield install_addon("browser_bug596336_2");
+ [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "2.0");
+ ok(aAddon.userDisabled, "Add-on should be disabled");
+
+ aAddon.uninstall();
+
+ is(get_list_item_count(), 0, "Should be no items in the list");
+});
+
+// Install version 1 click the remove button and then upgrade to version 2 with
+// the manager open
+add_task(function*() {
+ yield install_addon("browser_bug596336_1");
+ let [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "1.0");
+ ok(!aAddon.userDisabled, "Add-on should not be disabled");
+
+ let item = get_addon_element(gManagerWindow, "bug596336-1@tests.mozilla.org");
+ EventUtils.synthesizeMouseAtCenter(get_node(item, "remove-btn"), { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+ is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
+
+ yield install_addon("browser_bug596336_2");
+ [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "2.0");
+ ok(!aAddon.userDisabled, "Add-on should not be disabled");
+
+ aAddon.uninstall();
+
+ is(get_list_item_count(), 0, "Should be no items in the list");
+});
+
+// Install version 1, disable it, click the remove button and then upgrade to
+// version 2 with the manager open
+add_task(function*() {
+ yield install_addon("browser_bug596336_1");
+ let [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ aAddon.userDisabled = true;
+ yield check_addon(aAddon, "1.0");
+ ok(aAddon.userDisabled, "Add-on should be disabled");
+
+ let item = get_addon_element(gManagerWindow, "bug596336-1@tests.mozilla.org");
+ EventUtils.synthesizeMouseAtCenter(get_node(item, "remove-btn"), { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+ is_element_visible(get_class_node(item, "pending"), "Pending message should be visible");
+
+ yield install_addon("browser_bug596336_2");
+ [aAddon] = yield promiseAddonsByIDs(["bug596336-1@tests.mozilla.org"]);
+ yield check_addon(aAddon, "2.0");
+ ok(aAddon.userDisabled, "Add-on should be disabled");
+
+ aAddon.uninstall();
+
+ is(get_list_item_count(), 0, "Should be no items in the list");
+});
+
+add_task(function end_test() {
+ close_manager(gManagerWindow, finish);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug608316.js b/toolkit/mozapps/webextensions/test/browser/browser_bug608316.js
new file mode 100644
index 000000000..72bb61f49
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug608316.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 608316 - Test that cancelling an uninstall during the onUninstalling
+// event doesn't confuse the UI
+
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "addon 1",
+ version: "1.0"
+ }]);
+
+ run_next_test();
+}
+
+
+function end_test() {
+ finish();
+}
+
+
+add_test(function() {
+ var sawUninstall = false;
+ var listener = {
+ onUninstalling: function(aAddon, aRestartRequired) {
+ if (aAddon.id != "addon1@tests.mozilla.org")
+ return;
+ sawUninstall = true;
+ aAddon.cancelUninstall();
+ }
+ }
+
+ // Important to add this before opening the UI so it gets its events first
+ AddonManager.addAddonListener(listener);
+ registerCleanupFunction(function() {
+ AddonManager.removeAddonListener(listener);
+ });
+
+ open_manager("addons://list/extension", function(aManager) {
+ var addon = get_addon_element(aManager, "addon1@tests.mozilla.org");
+ isnot(addon, null, "Should see the add-on in the list");
+
+ var removeBtn = aManager.document.getAnonymousElementByAttribute(addon, "anonid", "remove-btn");
+ EventUtils.synthesizeMouseAtCenter(removeBtn, { }, aManager);
+
+ ok(sawUninstall, "Should have seen the uninstall event");
+ sawUninstall = false;
+
+ is(addon.getAttribute("pending"), "", "Add-on should not be uninstalling");
+
+ close_manager(aManager, function() {
+ ok(!sawUninstall, "Should not have seen another uninstall event");
+
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug610764.js b/toolkit/mozapps/webextensions/test/browser/browser_bug610764.js
new file mode 100644
index 000000000..58de88130
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug610764.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the discovery view is the default
+
+var gCategoryUtilities;
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager(null, function(aWindow) {
+ waitForFocus(function() {
+ // The last view is cached except when it is the search view so switch to
+ // that and reopen to ensure we see the default view
+ var searchBox = aWindow.document.getElementById("header-search");
+ searchBox.value = "bar";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, aWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, aWindow);
+
+ wait_for_view_load(aWindow, function() {
+ close_manager(aWindow, function() {
+ open_manager(null, function(aWindow) {
+ gCategoryUtilities = new CategoryUtilities(aWindow);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should show the discovery pane by default");
+
+ close_manager(aWindow, finish);
+ });
+ });
+ });
+ }, aWindow);
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug616841.js b/toolkit/mozapps/webextensions/test/browser/browser_bug616841.js
new file mode 100644
index 000000000..3cf6f5346
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug616841.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test_string_compare() {
+ ok("C".localeCompare("D") < 0, "C < D");
+ ok("D".localeCompare("C") > 0, "D > C");
+ ok("\u010C".localeCompare("D") < 0, "\u010C < D");
+ ok("D".localeCompare("\u010C") > 0, "D > \u010C");
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ test_string_compare();
+
+ AddonManager.getAddonByID("foo", function(aAddon) {
+ test_string_compare();
+ finish();
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug618502.js b/toolkit/mozapps/webextensions/test/browser/browser_bug618502.js
new file mode 100644
index 000000000..5bcc6baf1
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug618502.js
@@ -0,0 +1,44 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 608316 - Test that opening the manager to an add-on that doesn't exist
+// just loads the default view
+
+var gCategoryUtilities;
+
+function test() {
+ waitForExplicitFinish();
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+add_test(function() {
+ open_manager("addons://detail/foo", function(aManager) {
+ gCategoryUtilities = new CategoryUtilities(aManager);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should fall back to the discovery pane");
+
+ close_manager(aManager, run_next_test);
+ });
+});
+
+// Also test that opening directly to an add-on that does exist doesn't break
+// and selects the right category
+add_test(function() {
+ new MockProvider().createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "addon 1",
+ version: "1.0"
+ }]);
+
+ open_manager("addons://detail/addon1@tests.mozilla.org", function(aManager) {
+ gCategoryUtilities = new CategoryUtilities(aManager);
+ is(gCategoryUtilities.selectedCategory, "extension", "Should have selected the right category");
+
+ close_manager(aManager, run_next_test);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug679604.js b/toolkit/mozapps/webextensions/test/browser/browser_bug679604.js
new file mode 100644
index 000000000..e1ec605c2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug679604.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 679604 - Test that a XUL persisted category from an older version of
+// Firefox doesn't break the add-ons manager when that category doesn't exist
+
+var gManagerWindow;
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager(null, function(aWindow) {
+ var categories = aWindow.document.getElementById("categories");
+ categories.setAttribute("last-selected", "foo");
+ aWindow.document.persist("categories", "last-selected");
+
+ close_manager(aWindow, function() {
+ Services.prefs.clearUserPref(PREF_UI_LASTCATEGORY);
+
+ open_manager(null, function(aWindow) {
+ is(new CategoryUtilities(aWindow).selectedCategory, "discover",
+ "Should have loaded the right view");
+
+ close_manager(aWindow, finish);
+ });
+ });
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug714593.js b/toolkit/mozapps/webextensions/test/browser/browser_bug714593.js
new file mode 100644
index 000000000..b9a7faa5e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_bug714593.js
@@ -0,0 +1,140 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that installed addons in the search view load inline prefs properly
+
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const NO_MATCH_URL = TESTROOT + "browser_searching_empty.xml";
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+function test() {
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "inlinesettings2@tests.mozilla.org",
+ name: "Inline Settings (Regular)",
+ version: "1",
+ optionsURL: CHROMEROOT + "options.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_INLINE
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+/*
+ * Checks whether or not the Add-ons Manager is currently searching
+ *
+ * @param aExpectedSearching
+ * The expected isSearching state
+ */
+function check_is_searching(aExpectedSearching) {
+ var loading = gManagerWindow.document.getElementById("search-loading");
+ is(!is_hidden(loading), aExpectedSearching,
+ "Search throbber should be showing iff currently searching");
+}
+
+/*
+ * Completes a search
+ *
+ * @param aQuery
+ * The query to search for
+ * @param aFinishImmediately
+ * Boolean representing whether or not the search is expected to
+ * finish immediately
+ * @param aCallback
+ * The callback to call when the search is done
+ * @param aCategoryType
+ * The expected selected category after the search is done.
+ * Optional and defaults to "search"
+ */
+function search(aQuery, aFinishImmediately, aCallback, aCategoryType) {
+ // Point search to the correct xml test file
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, NO_MATCH_URL);
+
+ aCategoryType = aCategoryType ? aCategoryType : "search";
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = aQuery;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ var finishImmediately = true;
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, aCategoryType, "Expected category view should be selected");
+ is(gCategoryUtilities.isTypeVisible("search"), aCategoryType == "search",
+ "Search category should only be visible if it is the current view");
+ is(finishImmediately, aFinishImmediately, "Search should finish immediately only if expected");
+
+ aCallback();
+ });
+
+ finishImmediately = false
+ if (!aFinishImmediately)
+ check_is_searching(true);
+}
+
+/*
+ * Get item for a specific add-on by name
+ *
+ * @param aName
+ * The name of the add-on to search for
+ * @return Row of add-on if found, null otherwise
+ */
+function get_addon_item(aName) {
+ var id = aName + "@tests.mozilla.org";
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+ for (let row of rows) {
+ if (row.mAddon && row.mAddon.id == id)
+ return row;
+ }
+
+ return null;
+}
+
+add_test(function() {
+ search("settings", false, function() {
+ var localFilter = gManagerWindow.document.getElementById("search-filter-local");
+ EventUtils.synthesizeMouseAtCenter(localFilter, { }, gManagerWindow);
+
+ var item = get_addon_item("inlinesettings2");
+ // Force the XBL binding to apply.
+ item.clientTop;
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gManagerWindow.gViewController.currentViewObj, gManagerWindow.gDetailView, "View should have changed to detail");
+
+ var searchCategory = gManagerWindow.document.getElementById("category-search");
+ EventUtils.synthesizeMouseAtCenter(searchCategory, { }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gManagerWindow.gViewController.currentViewObj, gManagerWindow.gSearchView, "View should have changed back to search");
+
+ // Reset filter to remote to avoid breaking later tests.
+ var remoteFilter = gManagerWindow.document.getElementById("search-filter-remote");
+ EventUtils.synthesizeMouseAtCenter(remoteFilter, { }, gManagerWindow);
+ run_next_test();
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_cancelCompatCheck.js b/toolkit/mozapps/webextensions/test/browser/browser_cancelCompatCheck.js
new file mode 100644
index 000000000..e7c672212
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_cancelCompatCheck.js
@@ -0,0 +1,462 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that we can cancel the add-on compatibility check while it is
+// in progress (bug 772484).
+// Test framework copied from browser_bug557956.js
+
+const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul";
+
+const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
+const PREF_MIN_PLATFORM_COMPAT = "extensions.minCompatiblePlatformVersion";
+const PREF_METADATA_LASTUPDATE = "extensions.getAddons.cache.lastUpdate";
+
+var repo = {};
+Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", repo);
+Components.utils.import("resource://gre/modules/Promise.jsm", this);
+
+/**
+ * Test add-ons:
+ *
+ * Addon minVersion maxVersion Notes
+ * addon1 0 *
+ * addon2 0 0
+ * addon3 0 0
+ * addon4 1 *
+ * addon5 0 0 Made compatible by update check
+ * addon6 0 0 Made compatible by update check
+ * addon7 0 0 Has a broken update available
+ * addon8 0 0 Has an update available
+ * addon9 0 0 Has an update available
+ * addon10 0 0 Made incompatible by override check
+ */
+
+// describe the addons
+var ao1 = { file: "browser_bug557956_1", id: "bug557956-1@tests.mozilla.org"};
+var ao2 = { file: "browser_bug557956_2", id: "bug557956-2@tests.mozilla.org"};
+var ao3 = { file: "browser_bug557956_3", id: "bug557956-3@tests.mozilla.org"};
+var ao4 = { file: "browser_bug557956_4", id: "bug557956-4@tests.mozilla.org"};
+var ao5 = { file: "browser_bug557956_5", id: "bug557956-5@tests.mozilla.org"};
+var ao6 = { file: "browser_bug557956_6", id: "bug557956-6@tests.mozilla.org"};
+var ao7 = { file: "browser_bug557956_7", id: "bug557956-7@tests.mozilla.org"};
+var ao8 = { file: "browser_bug557956_8_1", id: "bug557956-8@tests.mozilla.org"};
+var ao9 = { file: "browser_bug557956_9_1", id: "bug557956-9@tests.mozilla.org"};
+var ao10 = { file: "browser_bug557956_10", id: "bug557956-10@tests.mozilla.org"};
+
+// Return a promise that resolves after the specified delay in MS
+function delayMS(aDelay) {
+ let deferred = Promise.defer();
+ setTimeout(deferred.resolve, aDelay);
+ return deferred.promise;
+}
+
+// Return a promise that resolves when the specified observer topic is notified
+function promise_observer(aTopic) {
+ let deferred = Promise.defer();
+ Services.obs.addObserver(function observe(aSubject, aObsTopic, aData) {
+ Services.obs.removeObserver(arguments.callee, aObsTopic);
+ deferred.resolve([aSubject, aData]);
+ }, aTopic, false);
+ return deferred.promise;
+}
+
+// Install a set of addons using a bogus update URL so that we can force
+// the compatibility update to happen later
+// @param aUpdateURL The real update URL to use after the add-ons are installed
+function promise_install_test_addons(aAddonList, aUpdateURL) {
+ info("Starting add-on installs");
+ var installs = [];
+ let deferred = Promise.defer();
+
+ // Use a blank update URL
+ Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
+
+ for (let addon of aAddonList) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/" + addon.file + ".xpi", function(aInstall) {
+ installs.push(aInstall);
+ }, "application/x-xpinstall");
+ }
+
+ var listener = {
+ installCount: 0,
+
+ onInstallEnded: function() {
+ this.installCount++;
+ if (this.installCount == installs.length) {
+ info("Done add-on installs");
+ // Switch to the test update URL
+ Services.prefs.setCharPref(PREF_UPDATEURL, aUpdateURL);
+ deferred.resolve();
+ }
+ }
+ };
+
+ for (let install of installs) {
+ install.addListener(listener);
+ install.install();
+ }
+
+ return deferred.promise;
+}
+
+function promise_addons_by_ids(aAddonIDs) {
+ info("promise_addons_by_ids " + aAddonIDs.toSource());
+ let deferred = Promise.defer();
+ AddonManager.getAddonsByIDs(aAddonIDs, deferred.resolve);
+ return deferred.promise;
+}
+
+function* promise_uninstall_test_addons() {
+ info("Starting add-on uninstalls");
+ let addons = yield promise_addons_by_ids([ao1.id, ao2.id, ao3.id, ao4.id, ao5.id,
+ ao6.id, ao7.id, ao8.id, ao9.id, ao10.id]);
+ let deferred = Promise.defer();
+ let uninstallCount = addons.length;
+ let listener = {
+ onUninstalled: function(aAddon) {
+ if (aAddon) {
+ info("Finished uninstalling " + aAddon.id);
+ }
+ if (--uninstallCount == 0) {
+ info("Done add-on uninstalls");
+ AddonManager.removeAddonListener(listener);
+ deferred.resolve();
+ }
+ }};
+ AddonManager.addAddonListener(listener);
+ for (let addon of addons) {
+ if (addon)
+ addon.uninstall();
+ else
+ listener.onUninstalled(null);
+ }
+ yield deferred.promise;
+}
+
+// Returns promise{window}, resolves with a handle to the compatibility
+// check window
+function promise_open_compatibility_window(aInactiveAddonIds) {
+ let deferred = Promise.defer();
+ // This will reset the longer timeout multiplier to 2 which will give each
+ // test that calls open_compatibility_window a minimum of 60 seconds to
+ // complete.
+ requestLongerTimeout(2);
+
+ var variant = Cc["@mozilla.org/variant;1"].
+ createInstance(Ci.nsIWritableVariant);
+ variant.setFromVariant(aInactiveAddonIds);
+
+ // Cannot be modal as we want to interract with it, shouldn't cause problems
+ // with testing though.
+ var features = "chrome,centerscreen,dialog,titlebar";
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+ getService(Ci.nsIWindowWatcher);
+ var win = ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
+
+ win.addEventListener("load", function() {
+ function page_shown(aEvent) {
+ if (aEvent.target.pageid)
+ info("Page " + aEvent.target.pageid + " shown");
+ }
+
+ win.removeEventListener("load", arguments.callee, false);
+
+ info("Compatibility dialog opened");
+
+ win.addEventListener("pageshow", page_shown, false);
+ win.addEventListener("unload", function() {
+ win.removeEventListener("unload", arguments.callee, false);
+ win.removeEventListener("pageshow", page_shown, false);
+ dump("Compatibility dialog closed\n");
+ }, false);
+
+ deferred.resolve(win);
+ }, false);
+ return deferred.promise;
+}
+
+function promise_window_close(aWindow) {
+ let deferred = Promise.defer();
+ aWindow.addEventListener("unload", function() {
+ aWindow.removeEventListener("unload", arguments.callee, false);
+ deferred.resolve(aWindow);
+ }, false);
+ return deferred.promise;
+}
+
+function promise_page(aWindow, aPageId) {
+ let deferred = Promise.defer();
+ var page = aWindow.document.getElementById(aPageId);
+ if (aWindow.document.getElementById("updateWizard").currentPage === page) {
+ deferred.resolve(aWindow);
+ } else {
+ page.addEventListener("pageshow", function() {
+ page.removeEventListener("pageshow", arguments.callee, false);
+ executeSoon(function() {
+ deferred.resolve(aWindow);
+ });
+ }, false);
+ }
+ return deferred.promise;
+}
+
+function get_list_names(aList) {
+ var items = [];
+ for (let listItem of aList.childNodes)
+ items.push(listItem.label);
+ items.sort();
+ return items;
+}
+
+// These add-ons became inactive during the upgrade
+var inactiveAddonIds = [
+ ao5.id,
+ ao6.id,
+ ao7.id,
+ ao8.id,
+ ao9.id
+];
+
+// Make sure the addons in the list are not installed
+function* check_addons_uninstalled(aAddonList) {
+ let foundList = yield promise_addons_by_ids(aAddonList.map(a => a.id));
+ for (let i = 0; i < aAddonList.length; i++) {
+ ok(!foundList[i], "Addon " + aAddonList[i].id + " is not installed");
+ }
+ info("Add-on uninstall check complete");
+ yield true;
+}
+
+// Test what happens when the user cancels during AddonRepository.repopulateCache()
+// Add-ons that have updates available should not update if they were disabled before
+// For this test, addon8 became disabled during update and addon9 was previously disabled,
+// so addon8 should update and addon9 should not
+add_task(function* cancel_during_repopulate() {
+ let a5, a8, a9, a10;
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
+ Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
+
+ let installsDone = promise_observer("TEST:all-updates-done");
+
+ // Don't pull compatibility data during add-on install
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
+ // Set up our test addons so that the server-side JS has a 500ms delay to make
+ // sure we cancel the dialog before we get the data we want to refill our
+ // AddonRepository cache
+ let addonList = [ao5, ao8, ao9, ao10];
+ yield promise_install_test_addons(addonList,
+ TESTROOT + "cancelCompatCheck.sjs?500");
+
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+ Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, TESTROOT + "browser_bug557956.xml");
+
+ [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
+ ok(!a5.isCompatible, "addon5 should not be compatible");
+ ok(!a8.isCompatible, "addon8 should not be compatible");
+ ok(!a9.isCompatible, "addon9 should not be compatible");
+
+ let compatWindow = yield promise_open_compatibility_window([ao5.id, ao8.id]);
+ var doc = compatWindow.document;
+ yield promise_page(compatWindow, "versioninfo");
+
+ // Brief delay to let the update window finish requesting all add-ons and start
+ // reloading the addon repository
+ yield delayMS(50);
+
+ info("Cancel the compatibility check dialog");
+ var button = doc.documentElement.getButton("cancel");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
+
+ info("Waiting for installs to complete");
+ yield installsDone;
+ ok(!repo.AddonRepository.isSearching, "Background installs are done");
+
+ // There should be no active updates
+ let getInstalls = Promise.defer();
+ AddonManager.getAllInstalls(getInstalls.resolve);
+ let installs = yield getInstalls.promise;
+ is (installs.length, 0, "There should be no active installs after background installs are done");
+
+ // addon8 should have updated in the background,
+ // addon9 was listed as previously disabled so it should not have updated
+ [a5, a8, a9, a10] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id, ao10.id]);
+ ok(a5.isCompatible, "addon5 should be compatible");
+ ok(a8.isCompatible, "addon8 should have been upgraded");
+ ok(!a9.isCompatible, "addon9 should not have been upgraded");
+ ok(!a10.isCompatible, "addon10 should not be compatible");
+
+ info("Updates done");
+ yield promise_uninstall_test_addons();
+ info("done uninstalling add-ons");
+});
+
+// User cancels after repopulateCache, while we're waiting for the addon.findUpdates()
+// calls in gVersionInfoPage_onPageShow() to complete
+// For this test, both addon8 and addon9 were disabled by this update, but addon8
+// is set to not auto-update, so only addon9 should update in the background
+add_task(function* cancel_during_findUpdates() {
+ let a5, a8, a9;
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
+
+ // Clear the AddonRepository-last-updated preference to ensure that it reloads
+ Services.prefs.clearUserPref(PREF_METADATA_LASTUPDATE);
+ let observeUpdateDone = promise_observer("TEST:addon-repository-data-updated");
+ let installsDone = promise_observer("TEST:all-updates-done");
+
+ // Don't pull compatibility data during add-on install
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
+ // No delay on the .sjs this time because we want the cache to repopulate
+ let addonList = [ao3, ao5, ao6, ao7, ao8, ao9];
+ yield promise_install_test_addons(addonList,
+ TESTROOT + "cancelCompatCheck.sjs");
+
+ [a8] = yield promise_addons_by_ids([ao8.id]);
+ a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
+
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+ let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
+ var doc = compatWindow.document;
+ yield promise_page(compatWindow, "versioninfo");
+
+ info("Waiting for repository-data-updated");
+ yield observeUpdateDone;
+
+ // Quick wait to make sure the findUpdates calls get queued
+ yield delayMS(5);
+
+ info("Cancel the compatibility check dialog");
+ var button = doc.documentElement.getButton("cancel");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
+
+ info("Waiting for installs to complete 2");
+ yield installsDone;
+ ok(!repo.AddonRepository.isSearching, "Background installs are done 2");
+
+ // addon8 should have updated in the background,
+ // addon9 was listed as previously disabled so it should not have updated
+ [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
+ ok(a5.isCompatible, "addon5 should be compatible");
+ ok(!a8.isCompatible, "addon8 should not have been upgraded");
+ ok(a9.isCompatible, "addon9 should have been upgraded");
+
+ let getInstalls = Promise.defer();
+ AddonManager.getAllInstalls(getInstalls.resolve);
+ let installs = yield getInstalls.promise;
+ is (installs.length, 0, "There should be no active installs after the dialog is cancelled 2");
+
+ info("findUpdates done");
+ yield promise_uninstall_test_addons();
+});
+
+// Cancelling during the 'mismatch' screen allows add-ons that can auto-update
+// to continue updating in the background and cancels any other updates
+// Same conditions as the previous test - addon8 and addon9 have updates available,
+// addon8 is set to not auto-update so only addon9 should become compatible
+add_task(function* cancel_mismatch() {
+ let a3, a5, a7, a8, a9;
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
+
+ // Clear the AddonRepository-last-updated preference to ensure that it reloads
+ Services.prefs.clearUserPref(PREF_METADATA_LASTUPDATE);
+ let installsDone = promise_observer("TEST:all-updates-done");
+
+ // Don't pull compatibility data during add-on install
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
+ // No delay on the .sjs this time because we want the cache to repopulate
+ let addonList = [ao3, ao5, ao6, ao7, ao8, ao9];
+ yield promise_install_test_addons(addonList,
+ TESTROOT + "cancelCompatCheck.sjs");
+
+ [a8] = yield promise_addons_by_ids([ao8.id]);
+ a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
+
+ // Check that the addons start out not compatible.
+ [a3, a7, a8, a9] = yield promise_addons_by_ids([ao3.id, ao7.id, ao8.id, ao9.id]);
+ ok(!a3.isCompatible, "addon3 should not be compatible");
+ ok(!a7.isCompatible, "addon7 should not be compatible");
+ ok(!a8.isCompatible, "addon8 should not be compatible");
+ ok(!a9.isCompatible, "addon9 should not be compatible");
+
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+ let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
+ var doc = compatWindow.document;
+ info("Wait for mismatch page");
+ yield promise_page(compatWindow, "mismatch");
+ info("Click the Don't Check button");
+ var button = doc.documentElement.getButton("cancel");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
+
+ yield promise_window_close(compatWindow);
+ info("Waiting for installs to complete in cancel_mismatch");
+ yield installsDone;
+
+ // addon8 should not have updated in the background,
+ // addon9 was listed as previously disabled so it should not have updated
+ [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
+ ok(a5.isCompatible, "addon5 should be compatible");
+ ok(!a8.isCompatible, "addon8 should not have been upgraded");
+ ok(a9.isCompatible, "addon9 should have been upgraded");
+
+ // Make sure there are no pending addon installs
+ let pInstalls = Promise.defer();
+ AddonManager.getAllInstalls(pInstalls.resolve);
+ let installs = yield pInstalls.promise;
+ ok(installs.length == 0, "No remaining add-on installs (" + installs.toSource() + ")");
+
+ yield promise_uninstall_test_addons();
+ yield check_addons_uninstalled(addonList);
+});
+
+// Cancelling during the 'mismatch' screen with only add-ons that have
+// no updates available
+add_task(function* cancel_mismatch_no_updates() {
+ let a3, a5, a6
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
+
+ // Don't pull compatibility data during add-on install
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
+ // No delay on the .sjs this time because we want the cache to repopulate
+ let addonList = [ao3, ao5, ao6];
+ yield promise_install_test_addons(addonList,
+ TESTROOT + "cancelCompatCheck.sjs");
+
+ // Check that the addons start out not compatible.
+ [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]);
+ ok(!a3.isCompatible, "addon3 should not be compatible");
+ ok(!a5.isCompatible, "addon5 should not be compatible");
+ ok(!a6.isCompatible, "addon6 should not be compatible");
+
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+ let compatWindow = yield promise_open_compatibility_window([ao3.id, ao5.id, ao6.id]);
+ var doc = compatWindow.document;
+ info("Wait for mismatch page");
+ yield promise_page(compatWindow, "mismatch");
+ info("Click the Don't Check button");
+ var button = doc.documentElement.getButton("cancel");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
+
+ yield promise_window_close(compatWindow);
+
+ [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]);
+ ok(!a3.isCompatible, "addon3 should not be compatible");
+ ok(a5.isCompatible, "addon5 should have become compatible");
+ ok(a6.isCompatible, "addon6 should have become compatible");
+
+ // Make sure there are no pending addon installs
+ let pInstalls = Promise.defer();
+ AddonManager.getAllInstalls(pInstalls.resolve);
+ let installs = yield pInstalls.promise;
+ ok(installs.length == 0, "No remaining add-on installs (" + installs.toSource() + ")");
+
+ yield promise_uninstall_test_addons();
+ yield check_addons_uninstalled(addonList);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_checkAddonCompatibility.js b/toolkit/mozapps/webextensions/test/browser/browser_checkAddonCompatibility.js
new file mode 100644
index 000000000..6c42e0126
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_checkAddonCompatibility.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that all bundled add-ons are compatible.
+
+function test() {
+ waitForExplicitFinish();
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ ok(AddonManager.strictCompatibility, "Strict compatibility should be enabled");
+
+ AddonManager.getAllAddons(function gAACallback(aAddons) {
+ // Sort add-ons (by type and name) to improve output.
+ aAddons.sort(function compareTypeName(a, b) {
+ return a.type.localeCompare(b.type) || a.name.localeCompare(b.name);
+ });
+
+ let allCompatible = true;
+ for (let a of aAddons) {
+ // Ignore plugins.
+ if (a.type == "plugin")
+ continue;
+
+ ok(a.isCompatible, a.type + " " + a.name + " " + a.version + " should be compatible");
+ allCompatible = allCompatible && a.isCompatible;
+ }
+ // Add a reminder.
+ if (!allCompatible)
+ ok(false, "As this test failed, test browser_bug557956.js should have failed, too.");
+
+ finish();
+ });
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_details.js b/toolkit/mozapps/webextensions/test/browser/browser_details.js
new file mode 100644
index 000000000..ce4c51b5a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_details.js
@@ -0,0 +1,1053 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests various aspects of the details view
+
+const { REQUIRE_SIGNING } = Components.utils.import("resource://gre/modules/addons/AddonConstants.jsm", {});
+
+const PREF_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault";
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const SEARCH_URL = TESTROOT + "browser_details.xml";
+const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+var gVersion = Services.appinfo.version;
+var gDate = new Date(2010, 7, 1);
+var infoURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "unsigned-addons";
+
+function open_details(aId, aType, aCallback) {
+ requestLongerTimeout(2);
+
+ gCategoryUtilities.openType(aType, function() {
+ var list = gManagerWindow.document.getElementById("addon-list");
+ var item = list.firstChild;
+ while (item) {
+ if ("mAddon" in item && item.mAddon.id == aId) {
+ list.ensureElementIsVisible(item);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, aCallback);
+ return;
+ }
+ item = item.nextSibling;
+ }
+ ok(false, "Should have found the add-on in the list");
+ });
+}
+
+function get(aId) {
+ return gManagerWindow.document.getElementById(aId);
+}
+
+function test() {
+ requestLongerTimeout(2);
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, "hotfix@tests.mozilla.org");
+
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on 1",
+ version: "2.1",
+ description: "Short description",
+ fullDescription: "Longer description",
+ type: "extension",
+ iconURL: "chrome://foo/skin/icon.png",
+ icon64URL: "chrome://foo/skin/icon64.png",
+ contributionURL: "http://foo.com",
+ contributionAmount: "$0.99",
+ sourceURI: Services.io.newURI("http://example.com/foo", null, null),
+ averageRating: 4,
+ reviewCount: 5,
+ reviewURL: "http://example.com/reviews",
+ homepageURL: "http://example.com/addon1",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "Test add-on 2",
+ version: "2.2",
+ description: "Short description",
+ creator: { name: "Mozilla", url: null },
+ type: "extension",
+ iconURL: "chrome://foo/skin/icon.png",
+ contributionURL: "http://foo.com",
+ contributionAmount: null,
+ updateDate: gDate,
+ permissions: 0,
+ screenshots: [{
+ url: "chrome://branding/content/about.png",
+ width: 200,
+ height: 150
+ }],
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "Test add-on 3",
+ description: "Short description",
+ creator: { name: "Mozilla", url: "http://www.mozilla.org" },
+ type: "extension",
+ sourceURI: Services.io.newURI("http://example.com/foo", null, null),
+ updateDate: gDate,
+ reviewCount: 1,
+ reviewURL: "http://example.com/reviews",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE,
+ isActive: false,
+ isCompatible: false,
+ appDisabled: true,
+ permissions: AddonManager.PERM_CAN_ENABLE |
+ AddonManager.PERM_CAN_DISABLE |
+ AddonManager.PERM_CAN_UPGRADE,
+ screenshots: [{
+ url: "http://example.com/screenshot",
+ width: 400,
+ height: 300,
+ thumbnailURL: "chrome://branding/content/icon64.png",
+ thumbnailWidth: 160,
+ thumbnailHeight: 120
+ }],
+ }, {
+ id: "addon4@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon4@tests.mozilla.org",
+ name: "Test add-on 4",
+ _userDisabled: true,
+ isActive: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ }, {
+ id: "addon5@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon5@tests.mozilla.org",
+ name: "Test add-on 5",
+ isActive: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
+ appDisabled: true
+ }, {
+ id: "addon6@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon6@tests.mozilla.org",
+ name: "Test add-on 6",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon7@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon7@tests.mozilla.org",
+ name: "Test add-on 7",
+ _userDisabled: true,
+ isActive: false
+ }, {
+ id: "addon8@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon8@tests.mozilla.org",
+ name: "Test add-on 8",
+ blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED
+ }, {
+ id: "addon9@tests.mozilla.org",
+ name: "Test add-on 9",
+ signedState: AddonManager.SIGNEDSTATE_MISSING,
+ }, {
+ id: "addon10@tests.mozilla.org",
+ name: "Test add-on 10",
+ signedState: AddonManager.SIGNEDSTATE_MISSING,
+ isActive: false,
+ appDisabled: true,
+ isCompatible: false,
+ }, {
+ id: "addon11@tests.mozilla.org",
+ name: "Test add-on 11",
+ signedState: AddonManager.SIGNEDSTATE_PRELIMINARY,
+ foreignInstall: true,
+ isActive: false,
+ appDisabled: true,
+ isCompatible: false,
+ }, {
+ id: "addon12@tests.mozilla.org",
+ name: "Test add-on 12",
+ signedState: AddonManager.SIGNEDSTATE_SIGNED,
+ foreignInstall: true,
+ }, {
+ id: "hotfix@tests.mozilla.org",
+ name: "Test hotfix 1",
+ }]);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+}
+
+function end_test() {
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+// Opens and tests the details view for add-on 1
+add_test(function() {
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 1", "Name should be correct");
+ is_element_visible(get("detail-version"), "Version should not be hidden");
+ is(get("detail-version").value, "2.1", "Version should be correct");
+ is(get("detail-icon").src, "chrome://foo/skin/icon64.png", "Icon should be correct");
+ is_element_hidden(get("detail-creator"), "Creator should be hidden");
+ is_element_hidden(get("detail-screenshot-box"), "Screenshot should be hidden");
+ is(get("detail-screenshot").width, "", "Screenshot dimensions should not be set");
+ is(get("detail-screenshot").height, "", "Screenshot dimensions should not be set");
+ is(get("detail-desc").textContent, "Short description", "Description should be correct");
+ is(get("detail-fulldesc").textContent, "Longer description", "Full description should be correct");
+
+ is_element_visible(get("detail-contributions"), "Contributions section should be visible");
+ is_element_visible(get("detail-contrib-suggested"), "Contributions amount should be visible");
+ ok(get("detail-contrib-suggested").value, "$0.99");
+
+ is_element_visible(get("detail-updates-row"), "Updates should not be hidden");
+ is_element_hidden(get("detail-dateUpdated"), "Update date should be hidden");
+
+ is_element_visible(get("detail-rating-row"), "Rating row should not be hidden");
+ is_element_visible(get("detail-rating"), "Rating should not be hidden");
+ is(get("detail-rating").averageRating, 4, "Rating should be correct");
+ is_element_visible(get("detail-reviews"), "Reviews should not be hidden");
+ is(get("detail-reviews").href, "http://example.com/reviews", "Review URL should be correct");
+ is(get("detail-reviews").value, "5 reviews", "Review text should be correct");
+
+ is_element_visible(get("detail-homepage-row"), "Homepage should be visible");
+ ok(get("detail-homepage").href, "http://example.com/addon1");
+ is_element_hidden(get("detail-repository-row"), "Repository profile should not be visible");
+
+ is_element_hidden(get("detail-size"), "Size should be hidden");
+
+ is_element_hidden(get("detail-downloads"), "Downloads should be hidden");
+
+ is_element_visible(get("detail-autoUpdate"), "Updates should not be hidden");
+ ok(get("detail-autoUpdate").childNodes[1].selected, "Updates ahould be automatic");
+ is_element_hidden(get("detail-findUpdates-btn"), "Check for updates should be hidden");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").lastChild, {}, gManagerWindow);
+ ok(get("detail-autoUpdate").lastChild.selected, "Updates should be manual");
+ is_element_visible(get("detail-findUpdates-btn"), "Check for updates should be visible");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").firstChild, {}, gManagerWindow);
+ ok(get("detail-autoUpdate").firstChild.selected, "Updates should be automatic");
+ is_element_hidden(get("detail-findUpdates-btn"), "Check for updates should be hidden");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Disable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-disable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 1 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Reopen it
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 1 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Undo disabling
+ EventUtils.synthesizeMouseAtCenter(get("detail-undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 2
+add_test(function() {
+ open_details("addon2@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 2", "Name should be correct");
+ is_element_visible(get("detail-version"), "Version should not be hidden");
+ is(get("detail-version").value, "2.2", "Version should be correct");
+ is(get("detail-icon").src, "chrome://foo/skin/icon.png", "Icon should be correct");
+
+ is_element_visible(get("detail-creator"), "Creator should not be hidden");
+ is_element_visible(get("detail-creator")._creatorName, "Creator name should not be hidden");
+ is(get("detail-creator")._creatorName.value, "Mozilla", "Creator should be correct");
+ is_element_hidden(get("detail-creator")._creatorLink, "Creator link should be hidden");
+
+ is_element_visible(get("detail-screenshot-box"), "Screenshot should be visible");
+ is(get("detail-screenshot").src, "chrome://branding/content/about.png", "Should be showing the full sized screenshot");
+ is(get("detail-screenshot").width, 200, "Screenshot dimensions should be set");
+ is(get("detail-screenshot").height, 150, "Screenshot dimensions should be set");
+ is(get("detail-screenshot").hasAttribute("loading"), true, "Screenshot should have loading attribute");
+ is(get("detail-desc").textContent, "Short description", "Description should be correct");
+ is_element_hidden(get("detail-fulldesc"), "Full description should be hidden");
+
+ is_element_visible(get("detail-contributions"), "Contributions section should be visible");
+ is_element_hidden(get("detail-contrib-suggested"), "Contributions amount should be hidden");
+
+ is_element_visible(get("detail-dateUpdated"), "Update date should not be hidden");
+ is(get("detail-dateUpdated").value, formatDate(gDate), "Update date should be correct");
+
+ is_element_hidden(get("detail-rating-row"), "Rating should be hidden");
+
+ is_element_hidden(get("detail-homepage-row"), "Homepage should not be visible");
+ is_element_hidden(get("detail-repository-row"), "Repository profile should not be visible");
+
+ is_element_hidden(get("detail-size"), "Size should be hidden");
+
+ is_element_hidden(get("detail-downloads"), "Downloads should be hidden");
+
+ is_element_hidden(get("detail-updates-row"), "Updates should be hidden");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_hidden(get("detail-uninstall-btn"), "Remove button should be hidden");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ get("detail-screenshot").addEventListener("load", function() {
+ this.removeEventListener("load", arguments.callee, false);
+ is(this.hasAttribute("loading"), false, "Screenshot should not have loading attribute");
+ run_next_test();
+ }, false);
+ });
+});
+
+// Opens and tests the details view for add-on 3
+add_test(function() {
+ open_details("addon3@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 3", "Name should be correct");
+ is_element_hidden(get("detail-version"), "Version should be hidden");
+ is(get("detail-icon").src, "", "Icon should be correct");
+
+ is_element_visible(get("detail-creator"), "Creator should not be hidden");
+ is_element_hidden(get("detail-creator")._creatorName, "Creator name should be hidden");
+ is_element_visible(get("detail-creator")._creatorLink, "Creator link should not be hidden");
+ is(get("detail-creator")._creatorLink.value, "Mozilla", "Creator link should be correct");
+ is(get("detail-creator")._creatorLink.href, "http://www.mozilla.org", "Creator link href should be correct");
+
+ is_element_visible(get("detail-screenshot-box"), "Screenshot should be visible");
+ is(get("detail-screenshot").src, "chrome://branding/content/icon64.png", "Should be showing the thumbnail");
+ is(get("detail-screenshot").width, 160, "Screenshot dimensions should be set");
+ is(get("detail-screenshot").height, 120, "Screenshot dimensions should be set");
+ is(get("detail-screenshot").hasAttribute("loading"), true, "Screenshot should have loading attribute");
+
+ is_element_hidden(get("detail-contributions"), "Contributions section should be hidden");
+
+ is_element_visible(get("detail-updates-row"), "Updates should not be hidden");
+ is_element_visible(get("detail-dateUpdated"), "Update date should not be hidden");
+ is(get("detail-dateUpdated").value, formatDate(gDate), "Update date should be correct");
+
+ is_element_visible(get("detail-rating-row"), "Rating row should not be hidden");
+ is_element_hidden(get("detail-rating"), "Rating should be hidden");
+ is_element_visible(get("detail-reviews"), "Reviews should not be hidden");
+ is(get("detail-reviews").href, "http://example.com/reviews", "Review URL should be correct");
+ is(get("detail-reviews").value, "1 review", "Review text should be correct");
+
+ is_element_hidden(get("detail-size"), "Size should be hidden");
+
+ is_element_hidden(get("detail-downloads"), "Downloads should be hidden");
+
+ is_element_visible(get("detail-autoUpdate"), "Updates should not be hidden");
+ ok(get("detail-autoUpdate").lastChild.selected, "Updates should be manual");
+ is_element_visible(get("detail-findUpdates-btn"), "Check for updates should be visible");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").childNodes[1], {}, gManagerWindow);
+ ok(get("detail-autoUpdate").childNodes[1].selected, "Updates should be automatic");
+ is_element_hidden(get("detail-findUpdates-btn"), "Check for updates should be hidden");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").lastChild, {}, gManagerWindow);
+ ok(get("detail-autoUpdate").lastChild.selected, "Updates should be manual");
+ is_element_visible(get("detail-findUpdates-btn"), "Check for updates should be visible");
+
+ info("Setting " + PREF_AUTOUPDATE_DEFAULT + " to true");
+ Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, true);
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").firstChild, {}, gManagerWindow);
+ ok(get("detail-autoUpdate").firstChild.selected, "Updates should be default");
+ is_element_hidden(get("detail-findUpdates-btn"), "Check for updates should be hidden");
+
+ info("Setting " + PREF_AUTOUPDATE_DEFAULT + " to false");
+ Services.prefs.setBoolPref(PREF_AUTOUPDATE_DEFAULT, false);
+ ok(get("detail-autoUpdate").firstChild.selected, "Updates should be default");
+ is_element_visible(get("detail-findUpdates-btn"), "Check for updates should be visible");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").childNodes[1], {}, gManagerWindow);
+ ok(get("detail-autoUpdate").childNodes[1].selected, "Updates should be automatic");
+ is_element_hidden(get("detail-findUpdates-btn"), "Check for updates should be hidden");
+ EventUtils.synthesizeMouseAtCenter(get("detail-autoUpdate").firstChild, {}, gManagerWindow);
+ ok(get("detail-autoUpdate").firstChild.selected, "Updates should be default");
+ is_element_visible(get("detail-findUpdates-btn"), "Check for updates should be visible");
+ Services.prefs.clearUserPref(PREF_AUTOUPDATE_DEFAULT);
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_hidden(get("detail-uninstall-btn"), "Remove button should be hidden");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 3 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ get("detail-screenshot").addEventListener("load", function() {
+ this.removeEventListener("load", arguments.callee, false);
+ is(this.hasAttribute("loading"), false, "Screenshot should not have loading attribute");
+ run_next_test();
+ }, false);
+ });
+});
+
+// Opens and tests the details view for add-on 4
+add_test(function() {
+ open_details("addon4@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 4", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 4 is known to cause security or stability issues.", "Warning message should be correct");
+ is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+ is(get("detail-warning-link").value, "More Information", "Warning link text should be correct");
+ is(get("detail-warning-link").href, "http://example.com/addon4@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Enable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 4 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Reopen it
+ open_details("addon4@tests.mozilla.org", "extension", function() {
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 4 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Undo enabling
+ EventUtils.synthesizeMouseAtCenter(get("detail-undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 4 is known to cause security or stability issues.", "Warning message should be correct");
+ is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+ is(get("detail-warning-link").value, "More Information", "Warning link text should be correct");
+ is(get("detail-warning-link").href, "http://example.com/addon4@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 5
+add_test(function() {
+ open_details("addon5@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 5", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_visible(get("detail-error"), "Error message should be visible");
+ is(get("detail-error").textContent, "Test add-on 5 has been disabled due to security or stability issues.", "Error message should be correct");
+ is_element_visible(get("detail-error-link"), "Error link should be visible");
+ is(get("detail-error-link").value, "More Information", "Error link text should be correct");
+ is(get("detail-error-link").href, "http://example.com/addon5@tests.mozilla.org", "Error link should be correct");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Opens and tests the details view for add-on 6
+add_test(function() {
+ open_details("addon6@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 6", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Disable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-disable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Reopen it
+ open_details("addon6@tests.mozilla.org", "extension", function() {
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be visible");
+
+ // Enable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 7
+add_test(function() {
+ open_details("addon7@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 7", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Enable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 7 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Reopen it
+ open_details("addon7@tests.mozilla.org", "extension", function() {
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 7 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Undo enabling
+ EventUtils.synthesizeMouseAtCenter(get("detail-undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 8
+add_test(function() {
+ open_details("addon8@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 8", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "An important update is available for Test add-on 8.", "Warning message should be correct");
+ is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+ is(get("detail-warning-link").value, "Update Now", "Warning link text should be correct");
+ is(get("detail-warning-link").href, "http://example.com/addon8@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ // Disable it
+ EventUtils.synthesizeMouseAtCenter(get("detail-disable-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 8 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Reopen it
+ open_details("addon8@tests.mozilla.org", "extension", function() {
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_visible(get("detail-enable-btn"), "Enable button should be visible");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-pending"), "Pending message should be visible");
+ is(get("detail-pending").textContent, "Test add-on 8 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ // Undo disabling
+ EventUtils.synthesizeMouseAtCenter(get("detail-undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "An important update is available for Test add-on 8.", "Warning message should be correct");
+ is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+ is(get("detail-warning-link").value, "Update Now", "Warning link text should be correct");
+ is(get("detail-warning-link").href, "http://example.com/addon8@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+});
+
+// These tests are only appropriate when signing can be turned off
+if (!REQUIRE_SIGNING) {
+ // Opens and tests the details view for add-on 9
+ add_test(function() {
+ open_details("addon9@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 9", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_visible(get("detail-warning"), "Error message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 9 could not be verified for use in " + gApp + ". Proceed with caution.", "Warning message should be correct");
+ is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+ is(get("detail-warning-link").value, "More Information", "Warning link text should be correct");
+ is(get("detail-warning-link").href, infoURL, "Warning link should be correct");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+}
+
+// Opens and tests the details view for add-on 9 with signing required
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ open_details("addon9@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 9", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_visible(get("detail-error"), "Error message should be visible");
+ is(get("detail-error").textContent, "Test add-on 9 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+ is_element_visible(get("detail-error-link"), "Error link should be visible");
+ is(get("detail-error-link").value, "More Information", "Error link text should be correct");
+ is(get("detail-error-link").href, infoURL, "Error link should be correct");
+
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// These tests are only appropriate when signing can be turned off
+if (!REQUIRE_SIGNING) {
+ // Opens and tests the details view for add-on 10
+ add_test(function() {
+ open_details("addon10@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 10", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 10 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+}
+
+// Opens and tests the details view for add-on 10 with signing required
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ open_details("addon10@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 10", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_visible(get("detail-error"), "Error message should be visible");
+ is(get("detail-error").textContent, "Test add-on 10 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+ is_element_visible(get("detail-error-link"), "Error link should be visible");
+ is(get("detail-error-link").value, "More Information", "Error link text should be correct");
+ is(get("detail-error-link").href, infoURL, "Error link should be correct");
+
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 11
+add_test(function() {
+ open_details("addon11@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 11", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 11 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Opens and tests the details view for add-on 11 with signing required
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ open_details("addon11@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 11", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on 11 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Opens and tests the details view for add-on 12
+add_test(function() {
+ open_details("addon12@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 12", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Opens and tests the details view for add-on 12 with signing required
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ open_details("addon12@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test add-on 12", "Name should be correct");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+
+ close_manager(gManagerWindow, function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Opens and tests the details view for hotfix 1
+add_test(function() {
+ open_details("hotfix@tests.mozilla.org", "extension", function() {
+ is(get("detail-name").textContent, "Test hotfix 1", "Name should be correct");
+
+ is_element_hidden(get("detail-updates-row"), "Updates should be hidden");
+
+ is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Tests that upgrades with onExternalInstall apply immediately
+add_test(function() {
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on replacement",
+ version: "2.5",
+ description: "Short description replacement",
+ fullDescription: "Longer description replacement",
+ type: "extension",
+ iconURL: "chrome://foo/skin/icon.png",
+ icon64URL: "chrome://foo/skin/icon264.png",
+ sourceURI: Services.io.newURI("http://example.com/foo", null, null),
+ averageRating: 2,
+ optionsURL: "chrome://foo/content/options.xul",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }]);
+
+ is(get("detail-name").textContent, "Test add-on replacement", "Name should be correct");
+ is_element_visible(get("detail-version"), "Version should not be hidden");
+ is(get("detail-version").value, "2.5", "Version should be correct");
+ is(get("detail-icon").src, "chrome://foo/skin/icon264.png", "Icon should be correct");
+ is_element_hidden(get("detail-creator"), "Creator should be hidden");
+ is_element_hidden(get("detail-screenshot-box"), "Screenshot should be hidden");
+ is(get("detail-desc").textContent, "Short description replacement", "Description should be correct");
+ is(get("detail-fulldesc").textContent, "Longer description replacement", "Full description should be correct");
+
+ is_element_hidden(get("detail-contributions"), "Contributions section should be hidden");
+
+ is_element_hidden(get("detail-dateUpdated"), "Update date should be hidden");
+
+ is_element_visible(get("detail-rating-row"), "Rating row should not be hidden");
+ is_element_visible(get("detail-rating"), "Rating should not be hidden");
+ is(get("detail-rating").averageRating, 2, "Rating should be correct");
+ is_element_hidden(get("detail-reviews"), "Reviews should be hidden");
+
+ is_element_hidden(get("detail-homepage-row"), "Homepage should be hidden");
+
+ is_element_hidden(get("detail-size"), "Size should be hidden");
+
+ is_element_hidden(get("detail-downloads"), "Downloads should be hidden");
+
+ is_element_visible(get("detail-prefs-btn"), "Preferences button should be visible");
+ is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+ is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+ is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+ is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+ is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+ is_element_hidden(get("detail-error"), "Error message should be hidden");
+ is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Check that onPropertyChanges for appDisabled updates the UI
+add_test(function() {
+ info("Checking that onPropertyChanges for appDisabled updates the UI");
+
+ AddonManager.getAddonByID("addon1@tests.mozilla.org", function(aAddon) {
+ aAddon.userDisabled = true;
+ aAddon.isCompatible = true;
+ aAddon.appDisabled = false;
+
+ open_details("addon1@tests.mozilla.org", "extension", function() {
+ is(get("detail-view").getAttribute("active"), "false", "Addon should not be marked as active");
+ is_element_hidden(get("detail-warning"), "Warning message should not be visible");
+
+ info("Making addon incompatible and appDisabled");
+ aAddon.isCompatible = false;
+ aAddon.appDisabled = true;
+
+ is(get("detail-view").getAttribute("active"), "false", "Addon should not be marked as active");
+ is_element_visible(get("detail-warning"), "Warning message should be visible");
+ is(get("detail-warning").textContent, "Test add-on replacement is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_discovery.js b/toolkit/mozapps/webextensions/test/browser/browser_discovery.js
new file mode 100644
index 000000000..ec336df2d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_discovery.js
@@ -0,0 +1,651 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the discovery view loads properly
+
+const MAIN_URL = "https://example.com/" + RELATIVE_DIR + "discovery.html";
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+var gLoadCompleteCallback = null;
+
+var gProgressListener = {
+ onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+ // Only care about the network stop status events
+ if (!(aStateFlags & (Ci.nsIWebProgressListener.STATE_IS_NETWORK)) ||
+ !(aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP)))
+ return;
+
+ if (gLoadCompleteCallback)
+ executeSoon(gLoadCompleteCallback);
+ gLoadCompleteCallback = null;
+ },
+
+ onLocationChange: function() { },
+ onSecurityChange: function() { },
+ onProgressChange: function() { },
+ onStatusChange: function() { },
+
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+ Ci.nsISupportsWeakReference]),
+};
+
+function test() {
+ // Switch to a known url
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
+ // Temporarily enable caching
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on 1",
+ type: "extension",
+ version: "2.2",
+ isCompatible: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED,
+ userDisabled: false
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "Test add-on 2",
+ type: "plugin",
+ version: "3.1.5",
+ isCompatible: true,
+ blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
+ userDisabled: false
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "Test add-on 3",
+ type: "theme",
+ version: "1.2b1",
+ isCompatible: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
+ userDisabled: true
+ }]);
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+function getURL(aBrowser) {
+ if (gManagerWindow.document.getElementById("discover-view").selectedPanel !=
+ aBrowser)
+ return null;
+
+ var url = aBrowser.currentURI.spec;
+ var pos = url.indexOf("#");
+ if (pos != -1)
+ return url.substring(0, pos);
+ return url;
+}
+
+function getHash(aBrowser) {
+ if (gManagerWindow.document.getElementById("discover-view").selectedPanel !=
+ aBrowser)
+ return null;
+
+ var url = aBrowser.currentURI.spec;
+ var pos = url.indexOf("#");
+ if (pos != -1)
+ return decodeURIComponent(url.substring(pos + 1));
+ return null;
+}
+
+function testHash(aBrowser, aTestAddonVisible, aCallback) {
+ var hash = getHash(aBrowser);
+ isnot(hash, null, "There should be a hash");
+ try {
+ var data = JSON.parse(hash);
+ }
+ catch (e) {
+ ok(false, "Hash should have been valid JSON: " + e);
+ aCallback();
+ return;
+ }
+ is(typeof data, "object", "Hash should be a JS object");
+
+ // Ensure that at least the test add-ons are present
+ if (aTestAddonVisible[0])
+ ok("addon1@tests.mozilla.org" in data, "Test add-on 1 should be listed");
+ else
+ ok(!("addon1@tests.mozilla.org" in data), "Test add-on 1 should not be listed");
+ if (aTestAddonVisible[1])
+ ok("addon2@tests.mozilla.org" in data, "Test add-on 2 should be listed");
+ else
+ ok(!("addon2@tests.mozilla.org" in data), "Test add-on 2 should not be listed");
+ if (aTestAddonVisible[2])
+ ok("addon3@tests.mozilla.org" in data, "Test add-on 3 should be listed");
+ else
+ ok(!("addon3@tests.mozilla.org" in data), "Test add-on 3 should not be listed");
+
+ // Test against all the add-ons the manager knows about since plugins and
+ // app extensions may exist
+ AddonManager.getAllAddons(function(aAddons) {
+ for (let addon of aAddons) {
+ if (!(addon.id in data)) {
+ // Test add-ons will have shown an error if necessary above
+ if (addon.id.substring(6) != "@tests.mozilla.org")
+ ok(false, "Add-on " + addon.id + " was not included in the data");
+ continue;
+ }
+
+ info("Testing data for add-on " + addon.id);
+ var addonData = data[addon.id];
+ is(addonData.name, addon.name, "Name should be correct");
+ is(addonData.version, addon.version, "Version should be correct");
+ is(addonData.type, addon.type, "Type should be correct");
+ is(addonData.userDisabled, addon.userDisabled, "userDisabled should be correct");
+ is(addonData.isBlocklisted, addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED, "blocklisted should be correct");
+ is(addonData.isCompatible, addon.isCompatible, "isCompatible should be correct");
+ }
+ aCallback();
+ });
+}
+
+function isLoading() {
+ var loading = gManagerWindow.document.getElementById("discover-view").selectedPanel ==
+ gManagerWindow.document.getElementById("discover-loading");
+ if (loading) {
+ is_element_visible(gManagerWindow.document.querySelector("#discover-loading .loading"),
+ "Loading message should be visible when its panel is the selected panel");
+ }
+ return loading;
+}
+
+function isError() {
+ return gManagerWindow.document.getElementById("discover-view").selectedPanel ==
+ gManagerWindow.document.getElementById("discover-error");
+}
+
+function clickLink(aId, aCallback) {
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ browser.addProgressListener(gProgressListener);
+
+ gLoadCompleteCallback = function() {
+ browser.removeProgressListener(gProgressListener);
+ aCallback();
+ };
+
+ var link = browser.contentDocument.getElementById(aId);
+ EventUtils.sendMouseEvent({type: "click"}, link);
+
+ executeSoon(function() {
+ ok(isLoading(), "Clicking a link should show the loading pane");
+ });
+}
+
+// Tests that switching to the discovery view displays the right url
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ gCategoryUtilities.openType("discover", function() {
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ testHash(browser, [true, true, true], function() {
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+
+ ok(isLoading(), "Should be loading at first");
+ });
+});
+
+// Tests that loading the add-ons manager with the discovery view as the last
+// selected view displays the right url
+add_test(function() {
+ // Hide one of the test add-ons
+ Services.prefs.setBoolPref("extensions.addon2@tests.mozilla.org.getAddons.cache.enabled", false);
+ Services.prefs.setBoolPref("extensions.addon3@tests.mozilla.org.getAddons.cache.enabled", true);
+
+ open_manager(null, function(aWindow) {
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ testHash(browser, [true, false, true], function() {
+ close_manager(gManagerWindow, run_next_test);
+ });
+ }, function(aWindow) {
+ gManagerWindow = aWindow;
+ ok(isLoading(), "Should be loading at first");
+ });
+});
+
+// Tests that loading the add-ons manager with the discovery view as the initial
+// view displays the right url
+add_test(function() {
+ Services.prefs.clearUserPref("extensions.addon2@tests.mozilla.org.getAddons.cache.enabled");
+ Services.prefs.setBoolPref("extensions.addon3@tests.mozilla.org.getAddons.cache.enabled", false);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ gCategoryUtilities.openType("extension", function() {
+ close_manager(gManagerWindow, function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ testHash(browser, [true, true, false], function() {
+ Services.prefs.clearUserPref("extensions.addon3@tests.mozilla.org.getAddons.cache.enabled");
+ close_manager(gManagerWindow, run_next_test);
+ });
+ }, function(aWindow) {
+ gManagerWindow = aWindow;
+ ok(isLoading(), "Should be loading at first");
+ });
+ });
+ });
+ });
+});
+
+// Tests that switching to the discovery view displays the right url
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ gCategoryUtilities.openType("discover", function() {
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ is(getHash(browser), null, "Hash should not have been passed");
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+});
+
+// Tests that loading the add-ons manager with the discovery view as the last
+// selected view displays the right url
+add_test(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ is(getHash(browser), null, "Hash should not have been passed");
+ close_manager(gManagerWindow, run_next_test);
+ });
+});
+
+// Tests that loading the add-ons manager with the discovery view as the initial
+// view displays the right url
+add_test(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ gCategoryUtilities.openType("extension", function() {
+ close_manager(gManagerWindow, function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "discover", "Should have loaded the right view");
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ is(getHash(browser), null, "Hash should not have been passed");
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Tests that navigating to an insecure page fails
+add_test(function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-http", function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ ok(isLoading(), "Should start loading again");
+ });
+ });
+ });
+});
+
+// Tests that navigating to a different domain fails
+add_test(function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-domain", function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ ok(isLoading(), "Should start loading again");
+ });
+ });
+ });
+});
+
+// Tests that navigating to a missing page fails
+add_test(function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-bad", function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ ok(isLoading(), "Should start loading again");
+ });
+ });
+ });
+});
+
+// Tests that navigating to a page on the same domain works
+add_test(function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-good", function() {
+ is(getURL(browser), "https://example.com/" + RELATIVE_DIR + "releaseNotes.xhtml", "Should have loaded the right url");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Tests repeated navigation to the same page followed by a navigation to a
+// different domain
+add_test(function() {
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ var count = 10;
+ function clickAgain(aCallback) {
+ if (count-- == 0)
+ aCallback();
+ else
+ clickLink("link-normal", clickAgain.bind(null, aCallback));
+ }
+
+ clickAgain(function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-domain", function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ ok(isLoading(), "Should start loading again");
+ });
+ });
+ });
+ });
+});
+
+// Loading an insecure main page should work if that is what the prefs say, should
+// also be able to navigate to a https page and back again
+add_test(function() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, TESTROOT + "discovery.html");
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), TESTROOT + "discovery.html", "Should have loaded the right url");
+
+ clickLink("link-normal", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ clickLink("link-http", function() {
+ is(getURL(browser), TESTROOT + "discovery.html", "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+});
+
+// Stopping the initial load should display the error page and then correctly
+// reload when switching away and back again
+add_test(function() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+
+ EventUtils.synthesizeMouse(gCategoryUtilities.get("discover"), 2, 2, { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ EventUtils.synthesizeMouse(gCategoryUtilities.get("discover"), 2, 2, { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ ok(isError(), "Should have shown the error page");
+
+ gCategoryUtilities.openType("extension", function() {
+ gCategoryUtilities.openType("discover", function() {
+ is(getURL(browser), MAIN_URL, "Should have loaded the right url");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+
+ ok(isLoading(), "Should be loading");
+ // This will stop the real page load
+ browser.stop();
+ });
+ });
+
+ ok(isLoading(), "Should be loading");
+ // This will actually stop the about:blank load
+ browser.stop();
+ });
+});
+
+// Test for Bug 703929 - Loading the discover view from a chrome XUL file fails when
+// the add-on manager is reopened.
+add_test(function() {
+ const url = "chrome://mochitests/content/" + RELATIVE_DIR + "addon_about.xul";
+ Services.prefs.setCharPref(PREF_DISCOVERURL, url);
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), url, "Loading a chrome XUL file should work");
+
+ restart_manager(gManagerWindow, "addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), url, "Should be able to load the chrome XUL file a second time");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+});
+
+// Bug 711693 - Send the compatibility mode when loading the Discovery pane
+add_test(function() {
+ info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'normal'");
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL + "?mode=%COMPATIBILITY_MODE%");
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL + "?mode=normal", "Should have loaded the right url");
+ close_manager(gManagerWindow, run_next_test);
+ });
+});
+
+add_test(function() {
+ info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'strict'");
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL + "?mode=strict", "Should have loaded the right url");
+ close_manager(gManagerWindow, run_next_test);
+ });
+});
+
+add_test(function() {
+ info("Test '%COMPATIBILITY_MODE%' in the URL is correctly replaced by 'ignore'");
+ Services.prefs.setBoolPref(PREF_CHECK_COMPATIBILITY, false);
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+ var browser = gManagerWindow.document.getElementById("discover-browser");
+ is(getURL(browser), MAIN_URL + "?mode=ignore", "Should have loaded the right url");
+ close_manager(gManagerWindow, run_next_test);
+ });
+});
+
+// Test for Bug 601442 - extensions.getAddons.showPane need to be update
+// for the new addon manager.
+function bug_601442_test_elements(visible) {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ if (visible)
+ ok(gCategoryUtilities.isTypeVisible("discover"), "Discover category should be visible");
+ else
+ ok(!gCategoryUtilities.isTypeVisible("discover"), "Discover category should not be visible");
+
+ gManagerWindow.loadView("addons://list/dictionary");
+ wait_for_view_load(gManagerWindow, function(aManager) {
+ var button = aManager.document.getElementById("discover-button-install");
+ if (visible)
+ ok(!is_hidden(button), "Discover button should be visible!");
+ else
+ ok(is_hidden(button), "Discover button should not be visible!");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+}
+
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_DISCOVER_ENABLED, false);
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, true);
+ bug_601442_test_elements(false);
+});
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_DISCOVER_ENABLED, true);
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, false);
+ bug_601442_test_elements(false);
+});
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_DISCOVER_ENABLED, false);
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, false);
+ bug_601442_test_elements(false);
+});
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_DISCOVER_ENABLED, true);
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, true);
+ bug_601442_test_elements(true);
+});
+
+// Test for Bug 1132971 - if extensions.getAddons.showPane is false,
+// the extensions pane should show by default
+add_test(function() {
+ Services.prefs.clearUserPref(PREF_UI_LASTCATEGORY);
+ Services.prefs.setBoolPref(PREF_DISCOVER_ENABLED, false);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be showing the extension view");
+ close_manager(gManagerWindow, run_next_test);
+ Services.prefs.clearUserPref(PREF_DISCOVER_ENABLED);
+ });
+});
+
+// Test for Bug 1219495 - should show placeholder content when offline
+add_test(function() {
+ // set a URL to cause an error
+ Services.prefs.setCharPref(PREF_DISCOVERURL, "https://nocert.example.com/");
+
+ open_manager("addons://discover/", function(aWindow) {
+ gManagerWindow = aWindow;
+
+ ok(isError(), "Should have shown the placeholder content");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_discovery_install.js b/toolkit/mozapps/webextensions/test/browser/browser_discovery_install.js
new file mode 100644
index 000000000..63516bd53
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_discovery_install.js
@@ -0,0 +1,133 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the discovery view can install add-ons correctly
+
+const MAIN_URL = "https://example.com/" + RELATIVE_DIR + "discovery_install.html";
+const GOOD_FRAMED_URL = "https://example.com/" + RELATIVE_DIR + "discovery_frame.html";
+const BAD_FRAMED_URL = "https://example.org/" + RELATIVE_DIR + "discovery_frame.html";
+
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
+
+// Temporarily enable caching
+Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+// Allow SSL from non-built-in certs
+Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+// Allow installs from the test site
+Services.perms.add(NetUtil.newURI("https://example.com/"), "install",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+Services.perms.add(NetUtil.newURI("https://example.org/"), "install",
+ Ci.nsIPermissionManager.ALLOW_ACTION);
+
+registerCleanupFunction(() => {
+ Services.perms.remove(NetUtil.newURI("https://example.com/"), "install");
+ Services.perms.remove(NetUtil.newURI("https://example.org/"), "install");
+ Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
+});
+
+function clickLink(frameLoader, id) {
+ let link = frameLoader.contentDocument.getElementById(id);
+ EventUtils.sendMouseEvent({type: "click"}, link);
+}
+
+function waitForInstall() {
+ return new Promise(resolve => {
+ wait_for_window_open((window) => {
+ is(window.location, "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul",
+ "Should have seen the install window");
+ window.document.documentElement.cancelDialog();
+ resolve();
+ });
+ });
+}
+
+function waitForFail() {
+ return new Promise(resolve => {
+ let listener = (subject, topic, data) => {
+ Services.obs.removeObserver(listener, topic);
+ resolve();
+ }
+ Services.obs.addObserver(listener, "addon-install-origin-blocked", false);
+ });
+}
+
+// Tests that navigating to an XPI attempts to install correctly
+add_task(function* test_install_direct() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+
+ clickLink(browser, "install-direct");
+ yield waitForInstall();
+
+ yield close_manager(managerWindow);
+});
+
+// Tests that installing via JS works correctly
+add_task(function* test_install_js() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+
+ clickLink(browser, "install-js");
+ yield waitForInstall();
+
+ yield close_manager(managerWindow);
+});
+
+// Installing from an inner-frame of the same origin should work
+add_task(function* test_install_inner_direct() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, GOOD_FRAMED_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+ let frame = browser.contentDocument.getElementById("frame");
+
+ clickLink(frame, "install-direct");
+ yield waitForInstall();
+
+ yield close_manager(managerWindow);
+});
+
+add_task(function* test_install_inner_js() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, GOOD_FRAMED_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+ let frame = browser.contentDocument.getElementById("frame");
+
+ clickLink(frame, "install-js");
+ yield waitForInstall();
+
+ yield close_manager(managerWindow);
+});
+
+// Installing from an inner-frame of a different origin should fail
+add_task(function* test_install_xorigin_direct() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, BAD_FRAMED_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+ let frame = browser.contentDocument.getElementById("frame");
+
+ clickLink(frame, "install-direct");
+ yield waitForFail();
+
+ yield close_manager(managerWindow);
+});
+
+add_task(function* test_install_xorigin_js() {
+ Services.prefs.setCharPref(PREF_DISCOVERURL, BAD_FRAMED_URL);
+
+ let managerWindow = yield open_manager("addons://discover/");
+ let browser = managerWindow.document.getElementById("discover-browser");
+ let frame = browser.contentDocument.getElementById("frame");
+
+ clickLink(frame, "install-js");
+ yield waitForFail();
+
+ yield close_manager(managerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_dragdrop.js b/toolkit/mozapps/webextensions/test/browser/browser_dragdrop.js
new file mode 100644
index 000000000..960e7e933
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_dragdrop.js
@@ -0,0 +1,234 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This tests simulated drag and drop of files into the add-ons manager.
+// We test with the add-ons manager in its own tab if in Firefox otherwise
+// in its own window.
+// Tests are only simulations of the drag and drop events, we cannot really do
+// this automatically.
+
+// Instead of loading EventUtils.js into the test scope in browser-test.js for all tests,
+// we only need EventUtils.js for a few files which is why we are using loadSubScript.
+var gManagerWindow;
+var EventUtils = {};
+this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
+ getService(Ci.mozIJSSubScriptLoader);
+this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/EventUtils.js", EventUtils);
+
+// This listens for the next opened window and checks it is of the right url.
+// opencallback is called when the new window is fully loaded
+// closecallback is called when the window is closed
+function WindowOpenListener(url, opencallback, closecallback) {
+ this.url = url;
+ this.opencallback = opencallback;
+ this.closecallback = closecallback;
+
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ wm.addListener(this);
+}
+
+WindowOpenListener.prototype = {
+ url: null,
+ opencallback: null,
+ closecallback: null,
+ window: null,
+ domwindow: null,
+
+ handleEvent: function(event) {
+ is(this.domwindow.document.location.href, this.url, "Should have opened the correct window");
+
+ this.domwindow.removeEventListener("load", this, false);
+ // Allow any other load handlers to execute
+ var self = this;
+ executeSoon(function() { self.opencallback(self.domwindow); } );
+ },
+
+ onWindowTitleChange: function(window, title) {
+ },
+
+ onOpenWindow: function(window) {
+ if (this.window)
+ return;
+
+ this.window = window;
+ this.domwindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIDOMWindow);
+ this.domwindow.addEventListener("load", this, false);
+ },
+
+ onCloseWindow: function(window) {
+ if (this.window != window)
+ return;
+
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+ .getService(Components.interfaces.nsIWindowMediator);
+ wm.removeListener(this);
+ this.opencallback = null;
+ this.window = null;
+ this.domwindow = null;
+
+ // Let the window close complete
+ executeSoon(this.closecallback);
+ this.closecallback = null;
+ }
+};
+
+var gSawInstallNotification = false;
+var gInstallNotificationObserver = {
+ observe: function(aSubject, aTopic, aData) {
+ var installInfo = aSubject.QueryInterface(Ci.amIWebInstallInfo);
+ if (gTestInWindow)
+ is(installInfo.browser, null, "Notification should have a null browser");
+ else
+ isnot(installInfo.browser, null, "Notification should have non-null browser");
+ gSawInstallNotification = true;
+ Services.obs.removeObserver(this, "addon-install-started");
+ }
+};
+
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+function test_confirmation(aWindow, aExpectedURLs) {
+ var list = aWindow.document.getElementById("itemList");
+ is(list.childNodes.length, aExpectedURLs.length, "Should be the right number of installs");
+
+ for (let url of aExpectedURLs) {
+ let found = false;
+ for (let node of list.children) {
+ if (node.url == url) {
+ found = true;
+ break;
+ }
+ }
+ ok(found, "Should have seen " + url + " in the list");
+ }
+
+ aWindow.document.documentElement.cancelDialog();
+}
+
+// Simulates dropping a URL onto the manager
+add_test(function() {
+ var url = TESTROOT + "addons/browser_dragdrop1.xpi";
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ test_confirmation(aWindow, [url]);
+ }, function() {
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+ run_next_test();
+ });
+
+ var viewContainer = gManagerWindow.document.getElementById("view-port");
+ var effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
+ [[{type: "text/x-moz-url", data: url}]],
+ "copy", gManagerWindow);
+ is(effect, "copy", "Drag should be accepted");
+});
+
+// Simulates dropping a file onto the manager
+add_test(function() {
+ var fileurl = get_addon_file_url("browser_dragdrop1.xpi");
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ test_confirmation(aWindow, [fileurl.spec]);
+ }, function() {
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+ run_next_test();
+ });
+
+ var viewContainer = gManagerWindow.document.getElementById("view-port");
+ var effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
+ [[{type: "application/x-moz-file", data: fileurl.file}]],
+ "copy", gManagerWindow);
+ is(effect, "copy", "Drag should be accepted");
+});
+
+// Simulates dropping two urls onto the manager
+add_test(function() {
+ var url1 = TESTROOT + "addons/browser_dragdrop1.xpi";
+ var url2 = TESTROOT2 + "addons/browser_dragdrop2.xpi";
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ test_confirmation(aWindow, [url1, url2]);
+ }, function() {
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+ run_next_test();
+ });
+
+ var viewContainer = gManagerWindow.document.getElementById("view-port");
+ var effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
+ [[{type: "text/x-moz-url", data: url1}],
+ [{type: "text/x-moz-url", data: url2}]],
+ "copy", gManagerWindow);
+ is(effect, "copy", "Drag should be accepted");
+});
+
+// Simulates dropping two files onto the manager
+add_test(function() {
+ var fileurl1 = get_addon_file_url("browser_dragdrop1.xpi");
+ var fileurl2 = get_addon_file_url("browser_dragdrop2.xpi");
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ test_confirmation(aWindow, [fileurl1.spec, fileurl2.spec]);
+ }, function() {
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+ run_next_test();
+ });
+
+ var viewContainer = gManagerWindow.document.getElementById("view-port");
+ var effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
+ [[{type: "application/x-moz-file", data: fileurl1.file}],
+ [{type: "application/x-moz-file", data: fileurl2.file}]],
+ "copy", gManagerWindow);
+ is(effect, "copy", "Drag should be accepted");
+});
+
+// Simulates dropping a file and a url onto the manager (weird, but should still work)
+add_test(function() {
+ var url = TESTROOT + "addons/browser_dragdrop1.xpi";
+ var fileurl = get_addon_file_url("browser_dragdrop2.xpi");
+
+ Services.obs.addObserver(gInstallNotificationObserver,
+ "addon-install-started", false);
+
+ new WindowOpenListener(INSTALL_URI, function(aWindow) {
+ test_confirmation(aWindow, [url, fileurl.spec]);
+ }, function() {
+ is(gSawInstallNotification, true, "Should have seen addon-install-started notification.");
+ run_next_test();
+ });
+
+ var viewContainer = gManagerWindow.document.getElementById("view-port");
+ var effect = EventUtils.synthesizeDrop(viewContainer, viewContainer,
+ [[{type: "text/x-moz-url", data: url}],
+ [{type: "application/x-moz-file", data: fileurl.file}]],
+ "copy", gManagerWindow);
+ is(effect, "copy", "Drag should be accepted");
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_eula.js b/toolkit/mozapps/webextensions/test/browser/browser_eula.js
new file mode 100644
index 000000000..befe9f1f2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_eula.js
@@ -0,0 +1,85 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that the eula is shown correctly for search results
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+var gSearchCount = 0;
+
+function test() {
+ requestLongerTimeout(2);
+ waitForExplicitFinish();
+
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+ Services.prefs.setCharPref("extensions.getAddons.search.url", TESTROOT + "browser_eula.xml");
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, finish);
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function installSearchResult(aCallback) {
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ // Search for something different each time
+ searchBox.value = "foo" + gSearchCount;
+ gSearchCount++;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ let remote = gManagerWindow.document.getElementById("search-filter-remote")
+ EventUtils.synthesizeMouseAtCenter(remote, { }, gManagerWindow);
+
+ let item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ ok(!!item, "Should see the search result in the list");
+
+ let status = get_node(item, "install-status");
+ EventUtils.synthesizeMouseAtCenter(get_node(status, "install-remote-btn"), {}, gManagerWindow);
+
+ item.mInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ });
+}
+
+// Install an add-on through the search page, accept the EULA and then undo it
+add_test(function() {
+ // Accept the EULA when it appears
+ let sawEULA = false;
+ wait_for_window_open(function(aWindow) {
+ sawEULA = true;
+ is(aWindow.location.href, "chrome://mozapps/content/extensions/eula.xul", "Window opened should be correct");
+ is(aWindow.document.getElementById("eula").value, "This is the EULA for this add-on", "EULA should be correct");
+
+ aWindow.document.documentElement.acceptDialog();
+ });
+
+ installSearchResult(function() {
+ ok(sawEULA, "Should have seen the EULA");
+
+ AddonManager.getAllInstalls(function(aInstalls) {
+ is(aInstalls.length, 1, "Should be one pending install");
+ aInstalls[0].cancel();
+
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_eula.xml b/toolkit/mozapps/webextensions/test/browser/browser_eula.xml
new file mode 100644
index 000000000..965ab8a0b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_eula.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="1">
+ <addon>
+ <name>Install Tests</name>
+ <type id='1'>Extension</type>
+ <guid>addon1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test add-on</summary>
+ <description>Test add-on</description>
+ <eula>This is the EULA for this add-on</eula>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="2">http://example.com/browser/toolkit/mozapps/extensions/test/browser/addons/browser_install1_2.xpi</install>
+ </addon>
+</searchresults>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_experiments.js b/toolkit/mozapps/webextensions/test/browser/browser_experiments.js
new file mode 100644
index 000000000..18a548de5
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_experiments.js
@@ -0,0 +1,654 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Components.utils.import("resource://gre/modules/Promise.jsm", this);
+
+var {AddonManagerTesting} = Components.utils.import("resource://testing-common/AddonManagerTesting.jsm", {});
+var {HttpServer} = Components.utils.import("resource://testing-common/httpd.js", {});
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gExperiments;
+var gHttpServer;
+
+var gSavedManifestURI;
+var gIsEnUsLocale;
+
+const SEC_IN_ONE_DAY = 24 * 60 * 60;
+const MS_IN_ONE_DAY = SEC_IN_ONE_DAY * 1000;
+
+function getExperimentAddons() {
+ let deferred = Promise.defer();
+ AddonManager.getAddonsByTypes(["experiment"], (addons) => {
+ deferred.resolve(addons);
+ });
+ return deferred.promise;
+}
+
+function getInstallItem() {
+ let doc = gManagerWindow.document;
+ let view = get_current_view(gManagerWindow);
+ let list = doc.getElementById("addon-list");
+
+ let node = list.firstChild;
+ while (node) {
+ if (node.getAttribute("status") == "installing") {
+ return node;
+ }
+ node = node.nextSibling;
+ }
+
+ return null;
+}
+
+function patchPolicy(policy, data) {
+ for (let key of Object.keys(data)) {
+ Object.defineProperty(policy, key, {
+ value: data[key],
+ writable: true,
+ });
+ }
+}
+
+function defineNow(policy, time) {
+ patchPolicy(policy, { now: () => new Date(time) });
+}
+
+function openDetailsView(aId) {
+ let item = get_addon_element(gManagerWindow, aId);
+ Assert.ok(item, "Should have got add-on element.");
+ is_element_visible(item, "Add-on element should be visible.");
+
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+
+ let deferred = Promise.defer();
+ wait_for_view_load(gManagerWindow, deferred.resolve);
+ return deferred.promise;
+}
+
+function clickRemoveButton(addonElement) {
+ let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "remove-btn");
+ if (!btn) {
+ return Promise.reject();
+ }
+
+ EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow);
+ let deferred = Promise.defer();
+ setTimeout(deferred.resolve, 0);
+ return deferred;
+}
+
+function clickUndoButton(addonElement) {
+ let btn = gManagerWindow.document.getAnonymousElementByAttribute(addonElement, "anonid", "undo-btn");
+ if (!btn) {
+ return Promise.reject();
+ }
+
+ EventUtils.synthesizeMouseAtCenter(btn, { clickCount: 1 }, gManagerWindow);
+ let deferred = Promise.defer();
+ setTimeout(deferred.resolve, 0);
+ return deferred;
+}
+
+add_task(function* initializeState() {
+ gManagerWindow = yield open_manager();
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("experiments.enabled");
+ Services.prefs.clearUserPref("toolkit.telemetry.enabled");
+ if (gHttpServer) {
+ gHttpServer.stop(() => {});
+ if (gSavedManifestURI !== undefined) {
+ Services.prefs.setCharPref("experments.manifest.uri", gSavedManifestURI);
+ }
+ }
+ if (gExperiments) {
+ let tmp = {};
+ Cu.import("resource:///modules/experiments/Experiments.jsm", tmp);
+ gExperiments._policy = new tmp.Experiments.Policy();
+ }
+ });
+
+ let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
+ gIsEnUsLocale = chrome.getSelectedLocale("global") == "en-US";
+
+ // The Experiments Manager will interfere with us by preventing installs
+ // of experiments it doesn't know about. We remove it from the equation
+ // because here we are only concerned with core Addon Manager operation,
+ // not the superset Experiments Manager has imposed.
+ if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
+ let tmp = {};
+ Cu.import("resource:///modules/experiments/Experiments.jsm", tmp);
+ // There is a race condition between XPCOM service initialization and
+ // this test running. We have to initialize the instance first, then
+ // uninitialize it to prevent this.
+ gExperiments = tmp.Experiments.instance();
+ yield gExperiments._mainTask;
+ yield gExperiments.uninit();
+ }
+});
+
+// On an empty profile with no experiments, the experiment category
+// should be hidden.
+add_task(function* testInitialState() {
+ Assert.ok(gCategoryUtilities.get("experiment", false), "Experiment tab is defined.");
+ Assert.ok(!gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab hidden by default.");
+});
+
+add_task(function* testExperimentInfoNotVisible() {
+ yield gCategoryUtilities.openType("extension");
+ let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+ is_element_hidden(el, "Experiment info not visible on other types.");
+});
+
+// If we have an active experiment, we should see the experiments tab
+// and that tab should have some messages.
+add_task(function* testActiveExperiment() {
+ let addon = yield install_addon("addons/browser_experiment1.xpi");
+
+ Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install.");
+ Assert.equal(addon.isActive, false, "Add-on is not active.");
+
+ Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible.");
+
+ yield gCategoryUtilities.openType("experiment");
+ let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+ is_element_visible(el, "Experiment info is visible on experiment tab.");
+});
+
+add_task(function* testExperimentLearnMore() {
+ // Actual URL is irrelevant.
+ Services.prefs.setCharPref("toolkit.telemetry.infoURL",
+ "http://mochi.test:8888/server.js");
+
+ yield gCategoryUtilities.openType("experiment");
+ let btn = gManagerWindow.document.getElementById("experiments-learn-more");
+
+ if (!gUseInContentUI) {
+ is_element_hidden(btn, "Learn more button hidden if not using in-content UI.");
+ Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
+
+ return;
+ }
+
+ is_element_visible(btn, "Learn more button visible.");
+
+ let deferred = Promise.defer();
+ window.addEventListener("DOMContentLoaded", function onLoad(event) {
+ info("Telemetry privacy policy window opened.");
+ window.removeEventListener("DOMContentLoaded", onLoad, false);
+
+ let browser = gBrowser.selectedBrowser;
+ let expected = Services.prefs.getCharPref("toolkit.telemetry.infoURL");
+ Assert.equal(browser.currentURI.spec, expected, "New tab should have loaded privacy policy.");
+ browser.contentWindow.close();
+
+ Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
+
+ deferred.resolve();
+ }, false);
+
+ info("Opening telemetry privacy policy.");
+ EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow);
+
+ yield deferred.promise;
+});
+
+add_task(function* testOpenPreferences() {
+ yield gCategoryUtilities.openType("experiment");
+ let btn = gManagerWindow.document.getElementById("experiments-change-telemetry");
+ if (!gUseInContentUI) {
+ is_element_hidden(btn, "Change telemetry button not enabled in out of window UI.");
+ info("Skipping preferences open test because not using in-content UI.");
+ return;
+ }
+
+ is_element_visible(btn, "Change telemetry button visible in in-content UI.");
+
+ let deferred = Promise.defer();
+ Services.obs.addObserver(function observer(prefWin, topic, data) {
+ Services.obs.removeObserver(observer, "advanced-pane-loaded");
+ info("Advanced preference pane opened.");
+ executeSoon(function() {
+ // We want this test to fail if the preferences pane changes.
+ let el = prefWin.document.getElementById("dataChoicesPanel");
+ is_element_visible(el);
+
+ prefWin.close();
+ info("Closed preferences pane.");
+
+ deferred.resolve();
+ });
+ }, "advanced-pane-loaded", false);
+
+ info("Loading preferences pane.");
+ // We need to focus before synthesizing the mouse event (bug 1240052) as
+ // synthesizeMouseAtCenter currently only synthesizes the mouse in the child process.
+ // This can cause some subtle differences if the child isn't focused.
+ yield SimpleTest.promiseFocus();
+ yield BrowserTestUtils.synthesizeMouseAtCenter("#experiments-change-telemetry", {},
+ gBrowser.selectedBrowser);
+
+ yield deferred.promise;
+});
+
+add_task(function* testButtonPresence() {
+ yield gCategoryUtilities.openType("experiment");
+ let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ // Corresponds to the uninstall permission.
+ is_element_visible(el, "Remove button is visible.");
+ // Corresponds to lack of disable permission.
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+ is_element_hidden(el, "Disable button not visible.");
+ // Corresponds to lack of enable permission.
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+ is_element_hidden(el, "Enable button not visible.");
+});
+
+// Remove the add-on we've been testing with.
+add_task(function* testCleanup() {
+ yield AddonManagerTesting.uninstallAddonByID("test-experiment1@experiments.mozilla.org");
+ // Verify some conditions, just in case.
+ let addons = yield getExperimentAddons();
+ Assert.equal(addons.length, 0, "No experiment add-ons are installed.");
+});
+
+// The following tests should ideally live in browser/experiments/. However,
+// they rely on some of the helper functions from head.js, which can't easily
+// be consumed from other directories. So, they live here.
+
+add_task(function* testActivateExperiment() {
+ if (!gExperiments) {
+ info("Skipping experiments test because that feature isn't available.");
+ return;
+ }
+
+ gHttpServer = new HttpServer();
+ gHttpServer.start(-1);
+ let root = "http://localhost:" + gHttpServer.identity.primaryPort + "/";
+ gHttpServer.registerPathHandler("/manifest", (request, response) => {
+ response.setStatusLine(null, 200, "OK");
+ response.write(JSON.stringify({
+ "version": 1,
+ "experiments": [
+ {
+ id: "experiment-1",
+ xpiURL: TESTROOT + "addons/browser_experiment1.xpi",
+ xpiHash: "IRRELEVANT",
+ startTime: Date.now() / 1000 - 3600,
+ endTime: Date.now() / 1000 + 3600,
+ maxActiveSeconds: 600,
+ appName: [Services.appinfo.name],
+ channel: [gExperiments._policy.updatechannel()],
+ },
+ ],
+ }));
+ response.processAsync();
+ response.finish();
+ });
+
+ gSavedManifestURI = Services.prefs.getCharPref("experiments.manifest.uri");
+ Services.prefs.setCharPref("experiments.manifest.uri", root + "manifest");
+
+ // We need to remove the cache file to help ensure consistent state.
+ yield OS.File.remove(gExperiments._cacheFilePath);
+
+ Services.prefs.setBoolPref("toolkit.telemetry.enabled", true);
+ Services.prefs.setBoolPref("experiments.enabled", true);
+
+ info("Initializing experiments service.");
+ yield gExperiments.init();
+ info("Experiments service finished first run.");
+
+ // Check conditions, just to be sure.
+ let experiments = yield gExperiments.getExperiments();
+ Assert.equal(experiments.length, 0, "No experiments known to the service.");
+
+ // This makes testing easier.
+ gExperiments._policy.ignoreHashes = true;
+
+ info("Manually updating experiments manifest.");
+ yield gExperiments.updateManifest();
+ info("Experiments update complete.");
+
+ let deferred = Promise.defer();
+ gHttpServer.stop(() => {
+ gHttpServer = null;
+
+ info("getting experiment by ID");
+ AddonManager.getAddonByID("test-experiment1@experiments.mozilla.org", (addon) => {
+ Assert.ok(addon, "Add-on installed via Experiments manager.");
+
+ deferred.resolve();
+ });
+ });
+
+ yield deferred.promise;
+
+ Assert.ok(gCategoryUtilities.isTypeVisible, "experiment", "Experiment tab visible.");
+ yield gCategoryUtilities.openType("experiment");
+ let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+ is_element_visible(el, "Experiment info is visible on experiment tab.");
+});
+
+add_task(function* testDeactivateExperiment() {
+ if (!gExperiments) {
+ return;
+ }
+
+ // Fake an empty manifest to purge data from previous manifest.
+ yield gExperiments._updateExperiments({
+ "version": 1,
+ "experiments": [],
+ });
+
+ yield gExperiments.disableExperiment("testing");
+
+ // We should have a record of the previously-active experiment.
+ let experiments = yield gExperiments.getExperiments();
+ Assert.equal(experiments.length, 1, "1 experiment is known.");
+ Assert.equal(experiments[0].active, false, "Experiment is not active.");
+
+ // We should have a previous experiment in the add-ons manager.
+ let deferred = Promise.defer();
+ AddonManager.getAddonsByTypes(["experiment"], (addons) => {
+ deferred.resolve(addons);
+ });
+ let addons = yield deferred.promise;
+ Assert.equal(addons.length, 1, "1 experiment add-on known.");
+ Assert.ok(addons[0].appDisabled, "It is a previous experiment.");
+ Assert.equal(addons[0].id, "experiment-1", "Add-on ID matches expected.");
+
+ // Verify the UI looks sane.
+
+ Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible.");
+ let item = get_addon_element(gManagerWindow, "experiment-1");
+ Assert.ok(item, "Got add-on element.");
+ Assert.ok(!item.active, "Element should not be active.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ // User control buttons should not be present because previous experiments
+ // should have no permissions.
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ is_element_hidden(el, "Remove button is not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+ is_element_hidden(el, "Disable button is not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+ is_element_hidden(el, "Enable button is not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
+ is_element_hidden(el, "Preferences button is not visible.");
+});
+
+add_task(function* testActivateRealExperiments() {
+ if (!gExperiments) {
+ info("Skipping experiments test because that feature isn't available.");
+ return;
+ }
+
+ yield gExperiments._updateExperiments({
+ "version": 1,
+ "experiments": [
+ {
+ id: "experiment-2",
+ xpiURL: TESTROOT + "addons/browser_experiment1.xpi",
+ xpiHash: "IRRELEVANT",
+ startTime: Date.now() / 1000 - 3600,
+ endTime: Date.now() / 1000 + 3600,
+ maxActiveSeconds: 600,
+ appName: [Services.appinfo.name],
+ channel: [gExperiments._policy.updatechannel()],
+ },
+ ],
+ });
+ yield gExperiments._run();
+
+ // Check the active experiment.
+
+ let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Active");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Less than a day remaining");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container");
+ is_element_hidden(el, "error-container should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container");
+ is_element_hidden(el, "warning-container should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container");
+ is_element_hidden(el, "pending-container should be hidden.");
+ let { version } = yield get_tooltip_info(item);
+ Assert.equal(version, undefined, "version should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
+ is_element_hidden(el, "disabled-postfix should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix");
+ is_element_hidden(el, "update-postfix should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet");
+ is_element_visible(el, "experiment-bullet should be visible.");
+
+ // Check the previous experiment.
+
+ item = get_addon_element(gManagerWindow, "experiment-1");
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Complete");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Less than a day ago");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "error-container");
+ is_element_hidden(el, "error-container should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning-container");
+ is_element_hidden(el, "warning-container should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "pending-container");
+ is_element_hidden(el, "pending-container should be hidden.");
+ ({ version } = yield get_tooltip_info(item));
+ Assert.equal(version, undefined, "version should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
+ is_element_hidden(el, "disabled-postfix should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "update-postfix");
+ is_element_hidden(el, "update-postfix should be hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "experiment-bullet");
+ is_element_visible(el, "experiment-bullet should be visible.");
+
+ // Install an "older" experiment.
+
+ yield gExperiments.disableExperiment("experiment-2");
+
+ let now = Date.now();
+ let fakeNow = now - 5 * MS_IN_ONE_DAY;
+ defineNow(gExperiments._policy, fakeNow);
+
+ yield gExperiments._updateExperiments({
+ "version": 1,
+ "experiments": [
+ {
+ id: "experiment-3",
+ xpiURL: TESTROOT + "addons/browser_experiment1.xpi",
+ xpiHash: "IRRELEVANT",
+ startTime: fakeNow / 1000 - SEC_IN_ONE_DAY,
+ endTime: now / 1000 + 10 * SEC_IN_ONE_DAY,
+ maxActiveSeconds: 100 * SEC_IN_ONE_DAY,
+ appName: [Services.appinfo.name],
+ channel: [gExperiments._policy.updatechannel()],
+ },
+ ],
+ });
+ yield gExperiments._run();
+
+ // Check the active experiment.
+
+ item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Active");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "10 days remaining");
+ }
+
+ // Disable it and check it's previous experiment entry.
+
+ yield gExperiments.disableExperiment("experiment-3");
+
+ item = get_addon_element(gManagerWindow, "experiment-3");
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Complete");
+ }
+
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "5 days ago");
+ }
+});
+
+add_task(function* testDetailView() {
+ if (!gExperiments) {
+ info("Skipping experiments test because that feature isn't available.");
+ return;
+ }
+
+ defineNow(gExperiments._policy, Date.now());
+ yield gExperiments._updateExperiments({
+ "version": 1,
+ "experiments": [
+ {
+ id: "experiment-4",
+ xpiURL: TESTROOT + "addons/browser_experiment1.xpi",
+ xpiHash: "IRRELEVANT",
+ startTime: Date.now() / 1000 - 3600,
+ endTime: Date.now() / 1000 + 3600,
+ maxActiveSeconds: 600,
+ appName: [Services.appinfo.name],
+ channel: [gExperiments._policy.updatechannel()],
+ },
+ ],
+ });
+ yield gExperiments._run();
+
+ // Check active experiment.
+
+ yield openDetailsView("test-experiment1@experiments.mozilla.org");
+
+ let el = gManagerWindow.document.getElementById("detail-experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Active");
+ }
+
+ el = gManagerWindow.document.getElementById("detail-experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Less than a day remaining");
+ }
+
+ el = gManagerWindow.document.getElementById("detail-version");
+ is_element_hidden(el, "detail-version should be hidden.");
+ el = gManagerWindow.document.getElementById("detail-creator");
+ is_element_hidden(el, "detail-creator should be hidden.");
+ el = gManagerWindow.document.getElementById("detail-experiment-bullet");
+ is_element_visible(el, "experiment-bullet should be visible.");
+
+ // Check previous experiment.
+
+ yield gCategoryUtilities.openType("experiment");
+ yield openDetailsView("experiment-3");
+
+ el = gManagerWindow.document.getElementById("detail-experiment-state");
+ is_element_visible(el, "Experiment state label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "Complete");
+ }
+
+ el = gManagerWindow.document.getElementById("detail-experiment-time");
+ is_element_visible(el, "Experiment time label should be visible.");
+ if (gIsEnUsLocale) {
+ Assert.equal(el.value, "5 days ago");
+ }
+
+ el = gManagerWindow.document.getElementById("detail-version");
+ is_element_hidden(el, "detail-version should be hidden.");
+ el = gManagerWindow.document.getElementById("detail-creator");
+ is_element_hidden(el, "detail-creator should be hidden.");
+ el = gManagerWindow.document.getElementById("detail-experiment-bullet");
+ is_element_visible(el, "experiment-bullet should be visible.");
+});
+
+add_task(function* testRemoveAndUndo() {
+ if (!gExperiments) {
+ info("Skipping experiments test because that feature isn't available.");
+ return;
+ }
+
+ yield gCategoryUtilities.openType("experiment");
+
+ let addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+ Assert.ok(addon, "Got add-on element.");
+
+ yield clickRemoveButton(addon);
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ let el = gManagerWindow.document.getAnonymousElementByAttribute(addon, "class", "pending");
+ is_element_visible(el, "Uninstall undo information should be visible.");
+
+ yield clickUndoButton(addon);
+ addon = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+ Assert.ok(addon, "Got add-on element.");
+});
+
+add_task(function* testCleanup() {
+ if (gExperiments) {
+ Services.prefs.clearUserPref("experiments.enabled");
+ Services.prefs.setCharPref("experiments.manifest.uri", gSavedManifestURI);
+
+ // We perform the uninit/init cycle to purge any leftover state.
+ yield OS.File.remove(gExperiments._cacheFilePath);
+ yield gExperiments.uninit();
+ yield gExperiments.init();
+
+ Services.prefs.clearUserPref("toolkit.telemetry.enabled");
+ }
+
+ // Check post-conditions.
+ let addons = yield getExperimentAddons();
+ Assert.equal(addons.length, 0, "No experiment add-ons are installed.");
+
+ yield close_manager(gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_globalwarnings.js b/toolkit/mozapps/webextensions/test/browser/browser_globalwarnings.js
new file mode 100644
index 000000000..663905a90
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_globalwarnings.js
@@ -0,0 +1,63 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Bug 566194 - safe mode / security & compatibility check status are not exposed in new addon manager UI
+
+function test() {
+ waitForExplicitFinish();
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+add_test(function() {
+ info("Testing compatibility checking warning");
+
+ info("Setting checkCompatibility to false");
+ AddonManager.checkCompatibility = false;
+
+ open_manager("addons://list/extension", function(aWindow) {
+ var hbox = aWindow.document.querySelector("#list-view hbox.global-warning-checkcompatibility");
+ is_element_visible(hbox, "Check Compatibility warning hbox should be visible");
+ var button = aWindow.document.querySelector("#list-view button.global-warning-checkcompatibility");
+ is_element_visible(button, "Check Compatibility warning button should be visible");
+
+ info("Clicking 'Enable' button");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+ is(AddonManager.checkCompatibility, true, "Check Compatibility pref should be cleared");
+ is_element_hidden(hbox, "Check Compatibility warning hbox should be hidden");
+ is_element_hidden(button, "Check Compatibility warning button should be hidden");
+
+ close_manager(aWindow, function() {
+ run_next_test();
+ });
+ });
+});
+
+add_test(function() {
+ info("Testing update security checking warning");
+
+ var pref = "extensions.checkUpdateSecurity";
+ info("Setting " + pref + " pref to false")
+ Services.prefs.setBoolPref(pref, false);
+
+ open_manager(null, function(aWindow) {
+ var hbox = aWindow.document.querySelector("#list-view hbox.global-warning-updatesecurity");
+ is_element_visible(hbox, "Check Update Security warning hbox should be visible");
+ var button = aWindow.document.querySelector("#list-view button.global-warning-updatesecurity");
+ is_element_visible(button, "Check Update Security warning button should be visible");
+
+ info("Clicking 'Enable' button");
+ EventUtils.synthesizeMouse(button, 2, 2, { }, aWindow);
+ is(Services.prefs.prefHasUserValue(pref), false, "Check Update Security pref should be cleared");
+ is_element_hidden(hbox, "Check Update Security warning hbox should be hidden");
+ is_element_hidden(button, "Check Update Security warning button should be hidden");
+
+ close_manager(aWindow, function() {
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_gmpProvider.js b/toolkit/mozapps/webextensions/test/browser/browser_gmpProvider.js
new file mode 100644
index 000000000..52079a263
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_gmpProvider.js
@@ -0,0 +1,418 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Promise.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
+var {AddonTestUtils} = Cu.import("resource://testing-common/AddonManagerTesting.jsm", {});
+var GMPScope = Cu.import("resource://gre/modules/addons/GMPProvider.jsm");
+
+const TEST_DATE = new Date(2013, 0, 1, 12);
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gIsEnUsLocale;
+
+var gMockAddons = [];
+
+for (let plugin of GMPScope.GMP_PLUGINS) {
+ let mockAddon = Object.freeze({
+ id: plugin.id,
+ isValid: true,
+ isInstalled: false,
+ isEME: (plugin.id == "gmp-widevinecdm" ||
+ plugin.id.indexOf("gmp-eme-") == 0) ? true : false,
+ });
+ gMockAddons.push(mockAddon);
+}
+
+var gInstalledAddonId = "";
+var gInstallDeferred = null;
+var gPrefs = Services.prefs;
+var getKey = GMPScope.GMPPrefs.getPrefKey;
+
+function MockGMPInstallManager() {
+}
+
+MockGMPInstallManager.prototype = {
+ checkForAddons: () => Promise.resolve({
+ usedFallback: true,
+ gmpAddons: gMockAddons
+ }),
+
+ installAddon: addon => {
+ gInstalledAddonId = addon.id;
+ gInstallDeferred.resolve();
+ return Promise.resolve();
+ },
+};
+
+var gOptionsObserver = {
+ lastDisplayed: null,
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic == AddonManager.OPTIONS_NOTIFICATION_DISPLAYED) {
+ this.lastDisplayed = aData;
+ }
+ }
+};
+
+function getInstallItem() {
+ let doc = gManagerWindow.document;
+ let list = doc.getElementById("addon-list");
+
+ let node = list.firstChild;
+ while (node) {
+ if (node.getAttribute("status") == "installing") {
+ return node;
+ }
+ node = node.nextSibling;
+ }
+
+ return null;
+}
+
+function openDetailsView(aId) {
+ let view = get_current_view(gManagerWindow);
+ Assert.equal(view.id, "list-view", "Should be in the list view to use this function");
+
+ let item = get_addon_element(gManagerWindow, aId);
+ Assert.ok(item, "Should have got add-on element.");
+ is_element_visible(item, "Add-on element should be visible.");
+
+ item.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+
+ let deferred = Promise.defer();
+ wait_for_view_load(gManagerWindow, deferred.resolve);
+ return deferred.promise;
+}
+
+add_task(function* initializeState() {
+ gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_LOGGING_DUMP, true);
+ gPrefs.setIntPref(GMPScope.GMPPrefs.KEY_LOGGING_LEVEL, 0);
+
+ gManagerWindow = yield open_manager();
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ registerCleanupFunction(Task.async(function*() {
+ Services.obs.removeObserver(gOptionsObserver, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
+
+ for (let addon of gMockAddons) {
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id));
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id));
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id));
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id));
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id));
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id));
+ }
+ gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_LOGGING_DUMP);
+ gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_LOGGING_LEVEL);
+ gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_UPDATE_LAST_CHECK);
+ gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_EME_ENABLED);
+ yield GMPScope.GMPProvider.shutdown();
+ GMPScope.GMPProvider.startup();
+ }));
+
+ let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
+ gIsEnUsLocale = chrome.getSelectedLocale("global") == "en-US";
+
+ Services.obs.addObserver(gOptionsObserver, AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, false);
+
+ // Start out with plugins not being installed, disabled and automatic updates
+ // disabled.
+ gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, true);
+ for (let addon of gMockAddons) {
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id), false);
+ gPrefs.setIntPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id), 0);
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id), false);
+ gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id), "");
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id), true);
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id), true);
+ }
+ yield GMPScope.GMPProvider.shutdown();
+ GMPScope.GMPProvider.startup();
+});
+
+add_task(function* testNotInstalledDisabled() {
+ Assert.ok(gCategoryUtilities.isTypeVisible("plugin"), "Plugin tab visible.");
+ yield gCategoryUtilities.openType("plugin");
+
+ for (let addon of gMockAddons) {
+ let item = get_addon_element(gManagerWindow, addon.id);
+ Assert.ok(item, "Got add-on element:" + addon.id);
+ item.parentNode.ensureElementIsVisible(item);
+ is(item.getAttribute("active"), "false");
+
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
+ is_element_hidden(el, "Warning notification is hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
+ is_element_visible(el, "disabled-postfix is visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+ is_element_hidden(el, "Disable button not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+ is_element_hidden(el, "Enable button not visible.");
+
+ let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
+ is_element_visible(menu, "State menu should be visible.");
+
+ let neverActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "never-activate-menuitem");
+ is(menu.selectedItem, neverActivate, "Plugin state should be never-activate.");
+ }
+});
+
+add_task(function* testNotInstalledDisabledDetails() {
+ for (let addon of gMockAddons) {
+ yield openDetailsView(addon.id);
+ let doc = gManagerWindow.document;
+
+ let el = doc.getElementsByClassName("disabled-postfix")[0];
+ is_element_visible(el, "disabled-postfix is visible.");
+ el = doc.getElementById("detail-findUpdates-btn");
+ is_element_visible(el, "Find updates link is visible.");
+ el = doc.getElementById("detail-warning");
+ is_element_hidden(el, "Warning notification is hidden.");
+ el = doc.getElementsByTagName("setting")[0];
+
+ yield gCategoryUtilities.openType("plugin");
+ }
+});
+
+add_task(function* testNotInstalled() {
+ for (let addon of gMockAddons) {
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id), true);
+ let item = get_addon_element(gManagerWindow, addon.id);
+ Assert.ok(item, "Got add-on element:" + addon.id);
+ item.parentNode.ensureElementIsVisible(item);
+ is(item.getAttribute("active"), "true");
+
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
+ is_element_visible(el, "Warning notification is visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
+ is_element_hidden(el, "disabled-postfix is hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+ is_element_hidden(el, "Disable button not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+ is_element_hidden(el, "Enable button not visible.");
+
+ let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
+ is_element_visible(menu, "State menu should be visible.");
+
+ let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "always-activate-menuitem");
+ is(menu.selectedItem, alwaysActivate, "Plugin state should be always-activate.");
+ }
+});
+
+add_task(function* testNotInstalledDetails() {
+ for (let addon of gMockAddons) {
+ yield openDetailsView(addon.id);
+ let doc = gManagerWindow.document;
+
+ let el = doc.getElementsByClassName("disabled-postfix")[0];
+ is_element_hidden(el, "disabled-postfix is hidden.");
+ el = doc.getElementById("detail-findUpdates-btn");
+ is_element_visible(el, "Find updates link is visible.");
+ el = doc.getElementById("detail-warning");
+ is_element_visible(el, "Warning notification is visible.");
+ el = doc.getElementsByTagName("setting")[0];
+
+ yield gCategoryUtilities.openType("plugin");
+ }
+});
+
+add_task(function* testInstalled() {
+ for (let addon of gMockAddons) {
+ gPrefs.setIntPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, addon.id),
+ TEST_DATE.getTime());
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, addon.id), false);
+ gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id), "1.2.3.4");
+
+ let item = get_addon_element(gManagerWindow, addon.id);
+ Assert.ok(item, "Got add-on element.");
+ item.parentNode.ensureElementIsVisible(item);
+ is(item.getAttribute("active"), "true");
+
+ let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "warning");
+ is_element_hidden(el, "Warning notification is hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "class", "disabled-postfix");
+ is_element_hidden(el, "disabled-postfix is hidden.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+ is_element_hidden(el, "Disable button not visible.");
+ el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+ is_element_hidden(el, "Enable button not visible.");
+
+ let menu = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "state-menulist");
+ is_element_visible(menu, "State menu should be visible.");
+
+ let alwaysActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "always-activate-menuitem");
+ is(menu.selectedItem, alwaysActivate, "Plugin state should be always-activate.");
+ }
+});
+
+add_task(function* testInstalledDetails() {
+ for (let addon of gMockAddons) {
+ yield openDetailsView(addon.id);
+ let doc = gManagerWindow.document;
+
+ let el = doc.getElementsByClassName("disabled-postfix")[0];
+ is_element_hidden(el, "disabled-postfix is hidden.");
+ el = doc.getElementById("detail-findUpdates-btn");
+ is_element_visible(el, "Find updates link is visible.");
+ el = doc.getElementById("detail-warning");
+ is_element_hidden(el, "Warning notification is hidden.");
+ el = doc.getElementsByTagName("setting")[0];
+
+ let contextMenu = doc.getElementById("addonitem-popup");
+ let deferred = Promise.defer();
+ let listener = () => {
+ contextMenu.removeEventListener("popupshown", listener, false);
+ deferred.resolve();
+ };
+ contextMenu.addEventListener("popupshown", listener, false);
+ el = doc.getElementsByClassName("detail-view-container")[0];
+ EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
+ EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
+ yield deferred.promise;
+ let menuSep = doc.getElementById("addonitem-menuseparator");
+ is_element_hidden(menuSep, "Menu separator is hidden.");
+ contextMenu.hidePopup();
+
+ yield gCategoryUtilities.openType("plugin");
+ }
+});
+
+add_task(function* testInstalledGlobalEmeDisabled() {
+ gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, false);
+ for (let addon of gMockAddons) {
+ let item = get_addon_element(gManagerWindow, addon.id);
+ if (addon.isEME) {
+ Assert.ok(!item, "Couldn't get add-on element.");
+ } else {
+ Assert.ok(item, "Got add-on element.");
+ }
+ }
+ gPrefs.setBoolPref(GMPScope.GMPPrefs.KEY_EME_ENABLED, true);
+});
+
+add_task(function* testPreferencesButton() {
+
+ let prefValues = [
+ { enabled: false, version: "" },
+ { enabled: false, version: "1.2.3.4" },
+ { enabled: true, version: "" },
+ { enabled: true, version: "1.2.3.4" },
+ ];
+
+ for (let preferences of prefValues) {
+ dump("Testing preferences button with pref settings: " +
+ JSON.stringify(preferences) + "\n");
+ for (let addon of gMockAddons) {
+ yield close_manager(gManagerWindow);
+ gManagerWindow = yield open_manager();
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ gPrefs.setCharPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, addon.id),
+ preferences.version);
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_ENABLED, addon.id),
+ preferences.enabled);
+
+ yield gCategoryUtilities.openType("plugin");
+ let doc = gManagerWindow.document;
+ let item = get_addon_element(gManagerWindow, addon.id);
+
+ let button = doc.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ let deferred = Promise.defer();
+ wait_for_view_load(gManagerWindow, deferred.resolve);
+ yield deferred.promise;
+
+ is(gOptionsObserver.lastDisplayed, addon.id);
+ }
+ }
+});
+
+add_task(function* testUpdateButton() {
+ gPrefs.clearUserPref(GMPScope.GMPPrefs.KEY_UPDATE_LAST_CHECK);
+
+ let originalInstallManager = GMPScope.GMPInstallManager;
+ Object.defineProperty(GMPScope, "GMPInstallManager", {
+ value: MockGMPInstallManager,
+ writable: true,
+ enumerable: true,
+ configurable: true
+ });
+
+ for (let addon of gMockAddons) {
+ yield gCategoryUtilities.openType("plugin");
+ let doc = gManagerWindow.document;
+ let item = get_addon_element(gManagerWindow, addon.id);
+
+ gInstalledAddonId = "";
+ gInstallDeferred = Promise.defer();
+
+ let button = doc.getAnonymousElementByAttribute(item, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ let deferred = Promise.defer();
+ wait_for_view_load(gManagerWindow, deferred.resolve);
+ yield deferred.promise;
+
+ button = doc.getElementById("detail-findUpdates-btn");
+ Assert.ok(button != null, "Got detail-findUpdates-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ yield gInstallDeferred.promise;
+
+ Assert.equal(gInstalledAddonId, addon.id);
+ }
+ Object.defineProperty(GMPScope, "GMPInstallManager", {
+ value: originalInstallManager,
+ writable: true,
+ enumerable: true,
+ configurable: true
+ });
+});
+
+add_task(function* testEmeSupport() {
+ for (let addon of gMockAddons) {
+ gPrefs.clearUserPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id));
+ }
+ yield GMPScope.GMPProvider.shutdown();
+ GMPScope.GMPProvider.startup();
+
+ for (let addon of gMockAddons) {
+ yield gCategoryUtilities.openType("plugin");
+ let doc = gManagerWindow.document;
+ let item = get_addon_element(gManagerWindow, addon.id);
+ if (addon.id == GMPScope.EME_ADOBE_ID) {
+ if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
+ Assert.ok(item, "Adobe EME supported, found add-on element.");
+ } else {
+ Assert.ok(!item,
+ "Adobe EME not supported, couldn't find add-on element.");
+ }
+ } else if (addon.id == GMPScope.WIDEVINE_ID) {
+ if (AppConstants.isPlatformAndVersionAtLeast("win", "6") ||
+ AppConstants.platform == "macosx" ||
+ AppConstants.platform == "linux") {
+ Assert.ok(item, "Widevine supported, found add-on element.");
+ } else {
+ Assert.ok(!item,
+ "Widevine not supported, couldn't find add-on element.");
+ }
+ } else {
+ Assert.ok(item, "Found add-on element.");
+ }
+ }
+
+ for (let addon of gMockAddons) {
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_VISIBLE, addon.id), true);
+ gPrefs.setBoolPref(getKey(GMPScope.GMPPrefs.KEY_PLUGIN_FORCE_SUPPORTED, addon.id), true);
+ }
+ yield GMPScope.GMPProvider.shutdown();
+ GMPScope.GMPProvider.startup();
+
+});
+
+add_task(function* test_cleanup() {
+ yield close_manager(gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_hotfix.js b/toolkit/mozapps/webextensions/test/browser/browser_hotfix.js
new file mode 100644
index 000000000..b7bb3f580
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_hotfix.js
@@ -0,0 +1,171 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
+const PREF_EM_HOTFIX_LASTVERSION = "extensions.hotfix.lastVersion";
+const PREF_EM_HOTFIX_URL = "extensions.hotfix.url";
+const PREF_EM_HOTFIX_CERTS = "extensions.hotfix.certs.";
+const PREF_EM_CERT_CHECKATTRIBUTES = "extensions.hotfix.cert.checkAttributes";
+
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
+const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
+
+const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
+const PREF_APP_UPDATE_URL = "app.update.url";
+
+const HOTFIX_ID = "hotfix@tests.mozilla.org";
+
+/*
+ * Register an addon install listener and return a promise that:
+ * resolves with the AddonInstall object if the install succeeds
+ * rejects with the AddonInstall if the install fails
+ */
+function promiseInstallListener() {
+ return new Promise((resolve, reject) => {
+ let listener = {
+ onInstallEnded: ai => {
+ AddonManager.removeInstallListener(listener);
+ resolve(ai);
+ },
+ onDownloadCancelled: ai => {
+ AddonManager.removeInstallListener(listener);
+ reject(ai);
+ }
+ };
+ AddonManager.addInstallListener(listener);
+ });
+}
+
+function promiseSuccessfulInstall() {
+ return promiseInstallListener().then(
+ aInstall => {
+ ok(true, "Should have seen the install complete");
+ is(aInstall.addon.id, HOTFIX_ID, "Should have installed the right add-on");
+ aInstall.addon.uninstall();
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_LASTVERSION);
+ },
+ aInstall => {
+ ok(false, "Should not have seen the download cancelled");
+ is(aInstall.addon.id, HOTFIX_ID, "Should have seen the right add-on");
+ });
+}
+
+function promiseFailedInstall() {
+ return promiseInstallListener().then(
+ aInstall => {
+ ok(false, "Should not have seen the install complete");
+ is(aInstall.addon.id, HOTFIX_ID, "Should have installed the right add-on");
+ aInstall.addon.uninstall();
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_LASTVERSION);
+ },
+ aInstall => {
+ ok(true, "Should have seen the download cancelled");
+ is(aInstall.addon.id, HOTFIX_ID, "Should have seen the right add-on");
+ });
+}
+
+add_task(function setup() {
+ var oldAusUrl = Services.prefs.getDefaultBranch(null).getCharPref(PREF_APP_UPDATE_URL);
+ Services.prefs.getDefaultBranch(null).setCharPref(PREF_APP_UPDATE_URL, TESTROOT + "ausdummy.xml");
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
+ Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+ Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, HOTFIX_ID);
+ var oldURL = Services.prefs.getCharPref(PREF_EM_HOTFIX_URL);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, TESTROOT + "signed_hotfix.rdf");
+
+ registerCleanupFunction(function() {
+ Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, false);
+ Services.prefs.getDefaultBranch(null).setCharPref(PREF_APP_UPDATE_URL, oldAusUrl);
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, oldURL);
+ Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
+ Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+
+ Services.prefs.clearUserPref(PREF_EM_CERT_CHECKATTRIBUTES);
+ var prefs = Services.prefs.getChildList(PREF_EM_HOTFIX_CERTS);
+ prefs.forEach(Services.prefs.clearUserPref);
+ });
+});
+
+add_task(function* check_no_cert_checks() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, false);
+ yield Promise.all([
+ promiseSuccessfulInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+});
+
+add_task(function* check_wrong_cert_fingerprint() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "foo");
+
+ yield Promise.all([
+ promiseFailedInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
+});
+
+add_task(function* check_right_cert_fingerprint() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
+
+ yield Promise.all([
+ promiseSuccessfulInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
+});
+
+add_task(function* check_multi_cert_fingerprint_1() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint", "foo");
+
+ yield Promise.all([
+ promiseSuccessfulInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint");
+});
+
+add_task(function* check_multi_cert_fingerprint_2() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "foo");
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
+
+ yield Promise.all([
+ promiseSuccessfulInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "2.sha1Fingerprint");
+});
+
+add_task(function* check_no_cert_no_checks() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, false);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_URL, TESTROOT + "unsigned_hotfix.rdf");
+
+ yield Promise.all([
+ promiseSuccessfulInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+});
+
+add_task(function* check_no_cert_cert_fingerprint_check() {
+ Services.prefs.setBoolPref(PREF_EM_CERT_CHECKATTRIBUTES, true);
+ Services.prefs.setCharPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint", "3E:B9:4E:07:12:FE:3C:01:41:46:13:46:FC:84:52:1A:8C:BE:1D:A2");
+
+ yield Promise.all([
+ promiseFailedInstall(),
+ AddonManagerPrivate.backgroundUpdateCheck()
+ ]);
+
+ Services.prefs.clearUserPref(PREF_EM_HOTFIX_CERTS + "1.sha1Fingerprint");
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings.js b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings.js
new file mode 100644
index 000000000..e2814ddf4
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings.js
@@ -0,0 +1,680 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests various aspects of the details view
+Components.utils.import("resource://gre/modules/Preferences.jsm");
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+const SETTINGS_ROWS = 9;
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+var observer = {
+ lastDisplayed: null,
+ callback: null,
+ checkDisplayed: function(aExpected) {
+ is(this.lastDisplayed, aExpected, "'addon-options-displayed' notification should have fired");
+ this.lastDisplayed = null;
+ },
+ checkNotDisplayed: function() {
+ is(this.lastDisplayed, null, "'addon-options-displayed' notification should not have fired");
+ },
+ lastHidden: null,
+ checkHidden: function(aExpected) {
+ is(this.lastHidden, aExpected, "'addon-options-hidden' notification should have fired");
+ this.lastHidden = null;
+ },
+ checkNotHidden: function() {
+ is(this.lastHidden, null, "'addon-options-hidden' notification should not have fired");
+ },
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic == AddonManager.OPTIONS_NOTIFICATION_DISPLAYED) {
+ this.lastDisplayed = aData;
+ // Test if the binding has applied before the observers are notified. We test the second setting here,
+ // because the code operates on the first setting and we want to check it applies to all.
+ var setting = aSubject.querySelector("rows > setting[first-row] ~ setting");
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(setting, "class", "preferences-title");
+ isnot(input, null, "XBL binding should be applied");
+
+ // Add some extra height to the scrolling pane to ensure that it needs to scroll when appropriate.
+ gManagerWindow.document.getElementById("detail-controls").style.marginBottom = "1000px";
+
+ if (this.callback) {
+ var tempCallback = this.callback;
+ this.callback = null;
+ tempCallback();
+ }
+ } else if (aTopic == AddonManager.OPTIONS_NOTIFICATION_HIDDEN) {
+ this.lastHidden = aData;
+ }
+ }
+};
+
+function installAddon(aCallback) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_inlinesettings1.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+}
+
+function checkScrolling(aShouldHaveScrolled) {
+ var detailView = gManagerWindow.document.getElementById("detail-view");
+ var boxObject = detailView.boxObject;
+ ok(detailView.scrollHeight > boxObject.height, "Page should require scrolling");
+ if (aShouldHaveScrolled)
+ isnot(detailView.scrollTop, 0, "Page should have scrolled");
+ else
+ is(detailView.scrollTop, 0, "Page should not have scrolled");
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "inlinesettings2@tests.mozilla.org",
+ name: "Inline Settings (Regular)",
+ version: "1",
+ optionsURL: CHROMEROOT + "options.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_INLINE,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_DISABLE,
+ }, {
+ id: "inlinesettings3@tests.mozilla.org",
+ name: "Inline Settings (More Options)",
+ description: "Tests for option types introduced after Mozilla 7.0",
+ version: "1",
+ optionsURL: CHROMEROOT + "more_options.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_INLINE
+ }, {
+ id: "noninlinesettings@tests.mozilla.org",
+ name: "Non-Inline Settings",
+ version: "1",
+ optionsURL: CHROMEROOT + "addon_prefs.xul"
+ }]);
+
+ installAddon(function () {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ Services.obs.addObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
+ false);
+ Services.obs.addObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
+ false);
+
+ run_next_test();
+ });
+ });
+}
+
+function end_test() {
+ Services.obs.removeObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
+
+ Services.prefs.clearUserPref("extensions.inlinesettings1.bool");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.boolint");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.integer");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.string");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.color");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.file");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.directory");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioBool");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioInt");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioString");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.menulist");
+
+ MockFilePicker.cleanup();
+
+ close_manager(gManagerWindow, function() {
+ observer.checkHidden("inlinesettings3@tests.mozilla.org");
+ Services.obs.removeObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_HIDDEN);
+
+ AddonManager.getAddonByID("inlinesettings1@tests.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+ finish();
+ });
+ });
+}
+
+// Addon with options.xul
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, "Options should be inline type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ run_next_test();
+});
+
+// Addon with inline preferences as optionsURL
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, "Options should be inline type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ run_next_test();
+});
+
+// Addon with non-inline preferences as optionsURL
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_DIALOG, "Options should be dialog type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ run_next_test();
+});
+
+// Addon with options.xul, also a test for the setting.xml bindings
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+ is(gManagerWindow.gViewController.currentViewId,
+ "addons://detail/inlinesettings1%40tests.mozilla.org/preferences",
+ "Current view should scroll to preferences");
+ checkScrolling(true);
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
+ Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
+ isnot(input.checked, true, "Checkbox should have initial value");
+ is(input.label, "Check box label", "Checkbox should be labelled");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ is(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), true, "Bool pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ isnot(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), false, "Bool pref should have been updated");
+
+ ok(!settings[1].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings1.boolint", 0);
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[1], "anonid", "input");
+ isnot(input.checked, true, "Checkbox should have initial value");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ is(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 1, "BoolInt pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ isnot(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 2, "BoolInt pref should have been updated");
+
+ ok(!settings[2].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings1.integer", 0);
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
+ is(input.value, "0", "Number box should have initial value");
+ input.select();
+ EventUtils.synthesizeKey("1", {}, gManagerWindow);
+ EventUtils.synthesizeKey("3", {}, gManagerWindow);
+ is(input.value, "13", "Number box should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 13, "Integer pref should have been updated");
+ EventUtils.synthesizeKey("VK_DOWN", {}, gManagerWindow);
+ is(input.value, "12", "Number box should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 12, "Integer pref should have been updated");
+
+ ok(!settings[3].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings1.string", "foo");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
+ is(input.value, "foo", "Text box should have initial value");
+ input.select();
+ EventUtils.synthesizeKey("b", {}, gManagerWindow);
+ EventUtils.synthesizeKey("a", {}, gManagerWindow);
+ EventUtils.synthesizeKey("r", {}, gManagerWindow);
+ is(input.value, "bar", "Text box should have updated value");
+ input.value += "\u03DE"; // Cheat to add this non-ASCII character without typing it.
+ EventUtils.synthesizeKey("/", {}, gManagerWindow);
+ is(input.value, "bar\u03DE/", "Text box should have updated value");
+ is(gManagerWindow.document.getBindingParent(gManagerWindow.document.activeElement), input, "Search box should not have focus");
+ is(Preferences.get("extensions.inlinesettings1.string", "wrong"), "bar\u03DE/", "String pref should have been updated");
+
+ ok(!settings[4].hasAttribute("first-row"), "Not the first row");
+ input = settings[4].firstElementChild;
+ is(input.value, "1", "Menulist should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("b", {}, gManagerWindow);
+ is(input.value, "2", "Menulist should have updated value");
+ is(gManagerWindow._testValue, "2", "Menulist oncommand handler should've updated the test value");
+ delete gManagerWindow._testValue;
+
+ ok(!settings[5].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings1.color", "#FF0000");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[5], "anonid", "input");
+ is(input.color, "#FF0000", "Color picker should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", {}, gManagerWindow);
+ input.hidePopup();
+ is(input.color, "#FF9900", "Color picker should have updated value");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated");
+
+ try {
+ ok(!settings[6].hasAttribute("first-row"), "Not the first row");
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
+ is(input.value, "", "Label value should be empty");
+ is(input.tooltipText, "", "Label tooltip should be empty");
+
+ var testFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ testFile.append("\u2622");
+ var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+
+ MockFilePicker.returnFiles = [testFile];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
+ is(input.value, testFile.path, "Label value should match file chosen");
+ is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
+ is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should match file chosen");
+
+ MockFilePicker.returnFiles = [curProcD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
+ is(input.value, testFile.path, "Label value should not have changed");
+ is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
+ is(Preferences.get("extensions.inlinesettings1.file", "wrong"), testFile.path, "File pref should not have changed");
+
+ ok(!settings[7].hasAttribute("first-row"), "Not the first row");
+ button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
+ is(input.value, "", "Label value should be empty");
+ is(input.tooltipText, "", "Label tooltip should be empty");
+
+ MockFilePicker.returnFiles = [testFile];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
+ is(input.value, testFile.path, "Label value should match file chosen");
+ is(input.tooltipText, testFile.path, "Label tooltip should match file chosen");
+ is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should match file chosen");
+
+ MockFilePicker.returnFiles = [curProcD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
+ is(input.value, testFile.path, "Label value should not have changed");
+ is(input.tooltipText, testFile.path, "Label tooltip should not have changed");
+ is(Preferences.get("extensions.inlinesettings1.directory", "wrong"), testFile.path, "Directory pref should not have changed");
+
+ var unsizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
+ var sizedInput = gManagerWindow.document.getAnonymousElementByAttribute(settings[8], "anonid", "input");
+ is(unsizedInput.clientWidth > sizedInput.clientWidth, true, "Input with size attribute should be smaller than input without");
+ } finally {
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ }
+ });
+});
+
+// Tests for the setting.xml bindings introduced after Mozilla 7
+add_test(function() {
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings3@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 4, "Grid should have settings children");
+
+ ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
+ Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
+ var radios = settings[0].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), true, "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[1], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), false, "Radio pref should have been updated");
+
+ ok(!settings[1].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings3.radioInt", 5);
+ radios = settings[1].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ isnot(radios[2].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 4, "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 6, "Radio pref should have been updated");
+
+ ok(!settings[2].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "juliet");
+ radios = settings[2].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ isnot(radios[2].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "india", "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
+ is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "kilo \u338F", "Radio pref should have been updated");
+
+ ok(!settings[3].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 8);
+ var input = settings[3].firstElementChild;
+ is(input.value, "8", "Menulist should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("n", {}, gManagerWindow);
+ is(input.value, "9", "Menulist should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.menulist"), 9, "Menulist pref should have been updated");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with inline preferences as optionsURL
+add_test(function() {
+ observer.checkHidden("inlinesettings3@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 5, "Grid should have settings children");
+
+ var node = settings[0];
+ node = settings[0];
+ is_element_hidden(node, "Unsupported settings should not be visible");
+ ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
+
+ node = settings[1];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(node.hasAttribute("first-row"), "First visible row should have first-row attribute");
+ var description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "Description Attribute", "Description node should contain description");
+
+ node = settings[2];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(!node.hasAttribute("first-row"), "Not the first row");
+ description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "Description Text Node", "Description node should contain description");
+
+ node = settings[3];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(!node.hasAttribute("first-row"), "Not the first row");
+ description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "This is a test, all this text should be visible", "Description node should contain description");
+ var button = node.firstElementChild;
+ isnot(button, null, "There should be a button");
+
+ node = settings[4];
+ is_element_hidden(node, "Unsupported settings should not be visible");
+ ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with non-inline preferences as optionsURL
+add_test(function() {
+ observer.checkHidden("inlinesettings2@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkNotDisplayed();
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ var button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with options.xul, disabling and enabling should hide and show settings UI
+add_test(function() {
+ observer.checkNotHidden();
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+ is(gManagerWindow.gViewController.currentViewId,
+ "addons://detail/inlinesettings1%40tests.mozilla.org",
+ "Current view should not scroll to preferences");
+ checkScrolling(false);
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ // disable
+ var button = gManagerWindow.document.getElementById("detail-disable-btn");
+ button.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ gCategoryUtilities.openType("extension", function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ // enable
+ var button = gManagerWindow.document.getElementById("detail-enable-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ observer.callback = function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+
+ settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ };
+ });
+ });
+ });
+});
+
+
+// Addon with options.xul that requires a restart to disable,
+// disabling and enabling should not hide and show settings UI.
+add_test(function() {
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ ok(settings.length > 0, "Grid should have settings children");
+
+ // disable
+ var button = gManagerWindow.document.getElementById("detail-disable-btn");
+ button.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ observer.checkNotHidden();
+
+ settings = grid.querySelectorAll("rows > setting");
+ ok(settings.length > 0, "Grid should still have settings children");
+
+ // cancel pending disable
+ button = gManagerWindow.document.getElementById("detail-enable-btn");
+ button.scrollIntoView();
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ observer.checkNotDisplayed();
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Tests bindings with existing prefs.
+add_test(function() {
+ observer.checkHidden("inlinesettings2@tests.mozilla.org");
+
+ // Ensure these prefs are set. They should be set above, but somebody might
+ // change the tests above.
+ var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
+ Services.prefs.setIntPref("extensions.inlinesettings1.boolint", 1);
+ Services.prefs.setIntPref("extensions.inlinesettings1.integer", 12);
+ Preferences.set("extensions.inlinesettings1.string", "bar\u03DE/");
+ Services.prefs.setCharPref("extensions.inlinesettings1.color", "#FF9900");
+ Services.prefs.setCharPref("extensions.inlinesettings1.file", profD.path);
+ Services.prefs.setCharPref("extensions.inlinesettings1.directory", profD.path);
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
+ is(input.checked, false, "Checkbox should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[1], "anonid", "input");
+ is(input.checked, true, "Checkbox should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
+ is(input.value, "12", "Number box should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
+ is(input.value, "bar\u03DE/", "Text box should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[5], "anonid", "input");
+ is(input.color, "#FF9900", "Color picker should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
+ is(input.value, profD.path, "Label should have initial value");
+ is(input.tooltipText, profD.path, "Label tooltip should have initial value");
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
+ is(input.value, profD.path, "Label value should have initial value");
+ is(input.tooltipText, profD.path, "Label tooltip should have initial value");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Tests bindings with existing prefs.
+add_test(function() {
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ // Ensure these prefs are set. They should be set above, but somebody might
+ // change the tests above.
+ Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
+ Services.prefs.setIntPref("extensions.inlinesettings3.radioInt", 6);
+ Preferences.set("extensions.inlinesettings3.radioString", "kilo \u338F");
+ Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 9);
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings3@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+
+ var radios = settings[0].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+
+ radios = settings[1].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ isnot(radios[1].selected, true, "Correct radio button should be selected");
+ is(radios[2].selected, true, "Correct radio button should be selected");
+
+ radios = settings[2].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ isnot(radios[1].selected, true, "Correct radio button should be selected");
+ is(radios[2].selected, true, "Correct radio button should be selected");
+
+ var input = settings[3].firstElementChild;
+ is(input.value, "9", "Menulist should have initial value");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_browser.js b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_browser.js
new file mode 100644
index 000000000..5a704530a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_browser.js
@@ -0,0 +1,207 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* globals TestUtils */
+
+var {Extension} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
+
+var gAddon;
+var gOtherAddon;
+var gManagerWindow;
+var gCategoryUtilities;
+
+var installedAddons = [];
+
+function installAddon(details) {
+ let id = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
+ .generateUUID().number;
+ if (!details.manifest) {
+ details.manifest = {};
+ }
+ details.manifest.applications = {gecko: {id}};
+ let xpi = Extension.generateXPI(details);
+
+ return AddonManager.installTemporaryAddon(xpi).then(addon => {
+ SimpleTest.registerCleanupFunction(function() {
+ addon.uninstall();
+
+ Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
+ xpi.remove(false);
+ });
+
+ return addon;
+ });
+}
+
+add_task(function*() {
+ gAddon = yield installAddon({
+ manifest: {
+ "options_ui": {
+ "page": "options.html",
+ }
+ },
+
+ files: {
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="UTF-8">
+ <style type="text/css">
+ body > p {
+ height: 300px;
+ margin: 0;
+ }
+ body.bigger > p {
+ height: 600px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>The quick mauve fox jumps over the opalescent dog.</p>
+ </body>
+ </html>`,
+ },
+ });
+
+ // Create another add-on with no inline options, to verify that detail
+ // view switches work correctly.
+ gOtherAddon = yield installAddon({});
+
+ gManagerWindow = yield open_manager("addons://list/extension");
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+});
+
+
+function* openDetailsBrowser(addonId) {
+ var addon = get_addon_element(gManagerWindow, addonId);
+
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_BROWSER,
+ "Options should be inline browser type");
+
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+
+ is_element_visible(button, "Preferences button should be visible");
+
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ yield TestUtils.topicObserved(AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
+ (subject, data) => data == addonId);
+
+ is(gManagerWindow.gViewController.currentViewId,
+ `addons://detail/${encodeURIComponent(addonId)}/preferences`,
+ "Current view should scroll to preferences");
+
+ var browser = gManagerWindow.document.querySelector(
+ "#detail-grid > rows > .inline-options-browser");
+ var rows = browser.parentNode;
+
+ ok(browser, "Grid should have a browser child");
+ is(browser.localName, "browser", "Grid should have a browser child");
+ is(browser.currentURI.spec, addon.mAddon.optionsURL, "Browser has the expected options URL loaded")
+
+ is(browser.clientWidth, rows.clientWidth,
+ "Browser should be the same width as its parent node");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ return browser;
+}
+
+
+add_task(function* test_inline_browser_addon() {
+ let browser = yield openDetailsBrowser(gAddon.id);
+
+ let body = browser.contentDocument.body;
+
+ function checkHeights(expected) {
+ is(body.clientHeight, expected, `Document body should be ${expected}px tall`);
+ is(body.clientHeight, body.scrollHeight,
+ "Document body should be tall enough to fit its contents");
+
+ let heightDiff = browser.clientHeight - expected;
+ ok(heightDiff >= 0 && heightDiff < 50,
+ "Browser should be slightly taller than the document body");
+ }
+
+ // Delay long enough to avoid hitting our resize rate limit.
+ let delay = () => new Promise(resolve => setTimeout(resolve, 300));
+
+ checkHeights(300);
+
+ info("Increase the document height, and expect the browser to grow correspondingly");
+ body.classList.toggle("bigger");
+
+ yield delay();
+
+ checkHeights(600);
+
+ info("Decrease the document height, and expect the browser to shrink correspondingly");
+ body.classList.toggle("bigger");
+
+ yield delay();
+
+ checkHeights(300);
+
+ yield new Promise(resolve =>
+ gCategoryUtilities.openType("extension", resolve));
+
+ browser = gManagerWindow.document.querySelector(
+ ".inline-options-browser");
+
+ is(browser, null, "Options browser should be removed from the document");
+});
+
+
+// Test that loading an add-on with no inline browser works as expected
+// after having viewed our main test add-on.
+add_task(function* test_plain_addon() {
+ var addon = get_addon_element(gManagerWindow, gOtherAddon.id);
+
+ is(addon.mAddon.optionsType, null, "Add-on should have no options");
+
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ yield EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 1 }, gManagerWindow);
+
+ EventUtils.synthesizeMouseAtCenter(addon, { clickCount: 2 }, gManagerWindow);
+
+ yield BrowserTestUtils.waitForEvent(gManagerWindow, "ViewChanged");
+
+ is(gManagerWindow.gViewController.currentViewId,
+ `addons://detail/${encodeURIComponent(gOtherAddon.id)}`,
+ "Detail view should be open");
+
+ var browser = gManagerWindow.document.querySelector(
+ "#detail-grid > rows > .inline-options-browser");
+
+ is(browser, null, "Detail view should have no inline browser");
+
+ yield new Promise(resolve =>
+ gCategoryUtilities.openType("extension", resolve));
+});
+
+
+// Test that loading the original add-on details successfully creates a
+// browser.
+add_task(function* test_inline_browser_addon_again() {
+ let browser = yield openDetailsBrowser(gAddon.id);
+
+ yield new Promise(resolve =>
+ gCategoryUtilities.openType("extension", resolve));
+
+ browser = gManagerWindow.document.querySelector(
+ ".inline-options-browser");
+
+ is(browser, null, "Options browser should be removed from the document");
+});
+
+add_task(function*() {
+ yield close_manager(gManagerWindow);
+
+ gManagerWindow = null;
+ gCategoryUtilities = null;
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_custom.js b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_custom.js
new file mode 100644
index 000000000..ecd10852d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_custom.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests various aspects of the details view
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+function installAddon(aCallback) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_inlinesettings1_custom.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ installAddon(function () {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ AddonManager.getAddonByID("inlinesettings1@tests.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+ finish();
+ });
+ });
+}
+
+// Addon with options.xul, with custom <setting> binding
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE, "Options should be inline type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ run_next_test();
+});
+
+// Addon with options.xul, also a test for the setting.xml bindings
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gManagerWindow.gViewController.currentViewId,
+ "addons://detail/inlinesettings1%40tests.mozilla.org/preferences",
+ "Current view should scroll to preferences");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 1, "Grid should have settings children");
+
+ ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
+
+ var style = window.getComputedStyle(settings[0], null);
+ is(style.getPropertyValue("background-color"), "rgb(0, 0, 255)", "Background color should be set");
+ is(style.getPropertyValue("display"), "-moz-grid-line", "Display should be set");
+ is(style.getPropertyValue("-moz-binding"), 'url("chrome://inlinesettings/content/binding.xml#custom")', "Binding should be set");
+
+ var label = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "label");
+ is(label.textContent, "Custom", "Localized string should be shown");
+
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
+ isnot(input, null, "Binding should be applied");
+ is(input.value, "Woah!", "Binding should be applied");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_info.js b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_info.js
new file mode 100644
index 000000000..ce618b7fa
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_inlinesettings_info.js
@@ -0,0 +1,574 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests various aspects of the details view
+Components.utils.import("resource://gre/modules/Preferences.jsm");
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+const SETTINGS_ROWS = 8;
+
+var MockFilePicker = SpecialPowers.MockFilePicker;
+MockFilePicker.init(window);
+
+var observer = {
+ lastDisplayed: null,
+ callback: null,
+ checkDisplayed: function(aExpected) {
+ is(this.lastDisplayed, aExpected, "'addon-options-displayed' notification should have fired");
+ this.lastDisplayed = null;
+ },
+ checkNotDisplayed: function() {
+ is(this.lastDisplayed, null, "'addon-options-displayed' notification should not have fired");
+ },
+ lastHidden: null,
+ checkHidden: function(aExpected) {
+ is(this.lastHidden, aExpected, "'addon-options-hidden' notification should have fired");
+ this.lastHidden = null;
+ },
+ checkNotHidden: function() {
+ is(this.lastHidden, null, "'addon-options-hidden' notification should not have fired");
+ },
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic == AddonManager.OPTIONS_NOTIFICATION_DISPLAYED) {
+ this.lastDisplayed = aData;
+ // Test if the binding has applied before the observers are notified. We test the second setting here,
+ // because the code operates on the first setting and we want to check it applies to all.
+ var setting = aSubject.querySelector("rows > setting[first-row] ~ setting");
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(setting, "class", "preferences-title");
+ isnot(input, null, "XBL binding should be applied");
+
+ // Add some extra height to the scrolling pane to ensure that it needs to scroll when appropriate.
+ gManagerWindow.document.getElementById("detail-controls").style.marginBottom = "1000px";
+
+ if (this.callback) {
+ var tempCallback = this.callback;
+ this.callback = null;
+ tempCallback();
+ }
+ } else if (aTopic == AddonManager.OPTIONS_NOTIFICATION_HIDDEN) {
+ this.lastHidden = aData;
+ }
+ }
+};
+
+function installAddon(aCallback) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_inlinesettings1_info.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+}
+
+function checkScrolling(aShouldHaveScrolled) {
+ var detailView = gManagerWindow.document.getElementById("detail-view");
+ var boxObject = detailView.boxObject;
+ ok(detailView.scrollHeight > boxObject.height, "Page should require scrolling");
+ if (aShouldHaveScrolled)
+ isnot(detailView.scrollTop, 0, "Page should have scrolled");
+ else
+ is(detailView.scrollTop, 0, "Page should not have scrolled");
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "inlinesettings2@tests.mozilla.org",
+ name: "Inline Settings (Regular)",
+ version: "1",
+ optionsURL: CHROMEROOT + "options.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_DISABLE,
+ }, {
+ id: "inlinesettings3@tests.mozilla.org",
+ name: "Inline Settings (More Options)",
+ description: "Tests for option types introduced after Mozilla 7.0",
+ version: "1",
+ optionsURL: CHROMEROOT + "more_options.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO
+ }, {
+ id: "noninlinesettings@tests.mozilla.org",
+ name: "Non-Inline Settings",
+ version: "1",
+ optionsURL: CHROMEROOT + "addon_prefs.xul"
+ }]);
+
+ installAddon(function () {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ Services.obs.addObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
+ false);
+ Services.obs.addObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_HIDDEN,
+ false);
+
+ run_next_test();
+ });
+ });
+}
+
+function end_test() {
+ Services.obs.removeObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_DISPLAYED);
+
+ Services.prefs.clearUserPref("extensions.inlinesettings1.bool");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.boolint");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.integer");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.string");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.color");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.file");
+ Services.prefs.clearUserPref("extensions.inlinesettings1.directory");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioBool");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioInt");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.radioString");
+ Services.prefs.clearUserPref("extensions.inlinesettings3.menulist");
+
+ MockFilePicker.cleanup();
+
+ close_manager(gManagerWindow, function() {
+ observer.checkHidden("inlinesettings2@tests.mozilla.org");
+ Services.obs.removeObserver(observer,
+ AddonManager.OPTIONS_NOTIFICATION_HIDDEN);
+
+ AddonManager.getAddonByID("inlinesettings1@tests.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+ finish();
+ });
+ });
+}
+
+// Addon with options.xul
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_hidden(button, "Preferences button should be hidden");
+
+ run_next_test();
+});
+
+// Addon with inline preferences as optionsURL
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_hidden(button, "Preferences button should be hidden");
+
+ run_next_test();
+});
+
+// Addon with non-inline preferences as optionsURL
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_DIALOG, "Options should be dialog type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ run_next_test();
+});
+
+// Addon with options.xul, also a test for the setting.xml bindings
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
+ Services.prefs.setBoolPref("extensions.inlinesettings1.bool", false);
+ var input = gManagerWindow.document.getAnonymousElementByAttribute(settings[0], "anonid", "input");
+ isnot(input.checked, true, "Checkbox should have initial value");
+ is(input.label, "Check box label", "Checkbox should be labelled");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ is(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), true, "Bool pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ isnot(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getBoolPref("extensions.inlinesettings1.bool"), false, "Bool pref should have been updated");
+
+ ok(!settings[1].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings1.boolint", 0);
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[1], "anonid", "input");
+ isnot(input.checked, true, "Checkbox should have initial value");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ is(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 1, "BoolInt pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(input, { clickCount: 1 }, gManagerWindow);
+ isnot(input.checked, true, "Checkbox should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.boolint"), 2, "BoolInt pref should have been updated");
+
+ ok(!settings[2].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings1.integer", 0);
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[2], "anonid", "input");
+ is(input.value, "0", "Number box should have initial value");
+ input.select();
+ EventUtils.synthesizeKey("1", {}, gManagerWindow);
+ EventUtils.synthesizeKey("3", {}, gManagerWindow);
+ is(input.value, "13", "Number box should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 13, "Integer pref should have been updated");
+ EventUtils.synthesizeKey("VK_DOWN", {}, gManagerWindow);
+ is(input.value, "12", "Number box should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings1.integer"), 12, "Integer pref should have been updated");
+
+ ok(!settings[3].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings1.string", "foo");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[3], "anonid", "input");
+ is(input.value, "foo", "Text box should have initial value");
+ input.select();
+ EventUtils.synthesizeKey("b", {}, gManagerWindow);
+ EventUtils.synthesizeKey("a", {}, gManagerWindow);
+ EventUtils.synthesizeKey("r", {}, gManagerWindow);
+ is(input.value, "bar", "Text box should have updated value");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.string"), "bar", "String pref should have been updated");
+
+ ok(!settings[4].hasAttribute("first-row"), "Not the first row");
+ input = settings[4].firstElementChild;
+ is(input.value, "1", "Menulist should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("b", {}, gManagerWindow);
+ is(input.value, "2", "Menulist should have updated value");
+ is(gManagerWindow._testValue, "2", "Menulist oncommand handler should've updated the test value");
+ delete gManagerWindow._testValue;
+
+ ok(!settings[5].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings1.color", "#FF0000");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[5], "anonid", "input");
+ is(input.color, "#FF0000", "Color picker should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RIGHT", {}, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", {}, gManagerWindow);
+ input.hidePopup();
+ is(input.color, "#FF9900", "Color picker should have updated value");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.color"), "#FF9900", "Color pref should have been updated");
+
+ try {
+ ok(!settings[6].hasAttribute("first-row"), "Not the first row");
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "button");
+
+ // Workaround for bug 1155324 - we need to ensure that the button is scrolled into view.
+ button.scrollIntoView();
+
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[6], "anonid", "input");
+ is(input.value, "", "Label value should be empty");
+ is(input.tooltipText, "", "Label tooltip should be empty");
+
+ var profD = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ var curProcD = Services.dirsvc.get("CurProcD", Ci.nsIFile);
+
+ MockFilePicker.returnFiles = [profD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
+ is(input.value, profD.path, "Label value should match file chosen");
+ is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should match file chosen");
+
+ MockFilePicker.returnFiles = [curProcD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeOpen, "File picker mode should be open file");
+ is(input.value, profD.path, "Label value should not have changed");
+ is(input.tooltipText, profD.path, "Label tooltip should not have changed");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.file"), profD.path, "File pref should not have changed");
+
+ ok(!settings[7].hasAttribute("first-row"), "Not the first row");
+ button = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "button");
+ input = gManagerWindow.document.getAnonymousElementByAttribute(settings[7], "anonid", "input");
+ is(input.value, "", "Label value should be empty");
+ is(input.tooltipText, "", "Label tooltip should be empty");
+
+ MockFilePicker.returnFiles = [profD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnOK;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
+ is(input.value, profD.path, "Label value should match file chosen");
+ is(input.tooltipText, profD.path, "Label tooltip should match file chosen");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should match file chosen");
+
+ MockFilePicker.returnFiles = [curProcD];
+ MockFilePicker.returnValue = Ci.nsIFilePicker.returnCancel;
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ is(MockFilePicker.mode, Ci.nsIFilePicker.modeGetFolder, "File picker mode should be directory");
+ is(input.value, profD.path, "Label value should not have changed");
+ is(input.tooltipText, profD.path, "Label tooltip should not have changed");
+ is(Services.prefs.getCharPref("extensions.inlinesettings1.directory"), profD.path, "Directory pref should not have changed");
+
+ } finally {
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ }
+ });
+});
+
+// Tests for the setting.xml bindings introduced after Mozilla 7
+add_test(function() {
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings3@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings3@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 4, "Grid should have settings children");
+
+ ok(settings[0].hasAttribute("first-row"), "First visible row should have first-row attribute");
+ Services.prefs.setBoolPref("extensions.inlinesettings3.radioBool", false);
+ var radios = settings[0].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), true, "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[1], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getBoolPref("extensions.inlinesettings3.radioBool"), false, "Radio pref should have been updated");
+
+ ok(!settings[1].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings3.radioInt", 5);
+ radios = settings[1].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ isnot(radios[2].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 4, "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.radioInt"), 6, "Radio pref should have been updated");
+
+ ok(!settings[2].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setCharPref("extensions.inlinesettings3.radioString", "juliet");
+ radios = settings[2].getElementsByTagName("radio");
+ isnot(radios[0].selected, true, "Correct radio button should be selected");
+ is(radios[1].selected, true, "Correct radio button should be selected");
+ isnot(radios[2].selected, true, "Correct radio button should be selected");
+ EventUtils.synthesizeMouseAtCenter(radios[0], { clickCount: 1 }, gManagerWindow);
+ is(Services.prefs.getCharPref("extensions.inlinesettings3.radioString"), "india", "Radio pref should have been updated");
+ EventUtils.synthesizeMouseAtCenter(radios[2], { clickCount: 1 }, gManagerWindow);
+ is(Preferences.get("extensions.inlinesettings3.radioString", "wrong"), "kilo \u338F", "Radio pref should have been updated");
+
+ ok(!settings[3].hasAttribute("first-row"), "Not the first row");
+ Services.prefs.setIntPref("extensions.inlinesettings3.menulist", 8);
+ var input = settings[3].firstElementChild;
+ is(input.value, "8", "Menulist should have initial value");
+ input.focus();
+ EventUtils.synthesizeKey("n", {}, gManagerWindow);
+ is(input.value, "9", "Menulist should have updated value");
+ is(Services.prefs.getIntPref("extensions.inlinesettings3.menulist"), 9, "Menulist pref should have been updated");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with inline preferences as optionsURL
+add_test(function() {
+ observer.checkHidden("inlinesettings3@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 5, "Grid should have settings children");
+
+ var node = settings[0];
+ node = settings[0];
+ is_element_hidden(node, "Unsupported settings should not be visible");
+ ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
+
+ node = settings[1];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(node.hasAttribute("first-row"), "First visible row should have first-row attribute");
+ var description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "Description Attribute", "Description node should contain description");
+
+ node = settings[2];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(!node.hasAttribute("first-row"), "Not the first row");
+ description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "Description Text Node", "Description node should contain description");
+
+ node = settings[3];
+ is(node.nodeName, "setting", "Should be a setting node");
+ ok(!node.hasAttribute("first-row"), "Not the first row");
+ description = gManagerWindow.document.getAnonymousElementByAttribute(node, "class", "preferences-description");
+ is(description.textContent, "This is a test, all this text should be visible", "Description node should contain description");
+ var button = node.firstElementChild;
+ isnot(button, null, "There should be a button");
+
+ node = settings[4];
+ is_element_hidden(node, "Unsupported settings should not be visible");
+ ok(!node.hasAttribute("first-row"), "Hidden row is not the first row");
+
+ button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with non-inline preferences as optionsURL
+add_test(function() {
+ observer.checkHidden("inlinesettings2@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "noninlinesettings@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkNotDisplayed();
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ var button = gManagerWindow.document.getElementById("detail-prefs-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
+
+// Addon with options.xul, disabling and enabling should hide and show settings UI
+add_test(function() {
+ observer.checkNotHidden();
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+ is(gManagerWindow.gViewController.currentViewId,
+ "addons://detail/inlinesettings1%40tests.mozilla.org",
+ "Current view should not scroll to preferences");
+ checkScrolling(false);
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ // disable
+ var button = gManagerWindow.document.getElementById("detail-disable-btn");
+ button.focus(); // make sure it's in view
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ gCategoryUtilities.openType("extension", function() {
+ var addon = get_addon_element(gManagerWindow, "inlinesettings1@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, 0, "Grid should not have settings children");
+
+ // enable
+ var button = gManagerWindow.document.getElementById("detail-enable-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ observer.callback = function() {
+ observer.checkDisplayed("inlinesettings1@tests.mozilla.org");
+
+ settings = grid.querySelectorAll("rows > setting");
+ is(settings.length, SETTINGS_ROWS, "Grid should have settings children");
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ };
+ });
+ });
+ });
+});
+
+
+// Addon with options.xul that requires a restart to disable,
+// disabling and enabling should not hide and show settings UI.
+add_test(function() {
+ observer.checkHidden("inlinesettings1@tests.mozilla.org");
+
+ var addon = get_addon_element(gManagerWindow, "inlinesettings2@tests.mozilla.org");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ observer.checkDisplayed("inlinesettings2@tests.mozilla.org");
+
+ var grid = gManagerWindow.document.getElementById("detail-grid");
+ var settings = grid.querySelectorAll("rows > setting");
+ ok(settings.length > 0, "Grid should have settings children");
+
+ // disable
+ var button = gManagerWindow.document.getElementById("detail-disable-btn");
+ button.focus(); // make sure it's in view
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ observer.checkNotHidden();
+
+ settings = grid.querySelectorAll("rows > setting");
+ ok(settings.length > 0, "Grid should still have settings children");
+
+ // cancel pending disable
+ button = gManagerWindow.document.getElementById("detail-enable-btn");
+ button.focus(); // make sure it's in view
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+ observer.checkNotDisplayed();
+
+ gCategoryUtilities.openType("extension", run_next_test);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_install.js b/toolkit/mozapps/webextensions/test/browser/browser_install.js
new file mode 100644
index 000000000..880a4624d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_install.js
@@ -0,0 +1,312 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests tha installs and undoing installs show up correctly
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+var gSearchCount = 0;
+
+function test() {
+ requestLongerTimeout(2);
+ waitForExplicitFinish();
+
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+ Services.prefs.setCharPref("extensions.getAddons.search.url", TESTROOT + "browser_install.xml");
+ // Allow http update checks
+ Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ Services.prefs.clearUserPref("extensions.checkUpdateSecurity");
+
+ AddonManager.getAddonByID("install1@tests.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+ finish();
+ });
+ });
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function installAddon(aCallback) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_install1_2.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+}
+
+function installUpgrade(aCallback) {
+ AddonManager.getAddonByID("install1@tests.mozilla.org", function(aAddon) {
+ aAddon.findUpdates({
+ onUpdateAvailable: function(aAddon, aInstall) {
+ is(get_list_item_count(), 1, "Should be only one item in the list");
+
+ aInstall.addListener({
+ onDownloadEnded: function() {
+ is(get_list_item_count(), 1, "Should be only one item in the list once the update has started");
+ },
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ aInstall.install();
+ }
+ }, AddonManager.UPDATE_WHEN_USER_REQUESTED);
+ });
+}
+
+function cancelInstall(aCallback) {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_install1_2.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onDownloadEnded: function(aInstall) {
+ executeSoon(function() {
+ aInstall.cancel();
+ aCallback();
+ });
+ return false;
+ }
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+}
+
+function installSearchResult(aCallback) {
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ // Search for something different each time
+ searchBox.value = "foo" + gSearchCount;
+ gSearchCount++;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ let remote = gManagerWindow.document.getElementById("search-filter-remote")
+ EventUtils.synthesizeMouseAtCenter(remote, { }, gManagerWindow);
+
+ let item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should see the search result in the list");
+
+ let status = get_node(item, "install-status");
+ EventUtils.synthesizeMouseAtCenter(get_node(status, "install-remote-btn"), {}, gManagerWindow);
+
+ item.mInstall.addListener({
+ onInstallEnded: function() {
+ executeSoon(aCallback);
+ }
+ });
+ });
+}
+
+function get_list_item_count() {
+ return get_test_items_in_list(gManagerWindow).length;
+}
+
+function check_undo_install() {
+ is(get_list_item_count(), 1, "Should be only one item in the list");
+
+ let item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should see the pending install in the list");
+ // Force XBL to apply
+ item.clientTop;
+ is_element_visible(get_node(item, "pending"), "Pending message should be visible");
+ is(get_node(item, "pending").textContent, "Install Tests will be installed after you restart " + gApp + ".", "Pending message should be correct");
+
+ EventUtils.synthesizeMouseAtCenter(get_node(item, "undo-btn"), {}, gManagerWindow);
+
+ is(get_list_item_count(), 0, "Should be no items in the list");
+
+ item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!item, "Should no longer see the pending install");
+}
+
+function check_undo_upgrade() {
+ is(get_list_item_count(), 1, "Should be only one item in the list");
+
+ let item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should see the pending upgrade in the list");
+ // Force XBL to apply
+ item.clientTop;
+ is_element_visible(get_node(item, "pending"), "Pending message should be visible");
+ is(get_node(item, "pending").textContent, "Install Tests will be updated after you restart " + gApp + ".", "Pending message should be correct");
+
+ EventUtils.synthesizeMouseAtCenter(get_node(item, "undo-btn"), {}, gManagerWindow);
+
+ is(get_list_item_count(), 1, "Should be only one item in the list");
+
+ item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should still see installed item in the list");
+ is_element_hidden(get_node(item, "pending"), "Pending message should be hidden");
+}
+
+// Install an add-on through the API with the manager open
+add_test(function() {
+ gCategoryUtilities.openType("extension", function() {
+ installAddon(function() {
+ check_undo_install();
+ run_next_test();
+ });
+ });
+});
+
+// Install an add-on with the manager closed then open it
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ installAddon(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_undo_install();
+ run_next_test();
+ });
+ });
+ });
+});
+
+// Install an add-on through the search page and then undo it
+add_test(function() {
+ installSearchResult(function() {
+ check_undo_install();
+ run_next_test();
+ });
+});
+
+// Install an add-on through the search page then switch to the extensions page
+// and then undo it
+add_test(function() {
+ installSearchResult(function() {
+ gCategoryUtilities.openType("extension", function() {
+ check_undo_install();
+ run_next_test();
+ });
+ });
+});
+
+// Install an add-on through the search page then re-open the manager and then
+// undo it
+add_test(function() {
+ installSearchResult(function() {
+ close_manager(gManagerWindow, function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_undo_install();
+ run_next_test();
+ });
+ });
+ });
+});
+
+// Cancel an install after download with the manager open
+add_test(function() {
+ cancelInstall(function() {
+ is(get_list_item_count(), 0, "Should be no items in the list");
+
+ run_next_test();
+ });
+});
+
+// Cancel an install after download with the manager closed
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ cancelInstall(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(get_list_item_count(), 0, "Should be no items in the list");
+
+ run_next_test();
+ });
+ });
+ });
+});
+
+// Install an existing add-on for the subsequent tests
+add_test(function() {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_install1_1.xpi",
+ function(aInstall) {
+ aInstall.addListener({
+ onInstallEnded: run_next_test
+ });
+ aInstall.install();
+ }, "application/x-xpinstall");
+});
+
+// Install an upgrade through the API with the manager open
+add_test(function() {
+ installAddon(function() {
+ check_undo_upgrade();
+ run_next_test();
+ });
+});
+
+// Install an upgrade through the API with the manager open
+add_test(function() {
+ installUpgrade(function() {
+ check_undo_upgrade();
+ run_next_test();
+ });
+});
+
+// Install an upgrade through the API with the manager closed
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ installAddon(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ check_undo_upgrade();
+ run_next_test();
+ });
+ });
+ });
+});
+
+// Cancel an upgrade after download with the manager open
+add_test(function() {
+ cancelInstall(function() {
+ is(get_list_item_count(), 1, "Should be no items in the list");
+ let item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should still see installed item in the list");
+ is_element_hidden(get_node(item, "pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Cancel an upgrade after download with the manager closed
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ cancelInstall(function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(get_list_item_count(), 1, "Should be no items in the list");
+ let item = get_addon_element(gManagerWindow, "install1@tests.mozilla.org");
+ ok(!!item, "Should still see installed item in the list");
+ is_element_hidden(get_node(item, "pending"), "Pending message should be hidden");
+
+ run_next_test();
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_install.rdf b/toolkit/mozapps/webextensions/test/browser/browser_install.rdf
new file mode 100644
index 000000000..437bf9b85
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_install.rdf
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:extension:install1@tests.mozilla.org">
+ <em:updates>
+ <Seq>
+ <li>
+ <Description>
+ <em:version>2.0</em:version>
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>https://example.com/browser/toolkit/mozapps/extensions/test/browser/browser_install1_3.xpi</em:updateLink>
+ <em:updateHash>sha1:4f0f4391914e3e036beca50cbac33958e5269643</em:updateHash>
+ </Description>
+ </em:targetApplication>
+ </Description>
+ </li>
+ </Seq>
+ </em:updates>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_install.rdf^headers^ b/toolkit/mozapps/webextensions/test/browser/browser_install.rdf^headers^
new file mode 100644
index 000000000..2e4f8163b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_install.rdf^headers^
@@ -0,0 +1 @@
+Connection: close
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_install.xml b/toolkit/mozapps/webextensions/test/browser/browser_install.xml
new file mode 100644
index 000000000..0643c811a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_install.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="1">
+ <addon>
+ <name>Install Tests</name>
+ <type id='1'>Extension</type>
+ <guid>install1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test add-on</summary>
+ <description>Test add-on</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="2">http://example.com/browser/toolkit/mozapps/extensions/test/browser/addons/browser_install1_2.xpi</install>
+ </addon>
+</searchresults>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpi b/toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpi
new file mode 100644
index 000000000..de3c90353
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_installssl.js b/toolkit/mozapps/webextensions/test/browser/browser_installssl.js
new file mode 100644
index 000000000..b0726ef9e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_installssl.js
@@ -0,0 +1,374 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const xpi = RELATIVE_DIR + "addons/browser_installssl.xpi";
+const redirect = RELATIVE_DIR + "redirect.sjs?";
+const SUCCESS = 0;
+const NETWORK_FAILURE = AddonManager.ERROR_NETWORK_FAILURE;
+
+const HTTP = "http://example.com/";
+const HTTPS = "https://example.com/";
+const NOCERT = "https://nocert.example.com/";
+const SELFSIGNED = "https://self-signed.example.com/";
+const UNTRUSTED = "https://untrusted.example.com/";
+const EXPIRED = "https://expired.example.com/";
+
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
+
+var gTests = [];
+var gStart = 0;
+var gLast = 0;
+var gPendingInstall = null;
+
+function test() {
+ gStart = Date.now();
+ requestLongerTimeout(4);
+ waitForExplicitFinish();
+
+ registerCleanupFunction(function() {
+ var cos = Cc["@mozilla.org/security/certoverride;1"].
+ getService(Ci.nsICertOverrideService);
+ cos.clearValidityOverride("nocert.example.com", -1);
+ cos.clearValidityOverride("self-signed.example.com", -1);
+ cos.clearValidityOverride("untrusted.example.com", -1);
+ cos.clearValidityOverride("expired.example.com", -1);
+
+ try {
+ Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
+ }
+ catch (e) {
+ }
+
+ if (gPendingInstall) {
+ gTests = [];
+ ok(false, "Timed out in the middle of downloading " + gPendingInstall.sourceURI.spec);
+ try {
+ gPendingInstall.cancel();
+ }
+ catch (e) {
+ }
+ }
+ });
+
+ run_next_test();
+}
+
+function end_test() {
+ info("All tests completed in " + (Date.now() - gStart) + "ms");
+ finish();
+}
+
+function add_install_test(mainURL, redirectURL, expectedStatus) {
+ gTests.push([mainURL, redirectURL, expectedStatus]);
+}
+
+function run_install_tests(callback) {
+ function run_next_install_test() {
+ if (gTests.length == 0) {
+ callback();
+ return;
+ }
+ gLast = Date.now();
+
+ let [mainURL, redirectURL, expectedStatus] = gTests.shift();
+ if (redirectURL) {
+ var url = mainURL + redirect + redirectURL + xpi;
+ var message = "Should have seen the right result for an install redirected from " +
+ mainURL + " to " + redirectURL;
+ }
+ else {
+ url = mainURL + xpi;
+ message = "Should have seen the right result for an install from " +
+ mainURL;
+ }
+
+ AddonManager.getInstallForURL(url, function(install) {
+ gPendingInstall = install;
+ install.addListener({
+ onDownloadEnded: function(install) {
+ is(SUCCESS, expectedStatus, message);
+ info("Install test ran in " + (Date.now() - gLast) + "ms");
+ // Don't proceed with the install
+ install.cancel();
+ gPendingInstall = null;
+ run_next_install_test();
+ return false;
+ },
+
+ onDownloadFailed: function(install) {
+ is(install.error, expectedStatus, message);
+ info("Install test ran in " + (Date.now() - gLast) + "ms");
+ gPendingInstall = null;
+ run_next_install_test();
+ }
+ });
+ install.install();
+ }, "application/x-xpinstall");
+ }
+
+ run_next_install_test();
+}
+
+// Add overrides for the bad certificates
+function addCertOverrides() {
+ addCertOverride("nocert.example.com", Ci.nsICertOverrideService.ERROR_MISMATCH);
+ addCertOverride("self-signed.example.com", Ci.nsICertOverrideService.ERROR_UNTRUSTED);
+ addCertOverride("untrusted.example.com", Ci.nsICertOverrideService.ERROR_UNTRUSTED);
+ addCertOverride("expired.example.com", Ci.nsICertOverrideService.ERROR_TIME);
+}
+
+// Runs tests with built-in certificates required, no certificate exceptions
+// and no hashes
+add_test(function() {
+ // Tests that a simple install works as expected.
+ add_install_test(HTTP, null, SUCCESS);
+ add_install_test(HTTPS, null, NETWORK_FAILURE);
+ add_install_test(NOCERT, null, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, null, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, null, NETWORK_FAILURE);
+ add_install_test(EXPIRED, null, NETWORK_FAILURE);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_install_test(HTTP, HTTP, SUCCESS);
+ add_install_test(HTTP, HTTPS, SUCCESS);
+ add_install_test(HTTP, NOCERT, NETWORK_FAILURE);
+ add_install_test(HTTP, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(HTTP, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(HTTP, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_install_test(HTTPS, HTTP, NETWORK_FAILURE);
+ add_install_test(HTTPS, HTTPS, NETWORK_FAILURE);
+ add_install_test(HTTPS, NOCERT, NETWORK_FAILURE);
+ add_install_test(HTTPS, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(HTTPS, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(HTTPS, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_install_test(NOCERT, HTTP, NETWORK_FAILURE);
+ add_install_test(NOCERT, HTTPS, NETWORK_FAILURE);
+ add_install_test(NOCERT, NOCERT, NETWORK_FAILURE);
+ add_install_test(NOCERT, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(NOCERT, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(NOCERT, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_install_test(SELFSIGNED, HTTP, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, HTTPS, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, NOCERT, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_install_test(UNTRUSTED, HTTP, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, HTTPS, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, NOCERT, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_install_test(EXPIRED, HTTP, NETWORK_FAILURE);
+ add_install_test(EXPIRED, HTTPS, NETWORK_FAILURE);
+ add_install_test(EXPIRED, NOCERT, NETWORK_FAILURE);
+ add_install_test(EXPIRED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, EXPIRED, NETWORK_FAILURE);
+
+ run_install_tests(run_next_test);
+});
+
+// Runs tests without requiring built-in certificates, no certificate
+// exceptions and no hashes
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+
+ // Tests that a simple install works as expected.
+ add_install_test(HTTP, null, SUCCESS);
+ add_install_test(HTTPS, null, SUCCESS);
+ add_install_test(NOCERT, null, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, null, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, null, NETWORK_FAILURE);
+ add_install_test(EXPIRED, null, NETWORK_FAILURE);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_install_test(HTTP, HTTP, SUCCESS);
+ add_install_test(HTTP, HTTPS, SUCCESS);
+ add_install_test(HTTP, NOCERT, NETWORK_FAILURE);
+ add_install_test(HTTP, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(HTTP, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(HTTP, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_install_test(HTTPS, HTTP, NETWORK_FAILURE);
+ add_install_test(HTTPS, HTTPS, SUCCESS);
+ add_install_test(HTTPS, NOCERT, NETWORK_FAILURE);
+ add_install_test(HTTPS, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(HTTPS, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(HTTPS, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_install_test(NOCERT, HTTP, NETWORK_FAILURE);
+ add_install_test(NOCERT, HTTPS, NETWORK_FAILURE);
+ add_install_test(NOCERT, NOCERT, NETWORK_FAILURE);
+ add_install_test(NOCERT, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(NOCERT, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(NOCERT, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_install_test(SELFSIGNED, HTTP, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, HTTPS, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, NOCERT, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_install_test(UNTRUSTED, HTTP, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, HTTPS, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, NOCERT, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_install_test(EXPIRED, HTTP, NETWORK_FAILURE);
+ add_install_test(EXPIRED, HTTPS, NETWORK_FAILURE);
+ add_install_test(EXPIRED, NOCERT, NETWORK_FAILURE);
+ add_install_test(EXPIRED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, EXPIRED, NETWORK_FAILURE);
+
+ run_install_tests(run_next_test);
+});
+
+// Runs tests with built-in certificates required, all certificate exceptions
+// and no hashes
+add_test(function() {
+ Services.prefs.clearUserPref(PREF_INSTALL_REQUIREBUILTINCERTS);
+ addCertOverrides();
+
+ // Tests that a simple install works as expected.
+ add_install_test(HTTP, null, SUCCESS);
+ add_install_test(HTTPS, null, NETWORK_FAILURE);
+ add_install_test(NOCERT, null, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, null, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, null, NETWORK_FAILURE);
+ add_install_test(EXPIRED, null, NETWORK_FAILURE);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_install_test(HTTP, HTTP, SUCCESS);
+ add_install_test(HTTP, HTTPS, SUCCESS);
+ add_install_test(HTTP, NOCERT, SUCCESS);
+ add_install_test(HTTP, SELFSIGNED, SUCCESS);
+ add_install_test(HTTP, UNTRUSTED, SUCCESS);
+ add_install_test(HTTP, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_install_test(HTTPS, HTTP, NETWORK_FAILURE);
+ add_install_test(HTTPS, HTTPS, NETWORK_FAILURE);
+ add_install_test(HTTPS, NOCERT, NETWORK_FAILURE);
+ add_install_test(HTTPS, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(HTTPS, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(HTTPS, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_install_test(NOCERT, HTTP, NETWORK_FAILURE);
+ add_install_test(NOCERT, HTTPS, NETWORK_FAILURE);
+ add_install_test(NOCERT, NOCERT, NETWORK_FAILURE);
+ add_install_test(NOCERT, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(NOCERT, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(NOCERT, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_install_test(SELFSIGNED, HTTP, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, HTTPS, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, NOCERT, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_install_test(UNTRUSTED, HTTP, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, HTTPS, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, NOCERT, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, EXPIRED, NETWORK_FAILURE);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_install_test(EXPIRED, HTTP, NETWORK_FAILURE);
+ add_install_test(EXPIRED, HTTPS, NETWORK_FAILURE);
+ add_install_test(EXPIRED, NOCERT, NETWORK_FAILURE);
+ add_install_test(EXPIRED, SELFSIGNED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, UNTRUSTED, NETWORK_FAILURE);
+ add_install_test(EXPIRED, EXPIRED, NETWORK_FAILURE);
+
+ run_install_tests(run_next_test);
+});
+
+// Runs tests without requiring built-in certificates, all certificate
+// exceptions and no hashes
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+
+ // Tests that a simple install works as expected.
+ add_install_test(HTTP, null, SUCCESS);
+ add_install_test(HTTPS, null, SUCCESS);
+ add_install_test(NOCERT, null, SUCCESS);
+ add_install_test(SELFSIGNED, null, SUCCESS);
+ add_install_test(UNTRUSTED, null, SUCCESS);
+ add_install_test(EXPIRED, null, SUCCESS);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_install_test(HTTP, HTTP, SUCCESS);
+ add_install_test(HTTP, HTTPS, SUCCESS);
+ add_install_test(HTTP, NOCERT, SUCCESS);
+ add_install_test(HTTP, SELFSIGNED, SUCCESS);
+ add_install_test(HTTP, UNTRUSTED, SUCCESS);
+ add_install_test(HTTP, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_install_test(HTTPS, HTTP, NETWORK_FAILURE);
+ add_install_test(HTTPS, HTTPS, SUCCESS);
+ add_install_test(HTTPS, NOCERT, SUCCESS);
+ add_install_test(HTTPS, SELFSIGNED, SUCCESS);
+ add_install_test(HTTPS, UNTRUSTED, SUCCESS);
+ add_install_test(HTTPS, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_install_test(NOCERT, HTTP, NETWORK_FAILURE);
+ add_install_test(NOCERT, HTTPS, SUCCESS);
+ add_install_test(NOCERT, NOCERT, SUCCESS);
+ add_install_test(NOCERT, SELFSIGNED, SUCCESS);
+ add_install_test(NOCERT, UNTRUSTED, SUCCESS);
+ add_install_test(NOCERT, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_install_test(SELFSIGNED, HTTP, NETWORK_FAILURE);
+ add_install_test(SELFSIGNED, HTTPS, SUCCESS);
+ add_install_test(SELFSIGNED, NOCERT, SUCCESS);
+ add_install_test(SELFSIGNED, SELFSIGNED, SUCCESS);
+ add_install_test(SELFSIGNED, UNTRUSTED, SUCCESS);
+ add_install_test(SELFSIGNED, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_install_test(UNTRUSTED, HTTP, NETWORK_FAILURE);
+ add_install_test(UNTRUSTED, HTTPS, SUCCESS);
+ add_install_test(UNTRUSTED, NOCERT, SUCCESS);
+ add_install_test(UNTRUSTED, SELFSIGNED, SUCCESS);
+ add_install_test(UNTRUSTED, UNTRUSTED, SUCCESS);
+ add_install_test(UNTRUSTED, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_install_test(EXPIRED, HTTP, NETWORK_FAILURE);
+ add_install_test(EXPIRED, HTTPS, SUCCESS);
+ add_install_test(EXPIRED, NOCERT, SUCCESS);
+ add_install_test(EXPIRED, SELFSIGNED, SUCCESS);
+ add_install_test(EXPIRED, UNTRUSTED, SUCCESS);
+ add_install_test(EXPIRED, EXPIRED, SUCCESS);
+
+ run_install_tests(run_next_test);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_list.js b/toolkit/mozapps/webextensions/test/browser/browser_list.js
new file mode 100644
index 000000000..49427329f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_list.js
@@ -0,0 +1,956 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests the list view
+
+var tempScope = {};
+Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", tempScope);
+var LightweightThemeManager = tempScope.LightweightThemeManager;
+const { REQUIRE_SIGNING } = Components.utils.import("resource://gre/modules/addons/AddonConstants.jsm", {});
+
+var gProvider;
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+var gVersion = Services.appinfo.version;
+var gBlocklistURL = Services.urlFormatter.formatURLPref("extensions.blocklist.detailsURL");
+var gDate = new Date(2010, 7, 16);
+var infoURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "unsigned-addons";
+
+const EXPECTED_ADDONS = 13;
+
+var gLWTheme = {
+ id: "4",
+ version: "1",
+ name: "Bling",
+ description: "SO MUCH BLING!",
+ author: "Pixel Pusher",
+ homepageURL: "http://mochi.test:8888/data/index.html",
+ headerURL: "http://mochi.test:8888/data/header.png",
+ footerURL: "http://mochi.test:8888/data/footer.png",
+ previewURL: "http://mochi.test:8888/data/preview.png",
+ iconURL: "http://mochi.test:8888/data/icon.png"
+ };
+
+add_task(function*() {
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on",
+ version: "1.0",
+ description: "A test add-on",
+ longDescription: " A longer description",
+ updateDate: gDate
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "Test add-on 2",
+ version: "2.0",
+ longDescription: " A longer description",
+ _userDisabled: true,
+ isActive: false,
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "Test add-on 3",
+ longDescription: " A longer description",
+ isActive: false,
+ isCompatible: false,
+ appDisabled: true,
+ permissions: AddonManager.PERM_CAN_ENABLE |
+ AddonManager.PERM_CAN_DISABLE |
+ AddonManager.PERM_CAN_UPGRADE
+ }, {
+ id: "addon4@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon4@tests.mozilla.org",
+ name: "Test add-on 4",
+ _userDisabled: true,
+ isActive: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_SOFTBLOCKED
+ }, {
+ id: "addon5@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon5@tests.mozilla.org",
+ name: "Test add-on 5",
+ isActive: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
+ appDisabled: true
+ }, {
+ id: "addon6@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon6@tests.mozilla.org",
+ name: "Test add-on 6",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon7@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon7@tests.mozilla.org",
+ name: "Test add-on 7",
+ blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED,
+ }, {
+ id: "addon8@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon8@tests.mozilla.org",
+ name: "Test add-on 8",
+ blocklistState: Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE,
+ }, {
+ id: "addon9@tests.mozilla.org",
+ blocklistURL: "http://example.com/addon9@tests.mozilla.org",
+ name: "Test add-on 9",
+ blocklistState: Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE,
+ }, {
+ id: "addon10@tests.mozilla.org",
+ name: "Test add-on 10",
+ signedState: AddonManager.SIGNEDSTATE_MISSING,
+ }, {
+ id: "addon11@tests.mozilla.org",
+ name: "Test add-on 11",
+ signedState: AddonManager.SIGNEDSTATE_MISSING,
+ isActive: false,
+ isCompatible: false,
+ appDisabled: true,
+ }, {
+ id: "addon12@tests.mozilla.org",
+ name: "Test add-on 12",
+ signedState: AddonManager.SIGNEDSTATE_PRELIMINARY,
+ foreignInstall: true,
+ }, {
+ id: "addon13@tests.mozilla.org",
+ name: "Test add-on 13",
+ signedState: AddonManager.SIGNEDSTATE_SIGNED,
+ foreignInstall: true,
+ }, {
+ id: "addon15@tests.mozilla.org",
+ name: "Test add-on 15",
+ hidden: true,
+ }]);
+
+ gManagerWindow = yield open_manager(null);
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+});
+
+function get_test_items() {
+ var tests = "@tests.mozilla.org";
+
+ var items = {};
+ var item = gManagerWindow.document.getElementById("addon-list").firstChild;
+
+ while (item) {
+ if (item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests &&
+ !is_hidden(item))
+ items[item.mAddon.name] = item;
+ item = item.nextSibling;
+ }
+
+ return items;
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function get_class_node(parent, cls) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "class", cls);
+}
+
+// Check that the list appears to have displayed correctly and trigger some
+// changes
+add_task(function*() {
+ yield gCategoryUtilities.openType("extension");
+ let items = get_test_items();
+ is(Object.keys(items).length, EXPECTED_ADDONS, "Should be the right number of add-ons installed");
+
+ info("Addon 1");
+ let addon = items["Test add-on"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ let { name, version } = yield get_tooltip_info(addon);
+ is(get_node(addon, "name").value, "Test add-on", "Name should be correct");
+ is(name, "Test add-on", "Tooltip name should be correct");
+ is(version, "1.0", "Tooltip version should be correct");
+ is(get_node(addon, "description").value, "A test add-on", "Description should be correct");
+ is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden");
+ is_element_hidden(get_class_node(addon, "update-postfix"), "Update postfix should be hidden");
+ is(get_node(addon, "date-updated").value, formatDate(gDate), "Update date should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Disabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "disable-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be visible");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Addon 2");
+ addon = items["Test add-on 2"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 2", "Name should be correct");
+ is(name, "Test add-on 2", "Tooltip name should be correct");
+ is(version, "2.0", "Tooltip version should be correct");
+ is_element_hidden(get_node(addon, "description"), "Description should be hidden");
+ is_element_visible(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be visible");
+ is_element_hidden(get_class_node(addon, "update-postfix"), "Update postfix should be hidden");
+ is(get_node(addon, "date-updated").value, "Unknown", "Date should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Enabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 2 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Addon 3");
+ addon = items["Test add-on 3"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 3", "Name should be correct");
+ is(name, "Test add-on 3", "Tooltip name should be correct");
+ is(version, undefined, "Tooltip version should be hidden");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_hidden(get_node(addon, "remove-btn"), "Remove button should be hidden");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+ is(get_node(addon, "warning").textContent, "Test add-on 3 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 4");
+ addon = items["Test add-on 4"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 4", "Name should be correct");
+ is(name, "Test add-on 4", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+ is(get_node(addon, "warning").textContent, "Test add-on 4 is known to cause security or stability issues.", "Warning message should be correct");
+ is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+ is(get_node(addon, "warning-link").value, "More Information", "Warning link text should be correct");
+ is(get_node(addon, "warning-link").href, "http://example.com/addon4@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Enabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 4 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Addon 5");
+ addon = items["Test add-on 5"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 5", "Name should be correct");
+ is(name, "Test add-on 5", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_visible(get_node(addon, "error"), "Error message should be visible");
+ is(get_node(addon, "error").textContent, "Test add-on 5 has been disabled due to security or stability issues.", "Error message should be correct");
+ is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+ is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
+ is(get_node(addon, "error-link").href, "http://example.com/addon5@tests.mozilla.org", "Error link should be correct");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 6");
+ addon = items["Test add-on 6"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 6", "Name should be correct");
+ is(name, "Test add-on 6", "Tooltip name should be correct");
+ is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be visible");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Disabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "disable-btn"), {}, gManagerWindow);
+ is_element_visible(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be visible");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be visible");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 7");
+ addon = items["Test add-on 7"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 7", "Name should be correct");
+ is(name, "Test add-on 7", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be hidden");
+ is(get_node(addon, "warning").textContent, "An important update is available for Test add-on 7.", "Warning message should be correct");
+ is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+ is(get_node(addon, "warning-link").value, "Update Now", "Warning link text should be correct");
+ is(get_node(addon, "warning-link").href, "http://example.com/addon7@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Disabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "disable-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be visible");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 7 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Addon 8");
+ addon = items["Test add-on 8"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 8", "Name should be correct");
+ is(name, "Test add-on 8", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_visible(get_node(addon, "error"), "Error message should be visible");
+ is(get_node(addon, "error").textContent, "Test add-on 8 is known to be vulnerable and should be updated.", "Error message should be correct");
+ is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+ is(get_node(addon, "error-link").value, "Update Now", "Error link text should be correct");
+ is(get_node(addon, "error-link").href, "http://example.com/addon8@tests.mozilla.org", "Error link should be correct");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 9");
+ addon = items["Test add-on 9"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 9", "Name should be correct");
+ is(name, "Test add-on 9", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_visible(get_node(addon, "error"), "Error message should be visible");
+ is(get_node(addon, "error").textContent, "Test add-on 9 is known to be vulnerable. Use with caution.", "Error message should be correct");
+ is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+ is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
+ is(get_node(addon, "error-link").href, "http://example.com/addon9@tests.mozilla.org", "Error link should be correct");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ // These tests are only appropriate when signing can be turned off
+ if (!REQUIRE_SIGNING) {
+ info("Addon 10");
+ addon = items["Test add-on 10"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 10", "Name should be correct");
+ is(name, "Test add-on 10", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+ is(get_node(addon, "warning").textContent, "Test add-on 10 could not be verified for use in " + gApp + ". Proceed with caution.", "Warning message should be correct");
+ is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+ is(get_node(addon, "warning-link").value, "More Information", "Warning link text should be correct");
+ is(get_node(addon, "warning-link").href, infoURL, "Warning link should be correct");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 11");
+ addon = items["Test add-on 11"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 11", "Name should be correct");
+ is(name, "Test add-on 11", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+ is(get_node(addon, "warning").textContent, "Test add-on 11 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Filter for disabled unsigned extensions shouldn't appear because signing checks are off");
+ let filterButton = gManagerWindow.document.getElementById("show-disabled-unsigned-extensions");
+ let showAllButton = gManagerWindow.document.getElementById("show-all-extensions");
+ let signingInfoUI = gManagerWindow.document.getElementById("disabled-unsigned-addons-info");
+ is_element_hidden(filterButton, "Button for showing disabled unsigned extensions should be hidden");
+ is_element_hidden(showAllButton, "Button for showing all extensions should be hidden");
+ is_element_hidden(signingInfoUI, "Signing info UI should be hidden");
+ }
+});
+
+// Check the add-ons are now in the right state
+add_task(function*() {
+ let [a1, a2, a4, a6] = yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
+ "addon2@tests.mozilla.org",
+ "addon4@tests.mozilla.org",
+ "addon6@tests.mozilla.org"]);
+
+ is(a1.pendingOperations, AddonManager.PENDING_DISABLE, "Add-on 1 should be pending disable");
+ is(a2.pendingOperations, AddonManager.PENDING_ENABLE, "Add-on 2 should be pending enable");
+ is(a4.pendingOperations, AddonManager.PENDING_ENABLE, "Add-on 4 should be pending enable");
+});
+
+// Reload the list to make sure the changes are still pending and that undoing
+// works
+add_task(function*() {
+ yield gCategoryUtilities.openType("plugin");
+ yield gCategoryUtilities.openType("extension");
+
+ let items = get_test_items();
+ is(Object.keys(items).length, EXPECTED_ADDONS, "Should be the right number of add-ons installed");
+
+ info("Addon 1");
+ let addon = items["Test add-on"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ let { name, version } = yield get_tooltip_info(addon);
+ is(get_node(addon, "name").value, "Test add-on", "Name should be correct");
+ is(name, "Test add-on", "Tooltip name should be correct");
+ is(version, "1.0", "Tooltip version should be correct");
+ is_element_visible(get_node(addon, "description"), "Description should be visible");
+ is(get_node(addon, "description").value, "A test add-on", "Description should be correct");
+ is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden");
+ is_element_hidden(get_class_node(addon, "update-postfix"), "Update postfix should be hidden");
+ is(get_node(addon, "date-updated").value, formatDate(gDate), "Update date should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Undoing");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 2");
+ addon = items["Test add-on 2"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 2", "Name should be correct");
+ is(name, "Test add-on 2", "Tooltip name should be correct");
+ is(version, "2.0", "Tooltip version should be correct");
+ is_element_hidden(get_node(addon, "description"), "Description should be hidden");
+ is_element_visible(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be visible");
+ is_element_hidden(get_class_node(addon, "update-postfix"), "Update postfix should be hidden");
+ is(get_node(addon, "date-updated").value, "Unknown", "Date should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 2 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Undoing");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 4");
+ addon = items["Test add-on 4"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 4", "Name should be correct");
+ is(name, "Test add-on 4", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 4 will be enabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Undoing");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+ is(get_node(addon, "warning").textContent, "Test add-on 4 is known to cause security or stability issues.", "Warning message should be correct");
+ is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+ is(get_node(addon, "warning-link").value, "More Information", "Warning link text should be correct");
+ is(get_node(addon, "warning-link").href, "http://example.com/addon4@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 6");
+ addon = items["Test add-on 6"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 6", "Name should be correct");
+ is(name, "Test add-on 6", "Tooltip name should be correct");
+ is_element_visible(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be visible");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be visible");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Enabling");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "enable-btn"), {}, gManagerWindow);
+ is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be visible");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+ info("Addon 7");
+ addon = items["Test add-on 7"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 7", "Name should be correct");
+ is(name, "Test add-on 7", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be visible");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be visible");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_visible(get_node(addon, "pending"), "Pending message should be visible");
+ is(get_node(addon, "pending").textContent, "Test add-on 7 will be disabled after you restart " + gApp + ".", "Pending message should be correct");
+
+ info("Undoing");
+ EventUtils.synthesizeMouseAtCenter(get_node(addon, "undo-btn"), {}, gManagerWindow);
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_visible(get_node(addon, "warning"), "Warning message should be hidden");
+ is(get_node(addon, "warning").textContent, "An important update is available for Test add-on 7.", "Warning message should be correct");
+ is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+ is(get_node(addon, "warning-link").value, "Update Now", "Warning link text should be correct");
+ is(get_node(addon, "warning-link").href, "http://example.com/addon7@tests.mozilla.org", "Warning link should be correct");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+});
+
+// Check the add-ons are now in the right state
+add_task(function*() {
+ let [a1, a2, a4] = yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
+ "addon2@tests.mozilla.org",
+ "addon4@tests.mozilla.org"]);
+
+ is(a1.pendingOperations, 0, "Add-on 1 should not have any pending operations");
+ is(a2.pendingOperations, 0, "Add-on 1 should not have any pending operations");
+ is(a4.pendingOperations, 0, "Add-on 1 should not have any pending operations");
+});
+
+// Check that upgrades with onExternalInstall take effect immediately
+add_task(function*() {
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on replacement",
+ version: "2.0",
+ description: "A test add-on with a new description",
+ updateDate: gDate,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon14@tests.mozilla.org",
+ name: "Test add-on 14",
+ hidden: true,
+ }]);
+
+ let items = get_test_items();
+ is(Object.keys(items).length, EXPECTED_ADDONS, "Should be the right number of add-ons installed");
+
+ let addon = items["Test add-on replacement"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ let { name, version } = yield get_tooltip_info(addon);
+ is(get_node(addon, "name").value, "Test add-on replacement", "Name should be correct");
+ is(name, "Test add-on replacement", "Tooltip name should be correct");
+ is(version, "2.0", "Tooltip version should be correct");
+ is_element_visible(get_node(addon, "description"), "Description should be visible");
+ is(get_node(addon, "description").value, "A test add-on with a new description", "Description should be correct");
+ is_element_hidden(get_class_node(addon, "disabled-postfix"), "Disabled postfix should be hidden");
+ is_element_hidden(get_class_node(addon, "update-postfix"), "Update postfix should be hidden");
+ is(get_node(addon, "date-updated").value, formatDate(gDate), "Update date should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+ is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+});
+
+// Check that focus changes correctly move around the selected list item
+add_task(function*() {
+ function is_node_in_list(aNode) {
+ var list = gManagerWindow.document.getElementById("addon-list");
+
+ while (aNode && aNode != list)
+ aNode = aNode.parentNode;
+
+ if (aNode)
+ return true;
+ return false;
+ }
+
+ // Ignore the OSX full keyboard access setting
+ Services.prefs.setBoolPref("accessibility.tabfocus_applies_to_xul", false);
+
+ let items = get_test_items();
+
+ var fm = Cc["@mozilla.org/focus-manager;1"].
+ getService(Ci.nsIFocusManager);
+
+ let addon = items["Test add-on 6"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ EventUtils.synthesizeMouseAtCenter(addon, { }, gManagerWindow);
+ is(fm.focusedElement, addon.parentNode, "Focus should have moved to the list");
+
+ EventUtils.synthesizeKey("VK_TAB", { }, gManagerWindow);
+ is(fm.focusedElement, get_node(addon, "details-btn"), "Focus should have moved to the more button");
+
+ EventUtils.synthesizeKey("VK_TAB", { }, gManagerWindow);
+ is(fm.focusedElement, get_node(addon, "disable-btn"), "Focus should have moved to the disable button");
+
+ EventUtils.synthesizeKey("VK_TAB", { }, gManagerWindow);
+ is(fm.focusedElement, get_node(addon, "remove-btn"), "Focus should have moved to the remove button");
+
+ EventUtils.synthesizeKey("VK_TAB", { }, gManagerWindow);
+ ok(!is_node_in_list(fm.focusedElement), "Focus should be outside the list");
+
+ EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, gManagerWindow);
+ is(fm.focusedElement, get_node(addon, "remove-btn"), "Focus should have moved to the remove button");
+
+ EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, gManagerWindow);
+ is(fm.focusedElement, get_node(addon, "details-btn"), "Focus should have moved to the more button");
+
+ EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, gManagerWindow);
+ is(fm.focusedElement, addon.parentNode, "Focus should have moved to the list");
+
+ EventUtils.synthesizeKey("VK_TAB", { shiftKey: true }, gManagerWindow);
+ ok(!is_node_in_list(fm.focusedElement), "Focus should be outside the list");
+
+ try {
+ Services.prefs.clearUserPref("accessibility.tabfocus_applies_to_xul");
+ }
+ catch (e) { }
+});
+
+
+add_task(function*() {
+ info("Enabling lightweight theme");
+ LightweightThemeManager.currentTheme = gLWTheme;
+
+ gManagerWindow.loadView("addons://list/theme");
+ yield new Promise(resolve => wait_for_view_load(gManagerWindow, resolve));
+
+ var addon = get_addon_element(gManagerWindow, "4@personas.mozilla.org");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ info("Disabling lightweight theme");
+ LightweightThemeManager.currentTheme = null;
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_visible(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ let [aAddon] = yield promiseAddonsByIDs(["4@personas.mozilla.org"]);
+ aAddon.uninstall();
+});
+
+// Check that onPropertyChanges for appDisabled updates the UI
+add_task(function*() {
+ info("Checking that onPropertyChanges for appDisabled updates the UI");
+
+ let [aAddon] = yield promiseAddonsByIDs(["addon2@tests.mozilla.org"]);
+ aAddon.userDisabled = true;
+ aAddon.isCompatible = true;
+ aAddon.appDisabled = false;
+
+ gManagerWindow.loadView("addons://list/extension");
+ yield new Promise(resolve => wait_for_view_load(gManagerWindow, resolve));
+ var el = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+
+ is(el.getAttribute("active"), "false", "Addon should not be marked as active");
+ is_element_hidden(get_node(el, "warning"), "Warning message should not be visible");
+
+ info("Making addon incompatible and appDisabled");
+ aAddon.isCompatible = false;
+ aAddon.appDisabled = true;
+
+ is(el.getAttribute("active"), "false", "Addon should not be marked as active");
+ is_element_visible(get_node(el, "warning"), "Warning message should be visible");
+ is(get_node(el, "warning").textContent, "Test add-on 2 is incompatible with " + gApp + " " + gVersion + ".", "Warning message should be correct");
+});
+
+// Check that the list displays correctly when signing is required
+add_task(function*() {
+ yield close_manager(gManagerWindow);
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+ gManagerWindow = yield open_manager(null);
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ yield gCategoryUtilities.openType("extension");
+ let items = get_test_items();
+ is(Object.keys(items).length, EXPECTED_ADDONS, "Should be the right number of add-ons installed");
+
+ info("Addon 10");
+ let addon = items["Test add-on 10"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ let { name, version } = yield get_tooltip_info(addon);
+ is(get_node(addon, "name").value, "Test add-on 10", "Name should be correct");
+ is(name, "Test add-on 10", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_visible(get_node(addon, "error"), "Error message should be visible");
+ is(get_node(addon, "error").textContent, "Test add-on 10 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+ is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+ is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
+ is(get_node(addon, "error-link").href, infoURL, "Error link should be correct");
+
+ info("Addon 11");
+ addon = items["Test add-on 11"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 11", "Name should be correct");
+ is(name, "Test add-on 11", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_visible(get_node(addon, "error"), "Error message should be visible");
+ is(get_node(addon, "error").textContent, "Test add-on 11 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+ is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+ is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
+ is(get_node(addon, "error-link").href, infoURL, "Error link should be correct");
+
+ info("Addon 12");
+ addon = items["Test add-on 12"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon))
+ is(get_node(addon, "name").value, "Test add-on 12", "Name should be correct");
+ is(name, "Test add-on 12", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+ is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+
+ info("Addon 13");
+ addon = items["Test add-on 13"];
+ addon.parentNode.ensureElementIsVisible(addon);
+ ({ name, version } = yield get_tooltip_info(addon));
+ is(get_node(addon, "name").value, "Test add-on 13", "Name should be correct");
+ is(name, "Test add-on 13", "Tooltip name should be correct");
+
+ is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+ is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+ is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+ is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+ is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+ is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+ is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+
+ info("Filter for disabled unsigned extensions");
+ let filterButton = gManagerWindow.document.getElementById("show-disabled-unsigned-extensions");
+ let showAllButton = gManagerWindow.document.getElementById("show-all-extensions");
+ let signingInfoUI = gManagerWindow.document.getElementById("disabled-unsigned-addons-info");
+ is_element_visible(filterButton, "Button for showing disabled unsigned extensions should be visible");
+ is_element_hidden(showAllButton, "Button for showing all extensions should be hidden");
+ is_element_hidden(signingInfoUI, "Signing info UI should be hidden");
+
+ filterButton.click();
+
+ yield new Promise(resolve => wait_for_view_load(gManagerWindow, resolve));
+
+ is_element_hidden(filterButton, "Button for showing disabled unsigned extensions should be hidden");
+ is_element_visible(showAllButton, "Button for showing all extensions should be visible");
+ is_element_visible(signingInfoUI, "Signing info UI should be visible");
+
+ items = get_test_items();
+ is(Object.keys(items).length, 2, "Two add-ons should be shown");
+ is(Object.keys(items)[0], "Test add-on 10", "The disabled unsigned extension should be shown");
+ is(Object.keys(items)[1], "Test add-on 11", "The disabled unsigned extension should be shown");
+
+ showAllButton.click();
+
+ yield new Promise(resolve => wait_for_view_load(gManagerWindow, resolve));
+
+ items = get_test_items();
+ is(Object.keys(items).length, EXPECTED_ADDONS, "All add-ons should be shown again");
+ is_element_visible(filterButton, "Button for showing disabled unsigned extensions should be visible again");
+ is_element_hidden(showAllButton, "Button for showing all extensions should be hidden again");
+ is_element_hidden(signingInfoUI, "Signing info UI should be hidden again");
+
+ Services.prefs.setBoolPref("xpinstall.signatures.required", false);
+});
+
+add_task(function*() {
+ return close_manager(gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_manualupdates.js b/toolkit/mozapps/webextensions/test/browser/browser_manualupdates.js
new file mode 100644
index 000000000..0c5eb2da6
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_manualupdates.js
@@ -0,0 +1,246 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests manual updates, including the Available Updates pane
+
+var gProvider;
+var gManagerWindow;
+var gCategoryUtilities;
+var gAvailableCategory;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "auto updating addon",
+ version: "1.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_ENABLE
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+
+add_test(function() {
+ gAvailableCategory = gManagerWindow.gCategories.get("addons://updates/available");
+ is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should initially be hidden");
+
+ gProvider.createAddons([{
+ id: "addon2@tests.mozilla.org",
+ name: "manually updating addon",
+ version: "1.0",
+ isCompatible: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }]);
+
+ is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should still be hidden");
+
+ run_next_test();
+});
+
+
+add_test(function() {
+ let finished = 0;
+ function maybeRunNext() {
+ if (++finished == 2)
+ run_next_test();
+ }
+
+ gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
+ gAvailableCategory.removeEventListener("CategoryBadgeUpdated", arguments.callee, false);
+ is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should now be visible");
+ is(gAvailableCategory.badgeCount, 1, "Badge for Available Updates should now be 1");
+ maybeRunNext();
+ }, false);
+
+ gCategoryUtilities.openType("extension", function() {
+ gProvider.createInstalls([{
+ name: "manually updating addon (new and improved!)",
+ existingAddon: gProvider.addons[1],
+ version: "1.1",
+ releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml", null, null)
+ }]);
+
+ var item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+ get_tooltip_info(item).then(({ version }) => {
+ is(version, "1.0", "Should still show the old version in the tooltip");
+ maybeRunNext();
+ });
+ });
+});
+
+
+add_test(function() {
+ wait_for_view_load(gManagerWindow, function() {
+ is(gManagerWindow.document.getElementById("categories").selectedItem.value, "addons://updates/available", "Available Updates category should now be selected");
+ is(gManagerWindow.gViewController.currentViewId, "addons://updates/available", "Available Updates view should be the current view");
+ run_next_test();
+ }, true);
+ EventUtils.synthesizeMouseAtCenter(gAvailableCategory, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("updates-list");
+ is(list.itemCount, 1, "Should be 1 available update listed");
+ var item = list.firstChild;
+ is(item.mAddon.id, "addon2@tests.mozilla.org", "Update item should be for the manually updating addon");
+
+ // The item in the list will be checking for update information asynchronously
+ // so we have to wait for it to complete. Doing the same async request should
+ // make our callback be called later.
+ AddonManager.getAllInstalls(run_next_test);
+});
+
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("updates-list");
+ var item = list.firstChild;
+ get_tooltip_info(item).then(({ version }) => {
+ is(version, "1.1", "Update item should have version number of the update");
+ var postfix = gManagerWindow.document.getAnonymousElementByAttribute(item, "class", "update-postfix");
+ is_element_visible(postfix, "'Update' postfix should be visible");
+ is_element_visible(item._updateAvailable, "");
+ is_element_visible(item._relNotesToggle, "Release notes toggle should be visible");
+ is_element_hidden(item._warning, "Incompatible warning should be hidden");
+ is_element_hidden(item._error, "Blocklist error should be hidden");
+
+ info("Opening release notes");
+ item.addEventListener("RelNotesToggle", function() {
+ item.removeEventListener("RelNotesToggle", arguments.callee, false);
+ info("Release notes now open");
+
+ is_element_hidden(item._relNotesLoading, "Release notes loading message should be hidden");
+ is_element_visible(item._relNotesError, "Release notes error message should be visible");
+ is(item._relNotes.childElementCount, 0, "Release notes should be empty");
+
+ info("Closing release notes");
+ item.addEventListener("RelNotesToggle", function() {
+ item.removeEventListener("RelNotesToggle", arguments.callee, false);
+ info("Release notes now closed");
+ info("Setting Release notes URI to something that should load");
+ gProvider.installs[0].releaseNotesURI = Services.io.newURI(TESTROOT + "releaseNotes.xhtml", null, null)
+
+ info("Re-opening release notes");
+ item.addEventListener("RelNotesToggle", function() {
+ item.removeEventListener("RelNotesToggle", arguments.callee, false);
+ info("Release notes now open");
+
+ is_element_hidden(item._relNotesLoading, "Release notes loading message should be hidden");
+ is_element_hidden(item._relNotesError, "Release notes error message should be hidden");
+ isnot(item._relNotes.childElementCount, 0, "Release notes should have been inserted into container");
+ run_next_test();
+
+ }, false);
+ EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
+ is_element_visible(item._relNotesLoading, "Release notes loading message should be visible");
+
+ }, false);
+ EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
+
+ }, false);
+ EventUtils.synthesizeMouseAtCenter(item._relNotesToggle, { }, gManagerWindow);
+ is_element_visible(item._relNotesLoading, "Release notes loading message should be visible");
+ });
+});
+
+
+add_test(function() {
+ var badgeUpdated = false;
+ var installCompleted = false;
+
+ gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
+ gAvailableCategory.removeEventListener("CategoryBadgeUpdated", arguments.callee, false);
+ if (installCompleted)
+ run_next_test();
+ else
+ badgeUpdated = true;
+ }, false);
+
+ var list = gManagerWindow.document.getElementById("updates-list");
+ var item = list.firstChild;
+ var updateBtn = item._updateBtn;
+ is_element_visible(updateBtn, "Update button should be visible");
+
+ var install = gProvider.installs[0];
+ var listener = {
+ onInstallStarted: function() {
+ info("Install started");
+ is_element_visible(item._installStatus, "Install progress widget should be visible");
+ },
+ onInstallEnded: function() {
+ install.removeTestListener(this);
+ info("Install ended");
+ is_element_hidden(item._installStatus, "Install progress widget should be hidden");
+
+ if (badgeUpdated)
+ run_next_test();
+ else
+ installCompleted = true;
+ }
+ };
+ install.addTestListener(listener);
+ EventUtils.synthesizeMouseAtCenter(updateBtn, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should still be visible");
+ is(gAvailableCategory.badgeCount, 0, "Badge for Available Updates should now be 0");
+
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should be hidden");
+
+ close_manager(gManagerWindow, function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ gAvailableCategory = gManagerWindow.gCategories.get("addons://updates/available");
+
+ is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should be hidden");
+
+ run_next_test();
+ });
+ });
+ });
+});
+
+add_test(function() {
+ gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
+ gAvailableCategory.removeEventListener("CategoryBadgeUpdated", arguments.callee, false);
+ is(gCategoryUtilities.isVisible(gAvailableCategory), true, "Available Updates category should now be visible");
+ is(gAvailableCategory.badgeCount, 1, "Badge for Available Updates should now be 1");
+
+ gAvailableCategory.addEventListener("CategoryBadgeUpdated", function() {
+ gAvailableCategory.removeEventListener("CategoryBadgeUpdated", arguments.callee, false);
+ is(gCategoryUtilities.isVisible(gAvailableCategory), false, "Available Updates category should now be hidden");
+
+ run_next_test();
+ }, false);
+
+ AddonManager.getAddonByID("addon2@tests.mozilla.org", function(aAddon) {
+ aAddon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE;
+ });
+ }, false);
+
+ gProvider.createInstalls([{
+ name: "manually updating addon (new and even more improved!)",
+ existingAddon: gProvider.addons[1],
+ version: "1.2",
+ releaseNotesURI: Services.io.newURI(TESTROOT + "thereIsNoFileHere.xhtml", null, null)
+ }]);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_metadataTimeout.js b/toolkit/mozapps/webextensions/test/browser/browser_metadataTimeout.js
new file mode 100644
index 000000000..98be4b7f8
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_metadataTimeout.js
@@ -0,0 +1,114 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test how update window behaves when metadata ping times out
+// bug 965788
+
+const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul";
+
+const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
+const PREF_MIN_PLATFORM_COMPAT = "extensions.minCompatiblePlatformVersion";
+const PREF_METADATA_LASTUPDATE = "extensions.getAddons.cache.lastUpdate";
+
+Components.utils.import("resource://gre/modules/Promise.jsm");
+
+var repo = {};
+var ARContext = Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", repo);
+
+// Mock out the XMLHttpRequest factory for AddonRepository so
+// we can reply with a timeout
+var pXHRStarted = Promise.defer();
+var oldXHRConstructor = ARContext.ServiceRequest;
+ARContext.ServiceRequest = function() {
+ this._handlers = new Map();
+ this.mozBackgroundRequest = false;
+ this.timeout = undefined;
+ this.open = function(aMethod, aURI, aAsync) {
+ this.method = aMethod;
+ this.uri = aURI;
+ this.async = aAsync;
+ info("Opened XHR for " + aMethod + " " + aURI);
+ };
+ this.overrideMimeType = function(aMimeType) {
+ this.mimeType = aMimeType;
+ };
+ this.addEventListener = function(aEvent, aHandler, aCapture) {
+ this._handlers.set(aEvent, aHandler);
+ };
+ this.send = function(aBody) {
+ info("Send XHR for " + this.method + " " + this.uri + " handlers: " + [this._handlers.keys()].join(", "));
+ pXHRStarted.resolve(this);
+ }
+};
+
+
+// Returns promise{window}, resolves with a handle to the compatibility
+// check window
+function promise_open_compatibility_window(aInactiveAddonIds) {
+ let deferred = Promise.defer();
+ // This will reset the longer timeout multiplier to 2 which will give each
+ // test that calls open_compatibility_window a minimum of 60 seconds to
+ // complete.
+ requestLongerTimeout(2);
+
+ var variant = Cc["@mozilla.org/variant;1"].
+ createInstance(Ci.nsIWritableVariant);
+ variant.setFromVariant(aInactiveAddonIds);
+
+ // Cannot be modal as we want to interract with it, shouldn't cause problems
+ // with testing though.
+ var features = "chrome,centerscreen,dialog,titlebar";
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
+ getService(Ci.nsIWindowWatcher);
+ var win = ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
+
+ win.addEventListener("load", function() {
+ function page_shown(aEvent) {
+ if (aEvent.target.pageid)
+ info("Page " + aEvent.target.pageid + " shown");
+ }
+
+ win.removeEventListener("load", arguments.callee, false);
+
+ info("Compatibility dialog opened");
+
+ win.addEventListener("pageshow", page_shown, false);
+ win.addEventListener("unload", function() {
+ win.removeEventListener("unload", arguments.callee, false);
+ win.removeEventListener("pageshow", page_shown, false);
+ dump("Compatibility dialog closed\n");
+ }, false);
+
+ deferred.resolve(win);
+ }, false);
+ return deferred.promise;
+}
+
+function promise_window_close(aWindow) {
+ let deferred = Promise.defer();
+ aWindow.addEventListener("unload", function() {
+ aWindow.removeEventListener("unload", arguments.callee, false);
+ deferred.resolve(aWindow);
+ }, false);
+ return deferred.promise;
+}
+
+// Start the compatibility update dialog, but use the mock XHR to respond with
+// a timeout
+add_task(function* amo_ping_timeout() {
+ Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
+ Services.prefs.clearUserPref(PREF_METADATA_LASTUPDATE);
+ let compatWindow = yield promise_open_compatibility_window([]);
+
+ let xhr = yield pXHRStarted.promise;
+ is(xhr.timeout, 30000, "XHR request should have 30 second timeout");
+ ok(xhr._handlers.has("timeout"), "Timeout handler set on XHR");
+ // call back the timeout handler
+ xhr._handlers.get("timeout")();
+
+ // Put the old XHR constructor back
+ ARContext.ServiceRequest = oldXHRConstructor;
+ // The window should close without further interaction
+ yield promise_window_close(compatWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_newaddon.js b/toolkit/mozapps/webextensions/test/browser/browser_newaddon.js
new file mode 100644
index 000000000..d450828ba
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_newaddon.js
@@ -0,0 +1,232 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests the new add-on tab
+
+var gProvider;
+
+function loadPage(aURL, aCallback, aBackground = false) {
+ let tab = gBrowser.addTab();
+ if (!aBackground)
+ gBrowser.selectedTab = tab;
+ let browser = tab.linkedBrowser;
+ browser.loadURI(aURL);
+ browser.addEventListener("AddonDisplayed", function(event) {
+ browser.removeEventListener("AddonDisplayed", arguments.callee, false);
+
+ aCallback(tab);
+ });
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test 1",
+ version: "5.3",
+ userDisabled: true,
+ seen: false,
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "Test 2",
+ version: "7.1",
+ creator: "Dave Townsend",
+ userDisabled: true,
+ seen: false
+ }]);
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+// Tests that ignoring a restartless add-on works
+add_test(function() {
+ loadPage("about:newaddon?id=addon1@tests.mozilla.org", function(aTab) {
+ var doc = aTab.linkedBrowser.contentDocument;
+ is(doc.getElementById("name").value, "Test 1 5.3", "Should say the right name");
+
+ is_element_hidden(doc.getElementById("author"), "Should be no author displayed");
+ is_element_hidden(doc.getElementById("location"), "Should be no location displayed");
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ AddonManager.getAddonByID("addon1@tests.mozilla.org", function(aAddon) {
+ ok(aAddon.seen, "Add-on should have been marked as seen");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("continue-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ is(gBrowser.tabs.length, 1, "Page should have been closed");
+
+ ok(aAddon.userDisabled, "Add-on should not have been enabled");
+
+ ok(!aAddon.isActive, "Add-on should not be running");
+
+ aAddon.seen = false;
+ run_next_test();
+ });
+ });
+});
+
+// Tests that enabling a restartless add-on works
+add_test(function() {
+ loadPage("about:newaddon?id=addon1@tests.mozilla.org", function(aTab) {
+ var doc = aTab.linkedBrowser.contentDocument;
+ is(doc.getElementById("name").value, "Test 1 5.3", "Should say the right name");
+
+ is_element_hidden(doc.getElementById("author"), "Should be no author displayed");
+ is_element_hidden(doc.getElementById("location"), "Should be no location displayed");
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ AddonManager.getAddonByID("addon1@tests.mozilla.org", function(aAddon) {
+ ok(aAddon.seen, "Add-on should have been marked as seen");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("allow"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("continue-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ is(gBrowser.tabs.length, 1, "Page should have been closed");
+
+ ok(!aAddon.userDisabled, "Add-on should now have been enabled");
+
+ ok(aAddon.isActive, "Add-on should now be running");
+
+ aAddon.userDisabled = true;
+ aAddon.seen = false;
+ run_next_test();
+ });
+ });
+});
+
+// Tests that ignoring a non-restartless add-on works
+add_test(function() {
+ loadPage("about:newaddon?id=addon2@tests.mozilla.org", function(aTab) {
+ var doc = aTab.linkedBrowser.contentDocument;
+ is(doc.getElementById("name").value, "Test 2 7.1", "Should say the right name");
+
+ is_element_visible(doc.getElementById("author"), "Should be an author displayed");
+ is(doc.getElementById("author").value, "By Dave Townsend", "Should have the right author");
+ is_element_hidden(doc.getElementById("location"), "Should be no location displayed");
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ AddonManager.getAddonByID("addon2@tests.mozilla.org", function(aAddon) {
+ ok(aAddon.seen, "Add-on should have been marked as seen");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("continue-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ is(gBrowser.tabs.length, 1, "Page should have been closed");
+
+ ok(aAddon.userDisabled, "Add-on should not have been enabled");
+
+ ok(!aAddon.isActive, "Add-on should not be running");
+
+ aAddon.seen = false;
+ run_next_test();
+ });
+ });
+});
+
+// Tests that enabling a non-restartless add-on works
+add_test(function() {
+ loadPage("about:newaddon?id=addon2@tests.mozilla.org", function(aTab) {
+ var doc = aTab.linkedBrowser.contentDocument;
+ is(doc.getElementById("name").value, "Test 2 7.1", "Should say the right name");
+
+ is_element_visible(doc.getElementById("author"), "Should be an author displayed");
+ is(doc.getElementById("author").value, "By Dave Townsend", "Should have the right author");
+ is_element_hidden(doc.getElementById("location"), "Should be no location displayed");
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ AddonManager.getAddonByID("addon2@tests.mozilla.org", function(aAddon) {
+ ok(aAddon.seen, "Add-on should have been marked as seen");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("allow"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("continue-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("restartPanel"),
+ "Should be showing the right buttons");
+
+ ok(!aAddon.userDisabled, "Add-on should now have been enabled");
+
+ ok(!aAddon.isActive, "Add-on should not be running");
+
+ ok(doc.getElementById("allow").disabled, "Should have disabled checkbox");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("cancel-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ ok(!doc.getElementById("allow").disabled, "Should have enabled checkbox");
+
+ ok(aAddon.userDisabled, "Add-on should not have been enabled");
+
+ ok(!aAddon.isActive, "Add-on should not be running");
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("allow"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ EventUtils.synthesizeMouseAtCenter(doc.getElementById("continue-button"),
+ {}, aTab.linkedBrowser.contentWindow);
+
+ ok(aAddon.userDisabled, "Add-on should not have been enabled");
+
+ ok(!aAddon.isActive, "Add-on should not be running");
+
+ is(gBrowser.tabs.length, 1, "Page should have been closed");
+
+ aAddon.seen = false;
+ run_next_test();
+ });
+ });
+});
+
+// Tests that opening the page in the background doesn't mark as seen
+add_test(function() {
+ loadPage("about:newaddon?id=addon1@tests.mozilla.org", function(aTab) {
+ var doc = aTab.linkedBrowser.contentDocument;
+ is(doc.getElementById("name").value, "Test 1 5.3", "Should say the right name");
+
+ is_element_hidden(doc.getElementById("author"), "Should be no author displayed");
+ is_element_hidden(doc.getElementById("location"), "Should be no location displayed");
+
+ is(doc.getElementById("buttonDeck").selectedPanel, doc.getElementById("continuePanel"),
+ "Should be showing the right buttons");
+
+ AddonManager.getAddonByID("addon1@tests.mozilla.org", function(aAddon) {
+ ok(!aAddon.seen, "Add-on should not have been marked as seen.");
+
+ gBrowser.selectedTab = aTab;
+
+ waitForFocus(function() {
+ ok(aAddon.seen, "Add-on should have been marked as seen after focusing the tab.");
+
+ gBrowser.removeTab(aTab);
+
+ run_next_test();
+ }, aTab.linkedBrowser.contentWindow);
+ });
+ }, true);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_openDialog.js b/toolkit/mozapps/webextensions/test/browser/browser_openDialog.js
new file mode 100644
index 000000000..f95365a4c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_openDialog.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests the dialog open by the Options button for addons that provide a
+// custom chrome-like protocol for optionsURL.
+
+var CustomChromeProtocol = {
+ scheme: "khrome",
+ defaultPort: -1,
+ protocolFlags: Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
+ Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
+ Ci.nsIProtocolHandler.URI_NORELATIVE |
+ Ci.nsIProtocolHandler.URI_NOAUTH,
+
+ newURI: function CCP_newURI(aSpec, aOriginCharset, aBaseUri) {
+ let uri = Cc["@mozilla.org/network/simple-uri;1"].
+ createInstance(Ci.nsIURI);
+ uri.spec = aSpec;
+ return uri;
+ },
+
+ newChannel2: function CCP_newChannel2(aURI, aLoadInfo) {
+ let url = Services.io.newURI("chrome:" + aURI.path, null, null);
+ let ch = Services.io.newChannelFromURIWithLoadInfo(url, aLoadInfo);
+ ch.originalURI = aURI;
+ return ch;
+ },
+
+ newChannel: function CCP_newChannel(aURI) {
+ return this.newChannel2(aURI, null);
+ },
+
+ allowPort: function CCP_allowPort(aPort, aScheme) {
+ return false;
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIProtocolHandler
+ ]),
+
+ classID: Components.ID("{399cb2d1-05dd-4363-896f-63b78e008cf8}"),
+
+ factory: {
+ registrar: Components.manager.QueryInterface(Ci.nsIComponentRegistrar),
+
+ register: function CCP_register() {
+ this.registrar.registerFactory(
+ CustomChromeProtocol.classID,
+ "CustomChromeProtocol",
+ "@mozilla.org/network/protocol;1?name=khrome",
+ this
+ );
+ },
+
+ unregister: function CCP_register() {
+ this.registrar.unregisterFactory(CustomChromeProtocol.classID, this);
+ },
+
+ // nsIFactory
+ createInstance: function BNPH_createInstance(aOuter, aIID) {
+ if (aOuter) {
+ throw Components.Exception("Class does not allow aggregation",
+ Components.results.NS_ERROR_NO_AGGREGATION);
+ }
+ return CustomChromeProtocol.QueryInterface(aIID);
+ },
+
+ lockFactory: function BNPH_lockFactory(aLock) {
+ throw Components.Exception("Function lockFactory is not implemented",
+ Components.results.NS_ERROR_NOT_IMPLEMENTED);
+ },
+
+ QueryInterface: XPCOMUtils.generateQI([
+ Ci.nsIFactory
+ ])
+ }
+}
+
+function test() {
+ waitForExplicitFinish();
+ requestLongerTimeout(2);
+
+ info("Registering custom chrome-like protocol.");
+ CustomChromeProtocol.factory.register();
+ registerCleanupFunction(() => CustomChromeProtocol.factory.unregister());
+
+ const ADDONS_LIST = [
+ { id: "test1@tests.mozilla.org",
+ name: "Test add-on 1",
+ optionsURL: CHROMEROOT + "addon_prefs.xul" },
+ { id: "test2@tests.mozilla.org",
+ name: "Test add-on 2",
+ optionsURL: (CHROMEROOT + "addon_prefs.xul").replace("chrome:", "khrome:") },
+ ];
+
+ var gProvider = new MockProvider();
+ gProvider.createAddons(ADDONS_LIST);
+
+ open_manager("addons://list/extension", function(aManager) {
+ let addonList = aManager.document.getElementById("addon-list");
+ let currentAddon;
+ let instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply");
+
+ function getAddonByName(aName) {
+ for (let addonItem of addonList.childNodes) {
+ if (addonItem.hasAttribute("name") &&
+ addonItem.getAttribute("name") == aName)
+ return addonItem;
+ }
+ return null;
+ }
+
+ function observer(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case "domwindowclosed":
+ // Give the preference window a chance to finish closing before
+ // closing the add-ons manager.
+ waitForFocus(function () {
+ test_next_addon();
+ });
+ break;
+ case "domwindowopened":
+ let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
+ waitForFocus(function () {
+ // If the openDialog privileges are wrong a new browser window
+ // will open, let the test proceed (and fail) rather than timeout.
+ if (win.location != currentAddon.optionsURL &&
+ win.location != "chrome://browser/content/browser.xul")
+ return;
+
+ is(win.location, currentAddon.optionsURL,
+ "The correct addon pref window should have opened");
+
+ let chromeFlags = win.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIWebNavigation).
+ QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
+ QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIXULWindow).chromeFlags;
+ ok(chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME &&
+ (instantApply || chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG),
+ "Window was open as a chrome dialog.");
+
+ win.close();
+ }, win);
+ break;
+ }
+ }
+
+ function test_next_addon() {
+ currentAddon = ADDONS_LIST.shift();
+ if (!currentAddon) {
+ Services.ww.unregisterNotification(observer);
+ close_manager(aManager, finish);
+ return;
+ }
+
+ info("Testing " + currentAddon.name);
+ let addonItem = getAddonByName(currentAddon.name, addonList);
+ let optionsBtn =
+ aManager.document.getAnonymousElementByAttribute(addonItem, "anonid",
+ "preferences-btn");
+ is(optionsBtn.hidden, false, "Prefs button should be visible.")
+
+ addonList.ensureElementIsVisible(addonItem);
+ EventUtils.synthesizeMouseAtCenter(optionsBtn, { }, aManager);
+ }
+
+ Services.ww.registerNotification(observer);
+ test_next_addon();
+ });
+
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_plugin_enabled_state_locked.js b/toolkit/mozapps/webextensions/test/browser/browser_plugin_enabled_state_locked.js
new file mode 100644
index 000000000..a9c7be4bc
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_plugin_enabled_state_locked.js
@@ -0,0 +1,124 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that state menu is displayed correctly (enabled or disabled) in the add-on manager
+// when the preference is unlocked / locked
+var {classes: Cc, interfaces: Ci} = Components;
+const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
+const gIsOSX = ("nsILocalFileMac" in Ci);
+const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
+ ("@mozilla.org/gio-service;1" in Cc);
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gPluginElement;
+
+function getTestPluginPref() {
+ let prefix = "plugin.state.";
+ if (gIsWindows)
+ return `${prefix}nptest`;
+ if (gIsLinux)
+ return `${prefix}libnptest`;
+ return `${prefix}test`;
+}
+
+registerCleanupFunction(() => {
+ Services.prefs.unlockPref(getTestPluginPref());
+ Services.prefs.clearUserPref(getTestPluginPref());
+});
+
+function getPlugins() {
+ return new Promise(resolve => {
+ AddonManager.getAddonsByTypes(["plugin"], plugins => resolve(plugins));
+ });
+}
+
+function getTestPlugin(aPlugins) {
+ let testPluginId;
+
+ for (let plugin of aPlugins) {
+ if (plugin.name == "Test Plug-in") {
+ testPluginId = plugin.id;
+ break;
+ }
+ }
+
+ Assert.ok(testPluginId, "Test Plug-in should exist");
+
+ let pluginElement = get_addon_element(gManagerWindow, testPluginId);
+ pluginElement.parentNode.ensureElementIsVisible(pluginElement);
+
+ return pluginElement;
+}
+
+function checkStateMenu(locked) {
+ Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+ "Preference lock state should be correct.");
+ let menuList = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "state-menulist");
+ // State menu should always have a selected item which must be visible
+ let selectedMenuItem = menuList.querySelector(".addon-control[selected=\"true\"]");
+
+ is_element_visible(menuList, "State menu should be visible.");
+ Assert.equal(menuList.disabled, locked,
+ "State menu should" + (locked === true ? "" : " not") + " be disabled.");
+
+ is_element_visible(selectedMenuItem, "State menu's selected item should be visible.");
+}
+
+function checkStateMenuDetail(locked) {
+ Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+ "Preference should be " + (locked === true ? "" : "un") + "locked.");
+
+ // open details menu
+ let details = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "details-btn");
+ is_element_visible(details, "Details link should be visible.");
+ EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
+
+ return new Promise(resolve => {
+ wait_for_view_load(gManagerWindow, function() {
+ let menuList = gManagerWindow.document.getElementById("detail-state-menulist");
+ is_element_visible(menuList, "Details state menu should be visible.");
+ Assert.equal(menuList.disabled, locked,
+ "Details state menu enabled state should be correct.");
+ resolve();
+ });
+ });
+}
+
+add_task(function* initializeState() {
+ Services.prefs.setIntPref(getTestPluginPref(), Ci.nsIPluginTag.STATE_ENABLED);
+ Services.prefs.unlockPref(getTestPluginPref());
+ gManagerWindow = yield open_manager();
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ yield gCategoryUtilities.openType("plugin");
+
+ let plugins = yield getPlugins();
+ gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is enabled if the preference is unlocked
+add_task(function* taskCheckStateMenuIsEnabled() {
+ checkStateMenu(false);
+ yield checkStateMenuDetail(false);
+});
+
+// Lock the preference and then reload the plugin category
+add_task(function* reinitializeState() {
+ // lock the preference
+ Services.prefs.lockPref(getTestPluginPref());
+ yield gCategoryUtilities.openType("plugin");
+ // Retrieve the test plugin element
+ let plugins = yield getPlugins();
+ gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is disabled if the preference is locked
+add_task(function* taskCheckStateMenuIsDisabled() {
+ checkStateMenu(true);
+ yield checkStateMenuDetail(true);
+});
+
+add_task(function* testCleanup() {
+ yield close_manager(gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_pluginprefs.js b/toolkit/mozapps/webextensions/test/browser/browser_pluginprefs.js
new file mode 100644
index 000000000..458e8e334
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_pluginprefs.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests the detail view of plugins
+
+var gManagerWindow;
+
+function test() {
+ waitForExplicitFinish();
+
+ open_manager("addons://list/plugin", function(aWindow) {
+ gManagerWindow = aWindow;
+
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+add_test(function() {
+ AddonManager.getAddonsByTypes(["plugin"], function(plugins) {
+ let testPluginId;
+ for (let plugin of plugins) {
+ if (plugin.name == "Test Plug-in") {
+ testPluginId = plugin.id;
+ break;
+ }
+ }
+ ok(testPluginId, "Test Plug-in should exist")
+
+ AddonManager.getAddonByID(testPluginId, function(testPlugin) {
+ let pluginEl = get_addon_element(gManagerWindow, testPluginId);
+ is(pluginEl.mAddon.optionsType, AddonManager.OPTIONS_TYPE_INLINE_INFO, "Options should be inline info type");
+ pluginEl.parentNode.ensureElementIsVisible(pluginEl);
+
+ let button = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "preferences-btn");
+ is_element_hidden(button, "Preferences button should be hidden");
+
+ button = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ let pluginLibraries = gManagerWindow.document.getElementById("pluginLibraries");
+ ok(pluginLibraries, "Plugin file name row should be displayed");
+ // the file name depends on the platform
+ ok(pluginLibraries.textContent, testPlugin.pluginLibraries, "Plugin file name should be displayed");
+
+ let pluginMimeTypes = gManagerWindow.document.getElementById("pluginMimeTypes");
+ ok(pluginMimeTypes, "Plugin mime type row should be displayed");
+ ok(pluginMimeTypes.textContent, "application/x-test (tst)", "Plugin mime type should be displayed");
+
+ run_next_test();
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_purchase.js b/toolkit/mozapps/webextensions/test/browser/browser_purchase.js
new file mode 100644
index 000000000..a815d10d5
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_purchase.js
@@ -0,0 +1,197 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that marketplace results show up in searches, are sorted right and
+// attempting to buy links through to the right webpage
+
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const SEARCH_URL = TESTROOT + "browser_purchase.xml";
+
+var gManagerWindow;
+
+function test() {
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
+
+ waitForExplicitFinish();
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+
+ waitForFocus(function() {
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "foo";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var remoteFilter = gManagerWindow.document.getElementById("search-filter-remote");
+ EventUtils.synthesizeMouseAtCenter(remoteFilter, { }, gManagerWindow);
+
+ run_next_test();
+ });
+ }, aWindow);
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ // Will have created an install so cancel it
+ AddonManager.getAllInstalls(function(aInstalls) {
+ is(aInstalls.length, 1, "Should have been one install created");
+ aInstalls[0].cancel();
+
+ finish();
+ });
+ });
+}
+
+function get_node(parent, anonid) {
+ return parent.ownerDocument.getAnonymousElementByAttribute(parent, "anonid", anonid);
+}
+
+function get_install_btn(parent) {
+ var installStatus = get_node(parent, "install-status");
+ return get_node(installStatus, "install-remote-btn");
+}
+
+function get_purchase_btn(parent) {
+ var installStatus = get_node(parent, "install-status");
+ return get_node(installStatus, "purchase-remote-btn");
+}
+
+// Tests that the expected results appeared
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("search-list");
+ var items = Array.filter(list.childNodes, function(e) {
+ return e.tagName == "richlistitem";
+ });
+
+ is(items.length, 5, "Should be 5 results");
+
+ is(get_node(items[0], "name").value, "Ludicrously Expensive Add-on", "Add-on 0 should be in expected position");
+ is_element_hidden(get_install_btn(items[0]), "Add-on 0 install button should be hidden");
+ is_element_visible(get_purchase_btn(items[0]), "Add-on 0 purchase button should be visible");
+ is(get_purchase_btn(items[0]).label, "Purchase for $101\u2026", "Add-on 0 should have the right price");
+
+ is(get_node(items[1], "name").value, "Cheap Add-on", "Add-on 1 should be in expected position");
+ is_element_hidden(get_install_btn(items[1]), "Add-on 1 install button should be hidden");
+ is_element_visible(get_purchase_btn(items[1]), "Add-on 1 purchase button should be visible");
+ is(get_purchase_btn(items[1]).label, "Purchase for $0.99\u2026", "Add-on 2 should have the right price");
+
+ is(get_node(items[2], "name").value, "Reasonable Add-on", "Add-on 2 should be in expected position");
+ is_element_hidden(get_install_btn(items[2]), "Add-on 2 install button should be hidden");
+ is_element_visible(get_purchase_btn(items[2]), "Add-on 2 purchase button should be visible");
+ is(get_purchase_btn(items[2]).label, "Purchase for $1\u2026", "Add-on 3 should have the right price");
+
+ is(get_node(items[3], "name").value, "Free Add-on", "Add-on 3 should be in expected position");
+ is_element_visible(get_install_btn(items[3]), "Add-on 3 install button should be visible");
+ is_element_hidden(get_purchase_btn(items[3]), "Add-on 3 purchase button should be hidden");
+
+ is(get_node(items[4], "name").value, "More Expensive Add-on", "Add-on 4 should be in expected position");
+ is_element_hidden(get_install_btn(items[4]), "Add-on 4 install button should be hidden");
+ is_element_visible(get_purchase_btn(items[4]), "Add-on 4 purchase button should be visible");
+ is(get_purchase_btn(items[4]).label, "Purchase for $1.01\u2026", "Add-on 4 should have the right price");
+
+ run_next_test();
+});
+
+// Tests that sorting by price works
+add_test(function() {
+ var list = gManagerWindow.document.getElementById("search-list");
+
+ var sorters = gManagerWindow.document.getElementById("search-sorters");
+ var priceSorter = get_node(sorters, "price-btn");
+ info("Changing sort order");
+ EventUtils.synthesizeMouseAtCenter(priceSorter, { }, gManagerWindow);
+
+ var items = Array.filter(list.childNodes, function(e) {
+ return e.tagName == "richlistitem";
+ });
+
+ is(get_node(items[0], "name").value, "Free Add-on", "Add-on 0 should be in expected position");
+ is(get_node(items[1], "name").value, "Cheap Add-on", "Add-on 1 should be in expected position");
+ is(get_node(items[2], "name").value, "Reasonable Add-on", "Add-on 2 should be in expected position");
+ is(get_node(items[3], "name").value, "More Expensive Add-on", "Add-on 3 should be in expected position");
+ is(get_node(items[4], "name").value, "Ludicrously Expensive Add-on", "Add-on 4 should be in expected position");
+
+ info("Changing sort order");
+ EventUtils.synthesizeMouseAtCenter(priceSorter, { }, gManagerWindow);
+
+ items = Array.filter(list.childNodes, function(e) {
+ return e.tagName == "richlistitem";
+ });
+
+ is(get_node(items[0], "name").value, "Ludicrously Expensive Add-on", "Add-on 0 should be in expected position");
+ is(get_node(items[1], "name").value, "More Expensive Add-on", "Add-on 1 should be in expected position");
+ is(get_node(items[2], "name").value, "Reasonable Add-on", "Add-on 2 should be in expected position");
+ is(get_node(items[3], "name").value, "Cheap Add-on", "Add-on 3 should be in expected position");
+ is(get_node(items[4], "name").value, "Free Add-on", "Add-on 4 should be in expected position");
+
+ run_next_test();
+});
+
+// Tests that clicking the buy button works from the list
+add_test(function() {
+ gBrowser.tabContainer.addEventListener("TabOpen", function listener(event) {
+ gBrowser.tabContainer.removeEventListener("TabOpen", listener, true);
+ function wantLoad(url) {
+ return url != "about:blank";
+ }
+ BrowserTestUtils.browserLoaded(event.target.linkedBrowser, false, wantLoad).then(() => {
+ is(gBrowser.currentURI.spec, TESTROOT + "releaseNotes.xhtml?addon5", "Should have loaded the right page");
+
+ gBrowser.removeCurrentTab();
+
+ if (gUseInContentUI) {
+ is(gBrowser.currentURI.spec, "about:addons", "Should be back to the add-ons manager");
+ run_next_test();
+ }
+ else {
+ waitForFocus(run_next_test, gManagerWindow);
+ }
+ });
+ }, true);
+
+ var list = gManagerWindow.document.getElementById("search-list");
+ EventUtils.synthesizeMouseAtCenter(get_purchase_btn(list.firstChild), { }, gManagerWindow);
+});
+
+// Tests that clicking the buy button from the details view works
+add_test(function() {
+ gBrowser.tabContainer.addEventListener("TabOpen", function listener(event) {
+ gBrowser.tabContainer.removeEventListener("TabOpen", listener, true);
+ function wantLoad(url) {
+ return url != "about:blank";
+ }
+ BrowserTestUtils.browserLoaded(event.target.linkedBrowser, false, wantLoad).then(() => {
+ is(gBrowser.currentURI.spec, TESTROOT + "releaseNotes.xhtml?addon4", "Should have loaded the right page");
+
+ gBrowser.removeCurrentTab();
+
+ if (gUseInContentUI) {
+ is(gBrowser.currentURI.spec, "about:addons", "Should be back to the add-ons manager");
+ run_next_test();
+ }
+ else {
+ waitForFocus(run_next_test, gManagerWindow);
+ }
+ });
+ }, true);
+
+ var list = gManagerWindow.document.getElementById("search-list");
+ var item = list.firstChild.nextSibling;
+ list.ensureElementIsVisible(item);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ var btn = gManagerWindow.document.getElementById("detail-purchase-btn");
+ is_element_visible(btn, "Purchase button should be visible");
+
+ EventUtils.synthesizeMouseAtCenter(btn, { }, gManagerWindow);
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_purchase.xml b/toolkit/mozapps/webextensions/test/browser/browser_purchase.xml
new file mode 100644
index 000000000..9d4b18880
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_purchase.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="100">
+ <addon>
+ <name>Ludicrously Expensive Add-on</name>
+ <type id='1'>Extension</type>
+ <guid>addon5@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <all_compatible_os>
+ <os>ALL</os>
+ </all_compatible_os>
+ <payment_data>
+ <link>http://example.com/browser/toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml?addon5</link>
+ <amount amount="101">$101</amount>
+ </payment_data>
+ </addon>
+ <addon>
+ <name>Cheap Add-on</name>
+ <type id='1'>Extension</type>
+ <guid>addon2@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <all_compatible_os>
+ <os>ALL</os>
+ </all_compatible_os>
+ <payment_data>
+ <link>http://example.com/browser/toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml?addon2</link>
+ <amount amount="0.99">$0.99</amount>
+ </payment_data>
+ </addon>
+ <addon>
+ <name>Reasonable Add-on</name>
+ <type id='1'>Extension</type>
+ <guid>addon3@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <all_compatible_os>
+ <os>ALL</os>
+ </all_compatible_os>
+ <payment_data>
+ <link>http://example.com/browser/toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml?addon3</link>
+ <amount amount="1">$1</amount>
+ </payment_data>
+ </addon>
+ <addon>
+ <name>Free Add-on</name>
+ <type id='1'>Extension</type>
+ <guid>addon1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <all_compatible_os>
+ <os>ALL</os>
+ </all_compatible_os>
+ <install size="1">http://example.com/addon1.xpi</install>
+ </addon>
+ <addon>
+ <name>More Expensive Add-on</name>
+ <type id='1'>Extension</type>
+ <guid>addon4@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <all_compatible_os>
+ <os>ALL</os>
+ </all_compatible_os>
+ <payment_data>
+ <link>http://example.com/browser/toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml?addon4</link>
+ <amount amount="1.01">$1.01</amount>
+ </payment_data>
+ </addon>
+</searchresults>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_recentupdates.js b/toolkit/mozapps/webextensions/test/browser/browser_recentupdates.js
new file mode 100644
index 000000000..02007dbbf
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_recentupdates.js
@@ -0,0 +1,125 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests the recent updates pane
+
+var gProvider;
+var gManagerWindow;
+var gCategoryUtilities;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "updated 6 hours ago",
+ version: "1.0",
+ updateDate: new Date(Date.now() - (1000 * 60 * 60 * 6)),
+ releaseNotesURI: Services.io.newURI(TESTROOT + "releaseNotes.xhtml", null, null)
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "updated 5 seconds ago",
+ version: "1.0",
+ updateDate: new Date(Date.now() - (1000 * 5))
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "updated 1 month ago",
+ version: "1.0",
+ updateDate: new Date(Date.now() - (1000 * 60 * 60 * 25 * 30))
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+
+add_test(function() {
+ info("Checking menuitem for Recent Updates opens that pane");
+ var recentCat = gManagerWindow.gCategories.get("addons://updates/recent");
+ is(gCategoryUtilities.isVisible(recentCat), false, "Recent Updates category should initially be hidden");
+
+ var utilsBtn = gManagerWindow.document.getElementById("header-utils-btn");
+ utilsBtn.addEventListener("popupshown", function() {
+ utilsBtn.removeEventListener("popupshown", arguments.callee, false);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.isVisible(recentCat), true, "Recent Updates category should now be visible");
+ is(gManagerWindow.document.getElementById("categories").selectedItem.value, "addons://updates/recent", "Recent Updates category should now be selected");
+ is(gManagerWindow.gViewController.currentViewId, "addons://updates/recent", "Recent Updates view should be the current view");
+ run_next_test();
+ }, true);
+ var menuitem = gManagerWindow.document.getElementById("utils-viewUpdates");
+ EventUtils.synthesizeMouse(menuitem, 2, 2, { }, gManagerWindow);
+ }, false);
+ EventUtils.synthesizeMouse(utilsBtn, 2, 2, { }, gManagerWindow);
+});
+
+
+add_test(function() {
+ var updatesList = gManagerWindow.document.getElementById("updates-list");
+ var sorters = gManagerWindow.document.getElementById("updates-sorters");
+ var dateSorter = gManagerWindow.document.getAnonymousElementByAttribute(sorters, "anonid", "date-btn");
+ var nameSorter = gManagerWindow.document.getAnonymousElementByAttribute(sorters, "anonid", "name-btn");
+
+ function check_order(expected) {
+ var items = updatesList.getElementsByTagName("richlistitem");
+ var possible = ["addon1@tests.mozilla.org", "addon2@tests.mozilla.org", "addon3@tests.mozilla.org"];
+ for (let item of items) {
+ let itemId = item.mAddon.id;
+ if (possible.indexOf(itemId) == -1)
+ continue; // skip over any other addons, such as shipped addons that would update on every build
+ isnot(expected.length, 0, "Should be expecting more items");
+ is(itemId, expected.shift(), "Should get expected item based on sort order");
+ if (itemId == "addon1@tests.mozilla.org")
+ is_element_visible(item._relNotesToggle, "Release notes toggle should be visible for addon with release notes");
+ else
+ is_element_hidden(item._relNotesToggle, "Release notes toggle should be hidden for addon with no release notes");
+ }
+ }
+
+ is_element_visible(dateSorter);
+ is_element_visible(nameSorter);
+
+ // sorted by date, descending
+ check_order(["addon2@tests.mozilla.org", "addon1@tests.mozilla.org"]);
+
+ // sorted by date, ascending
+ EventUtils.synthesizeMouseAtCenter(dateSorter, { }, gManagerWindow);
+ check_order(["addon1@tests.mozilla.org", "addon2@tests.mozilla.org"]);
+
+ // sorted by name, ascending
+ EventUtils.synthesizeMouseAtCenter(nameSorter, { }, gManagerWindow);
+ check_order(["addon2@tests.mozilla.org", "addon1@tests.mozilla.org"]);
+
+ // sorted by name, descending
+ EventUtils.synthesizeMouseAtCenter(nameSorter, { }, gManagerWindow);
+ check_order(["addon1@tests.mozilla.org", "addon2@tests.mozilla.org"]);
+
+ run_next_test();
+});
+
+
+add_test(function() {
+ close_manager(gManagerWindow, function() {
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ var recentCat = gManagerWindow.gCategories.get("addons://updates/recent");
+ is(gCategoryUtilities.isVisible(recentCat), true, "Recent Updates category should still be visible");
+
+ run_next_test();
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_searching.js b/toolkit/mozapps/webextensions/test/browser/browser_searching.js
new file mode 100644
index 000000000..907d9b105
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_searching.js
@@ -0,0 +1,698 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that searching for add-ons works correctly
+
+const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
+const SEARCH_URL = TESTROOT + "browser_searching.xml";
+const NO_MATCH_URL = TESTROOT + "browser_searching_empty.xml";
+
+const QUERY = "SEARCH";
+const NO_MATCH_QUERY = "NOMATCHQUERY";
+const REMOTE_TO_INSTALL = "remote1";
+const REMOTE_INSTALL_URL = TESTROOT + "addons/browser_searching.xpi";
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+var gServer;
+var gAddonInstalled = false;
+
+function test() {
+ requestLongerTimeout(2);
+ // Turn on searching for this test
+ Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "PASS - f",
+ description: "Test description - SEARCH",
+ size: 3,
+ version: "1.0",
+ updateDate: new Date(2010, 4, 2, 0, 0, 1)
+ }, {
+ id: "fail-addon1@tests.mozilla.org",
+ name: "FAIL",
+ description: "Does not match query"
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "PASS - c",
+ description: "Test description - reSEARCHing SEARCH SEARCH",
+ size: 6,
+ version: "2.0",
+ updateDate: new Date(2010, 4, 2, 0, 0, 0)
+ }]);
+
+ var installs = gProvider.createInstalls([{
+ name: "PASS - a - SEARCHing",
+ sourceURI: "http://example.com/install1.xpi"
+ }, {
+ name: "PASS - g - reSEARCHing SEARCH",
+ sourceURI: "http://example.com/install2.xpi"
+ }, {
+ // Does not match query
+ name: "FAIL",
+ sourceURI: "http://example.com/fail-install1.xpi"
+ }]);
+
+ for (let install of installs )
+ install.install();
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ var installedAddon = get_addon_item(REMOTE_TO_INSTALL).mAddon;
+ installedAddon.uninstall();
+
+ AddonManager.getAllInstalls(function(aInstallsList) {
+ for (var install of aInstallsList) {
+ var sourceURI = install.sourceURI.spec;
+ if (sourceURI == REMOTE_INSTALL_URL ||
+ sourceURI.match(/^http:\/\/example\.com\/(.+)\.xpi$/) != null)
+ install.cancel();
+ }
+
+ finish();
+ });
+ });
+}
+
+function getAnonymousElementByAttribute(aElement, aName, aValue) {
+ return gManagerWindow.document.getAnonymousElementByAttribute(aElement,
+ aName,
+ aValue);
+}
+
+/*
+ * Checks whether or not the Add-ons Manager is currently searching
+ *
+ * @param aExpectedSearching
+ * The expected isSearching state
+ */
+function check_is_searching(aExpectedSearching) {
+ var loading = gManagerWindow.document.getElementById("search-loading");
+ is(!is_hidden(loading), aExpectedSearching,
+ "Search throbber should be showing iff currently searching");
+}
+
+/*
+ * Completes a search
+ *
+ * @param aQuery
+ * The query to search for
+ * @param aFinishImmediately
+ * Boolean representing whether or not the search is expected to
+ * finish immediately
+ * @param aCallback
+ * The callback to call when the search is done
+ * @param aCategoryType
+ * The expected selected category after the search is done.
+ * Optional and defaults to "search"
+ */
+function search(aQuery, aFinishImmediately, aCallback, aCategoryType) {
+ // Point search to the correct xml test file
+ var url = (aQuery == NO_MATCH_QUERY) ? NO_MATCH_URL : SEARCH_URL;
+ Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, url);
+
+ aCategoryType = aCategoryType ? aCategoryType : "search";
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = aQuery;
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ var finishImmediately = true;
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, aCategoryType, "Expected category view should be selected");
+ is(gCategoryUtilities.isTypeVisible("search"), aCategoryType == "search",
+ "Search category should only be visible if it is the current view");
+ check_is_searching(false);
+ is(finishImmediately, aFinishImmediately, "Search should finish immediately only if expected");
+
+ aCallback();
+ });
+
+ finishImmediately = false
+ if (!aFinishImmediately)
+ check_is_searching(true);
+}
+
+/*
+ * Return results of a search
+ *
+ * @return Array of objects, each containing the name and item of a specific
+ * result
+ */
+function get_actual_results() {
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+
+ var results = [];
+ for (var item of rows) {
+
+ // Only consider items that are currently showing
+ var style = gManagerWindow.document.defaultView.getComputedStyle(item, "");
+ if (style.display == "none" || style.visibility != "visible")
+ continue;
+
+ if (item.mInstall || item.isPending("install")) {
+ var sourceURI = item.mInstall.sourceURI.spec;
+ if (sourceURI == REMOTE_INSTALL_URL) {
+ results.push({name: REMOTE_TO_INSTALL, item: item});
+ continue;
+ }
+
+ let result = sourceURI.match(/^http:\/\/example\.com\/(.+)\.xpi$/);
+ if (result != null) {
+ is(item.mInstall.name.indexOf("PASS"), 0, "Install name should start with PASS");
+ results.push({name: result[1], item: item});
+ continue;
+ }
+ }
+ else if (item.mAddon) {
+ let result = item.mAddon.id.match(/^(.+)@tests\.mozilla\.org$/);
+ if (result != null) {
+ is(item.mAddon.name.indexOf("PASS"), 0, "Addon name should start with PASS");
+ results.push({name: result[1], item: item});
+ continue;
+ }
+ }
+ else {
+ ok(false, "Found an item in the list that was neither installing or installed");
+ }
+ }
+
+ return results;
+}
+
+/*
+ * Returns expected results when searching for QUERY with default ordering
+ *
+ * @param aSortBy
+ * How the results are sorted (e.g. "name")
+ * @param aLocalExpected
+ * Boolean representing if local results are expected
+ * @return A pair: [array of results with an expected order,
+ * array of results with unknown order]
+ */
+function get_expected_results(aSortBy, aLocalExpected) {
+ var expectedOrder = null, unknownOrder = null;
+ switch (aSortBy) {
+ case "relevancescore":
+ expectedOrder = [ "addon2", "remote1", "install2", "addon1",
+ "install1", "remote2", "remote3", "remote4" ];
+ unknownOrder = [];
+ break;
+ case "name":
+ // Defaults to ascending order
+ expectedOrder = [ "install1", "remote1", "addon2", "remote2",
+ "remote3", "addon1", "install2", "remote4" ];
+ unknownOrder = [];
+ break;
+ case "dateUpdated":
+ expectedOrder = [ "addon1", "addon2" ];
+ // Updated date not available for installs and remote add-ons
+ unknownOrder = [ "install1", "install2", "remote1",
+ "remote2", "remote3", "remote4" ];
+ break;
+ default:
+ ok(false, "Should recognize sortBy when checking the order of items");
+ }
+
+ // Only keep expected results
+ function filterResults(aId) {
+ // Include REMOTE_TO_INSTALL as a local add-on if it has been installed
+ if (gAddonInstalled && aId == REMOTE_TO_INSTALL)
+ return aLocalExpected;
+
+ if (aId.indexOf("addon") == 0 || aId.indexOf("install") == 0)
+ return aLocalExpected;
+ if (aId.indexOf("remote") == 0)
+ return !aLocalExpected;
+
+ return false;
+ }
+
+
+ return [expectedOrder.filter(filterResults),
+ unknownOrder.filter(filterResults)]
+}
+
+/*
+ * Check that the actual and expected results are the same
+ *
+ * @param aQuery
+ * The search query used
+ * @param aSortBy
+ * How the results are sorted (e.g. "name")
+ * @param aReverseOrder
+ * Boolean representing if the results are in reverse default order
+ * @param aShowLocal
+ * Boolean representing if local results are being shown
+ */
+function check_results(aQuery, aSortBy, aReverseOrder, aShowLocal) {
+
+ var xpinstall_enabled = true;
+ try {
+ xpinstall_enabled = Services.prefs.getBoolPref(PREF_XPI_ENABLED);
+ }
+ catch (e) {}
+
+ // When XPI Instalation is disabled, those buttons are hidden and unused
+ if (xpinstall_enabled) {
+ var localFilterSelected = gManagerWindow.document.getElementById("search-filter-local").selected;
+ var remoteFilterSelected = gManagerWindow.document.getElementById("search-filter-remote").selected;
+ is(localFilterSelected, aShowLocal, "Local filter should be selected if showing local items");
+ is(remoteFilterSelected, !aShowLocal, "Remote filter should be selected if showing remote items");
+ }
+
+ // Get expected order assuming default order
+ var expectedOrder = [], unknownOrder = [];
+ if (aQuery == QUERY)
+ [expectedOrder, unknownOrder] = get_expected_results(aSortBy, aShowLocal);
+
+ // Get actual order of results
+ var actualResults = get_actual_results();
+ var actualOrder = actualResults.map(result => result.name);
+
+ // Reverse array of actual results if supposed to be in reverse order.
+ // Reverse actualOrder instead of expectedOrder so can always check
+ // expectedOrder before unknownOrder
+ if (aReverseOrder)
+ actualOrder.reverse();
+
+ // Check actual vs. expected list of results
+ var totalExpectedResults = expectedOrder.length + unknownOrder.length;
+ is(actualOrder.length, totalExpectedResults, "Should get correct number of results");
+
+ // Check the "first" and "last" attributes are set correctly
+ for (let i = 0; i < actualResults.length; i++) {
+ if (i == 0) {
+ is(actualResults[0].item.hasAttribute("first"), true,
+ "First item should have 'first' attribute set");
+ is(actualResults[0].item.hasAttribute("last"), false,
+ "First item should not have 'last' attribute set");
+ } else if (i == (actualResults.length - 1)) {
+ is(actualResults[actualResults.length - 1].item.hasAttribute("first"), false,
+ "Last item should not have 'first' attribute set");
+ is(actualResults[actualResults.length - 1].item.hasAttribute("last"), true,
+ "Last item should have 'last' attribute set");
+ } else {
+ is(actualResults[i].item.hasAttribute("first"), false,
+ "Item " + i + " should not have 'first' attribute set");
+ is(actualResults[i].item.hasAttribute("last"), false,
+ "Item " + i + " should not have 'last' attribute set");
+ }
+ }
+
+ var i = 0;
+ for (; i < expectedOrder.length; i++)
+ is(actualOrder[i], expectedOrder[i], "Should have seen expected item");
+
+ // Items with data that is unknown can appear in any order among themselves,
+ // so just check that these items exist
+ for (; i < actualOrder.length; i++) {
+ var unknownOrderIndex = unknownOrder.indexOf(actualOrder[i]);
+ ok(unknownOrderIndex >= 0, "Should expect to see item with data that is unknown");
+ unknownOrder[unknownOrderIndex] = null;
+ }
+
+ // Check status of empty notice
+ var emptyNotice = gManagerWindow.document.getElementById("search-list-empty");
+ is(emptyNotice.hidden, totalExpectedResults > 0,
+ "Empty notice should be hidden only if expecting shown items");
+}
+
+/*
+ * Check results of a search with different filterings
+ *
+ * @param aQuery
+ * The search query used
+ * @param aSortBy
+ * How the results are sorted (e.g. "name")
+ * @param aReverseOrder
+ * Boolean representing if the results are in reverse default order
+ * @param aLocalOnly
+ * Boolean representing if the results are local only, can be undefined
+ */
+function check_filtered_results(aQuery, aSortBy, aReverseOrder, aLocalOnly) {
+ var localFilter = gManagerWindow.document.getElementById("search-filter-local");
+ var remoteFilter = gManagerWindow.document.getElementById("search-filter-remote");
+
+ var list = gManagerWindow.document.getElementById("search-list");
+ list.ensureElementIsVisible(localFilter);
+
+ // Check with showing local add-ons
+ EventUtils.synthesizeMouseAtCenter(localFilter, { }, gManagerWindow);
+ check_results(aQuery, aSortBy, aReverseOrder, true);
+
+ // Check with showing remote add-ons
+ aLocalOnly = aLocalOnly || false;
+ EventUtils.synthesizeMouseAtCenter(remoteFilter, { }, gManagerWindow);
+ check_results(aQuery, aSortBy, aReverseOrder, aLocalOnly);
+}
+
+/*
+ * Get item for a specific add-on by name
+ *
+ * @param aName
+ * The name of the add-on to search for
+ * @return Row of add-on if found, null otherwise
+ */
+function get_addon_item(aName) {
+ var id = aName + "@tests.mozilla.org";
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+ for (var row of rows) {
+ if (row.mAddon && row.mAddon.id == id)
+ return row;
+ }
+
+ return null;
+}
+
+/*
+ * Get item for a specific install by name
+ *
+ * @param aName
+ * The name of the install to search for
+ * @return Row of install if found, null otherwise
+ */
+function get_install_item(aName) {
+ var sourceURI = "http://example.com/" + aName + ".xpi";
+ var list = gManagerWindow.document.getElementById("search-list");
+ var rows = list.getElementsByTagName("richlistitem");
+ for (var row of rows) {
+ if (row.mInstall && row.mInstall.sourceURI.spec == sourceURI)
+ return row;
+ }
+
+ return null;
+}
+
+/*
+ * Gets the install button for a specific item
+ *
+ * @param aItem
+ * The item to get the install button for
+ * @return The install button for aItem
+ */
+function get_install_button(aItem) {
+ isnot(aItem, null, "Item should not be null when checking state of install button");
+ var installStatus = getAnonymousElementByAttribute(aItem, "anonid", "install-status");
+ return getAnonymousElementByAttribute(installStatus, "anonid", "install-remote-btn");
+}
+
+
+// Tests that searching for the empty string does nothing when not in the search view
+add_test(function() {
+ is(gCategoryUtilities.isTypeVisible("search"), false, "Search category should initially be hidden");
+
+ var selectedCategory = gCategoryUtilities.selectedCategory;
+ isnot(selectedCategory, "search", "Selected type should not initially be the search view");
+ search("", true, run_next_test, selectedCategory);
+});
+
+// Tests that the results from a query are sorted by relevancescore in descending order.
+// Also test that double clicking non-install items goes to the detail view, and that
+// only remote items have install buttons showing
+add_test(function() {
+ search(QUERY, false, function() {
+ check_filtered_results(QUERY, "relevancescore", false);
+
+ var list = gManagerWindow.document.getElementById("search-list");
+ var results = get_actual_results();
+ for (var result of results) {
+ var installBtn = get_install_button(result.item);
+ is(installBtn.hidden, result.name.indexOf("remote") != 0,
+ "Install button should only be showing for remote items");
+ }
+
+ var currentIndex = -1;
+ function run_next_double_click_test() {
+ currentIndex++;
+ if (currentIndex >= results.length) {
+ run_next_test();
+ return;
+ }
+
+ var result = results[currentIndex];
+ if (result.name.indexOf("install") == 0) {
+ run_next_double_click_test();
+ return;
+ }
+
+ var item = result.item;
+ list.ensureElementIsVisible(item);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ var name = gManagerWindow.document.getElementById("detail-name").textContent;
+ is(name, item.mAddon.name, "Name in detail view should be correct");
+ var version = gManagerWindow.document.getElementById("detail-version").value;
+ is(version, item.mAddon.version, "Version in detail view should be correct");
+
+ EventUtils.synthesizeMouseAtCenter(gManagerWindow.document.getElementById("category-search"),
+ { }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, run_next_double_click_test);
+ });
+ }
+
+ run_next_double_click_test();
+ });
+});
+
+// Tests that the sorters and filters correctly manipulate the results
+add_test(function() {
+ var sorters = gManagerWindow.document.getElementById("search-sorters");
+ var originalHandler = sorters.handler;
+
+ var sorterNames = ["name", "dateUpdated"];
+ var buttonIds = ["name-btn", "date-btn"];
+ var currentIndex = 0;
+ var currentReversed = false;
+
+ function run_sort_test() {
+ if (currentIndex >= sorterNames.length) {
+ sorters.handler = originalHandler;
+ run_next_test();
+ return;
+ }
+
+ // Simulate clicking on a specific sorter
+ var buttonId = buttonIds[currentIndex];
+ var sorter = getAnonymousElementByAttribute(sorters, "anonid", buttonId);
+ is_element_visible(sorter);
+ EventUtils.synthesizeMouseAtCenter(sorter, { }, gManagerWindow);
+ }
+
+ sorters.handler = {
+ onSortChanged: function(aSortBy, aAscending) {
+ if (originalHandler && "onSortChanged" in originalHandler)
+ originalHandler.onSortChanged(aSortBy, aAscending);
+
+ check_filtered_results(QUERY, sorterNames[currentIndex], currentReversed);
+
+ if (currentReversed)
+ currentIndex++;
+ currentReversed = !currentReversed;
+
+ run_sort_test();
+ }
+ };
+
+ check_filtered_results(QUERY, "relevancescore", false);
+ run_sort_test();
+});
+
+// Tests that searching for the empty string does nothing when in search view
+add_test(function() {
+ search("", true, function() {
+ check_filtered_results(QUERY, "dateUpdated", true);
+ run_next_test();
+ });
+});
+
+// Tests that clicking a different category hides the search query
+add_test(function() {
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.isTypeVisible("search"), false, "Search category should be hidden");
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+ run_next_test();
+ });
+});
+
+// Tests that re-searching for query doesn't actually complete a new search,
+// and the last sort is still used
+add_test(function() {
+ search(QUERY, true, function() {
+ check_filtered_results(QUERY, "dateUpdated", true);
+ run_next_test();
+ });
+});
+
+// Tests that getting zero results works correctly
+add_test(function() {
+ search(NO_MATCH_QUERY, false, function() {
+ check_filtered_results(NO_MATCH_QUERY, "relevancescore", false);
+ run_next_test();
+ });
+});
+
+// Tests that installing a remote add-on works
+add_test(function() {
+ var installBtn = null;
+
+ var listener = {
+ onInstallEnded: function(aInstall, aAddon) {
+ // Don't immediately consider the installed add-on as local because
+ // if the user was filtering out local add-ons, the installed add-on
+ // would vanish. Only consider add-on as local on new searches.
+
+ aInstall.removeListener(this);
+
+ is(installBtn.hidden, true, "Install button should be hidden after install ended");
+ check_filtered_results(QUERY, "relevancescore", false);
+ run_next_test();
+ }
+ }
+
+ search(QUERY, false, function() {
+ var list = gManagerWindow.document.getElementById("search-list");
+ var remoteItem = get_addon_item(REMOTE_TO_INSTALL);
+ list.ensureElementIsVisible(remoteItem);
+
+ installBtn = get_install_button(remoteItem);
+ is(installBtn.hidden, false, "Install button should be showing before install");
+ remoteItem.mAddon.install.addListener(listener);
+ EventUtils.synthesizeMouseAtCenter(installBtn, { }, gManagerWindow);
+ });
+});
+
+// Tests that re-searching for query results in correct results
+add_test(function() {
+ // Select a different category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.isTypeVisible("search"), false, "Search category should be hidden");
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var installBtn = get_install_button(get_addon_item(REMOTE_TO_INSTALL));
+ is(installBtn.hidden, true, "Install button should be hidden for installed item");
+
+ search(QUERY, true, function() {
+ check_filtered_results(QUERY, "relevancescore", false);
+ run_next_test();
+ });
+ });
+});
+
+// Tests that incompatible add-ons are shown with a warning if compatibility checking is disabled
+add_test(function() {
+ AddonManager.checkCompatibility = false;
+ search("incompatible", false, function() {
+ var item = get_addon_item("remote5");
+ is_element_visible(item, "Incompatible addon should be visible");
+ is(item.getAttribute("notification"), "warning", "Compatibility warning should be shown");
+
+ item = get_addon_item("remote6");
+ is(item, null, "Addon incompatible with the product should not be visible");
+
+ AddonManager.checkCompatibility = true;
+ run_next_test();
+ });
+});
+
+// Tests that compatible-by-default addons are shown if strict compatibility checking is disabled
+add_test(function() {
+ restart_manager(gManagerWindow, "addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
+ search("incompatible", false, function() {
+ var item = get_addon_item("remote5");
+ is_element_visible(item, "Incompatible addon should be visible");
+ isnot(item.getAttribute("notification"), "warning", "Compatibility warning should not be shown");
+
+ item = get_addon_item("remote6");
+ is(item, null, "Addon incompatible with the product should not be visible");
+
+ Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
+ run_next_test();
+ });
+ });
+});
+
+
+// Tests that restarting the manager doesn't change search results
+add_test(function() {
+ restart_manager(gManagerWindow, null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ // We never restore to the search pane
+ is(gCategoryUtilities.selectedCategory, "discover", "View should have changed to discover");
+
+ // Installed add-on is considered local on new search
+ gAddonInstalled = true;
+
+ // Switch over to extensions list so we can do a new search
+ gCategoryUtilities.openType("extension", function() {
+ search(QUERY, false, function() {
+ check_filtered_results(QUERY, "relevancescore", false);
+
+ var installBtn = get_install_button(get_addon_item(REMOTE_TO_INSTALL));
+ is(installBtn.hidden, true, "Install button should be hidden for installed item");
+
+ run_next_test();
+ });
+ });
+ });
+});
+
+function bug_815120_test_search(aLocalOnly) {
+ restart_manager(gManagerWindow, "addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ // Installed add-on is considered local on new search
+ gAddonInstalled = true;
+
+ // The search buttons should be hidden in the LocalOnly setup
+ var localFilterButton = aWindow.document.getElementById("search-filter-local");
+ is(aLocalOnly, is_hidden(localFilterButton), "Local filter button visibility does not match, aLocalOnly = " + aLocalOnly);
+
+ var remoteFilterButton = aWindow.document.getElementById("search-filter-remote");
+ is(aLocalOnly, is_hidden(remoteFilterButton), "Remote filter button visibility does not match, aLocalOnly = " + aLocalOnly);
+
+ search(QUERY, false, function() {
+ check_filtered_results(QUERY, "relevancescore", false, aLocalOnly);
+ run_next_test();
+ });
+ });
+}
+
+// Tests for Bug 815120
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, false);
+ bug_815120_test_search(true);
+});
+
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_XPI_ENABLED, true);
+ bug_815120_test_search(false);
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_searching.xml b/toolkit/mozapps/webextensions/test/browser/browser_searching.xml
new file mode 100644
index 000000000..a3537b269
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_searching.xml
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="100">
+ <addon>
+ <name>FAIL</name>
+ <type id='1'>Extension</type>
+ <guid>addon1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Addon already installed - SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/addon1.xpi</install>
+ </addon>
+ <addon>
+ <name>FAIL</name>
+ <type id='9'>lightweight theme</type>
+ <guid>addon12345@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Addon with uninstallable type shouldn't be visible in search</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/addon1.xpi</install>
+ </addon>
+ <addon>
+ <name>FAIL</name>
+ <type id='1'>Extension</type>
+ <guid>install1@tests.mozilla.org</guid>
+ <version>1.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Install already exists - SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/install1.xpi</install>
+ </addon>
+ <addon>
+ <name>PASS - b</name>
+ <type id='1'>Extension</type>
+ <guid>remote1@tests.mozilla.org</guid>
+ <version>3.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary - SEARCH SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="2">http://example.com/browser/toolkit/mozapps/extensions/test/browser/addons/browser_searching.xpi</install>
+ </addon>
+ <addon>
+ <name>PASS - d</name>
+ <type id='1'>Extension</type>
+ <guid>remote2@tests.mozilla.org</guid>
+ <version>4.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary - SEARCHing SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="5">http://example.com/remote2.xpi</install>
+ </addon>
+ <addon>
+ <name>PASS - e</name>
+ <type id='1'>Extension</type>
+ <guid>remote3@tests.mozilla.org</guid>
+ <version>5.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary - Does not match query</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/remote3.xpi</install>
+ </addon>
+ <addon>
+ <name>PASS - h</name>
+ <type id='1'>Extension</type>
+ <guid>remote4@tests.mozilla.org</guid>
+ <version>6.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Test summary - SEARCHing SEARCH SEARCH</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>*</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="4">http://example.com/remote4.xpi</install>
+ </addon>
+ <addon>
+ <name>PASS - i</name>
+ <type id='1'>Extension</type>
+ <guid>remote5@tests.mozilla.org</guid>
+ <version>6.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Incompatible test</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Firefox</name>
+ <appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
+ <min_version>0</min_version>
+ <max_version>1</max_version>
+ </application>
+ <application>
+ <name>SeaMonkey</name>
+ <appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
+ <min_version>0</min_version>
+ <max_version>1</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/addon1.xpi</install>
+ </addon>
+ <addon>
+ <name>FAIL - j</name>
+ <type id='1'>Extension</type>
+ <guid>remote6@tests.mozilla.org</guid>
+ <version>6.0</version>
+ <authors>
+ <author>
+ <name>Test Creator</name>
+ <link>http://example.com/creator.html</link>
+ </author>
+ </authors>
+ <status id='4'>Public</status>
+ <summary>Incompatible test</summary>
+ <description>Test description</description>
+ <compatible_applications>
+ <application>
+ <name>Fake Product</name>
+ <appID>fakeproduct@mozilla.org</appID>
+ <min_version>0</min_version>
+ <max_version>1</max_version>
+ </application>
+ </compatible_applications>
+ <compatible_os>ALL</compatible_os>
+ <install size="1">http://example.com/addon1.xpi</install>
+ </addon>
+</searchresults>
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_searching_empty.xml b/toolkit/mozapps/webextensions/test/browser/browser_searching_empty.xml
new file mode 100644
index 000000000..24f6cb89f
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_searching_empty.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<searchresults total_results="100" />
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_sorting.js b/toolkit/mozapps/webextensions/test/browser/browser_sorting.js
new file mode 100644
index 000000000..b57e7a6f7
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_sorting.js
@@ -0,0 +1,372 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that sorting of add-ons works correctly
+// (this test uses the list view, even though it no longer has sort buttons - see bug 623207)
+
+var gManagerWindow;
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+ gProvider.createAddons([{
+ // enabledInstalled group
+ // * Enabled
+ // * Incompatible but enabled because compatibility checking is off
+ // * Waiting to be installed
+ // * Waiting to be enabled
+ id: "test1@tests.mozilla.org",
+ name: "Test add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 2, 0, 0, 0),
+ size: 1,
+ pendingOperations: AddonManager.PENDING_NONE,
+ }, {
+ id: "test2@tests.mozilla.org",
+ name: "a first add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 1, 23, 59, 59),
+ size: 265,
+ pendingOperations: AddonManager.PENDING_UPGRADE,
+ isActive: true,
+ isCompatible: false,
+ }, {
+ id: "test3@tests.mozilla.org",
+ name: "\u010Cesk\u00FD slovn\u00EDk", // Český slovník
+ description: "foo",
+ updateDate: new Date(2010, 4, 2, 0, 0, 1),
+ size: 12,
+ pendingOperations: AddonManager.PENDING_INSTALL,
+ isActive: false,
+ }, {
+ id: "test4@tests.mozilla.org",
+ name: "canadian dictionary",
+ updateDate: new Date(1970, 0, 1, 0, 0, 0),
+ description: "foo",
+ isActive: true,
+ }, {
+ id: "test5@tests.mozilla.org",
+ name: "croatian dictionary",
+ description: "foo",
+ updateDate: new Date(2012, 12, 12, 0, 0, 0),
+ size: 5,
+ pendingOperations: AddonManager.PENDING_ENABLE,
+ isActive: false,
+ }, {
+ // pendingDisable group
+ // * Waiting to be disabled
+ id: "test6@tests.mozilla.org",
+ name: "orange Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 2, 0, 0, 0),
+ size: 142,
+ isCompatible: false,
+ isActive: true,
+ pendingOperations: AddonManager.PENDING_DISABLE,
+ }, {
+ id: "test7@tests.mozilla.org",
+ name: "Blue Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 1, 23, 59, 59),
+ size: 65,
+ isActive: true,
+ pendingOperations: AddonManager.PENDING_DISABLE,
+ }, {
+ id: "test8@tests.mozilla.org",
+ name: "Green Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 3, 0, 0, 1),
+ size: 125,
+ pendingOperations: AddonManager.PENDING_DISABLE,
+ }, {
+ id: "test9@tests.mozilla.org",
+ name: "red Add-on",
+ updateDate: new Date(2011, 4, 1, 0, 0, 0),
+ description: "foo",
+ isCompatible: false,
+ pendingOperations: AddonManager.PENDING_DISABLE,
+ }, {
+ id: "test10@tests.mozilla.org",
+ name: "Purple Add-on",
+ description: "foo",
+ updateDate: new Date(2012, 12, 12, 0, 0, 0),
+ size: 56,
+ isCompatible: false,
+ pendingOperations: AddonManager.PENDING_DISABLE,
+ }, {
+ // pendingUninstall group
+ // * Waiting to be removed
+ id: "test11@tests.mozilla.org",
+ name: "amber Add-on",
+ description: "foo",
+ updateDate: new Date(1978, 4, 2, 0, 0, 0),
+ size: 142,
+ isActive: false,
+ appDisabled: true,
+ pendingOperations: AddonManager.PENDING_UNINSTALL,
+ }, {
+ id: "test12@tests.mozilla.org",
+ name: "Salmon Add-on - pending disable",
+ description: "foo",
+ updateDate: new Date(2054, 4, 1, 23, 59, 59),
+ size: 65,
+ isActive: true,
+ pendingOperations: AddonManager.PENDING_UNINSTALL,
+ }, {
+ id: "test13@tests.mozilla.org",
+ name: "rose Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 2, 0, 0, 1),
+ size: 125,
+ isActive: false,
+ userDisabled: true,
+ pendingOperations: AddonManager.PENDING_UNINSTALL,
+ }, {
+ id: "test14@tests.mozilla.org",
+ name: "Violet Add-on",
+ updateDate: new Date(2010, 5, 1, 0, 0, 0),
+ description: "foo",
+ isActive: false,
+ appDisabled: true,
+ pendingOperations: AddonManager.PENDING_UNINSTALL,
+ }, {
+ id: "test15@tests.mozilla.org",
+ name: "white Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 12, 0, 0, 0),
+ size: 56,
+ isActive: false,
+ userDisabled: true,
+ pendingOperations: AddonManager.PENDING_UNINSTALL,
+ }, {
+ // disabledIncompatibleBlocked group
+ // * Disabled
+ // * Incompatible
+ // * Blocklisted
+ id: "test16@tests.mozilla.org",
+ name: "grimsby Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 1, 0, 0, 0),
+ size: 142,
+ isActive: false,
+ appDisabled: true,
+ }, {
+ id: "test17@tests.mozilla.org",
+ name: "beamsville Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 8, 23, 59, 59),
+ size: 65,
+ isActive: false,
+ userDisabled: true,
+ }, {
+ id: "test18@tests.mozilla.org",
+ name: "smithville Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 3, 0, 0, 1),
+ size: 125,
+ isActive: false,
+ userDisabled: true,
+ blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED,
+ }, {
+ id: "test19@tests.mozilla.org",
+ name: "dunnville Add-on",
+ updateDate: new Date(2010, 4, 2, 0, 0, 0),
+ description: "foo",
+ isActive: false,
+ appDisabled: true,
+ isCompatible: false,
+ blocklistState: Ci.nsIBlocklistService.STATE_NOT_BLOCKED,
+ }, {
+ id: "test20@tests.mozilla.org",
+ name: "silverdale Add-on",
+ description: "foo",
+ updateDate: new Date(2010, 4, 12, 0, 0, 0),
+ size: 56,
+ isActive: false,
+ appDisabled: true,
+ blocklistState: Ci.nsIBlocklistService.STATE_BLOCKED,
+ }]);
+
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+function set_order(aSortBy, aAscending) {
+ var list = gManagerWindow.document.getElementById("addon-list");
+ var elements = [];
+ var node = list.firstChild;
+ while (node) {
+ elements.push(node);
+ node = node.nextSibling;
+ }
+ gManagerWindow.sortElements(elements, ["uiState", aSortBy], aAscending);
+ for (let element of elements)
+ list.appendChild(element);
+}
+
+function check_order(aExpectedOrder) {
+ var order = [];
+ var list = gManagerWindow.document.getElementById("addon-list");
+ var node = list.firstChild;
+ while (node) {
+ var id = node.getAttribute("value");
+ if (id && id.endsWith("@tests.mozilla.org"))
+ order.push(node.getAttribute("value"));
+ node = node.nextSibling;
+ }
+
+ is(order.toSource(), aExpectedOrder.toSource(), "Should have seen the right order");
+}
+
+// Tests that ascending name ordering was the default
+add_test(function() {
+
+ check_order([
+ "test2@tests.mozilla.org",
+ "test4@tests.mozilla.org",
+ "test3@tests.mozilla.org",
+ "test5@tests.mozilla.org",
+ "test1@tests.mozilla.org",
+ "test7@tests.mozilla.org",
+ "test8@tests.mozilla.org",
+ "test6@tests.mozilla.org",
+ "test10@tests.mozilla.org",
+ "test9@tests.mozilla.org",
+ "test11@tests.mozilla.org",
+ "test13@tests.mozilla.org",
+ "test12@tests.mozilla.org",
+ "test14@tests.mozilla.org",
+ "test15@tests.mozilla.org",
+ "test17@tests.mozilla.org",
+ "test19@tests.mozilla.org",
+ "test16@tests.mozilla.org",
+ "test20@tests.mozilla.org",
+ "test18@tests.mozilla.org",
+ ]);
+ run_next_test();
+});
+
+// Tests that switching to date ordering works
+add_test(function() {
+ set_order("updateDate", false);
+
+ // When we're ascending with updateDate, it's from newest
+ // to oldest.
+
+ check_order([
+ "test5@tests.mozilla.org",
+ "test3@tests.mozilla.org",
+ "test1@tests.mozilla.org",
+ "test2@tests.mozilla.org",
+ "test4@tests.mozilla.org",
+ "test10@tests.mozilla.org",
+ "test9@tests.mozilla.org",
+ "test8@tests.mozilla.org",
+ "test6@tests.mozilla.org",
+ "test7@tests.mozilla.org",
+ "test12@tests.mozilla.org",
+ "test14@tests.mozilla.org",
+ "test15@tests.mozilla.org",
+ "test13@tests.mozilla.org",
+ "test11@tests.mozilla.org",
+ "test20@tests.mozilla.org",
+ "test17@tests.mozilla.org",
+ "test18@tests.mozilla.org",
+ "test19@tests.mozilla.org",
+ "test16@tests.mozilla.org",
+ ]);
+
+ set_order("updateDate", true);
+
+ check_order([
+ "test4@tests.mozilla.org",
+ "test2@tests.mozilla.org",
+ "test1@tests.mozilla.org",
+ "test3@tests.mozilla.org",
+ "test5@tests.mozilla.org",
+ "test7@tests.mozilla.org",
+ "test6@tests.mozilla.org",
+ "test8@tests.mozilla.org",
+ "test9@tests.mozilla.org",
+ "test10@tests.mozilla.org",
+ "test11@tests.mozilla.org",
+ "test13@tests.mozilla.org",
+ "test15@tests.mozilla.org",
+ "test14@tests.mozilla.org",
+ "test12@tests.mozilla.org",
+ "test16@tests.mozilla.org",
+ "test19@tests.mozilla.org",
+ "test18@tests.mozilla.org",
+ "test17@tests.mozilla.org",
+ "test20@tests.mozilla.org",
+ ]);
+
+ run_next_test();
+});
+
+// Tests that switching to name ordering works
+add_test(function() {
+ set_order("name", true);
+
+ check_order([
+ "test2@tests.mozilla.org",
+ "test4@tests.mozilla.org",
+ "test3@tests.mozilla.org",
+ "test5@tests.mozilla.org",
+ "test1@tests.mozilla.org",
+ "test7@tests.mozilla.org",
+ "test8@tests.mozilla.org",
+ "test6@tests.mozilla.org",
+ "test10@tests.mozilla.org",
+ "test9@tests.mozilla.org",
+ "test11@tests.mozilla.org",
+ "test13@tests.mozilla.org",
+ "test12@tests.mozilla.org",
+ "test14@tests.mozilla.org",
+ "test15@tests.mozilla.org",
+ "test17@tests.mozilla.org",
+ "test19@tests.mozilla.org",
+ "test16@tests.mozilla.org",
+ "test20@tests.mozilla.org",
+ "test18@tests.mozilla.org",
+ ]);
+
+ set_order("name", false);
+
+ check_order([
+ "test1@tests.mozilla.org",
+ "test5@tests.mozilla.org",
+ "test3@tests.mozilla.org",
+ "test4@tests.mozilla.org",
+ "test2@tests.mozilla.org",
+ "test9@tests.mozilla.org",
+ "test10@tests.mozilla.org",
+ "test6@tests.mozilla.org",
+ "test8@tests.mozilla.org",
+ "test7@tests.mozilla.org",
+ "test15@tests.mozilla.org",
+ "test14@tests.mozilla.org",
+ "test12@tests.mozilla.org",
+ "test13@tests.mozilla.org",
+ "test11@tests.mozilla.org",
+ "test18@tests.mozilla.org",
+ "test20@tests.mozilla.org",
+ "test16@tests.mozilla.org",
+ "test19@tests.mozilla.org",
+ "test17@tests.mozilla.org",
+ ]);
+
+ run_next_test();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_sorting_plugins.js b/toolkit/mozapps/webextensions/test/browser/browser_sorting_plugins.js
new file mode 100644
index 000000000..2bb6b4ba4
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_sorting_plugins.js
@@ -0,0 +1,95 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that sorting of plugins works correctly
+// (this test checks that plugins with "ask to activate" state appear after those with
+// "always activate" and before those with "never activate")
+
+var gManagerWindow;
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+ gProvider.createAddons([{
+ // enabledInstalled group
+ // * Always activate
+ // * Ask to activate
+ // * Never activate
+ id: "test1@tests.mozilla.org",
+ name: "Java Applet Plug-in Java 7 Update 51",
+ description: "foo",
+ type: "plugin",
+ isActive: true,
+ userDisabled: AddonManager.STATE_ASK_TO_ACTIVATE
+ }, {
+ id: "test2@tests.mozilla.org",
+ name: "Quick Time Plug-in",
+ description: "foo",
+ type: "plugin",
+ isActive: true,
+ userDisabled: false
+ }, {
+ id: "test3@tests.mozilla.org",
+ name: "Shockwave Flash",
+ description: "foo",
+ type: "plugin",
+ isActive: false,
+ userDisabled: true
+ }, {
+ id: "test4@tests.mozilla.org",
+ name: "Adobe Reader Plug-in",
+ description: "foo",
+ type: "plugin",
+ isActive: true,
+ userDisabled: AddonManager.STATE_ASK_TO_ACTIVATE
+ }, {
+ id: "test5@tests.mozilla.org",
+ name: "3rd Party Plug-in",
+ description: "foo",
+ type: "plugin",
+ isActive: true,
+ userDisabled: false
+ }]);
+
+ open_manager("addons://list/plugin", function(aWindow) {
+ gManagerWindow = aWindow;
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+function check_order(aExpectedOrder) {
+ var order = [];
+ var list = gManagerWindow.document.getElementById("addon-list");
+ var node = list.firstChild;
+ while (node) {
+ var id = node.getAttribute("value");
+ if (id && id.endsWith("@tests.mozilla.org"))
+ order.push(node.getAttribute("value"));
+ node = node.nextSibling;
+ }
+
+ is(order.toSource(), aExpectedOrder.toSource(), "Should have seen the right order");
+}
+
+// Tests that ascending name ordering was the default
+add_test(function() {
+
+ check_order([
+ "test5@tests.mozilla.org",
+ "test2@tests.mozilla.org",
+ "test4@tests.mozilla.org",
+ "test1@tests.mozilla.org",
+ "test3@tests.mozilla.org"
+ ]);
+
+ run_next_test();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_system_addons_are_e10s.js b/toolkit/mozapps/webextensions/test/browser/browser_system_addons_are_e10s.js
new file mode 100644
index 000000000..37ab76542
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_system_addons_are_e10s.js
@@ -0,0 +1,13 @@
+"use strict";
+
+add_task(function* test_enabled() {
+ let addons = yield new Promise(resolved => AddonManager.getAllAddons(resolved));
+ for (let addon of addons) {
+ if (addon.isSystem) {
+ ok(addon.multiprocessCompatible,
+ `System addon ${addon.id} is not marked as multiprocess compatible`);
+ ok(!addon.unpack,
+ `System add-on ${addon.id} isn't a packed add-on.`);
+ }
+ }
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_tabsettings.js b/toolkit/mozapps/webextensions/test/browser/browser_tabsettings.js
new file mode 100644
index 000000000..2838698c7
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_tabsettings.js
@@ -0,0 +1,100 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests various aspects of the details view
+
+var gManagerWindow;
+var gCategoryUtilities;
+var gProvider;
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "tabsettings@tests.mozilla.org",
+ name: "Tab Settings",
+ version: "1",
+ optionsURL: CHROMEROOT + "addon_prefs.xul",
+ optionsType: AddonManager.OPTIONS_TYPE_TAB
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+add_test(function() {
+ var addon = get_addon_element(gManagerWindow, "tabsettings@tests.mozilla.org");
+ is(addon.mAddon.optionsType, AddonManager.OPTIONS_TYPE_TAB, "Options should be inline type");
+ addon.parentNode.ensureElementIsVisible(addon);
+
+ var button = gManagerWindow.document.getAnonymousElementByAttribute(addon, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ if (gUseInContentUI) {
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+
+ var browser = gBrowser.selectedBrowser;
+ browser.addEventListener("DOMContentLoaded", function() {
+ browser.removeEventListener("DOMContentLoaded", arguments.callee, false);
+ is(browser.currentURI.spec, addon.mAddon.optionsURL, "New tab should have loaded the options URL");
+ browser.contentWindow.close();
+ run_next_test();
+ }, false);
+ return;
+ }
+
+ let instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply");
+
+ function observer(aSubject, aTopic, aData) {
+ switch (aTopic) {
+ case "domwindowclosed":
+ // Give the preference window a chance to finish closing before
+ // closing the add-ons manager.
+ waitForFocus(function () {
+ Services.ww.unregisterNotification(observer);
+ run_next_test();
+ });
+ break;
+ case "domwindowopened":
+ let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
+ waitForFocus(function () {
+ // If the openDialog privileges are wrong a new browser window
+ // will open, let the test proceed (and fail) rather than timeout.
+ if (win.location != addon.mAddon.optionsURL &&
+ win.location != "chrome://browser/content/browser.xul")
+ return;
+
+ is(win.location, addon.mAddon.optionsURL,
+ "The correct addon pref window should have opened");
+
+ let chromeFlags = win.QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIWebNavigation).
+ QueryInterface(Ci.nsIDocShellTreeItem).treeOwner.
+ QueryInterface(Ci.nsIInterfaceRequestor).
+ getInterface(Ci.nsIXULWindow).chromeFlags;
+ ok(chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME &&
+ (instantApply || chromeFlags & Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG),
+ "Window was open as a chrome dialog.");
+
+ win.close();
+ }, win);
+ break;
+ }
+ }
+
+ Services.ww.registerNotification(observer);
+ EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_task_next_test.js b/toolkit/mozapps/webextensions/test/browser/browser_task_next_test.js
new file mode 100644
index 000000000..5ff2aff78
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_task_next_test.js
@@ -0,0 +1,17 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Test that we throw if a test created with add_task()
+// calls run_next_test
+
+add_task(function* run_next_throws() {
+ let err = null;
+ try {
+ run_next_test();
+ } catch (e) {
+ err = e;
+ info("run_next_test threw " + err);
+ }
+ ok(err, "run_next_test() should throw an error inside an add_task test");
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_types.js b/toolkit/mozapps/webextensions/test/browser/browser_types.js
new file mode 100644
index 000000000..8abb0ff73
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_types.js
@@ -0,0 +1,473 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that registering new types works
+
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gProvider = {
+};
+
+var gTypes = [
+ new AddonManagerPrivate.AddonType("type1", null, "Type 1",
+ AddonManager.VIEW_TYPE_LIST, 4500),
+ new AddonManagerPrivate.AddonType("missing1", null, "Missing 1"),
+ new AddonManagerPrivate.AddonType("type2", null, "Type 1",
+ AddonManager.VIEW_TYPE_LIST, 5100,
+ AddonManager.TYPE_UI_HIDE_EMPTY),
+ {
+ id: "type3",
+ name: "Type 3",
+ uiPriority: 5200,
+ viewType: AddonManager.VIEW_TYPE_LIST
+ }
+];
+
+function go_back(aManager) {
+ if (gUseInContentUI) {
+ gBrowser.goBack();
+ } else {
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("back-btn"),
+ { }, aManager);
+ }
+}
+
+function go_forward(aManager) {
+ if (gUseInContentUI) {
+ gBrowser.goForward();
+ } else {
+ EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("forward-btn"),
+ { }, aManager);
+ }
+}
+
+function check_state(aManager, canGoBack, canGoForward) {
+ var doc = aManager.document;
+
+ if (gUseInContentUI) {
+ is(gBrowser.canGoBack, canGoBack, "canGoBack should be correct");
+ is(gBrowser.canGoForward, canGoForward, "canGoForward should be correct");
+ }
+
+ if (!is_hidden(doc.getElementById("back-btn"))) {
+ is(!doc.getElementById("back-btn").disabled, canGoBack, "Back button should have the right state");
+ is(!doc.getElementById("forward-btn").disabled, canGoForward, "Forward button should have the right state");
+ }
+}
+
+function test() {
+ waitForExplicitFinish();
+
+ run_next_test();
+}
+
+function end_test() {
+ finish();
+}
+
+// Add a new type, open the manager and make sure it is in the right place
+add_test(function() {
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.get("type2"), "Type 2 should be present");
+ ok(!gCategoryUtilities.get("missing1", true), "Missing 1 should be absent");
+
+ is(gCategoryUtilities.get("type1").previousSibling.getAttribute("value"),
+ "addons://list/extension", "Type 1 should be in the right place");
+ is(gCategoryUtilities.get("type2").previousSibling.getAttribute("value"),
+ "addons://list/theme", "Type 2 should be in the right place");
+
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+ ok(!gCategoryUtilities.isTypeVisible("type2"), "Type 2 should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Select the type, close the manager and remove it then open the manager and
+// check we're back to the default view
+add_test(function() {
+ gCategoryUtilities.openType("type1", function() {
+ close_manager(gManagerWindow, function() {
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should be absent");
+ ok(!gCategoryUtilities.get("type2", true), "Type 2 should be absent");
+ ok(!gCategoryUtilities.get("missing1", true), "Missing 1 should be absent");
+
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be back to the default view");
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+});
+
+// Add a type while the manager is still open and check it appears
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should be absent");
+ ok(!gCategoryUtilities.get("type2", true), "Type 2 should be absent");
+ ok(!gCategoryUtilities.get("missing1", true), "Missing 1 should be absent");
+
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.get("type2"), "Type 2 should be present");
+ ok(!gCategoryUtilities.get("missing1", true), "Missing 1 should be absent");
+
+ is(gCategoryUtilities.get("type1").previousSibling.getAttribute("value"),
+ "addons://list/extension", "Type 1 should be in the right place");
+ is(gCategoryUtilities.get("type2").previousSibling.getAttribute("value"),
+ "addons://list/theme", "Type 2 should be in the right place");
+
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+ ok(!gCategoryUtilities.isTypeVisible("type2"), "Type 2 should be hidden");
+
+ run_next_test();
+ });
+});
+
+// Remove the type while it is beng viewed and check it is replaced with the
+// default view
+add_test(function() {
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("plugin", function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "type1", "Should be showing the custom view");
+ check_state(gManagerWindow, true, true);
+
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should be absent");
+ ok(!gCategoryUtilities.get("type2", true), "Type 2 should be absent");
+ ok(!gCategoryUtilities.get("missing1", true), "Missing 1 should be absent");
+
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be back to the default view");
+ check_state(gManagerWindow, true, true);
+
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be showing the extension view");
+ check_state(gManagerWindow, false, true);
+
+ go_forward(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be back to the default view");
+ check_state(gManagerWindow, true, true);
+
+ go_forward(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "Should be back to the plugins view");
+ check_state(gManagerWindow, true, false);
+
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be back to the default view");
+ check_state(gManagerWindow, true, true);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Test that when going back to a now missing category we skip it
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("plugin", function() {
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be back to the first view");
+ check_state(gManagerWindow, false, true);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Test that when going forward to a now missing category we skip it
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("plugin", function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be back to the extension view");
+
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_forward(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "Should be back to the plugin view");
+ check_state(gManagerWindow, true, false);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Test that when going back to a now missing category and we can't go back any
+// any further then we just display the default view
+add_test(function() {
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ open_manager("addons://list/type1", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "type1", "Should be at the custom view");
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("extension", function() {
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be at the default view");
+ check_state(gManagerWindow, false, true);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+});
+
+// Test that when going forward to a now missing category and we can't go
+// forward any further then we just display the default view
+add_test(function() {
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be at the extension view");
+
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_forward(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be at the default view");
+ check_state(gManagerWindow, true, false);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Test that when going back we skip multiple missing categories
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("type3", function() {
+ gCategoryUtilities.openType("plugin", function() {
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be back to the first view");
+ check_state(gManagerWindow, false, true);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+ });
+});
+
+// Test that when going forward we skip multiple missing categories
+add_test(function() {
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("type3", function() {
+ gCategoryUtilities.openType("plugin", function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ go_back(gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be back to the extension view");
+
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_forward(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "Should be back to the plugin view");
+ check_state(gManagerWindow, true, false);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
+
+// Test that when going back we skip all missing categories and when we can't go
+// back any any further then we just display the default view
+add_test(function() {
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ open_manager("addons://list/type1", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ is(gCategoryUtilities.selectedCategory, "type1", "Should be at the custom view");
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type3", function() {
+ gCategoryUtilities.openType("extension", function() {
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be at the default view");
+ check_state(gManagerWindow, false, true);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+});
+
+// Test that when going forward we skip all missing categories and when we can't
+// go back any any further then we just display the default view
+add_test(function() {
+ AddonManagerPrivate.registerProvider(gProvider, gTypes);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+
+ ok(gCategoryUtilities.get("type1"), "Type 1 should be present");
+ ok(gCategoryUtilities.isTypeVisible("type1"), "Type 1 should be visible");
+
+ gCategoryUtilities.openType("type1", function() {
+ gCategoryUtilities.openType("type3", function() {
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ go_back(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "Should be at the extension view");
+
+ AddonManagerPrivate.unregisterProvider(gProvider);
+
+ ok(!gCategoryUtilities.get("type1", true), "Type 1 should not be present");
+
+ go_forward(gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "discover", "Should be at the default view");
+ check_state(gManagerWindow, true, false);
+
+ close_manager(gManagerWindow, run_next_test);
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_uninstalling.js b/toolkit/mozapps/webextensions/test/browser/browser_uninstalling.js
new file mode 100644
index 000000000..a9329e496
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_uninstalling.js
@@ -0,0 +1,1098 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that searching for add-ons works correctly
+
+var gManagerWindow;
+var gDocument;
+var gCategoryUtilities;
+var gProvider;
+
+function test() {
+ requestLongerTimeout(2);
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Uninstall needs restart",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_UNINSTALL
+ }, {
+ id: "addon2@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 1",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon3@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 2",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon4@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 3",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon5@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 4",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon6@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 5",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon7@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 6",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon8@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 7",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }, {
+ id: "addon9@tests.mozilla.org",
+ name: "Uninstall doesn't need restart 8",
+ type: "extension",
+ operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
+ }]);
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gDocument = gManagerWindow.document;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+function get_item_in_list(aId, aList) {
+ var item = aList.firstChild;
+ while (item) {
+ if ("mAddon" in item && item.mAddon.id == aId) {
+ aList.ensureElementIsVisible(item);
+ return item;
+ }
+ item = item.nextSibling;
+ }
+ return null;
+}
+
+// Tests that uninstalling a normal add-on from the list view can be undone
+add_test(function() {
+ var ID = "addon1@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ ok(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL, "Add-on should require a restart to uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a restartless add-on from the list view can be undone
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(aAddon.isActive, "Add-on should be active");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a disabled restartless add-on from the list view can
+// be undone and doesn't re-enable
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ aAddon.userDisabled = true;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ aAddon.userDisabled = false;
+ ok(aAddon.isActive, "Add-on should be active");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a normal add-on from the search view can be undone
+add_test(function() {
+ var ID = "addon1@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ ok(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL, "Add-on should require a restart to uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a restartless add-on from the search view can be undone
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(aAddon.isActive, "Add-on should be active");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a disabled restartless add-on from the search view can
+// be undone and doesn't re-enable
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ aAddon.userDisabled = true;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ aAddon.userDisabled = false;
+ ok(aAddon.isActive, "Add-on should be active");
+
+ run_next_test();
+ });
+ });
+});
+
+// Tests that uninstalling a normal add-on from the details view switches back
+// to the list view and can be undone
+add_test(function() {
+ var ID = "addon1@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ ok(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL, "Add-on should require a restart to uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(get_current_view(gManagerWindow).id, "detail-view", "Should be in the detail view");
+
+ var button = gDocument.getElementById("detail-uninstall-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ // Force XBL to apply
+ item.clientTop;
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
+
+// Tests that uninstalling a restartless add-on from the details view switches
+// back to the list view and can be undone
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(get_current_view(gManagerWindow).id, "detail-view", "Should be in the detail view");
+
+ var button = gDocument.getElementById("detail-uninstall-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ // Force XBL to apply
+ item.clientTop;
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(aAddon.isActive, "Add-on should be active");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
+
+// Tests that uninstalling a restartless add-on from the details view switches
+// back to the list view and can be undone and doesn't re-enable
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ aAddon.userDisabled = true;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 1 }, gManagerWindow);
+ EventUtils.synthesizeMouseAtCenter(item, { clickCount: 2 }, gManagerWindow);
+ wait_for_view_load(gManagerWindow, function() {
+ is(get_current_view(gManagerWindow).id, "detail-view", "Should be in the detail view");
+
+ var button = gDocument.getElementById("detail-uninstall-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ // Force XBL to apply
+ item.clientTop;
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ ok(!aAddon.isActive, "Add-on should be inactive");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ aAddon.userDisabled = false;
+ ok(aAddon.isActive, "Add-on should be active");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
+
+// Tests that a normal add-on pending uninstall shows up in the list view
+add_test(function() {
+ var ID = "addon1@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ ok(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL, "Add-on should require a restart to uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ gCategoryUtilities.openType("plugin", function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "View should have changed to plugin");
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
+
+// Tests that a normal add-on pending uninstall shows up in the search view
+add_test(function() {
+ var ID = "addon1@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ ok(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL, "Add-on should require a restart to uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ gCategoryUtilities.openType("plugin", function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "View should have changed to plugin");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(!!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should be pending uninstall");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(!button.hidden, "Restart button should not be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+});
+
+// Tests that switching away from the list view finalises the uninstall of
+// multiple restartless add-ons
+add_test(function() {
+ var ID = "addon2@tests.mozilla.org";
+ var ID2 = "addon6@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ item = get_item_in_list(ID2, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ gCategoryUtilities.openType("plugin", function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "View should have changed to extension");
+
+ AddonManager.getAddonsByIDs([ID, ID2], function([aAddon, aAddon2]) {
+ is(aAddon, null, "Add-on should no longer be installed");
+ is(aAddon2, null, "Second add-on should no longer be installed");
+
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ is(item, null, "Should not have found the add-on in the list");
+ item = get_item_in_list(ID2, list);
+ is(item, null, "Should not have found the second add-on in the list");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that switching away from the search view finalises the uninstall of
+// multiple restartless add-ons
+add_test(function() {
+ var ID = "addon3@tests.mozilla.org";
+ var ID2 = "addon7@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ item = get_item_in_list(ID2, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ gCategoryUtilities.openType("plugin", function() {
+ is(gCategoryUtilities.selectedCategory, "plugin", "View should have changed to extension");
+
+ AddonManager.getAddonsByIDs([ID, ID2], function([aAddon, aAddon2]) {
+ is(aAddon, null, "Add-on should no longer be installed");
+ is(aAddon2, null, "Second add-on should no longer be installed");
+
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ var item = get_item_in_list(ID, list);
+ is(item, null, "Should not have found the add-on in the list");
+ item = get_item_in_list(ID2, list);
+ is(item, null, "Should not have found the second add-on in the list");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that closing the manager from the list view finalises the uninstall of
+// multiple restartless add-ons
+add_test(function() {
+ var ID = "addon4@tests.mozilla.org";
+ var ID2 = "addon8@tests.mozilla.org";
+ var list = gDocument.getElementById("addon-list");
+
+ // Select the extensions category
+ gCategoryUtilities.openType("extension", function() {
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ item = get_item_in_list(ID2, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ close_manager(gManagerWindow, function() {
+ AddonManager.getAddonsByIDs([ID, ID2], function([aAddon, aAddon2]) {
+ is(aAddon, null, "Add-on should no longer be installed");
+ is(aAddon2, null, "Second add-on should no longer be installed");
+
+ open_manager(null, function(aWindow) {
+ gManagerWindow = aWindow;
+ gDocument = gManagerWindow.document;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ var list = gDocument.getElementById("addon-list");
+
+ is(gCategoryUtilities.selectedCategory, "extension", "View should have changed to extension");
+
+ var item = get_item_in_list(ID, list);
+ is(item, null, "Should not have found the add-on in the list");
+ item = get_item_in_list(ID2, list);
+ is(item, null, "Should not have found the second add-on in the list");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+});
+
+// Tests that closing the manager from the search view finalises the uninstall
+// of multiple restartless add-ons
+add_test(function() {
+ var ID = "addon5@tests.mozilla.org";
+ var ID2 = "addon9@tests.mozilla.org";
+ var list = gDocument.getElementById("search-list");
+
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ // Make sure to show local add-ons
+ EventUtils.synthesizeMouseAtCenter(gDocument.getElementById("search-filter-local"), { }, gManagerWindow);
+
+ AddonManager.getAddonByID(ID, function(aAddon) {
+ ok(aAddon.isActive, "Add-on should be active");
+ ok(!(aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL), "Add-on should not require a restart to uninstall");
+ ok(!(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL), "Add-on should not be pending uninstall");
+
+ var item = get_item_in_list(ID, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ var button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ // Force XBL to apply
+ item.clientTop;
+
+ is(item.getAttribute("pending"), "uninstall", "Add-on should be uninstalling");
+
+ ok(aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL, "Add-on should be pending uninstall");
+ ok(!aAddon.isActive, "Add-on should be inactive");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "restart-btn");
+ isnot(button, null, "Should have a restart button");
+ ok(button.hidden, "Restart button should be hidden");
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "undo-btn");
+ isnot(button, null, "Should have an undo button");
+
+ item = get_item_in_list(ID2, list);
+ isnot(item, null, "Should have found the add-on in the list");
+
+ button = gDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+ isnot(button, null, "Should have a remove button");
+ ok(!button.disabled, "Button should not be disabled");
+
+ EventUtils.synthesizeMouseAtCenter(button, { }, gManagerWindow);
+
+ close_manager(gManagerWindow, function() {
+ AddonManager.getAddonsByIDs([ID, ID2], function([aAddon, aAddon2]) {
+ is(aAddon, null, "Add-on should no longer be installed");
+ is(aAddon2, null, "Second add-on should no longer be installed");
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gDocument = gManagerWindow.document;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ var list = gDocument.getElementById("search-list");
+ var searchBox = gManagerWindow.document.getElementById("header-search");
+
+ searchBox.value = "Uninstall";
+
+ EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
+ EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
+
+ wait_for_view_load(gManagerWindow, function() {
+ is(gCategoryUtilities.selectedCategory, "search", "View should have changed to search");
+
+ var item = get_item_in_list(ID, list);
+ is(item, null, "Should not have found the add-on in the list");
+ item = get_item_in_list(ID2, list);
+ is(item, null, "Should not have found the second add-on in the list");
+
+ run_next_test();
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_update.js b/toolkit/mozapps/webextensions/test/browser/browser_update.js
new file mode 100644
index 000000000..09ceb1240
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_update.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that updates correctly flush caches and that new files gets updated.
+
+function test() {
+ requestLongerTimeout(2);
+ waitForExplicitFinish();
+
+ Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
+
+ run_next_test();
+}
+
+// Install a first version
+add_test(function() {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_update1_1.xpi",
+ function(aInstall) {
+ aInstall.install();
+ }, "application/x-xpinstall");
+
+ Services.ppmm.addMessageListener("my-addon-1", function messageListener() {
+ Services.ppmm.removeMessageListener("my-addon-1", messageListener);
+ ok(true, "first version sent frame script message");
+ run_next_test();
+ });
+});
+
+// Update to a second version and verify that content gets updated
+add_test(function() {
+ AddonManager.getInstallForURL(TESTROOT + "addons/browser_update1_2.xpi",
+ function(aInstall) {
+ aInstall.install();
+ }, "application/x-xpinstall");
+
+ Services.ppmm.addMessageListener("my-addon-2", function messageListener() {
+ Services.ppmm.removeMessageListener("my-addon-2", messageListener);
+ ok(true, "second version sent frame script message");
+ run_next_test();
+ });
+});
+
+// Finally, cleanup things
+add_test(function() {
+ Services.prefs.setBoolPref("xpinstall.signatures.required", true);
+
+ AddonManager.getAddonByID("update1@tests.mozilla.org", function(aAddon) {
+ aAddon.uninstall();
+
+ finish();
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_updateid.js b/toolkit/mozapps/webextensions/test/browser/browser_updateid.js
new file mode 100644
index 000000000..0fe3eeec5
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_updateid.js
@@ -0,0 +1,84 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that updates that change an add-on's ID show up correctly in the UI
+
+var gProvider;
+var gManagerWindow;
+var gCategoryUtilities;
+
+var gApp = document.getElementById("bundle_brand").getString("brandShortName");
+
+function test() {
+ waitForExplicitFinish();
+
+ gProvider = new MockProvider();
+
+ gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "manually updating addon",
+ version: "1.0",
+ applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
+ }]);
+
+ open_manager("addons://list/extension", function(aWindow) {
+ gManagerWindow = aWindow;
+ gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+ run_next_test();
+ });
+}
+
+function end_test() {
+ close_manager(gManagerWindow, function() {
+ finish();
+ });
+}
+
+add_test(function() {
+ gCategoryUtilities.openType("extension", function() {
+ gProvider.createInstalls([{
+ name: "updated add-on",
+ existingAddon: gProvider.addons[0],
+ version: "2.0"
+ }]);
+ var newAddon = new MockAddon("addon2@tests.mozilla.org");
+ newAddon.name = "updated add-on";
+ newAddon.version = "2.0";
+ newAddon.pendingOperations = AddonManager.PENDING_INSTALL;
+ gProvider.installs[0]._addonToInstall = newAddon;
+
+ var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ var name = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "name");
+ is(name.value, "manually updating addon", "Should show the old name in the list");
+ get_tooltip_info(item).then(({ name, version }) => {
+ is(name, "manually updating addon", "Should show the old name in the tooltip");
+ is(version, "1.0", "Should still show the old version in the tooltip");
+
+ var update = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
+ is_element_visible(update, "Update button should be visible");
+
+ item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+ is(item, null, "Should not show the new version in the list");
+
+ run_next_test();
+ });
+ });
+});
+
+add_test(function() {
+ var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
+ var update = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
+ EventUtils.synthesizeMouseAtCenter(update, { }, gManagerWindow);
+
+ var pending = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "pending");
+ is_element_visible(pending, "Pending message should be visible");
+ is(pending.textContent,
+ get_string("notification.upgrade", "manually updating addon", gApp),
+ "Pending message should be correct");
+
+ item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
+ is(item, null, "Should not show the new version in the list");
+
+ run_next_test();
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_updatessl.js b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.js
new file mode 100644
index 000000000..8b816c927
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.js
@@ -0,0 +1,370 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+var tempScope = {};
+Components.utils.import("resource://gre/modules/addons/AddonUpdateChecker.jsm", tempScope);
+var AddonUpdateChecker = tempScope.AddonUpdateChecker;
+
+const updaterdf = RELATIVE_DIR + "browser_updatessl.rdf";
+const redirect = RELATIVE_DIR + "redirect.sjs?";
+const SUCCESS = 0;
+const DOWNLOAD_ERROR = AddonUpdateChecker.ERROR_DOWNLOAD_ERROR;
+
+const HTTP = "http://example.com/";
+const HTTPS = "https://example.com/";
+const NOCERT = "https://nocert.example.com/";
+const SELFSIGNED = "https://self-signed.example.com/";
+const UNTRUSTED = "https://untrusted.example.com/";
+const EXPIRED = "https://expired.example.com/";
+
+const PREF_UPDATE_REQUIREBUILTINCERTS = "extensions.update.requireBuiltInCerts";
+
+var gTests = [];
+var gStart = 0;
+var gLast = 0;
+
+var HTTPObserver = {
+ observeActivity: function(aChannel, aType, aSubtype, aTimestamp, aSizeData,
+ aStringData) {
+ aChannel.QueryInterface(Ci.nsIChannel);
+
+ dump("*** HTTP Activity 0x" + aType.toString(16) + " 0x" + aSubtype.toString(16) +
+ " " + aChannel.URI.spec + "\n");
+ }
+};
+
+function test() {
+ gStart = Date.now();
+ requestLongerTimeout(4);
+ waitForExplicitFinish();
+
+ let observerService = Cc["@mozilla.org/network/http-activity-distributor;1"].
+ getService(Ci.nsIHttpActivityDistributor);
+ observerService.addObserver(HTTPObserver);
+
+ registerCleanupFunction(function() {
+ observerService.removeObserver(HTTPObserver);
+ });
+
+ run_next_test();
+}
+
+function end_test() {
+ Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+
+ var cos = Cc["@mozilla.org/security/certoverride;1"].
+ getService(Ci.nsICertOverrideService);
+ cos.clearValidityOverride("nocert.example.com", -1);
+ cos.clearValidityOverride("self-signed.example.com", -1);
+ cos.clearValidityOverride("untrusted.example.com", -1);
+ cos.clearValidityOverride("expired.example.com", -1);
+
+ info("All tests completed in " + (Date.now() - gStart) + "ms");
+ finish();
+}
+
+function add_update_test(mainURL, redirectURL, expectedStatus) {
+ gTests.push([mainURL, redirectURL, expectedStatus]);
+}
+
+function run_update_tests(callback) {
+ function run_next_update_test() {
+ if (gTests.length == 0) {
+ callback();
+ return;
+ }
+ gLast = Date.now();
+
+ let [mainURL, redirectURL, expectedStatus] = gTests.shift();
+ if (redirectURL) {
+ var url = mainURL + redirect + redirectURL + updaterdf;
+ var message = "Should have seen the right result for an update check redirected from " +
+ mainURL + " to " + redirectURL;
+ }
+ else {
+ url = mainURL + updaterdf;
+ message = "Should have seen the right result for an update check from " +
+ mainURL;
+ }
+
+ AddonUpdateChecker.checkForUpdates("addon1@tests.mozilla.org",
+ null, url, {
+ onUpdateCheckComplete: function(updates) {
+ is(updates.length, 1, "Should be the right number of results");
+ is(SUCCESS, expectedStatus, message);
+ info("Update test ran in " + (Date.now() - gLast) + "ms");
+ run_next_update_test();
+ },
+
+ onUpdateCheckError: function(status) {
+ is(status, expectedStatus, message);
+ info("Update test ran in " + (Date.now() - gLast) + "ms");
+ run_next_update_test();
+ }
+ });
+ }
+
+ run_next_update_test();
+}
+
+// Add overrides for the bad certificates
+function addCertOverrides() {
+ addCertOverride("nocert.example.com", Ci.nsICertOverrideService.ERROR_MISMATCH);
+ addCertOverride("self-signed.example.com", Ci.nsICertOverrideService.ERROR_UNTRUSTED);
+ addCertOverride("untrusted.example.com", Ci.nsICertOverrideService.ERROR_UNTRUSTED);
+ addCertOverride("expired.example.com", Ci.nsICertOverrideService.ERROR_TIME);
+}
+
+// Runs tests with built-in certificates required and no certificate exceptions.
+add_test(function() {
+ // Tests that a simple update.rdf retrieval works as expected.
+ add_update_test(HTTP, null, SUCCESS);
+ add_update_test(HTTPS, null, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, null, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, null, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, null, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, null, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_update_test(HTTP, HTTP, SUCCESS);
+ add_update_test(HTTP, HTTPS, SUCCESS);
+ add_update_test(HTTP, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(HTTP, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(HTTP, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(HTTP, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_update_test(HTTPS, HTTP, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_update_test(NOCERT, HTTP, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_update_test(SELFSIGNED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_update_test(UNTRUSTED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_update_test(EXPIRED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, EXPIRED, DOWNLOAD_ERROR);
+
+ run_update_tests(run_next_test);
+});
+
+// Runs tests without requiring built-in certificates and no certificate
+// exceptions.
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
+
+ // Tests that a simple update.rdf retrieval works as expected.
+ add_update_test(HTTP, null, SUCCESS);
+ add_update_test(HTTPS, null, SUCCESS);
+ add_update_test(NOCERT, null, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, null, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, null, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, null, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_update_test(HTTP, HTTP, SUCCESS);
+ add_update_test(HTTP, HTTPS, SUCCESS);
+ add_update_test(HTTP, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(HTTP, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(HTTP, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(HTTP, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_update_test(HTTPS, HTTP, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, HTTPS, SUCCESS);
+ add_update_test(HTTPS, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_update_test(NOCERT, HTTP, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_update_test(SELFSIGNED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_update_test(UNTRUSTED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_update_test(EXPIRED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, EXPIRED, DOWNLOAD_ERROR);
+
+ run_update_tests(run_next_test);
+});
+
+// Runs tests with built-in certificates required and all certificate exceptions.
+add_test(function() {
+ Services.prefs.clearUserPref(PREF_UPDATE_REQUIREBUILTINCERTS);
+ addCertOverrides();
+
+ // Tests that a simple update.rdf retrieval works as expected.
+ add_update_test(HTTP, null, SUCCESS);
+ add_update_test(HTTPS, null, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, null, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, null, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, null, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, null, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_update_test(HTTP, HTTP, SUCCESS);
+ add_update_test(HTTP, HTTPS, SUCCESS);
+ add_update_test(HTTP, NOCERT, SUCCESS);
+ add_update_test(HTTP, SELFSIGNED, SUCCESS);
+ add_update_test(HTTP, UNTRUSTED, SUCCESS);
+ add_update_test(HTTP, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_update_test(HTTPS, HTTP, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_update_test(NOCERT, HTTP, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_update_test(SELFSIGNED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_update_test(UNTRUSTED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, EXPIRED, DOWNLOAD_ERROR);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_update_test(EXPIRED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, HTTPS, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, NOCERT, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, SELFSIGNED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, UNTRUSTED, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, EXPIRED, DOWNLOAD_ERROR);
+
+ run_update_tests(run_next_test);
+});
+
+// Runs tests without requiring built-in certificates and all certificate
+// exceptions.
+add_test(function() {
+ Services.prefs.setBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, false);
+
+ // Tests that a simple update.rdf retrieval works as expected.
+ add_update_test(HTTP, null, SUCCESS);
+ add_update_test(HTTPS, null, SUCCESS);
+ add_update_test(NOCERT, null, SUCCESS);
+ add_update_test(SELFSIGNED, null, SUCCESS);
+ add_update_test(UNTRUSTED, null, SUCCESS);
+ add_update_test(EXPIRED, null, SUCCESS);
+
+ // Tests that redirecting from http to other servers works as expected
+ add_update_test(HTTP, HTTP, SUCCESS);
+ add_update_test(HTTP, HTTPS, SUCCESS);
+ add_update_test(HTTP, NOCERT, SUCCESS);
+ add_update_test(HTTP, SELFSIGNED, SUCCESS);
+ add_update_test(HTTP, UNTRUSTED, SUCCESS);
+ add_update_test(HTTP, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from valid https to other servers works as expected
+ add_update_test(HTTPS, HTTP, DOWNLOAD_ERROR);
+ add_update_test(HTTPS, HTTPS, SUCCESS);
+ add_update_test(HTTPS, NOCERT, SUCCESS);
+ add_update_test(HTTPS, SELFSIGNED, SUCCESS);
+ add_update_test(HTTPS, UNTRUSTED, SUCCESS);
+ add_update_test(HTTPS, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from nocert https to other servers works as expected
+ add_update_test(NOCERT, HTTP, DOWNLOAD_ERROR);
+ add_update_test(NOCERT, HTTPS, SUCCESS);
+ add_update_test(NOCERT, NOCERT, SUCCESS);
+ add_update_test(NOCERT, SELFSIGNED, SUCCESS);
+ add_update_test(NOCERT, UNTRUSTED, SUCCESS);
+ add_update_test(NOCERT, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from self-signed https to other servers works as expected
+ add_update_test(SELFSIGNED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(SELFSIGNED, HTTPS, SUCCESS);
+ add_update_test(SELFSIGNED, NOCERT, SUCCESS);
+ add_update_test(SELFSIGNED, SELFSIGNED, SUCCESS);
+ add_update_test(SELFSIGNED, UNTRUSTED, SUCCESS);
+ add_update_test(SELFSIGNED, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from untrusted https to other servers works as expected
+ add_update_test(UNTRUSTED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(UNTRUSTED, HTTPS, SUCCESS);
+ add_update_test(UNTRUSTED, NOCERT, SUCCESS);
+ add_update_test(UNTRUSTED, SELFSIGNED, SUCCESS);
+ add_update_test(UNTRUSTED, UNTRUSTED, SUCCESS);
+ add_update_test(UNTRUSTED, EXPIRED, SUCCESS);
+
+ // Tests that redirecting from expired https to other servers works as expected
+ add_update_test(EXPIRED, HTTP, DOWNLOAD_ERROR);
+ add_update_test(EXPIRED, HTTPS, SUCCESS);
+ add_update_test(EXPIRED, NOCERT, SUCCESS);
+ add_update_test(EXPIRED, SELFSIGNED, SUCCESS);
+ add_update_test(EXPIRED, UNTRUSTED, SUCCESS);
+ add_update_test(EXPIRED, EXPIRED, SUCCESS);
+
+ run_update_tests(run_next_test);
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf
new file mode 100644
index 000000000..f24573847
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:extension:addon1@tests.mozilla.org">
+ <em:updates>
+ <Seq>
+ <li>
+ <Description>
+ <em:version>2.0</em:version>
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>20</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+ </Description>
+ </li>
+ </Seq>
+ </em:updates>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf^headers^ b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf^headers^
new file mode 100644
index 000000000..2e4f8163b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_updatessl.rdf^headers^
@@ -0,0 +1 @@
+Connection: close
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi.js
new file mode 100644
index 000000000..ca8e41aad
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi.js
@@ -0,0 +1,106 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const TESTPAGE = `${SECURE_TESTROOT}webapi_checkavailable.html`;
+
+Services.prefs.setBoolPref("extensions.webapi.testing", true);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webapi.testing");
+});
+
+function testWithAPI(task) {
+ return function*() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, task);
+ }
+}
+
+let gProvider = new MockProvider();
+
+let addons = gProvider.createAddons([{
+ id: "addon1@tests.mozilla.org",
+ name: "Test add-on 1",
+ version: "2.1",
+ description: "Short description",
+ type: "extension",
+ userDisabled: false,
+ isActive: true,
+}, {
+ id: "addon2@tests.mozilla.org",
+ name: "Test add-on 2",
+ version: "5.3.7ab",
+ description: null,
+ type: "theme",
+ userDisabled: false,
+ isActive: false,
+}, {
+ id: "addon3@tests.mozilla.org",
+ name: "Test add-on 3",
+ version: "1",
+ description: "Longer description",
+ type: "extension",
+ userDisabled: true,
+ isActive: false,
+}, {
+ id: "addon4@tests.mozilla.org",
+ name: "Test add-on 4",
+ version: "1",
+ description: "Longer description",
+ type: "extension",
+ userDisabled: false,
+ isActive: true,
+}]);
+
+addons[3].permissions &= ~AddonManager.PERM_CAN_UNINSTALL;
+
+function API_getAddonByID(browser, id) {
+ return ContentTask.spawn(browser, id, function*(id) {
+ let addon = yield content.navigator.mozAddonManager.getAddonByID(id);
+
+ // We can't send native objects back so clone its properties.
+ let result = {};
+ for (let prop in addon) {
+ result[prop] = addon[prop];
+ }
+
+ return result;
+ });
+}
+
+add_task(testWithAPI(function*(browser) {
+ function compareObjects(web, real) {
+ for (let prop of Object.keys(web)) {
+ let webVal = web[prop];
+ let realVal = real[prop];
+
+ switch (prop) {
+ case "isEnabled":
+ realVal = !real.userDisabled;
+ break;
+
+ case "canUninstall":
+ realVal = Boolean(real.permissions & AddonManager.PERM_CAN_UNINSTALL);
+ break;
+ }
+
+ // null and undefined don't compare well so stringify them first
+ if (realVal === null || realVal === undefined) {
+ realVal = `${realVal}`;
+ webVal = `${webVal}`;
+ }
+
+ is(webVal, realVal, `Property ${prop} should have the right value in add-on ${real.id}`);
+ }
+ }
+
+ let [a1, a2, a3] = yield promiseAddonsByIDs(["addon1@tests.mozilla.org",
+ "addon2@tests.mozilla.org",
+ "addon3@tests.mozilla.org"]);
+ let w1 = yield API_getAddonByID(browser, "addon1@tests.mozilla.org");
+ let w2 = yield API_getAddonByID(browser, "addon2@tests.mozilla.org");
+ let w3 = yield API_getAddonByID(browser, "addon3@tests.mozilla.org");
+
+ compareObjects(w1, a1);
+ compareObjects(w2, a2);
+ compareObjects(w3, a3);
+}));
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi_access.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi_access.js
new file mode 100644
index 000000000..f4b1dc745
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi_access.js
@@ -0,0 +1,127 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webapi.testing");
+});
+
+function check_frame_availability(browser) {
+ return ContentTask.spawn(browser, null, function*() {
+ let frame = content.document.getElementById("frame");
+ return frame.contentWindow.document.getElementById("result").textContent == "true";
+ });
+}
+
+function check_availability(browser) {
+ return ContentTask.spawn(browser, null, function*() {
+ return content.document.getElementById("result").textContent == "true";
+ });
+}
+
+// Test that initially the API isn't available in the test domain
+add_task(function* test_not_available() {
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT}webapi_checkavailable.html`,
+ function* test_not_available(browser) {
+ let available = yield check_availability(browser);
+ ok(!available, "API should not be available.");
+ })
+});
+
+// Test that with testing on the API is available in the test domain
+add_task(function* test_available() {
+ Services.prefs.setBoolPref("extensions.webapi.testing", true);
+
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT}webapi_checkavailable.html`,
+ function* test_not_available(browser) {
+ let available = yield check_availability(browser);
+ ok(available, "API should be available.");
+ })
+});
+
+// Test that the API is not available in a bad domain
+add_task(function* test_bad_domain() {
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT2}webapi_checkavailable.html`,
+ function* test_not_available(browser) {
+ let available = yield check_availability(browser);
+ ok(!available, "API should not be available.");
+ })
+});
+
+// Test that the API is only available in https sites
+add_task(function* test_not_available_http() {
+ yield BrowserTestUtils.withNewTab(`${TESTROOT}webapi_checkavailable.html`,
+ function* test_not_available(browser) {
+ let available = yield check_availability(browser);
+ ok(!available, "API should not be available.");
+ })
+});
+
+// Test that the API is available when in a frame of the test domain
+add_task(function* test_available_framed() {
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT}webapi_checkframed.html`,
+ function* test_available(browser) {
+ let available = yield check_frame_availability(browser);
+ ok(available, "API should be available.");
+ })
+});
+
+// Test that if the external frame is http then the inner frame doesn't have
+// the API
+add_task(function* test_not_available_http_framed() {
+ yield BrowserTestUtils.withNewTab(`${TESTROOT}webapi_checkframed.html`,
+ function* test_not_available(browser) {
+ let available = yield check_frame_availability(browser);
+ ok(!available, "API should not be available.");
+ })
+});
+
+// Test that if the external frame is a bad domain then the inner frame doesn't
+// have the API
+add_task(function* test_not_available_framed() {
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT2}webapi_checkframed.html`,
+ function* test_not_available(browser) {
+ let available = yield check_frame_availability(browser);
+ ok(!available, "API should not be available.");
+ })
+});
+
+// Test that a window navigated to a bad domain doesn't allow access to the API
+add_task(function* test_navigated_window() {
+ yield BrowserTestUtils.withNewTab(`${SECURE_TESTROOT2}webapi_checknavigatedwindow.html`,
+ function* test_available(browser) {
+ let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser);
+
+ yield ContentTask.spawn(browser, null, function*() {
+ yield content.wrappedJSObject.openWindow();
+ });
+
+ // Should be a new tab open
+ let tab = yield tabPromise;
+ let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab));
+
+ ContentTask.spawn(browser, null, function*() {
+ content.wrappedJSObject.navigate();
+ });
+
+ yield loadPromise;
+
+ let available = yield ContentTask.spawn(browser, null, function*() {
+ return content.wrappedJSObject.check();
+ });
+
+ ok(!available, "API should not be available.");
+
+ gBrowser.removeTab(tab);
+ })
+});
+
+// Check that if a page is embedded in a chrome content UI that it can still
+// access the API.
+add_task(function* test_chrome_frame() {
+ yield BrowserTestUtils.withNewTab(`${CHROMEROOT}webapi_checkchromeframe.xul`,
+ function* test_available(browser) {
+ let available = yield check_frame_availability(browser);
+ ok(available, "API should be available.");
+ })
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi_addon_listener.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi_addon_listener.js
new file mode 100644
index 000000000..b8049f13c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi_addon_listener.js
@@ -0,0 +1,174 @@
+const TESTPAGE = `${SECURE_TESTROOT}webapi_addon_listener.html`;
+
+Services.prefs.setBoolPref("extensions.webapi.testing", true);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webapi.testing");
+});
+
+
+function* getListenerEvents(browser) {
+ let result = yield ContentTask.spawn(browser, null, function*() {
+ return content.document.getElementById("result").textContent;
+ });
+
+ return result.split('\n').map(JSON.parse);
+}
+
+const RESTART_ID = "restart@tests.mozilla.org";
+const RESTART_DISABLED_ID = "restart_disabled@tests.mozilla.org";
+const RESTARTLESS_ID = "restartless@tests.mozilla.org";
+const INSTALL_ID = "install@tests.mozilla.org";
+const CANCEL_ID = "cancel@tests.mozilla.org";
+
+let provider = new MockProvider(false);
+provider.createAddons([
+ {
+ id: RESTART_ID,
+ name: "Add-on that requires restart",
+ },
+ {
+ id: RESTART_DISABLED_ID,
+ name: "Disabled add-on that requires restart",
+ userDisabled: true,
+ },
+ {
+ id: RESTARTLESS_ID,
+ name: "Restartless add-on",
+ operationsRequiringRestart: AddonManager.OP_NEED_RESTART_NONE,
+ },
+ {
+ id: CANCEL_ID,
+ name: "Add-on for uninstall cancel",
+ },
+]);
+
+// Test disable of add-on requiring restart
+add_task(function* test_disable() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(RESTART_ID);
+ is(addon.userDisabled, false, "addon is enabled");
+
+ // disable it
+ addon.userDisabled = true;
+ is(addon.userDisabled, true, "addon was disabled successfully");
+
+ let events = yield getListenerEvents(browser);
+
+ // Just a single onDisabling since restart is needed to complete
+ let expected = [
+ {id: RESTART_ID, needsRestart: true, event: "onDisabling"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected disable event");
+ });
+});
+
+// Test enable of add-on requiring restart
+add_task(function* test_enable() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(RESTART_DISABLED_ID);
+ is(addon.userDisabled, true, "addon is disabled");
+
+ // enable it
+ addon.userDisabled = false;
+ is(addon.userDisabled, false, "addon was enabled successfully");
+
+ let events = yield getListenerEvents(browser);
+
+ // Just a single onEnabling since restart is needed to complete
+ let expected = [
+ {id: RESTART_DISABLED_ID, needsRestart: true, event: "onEnabling"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected enable event");
+ });
+});
+
+// Test enable/disable events for restartless
+add_task(function* test_restartless() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(RESTARTLESS_ID);
+ is(addon.userDisabled, false, "addon is enabled");
+
+ // disable it
+ addon.userDisabled = true;
+ is(addon.userDisabled, true, "addon was disabled successfully");
+
+ // re-enable it
+ addon.userDisabled = false;
+ is(addon.userDisabled, false, "addon was re-enabled successfuly");
+
+ let events = yield getListenerEvents(browser);
+ let expected = [
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onDisabling"},
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onDisabled"},
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onEnabling"},
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onEnabled"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected disable/enable events");
+ });
+});
+
+// Test install events
+add_task(function* test_restartless() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = new MockAddon(INSTALL_ID, "installme", null,
+ AddonManager.OP_NEED_RESTART_NONE);
+ let install = new MockInstall(null, null, addon);
+
+ let installPromise = new Promise(resolve => {
+ install.addTestListener({
+ onInstallEnded: resolve,
+ });
+ });
+
+ provider.addInstall(install);
+ install.install();
+
+ yield installPromise;
+
+ let events = yield getListenerEvents(browser);
+ let expected = [
+ {id: INSTALL_ID, needsRestart: false, event: "onInstalling"},
+ {id: INSTALL_ID, needsRestart: false, event: "onInstalled"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected install events");
+ });
+});
+
+// Test uninstall
+add_task(function* test_uninstall() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(RESTARTLESS_ID);
+ isnot(addon, null, "Found add-on for uninstall");
+
+ addon.uninstall();
+
+ let events = yield getListenerEvents(browser);
+ let expected = [
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onUninstalling"},
+ {id: RESTARTLESS_ID, needsRestart: false, event: "onUninstalled"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected uninstall events");
+ });
+});
+
+// Test cancel of uninstall.
+add_task(function* test_cancel() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(CANCEL_ID);
+ isnot(addon, null, "Found add-on for cancelling uninstall");
+
+ addon.uninstall();
+
+ let events = yield getListenerEvents(browser);
+ let expected = [
+ {id: CANCEL_ID, needsRestart: true, event: "onUninstalling"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected uninstalling event");
+
+ addon.cancelUninstall();
+ events = yield getListenerEvents(browser);
+ expected.push({id: CANCEL_ID, needsRestart: false, event: "onOperationCancelled"});
+ Assert.deepEqual(events, expected, "Got expected cancel event");
+ });
+});
+
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi_enable.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi_enable.js
new file mode 100644
index 000000000..27d8029c5
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi_enable.js
@@ -0,0 +1,62 @@
+const TESTPAGE = `${SECURE_TESTROOT}webapi_addon_listener.html`;
+
+Services.prefs.setBoolPref("extensions.webapi.testing", true);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webapi.testing");
+});
+
+function* getListenerEvents(browser) {
+ let result = yield ContentTask.spawn(browser, null, function*() {
+ return content.document.getElementById("result").textContent;
+ });
+
+ return result.split('\n').map(JSON.parse);
+}
+
+const ID = "test@tests.mozilla.org";
+
+let provider = new MockProvider(false);
+provider.createAddons([
+ {
+ id: ID,
+ name: "Test add-on",
+ operationsRequiringRestart: AddonManager.OP_NEED_RESTART_NONE,
+ },
+]);
+
+// Test disable and enable from content
+add_task(function* () {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, function*(browser) {
+ let addon = yield promiseAddonByID(ID);
+ isnot(addon, null, "Test addon exists");
+ is(addon.userDisabled, false, "addon is enabled");
+
+ // Disable the addon from content.
+ yield ContentTask.spawn(browser, null, function* () {
+ return content.navigator.mozAddonManager
+ .getAddonByID("test@tests.mozilla.org")
+ .then(addon => { addon.setEnabled(false); });
+ });
+
+ let events = yield getListenerEvents(browser);
+ let expected = [
+ {id: ID, needsRestart: false, event: "onDisabling"},
+ {id: ID, needsRestart: false, event: "onDisabled"},
+ ];
+ Assert.deepEqual(events, expected, "Got expected disable events");
+
+ // Enable the addon from content.
+ yield ContentTask.spawn(browser, null, function* () {
+ return content.navigator.mozAddonManager
+ .getAddonByID("test@tests.mozilla.org")
+ .then(addon => { addon.setEnabled(true); });
+ });
+
+ events = yield getListenerEvents(browser);
+ expected = expected.concat([
+ {id: ID, needsRestart: false, event: "onEnabling"},
+ {id: ID, needsRestart: false, event: "onEnabled"},
+ ]);
+ Assert.deepEqual(events, expected, "Got expected enable events");
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi_install.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi_install.js
new file mode 100644
index 000000000..bc31c2331
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi_install.js
@@ -0,0 +1,311 @@
+const TESTPAGE = `${SECURE_TESTROOT}webapi_checkavailable.html`;
+const XPI_URL = `${SECURE_TESTROOT}addons/browser_webapi_install.xpi`;
+const XPI_SHA = "sha256:d4bab17ff9ba5f635e97c84021f4c527c502250d62ab7f6e6c9e8ee28822f772";
+
+const ID = "webapi_install@tests.mozilla.org";
+// eh, would be good to just stat the real file instead of this...
+const XPI_LEN = 4782;
+
+function waitForClear() {
+ const MSG = "WebAPICleanup";
+ return new Promise(resolve => {
+ let listener = {
+ receiveMessage: function(msg) {
+ if (msg.name == MSG) {
+ Services.mm.removeMessageListener(MSG, listener);
+ resolve();
+ }
+ }
+ };
+
+ Services.mm.addMessageListener(MSG, listener, true);
+ });
+}
+
+add_task(function* setup() {
+ yield SpecialPowers.pushPrefEnv({
+ set: [["extensions.webapi.testing", true],
+ ["extensions.install.requireBuiltInCerts", false]],
+ });
+ info("added preferences");
+});
+
+// Wrapper around a common task to run in the content process to test
+// the mozAddonManager API. Takes a URL for the XPI to install and an
+// array of steps, each of which can either be an action to take
+// (i.e., start or cancel the install) or an install event to wait for.
+// Steps that look for a specific event may also include a "props" property
+// with properties that the AddonInstall object is expected to have when
+// that event is triggered.
+function* testInstall(browser, args, steps, description) {
+ let success = yield ContentTask.spawn(browser, {args, steps}, function* (opts) {
+ let { args, steps } = opts;
+ let install = yield content.navigator.mozAddonManager.createInstall(args);
+ if (!install) {
+ yield Promise.reject("createInstall() did not return an install object");
+ }
+
+ // Check that the initial state of the AddonInstall is sane.
+ if (install.state != "STATE_AVAILABLE") {
+ yield Promise.reject("new install should be in STATE_AVAILABLE");
+ }
+ if (install.error != null) {
+ yield Promise.reject("new install should have null error");
+ }
+
+ const events = [
+ "onDownloadStarted",
+ "onDownloadProgress",
+ "onDownloadEnded",
+ "onDownloadCancelled",
+ "onDownloadFailed",
+ "onInstallStarted",
+ "onInstallEnded",
+ "onInstallCancelled",
+ "onInstallFailed",
+ ];
+ let eventWaiter = null;
+ let receivedEvents = [];
+ let prevEvent = null;
+ events.forEach(event => {
+ install.addEventListener(event, e => {
+ receivedEvents.push({
+ event,
+ state: install.state,
+ error: install.error,
+ progress: install.progress,
+ maxProgress: install.maxProgress,
+ });
+ if (eventWaiter) {
+ eventWaiter();
+ }
+ });
+ });
+
+ // Returns a promise that is resolved when the given event occurs
+ // or rejects if a different event comes first or if props is supplied
+ // and properties on the AddonInstall don't match those in props.
+ function expectEvent(event, props) {
+ return new Promise((resolve, reject) => {
+ function check() {
+ let received = receivedEvents.shift();
+ // Skip any repeated onDownloadProgress events.
+ while (received &&
+ received.event == prevEvent &&
+ prevEvent == "onDownloadProgress") {
+ received = receivedEvents.shift();
+ }
+ // Wait for more events if we skipped all there were.
+ if (!received) {
+ eventWaiter = () => {
+ eventWaiter = null;
+ check();
+ }
+ return;
+ }
+ prevEvent = received.event;
+ if (received.event != event) {
+ let err = new Error(`expected ${event} but got ${received.event}`);
+ reject(err);
+ }
+ if (props) {
+ for (let key of Object.keys(props)) {
+ if (received[key] != props[key]) {
+ throw new Error(`AddonInstall property ${key} was ${received[key]} but expected ${props[key]}`);
+ }
+ }
+ }
+ resolve();
+ }
+ check();
+ });
+ }
+
+ while (steps.length > 0) {
+ let nextStep = steps.shift();
+ if (nextStep.action) {
+ if (nextStep.action == "install") {
+ yield install.install();
+ } else if (nextStep.action == "cancel") {
+ yield install.cancel();
+ } else {
+ throw new Error(`unknown action ${nextStep.action}`);
+ }
+ } else {
+ yield expectEvent(nextStep.event, nextStep.props);
+ }
+ }
+
+ return true;
+ });
+
+ is(success, true, description);
+}
+
+function makeInstallTest(task) {
+ return function*() {
+ // withNewTab() will close the test tab before returning, at which point
+ // the cleanup event will come from the content process. We need to see
+ // that event but don't want to race to install a listener for it after
+ // the tab is closed. So set up the listener now but don't yield the
+ // listening promise until below.
+ let clearPromise = waitForClear();
+
+ yield BrowserTestUtils.withNewTab(TESTPAGE, task);
+
+ yield clearPromise;
+ is(AddonManager.webAPI.installs.size, 0, "AddonInstall was cleaned up");
+ };
+}
+
+function makeRegularTest(options, what) {
+ return makeInstallTest(function* (browser) {
+ let steps = [
+ {action: "install"},
+ {
+ event: "onDownloadStarted",
+ props: {state: "STATE_DOWNLOADING"},
+ },
+ {
+ event: "onDownloadProgress",
+ props: {maxProgress: XPI_LEN},
+ },
+ {
+ event: "onDownloadEnded",
+ props: {
+ state: "STATE_DOWNLOADED",
+ progress: XPI_LEN,
+ maxProgress: XPI_LEN,
+ },
+ },
+ {
+ event: "onInstallStarted",
+ props: {state: "STATE_INSTALLING"},
+ },
+ {
+ event: "onInstallEnded",
+ props: {state: "STATE_INSTALLED"},
+ },
+ ];
+
+ yield testInstall(browser, options, steps, what);
+
+ let version = Services.prefs.getIntPref("webapitest.active_version");
+ is(version, 1, "the install really did work");
+
+ // Sanity check to ensure that the test in makeInstallTest() that
+ // installs.size == 0 means we actually did clean up.
+ ok(AddonManager.webAPI.installs.size > 0, "webAPI is tracking the AddonInstall");
+
+ let addons = yield promiseAddonsByIDs([ID]);
+ isnot(addons[0], null, "Found the addon");
+
+ yield addons[0].uninstall();
+
+ addons = yield promiseAddonsByIDs([ID]);
+ is(addons[0], null, "Addon was uninstalled");
+ });
+}
+
+add_task(makeRegularTest({url: XPI_URL}, "a basic install works"));
+add_task(makeRegularTest({url: XPI_URL, hash: null}, "install with hash=null works"));
+add_task(makeRegularTest({url: XPI_URL, hash: ""}, "install with empty string for hash works"));
+add_task(makeRegularTest({url: XPI_URL, hash: XPI_SHA}, "install with hash works"));
+
+add_task(makeInstallTest(function* (browser) {
+ let steps = [
+ {action: "cancel"},
+ {
+ event: "onDownloadCancelled",
+ props: {
+ state: "STATE_CANCELLED",
+ error: null,
+ },
+ }
+ ];
+
+ yield testInstall(browser, {url: XPI_URL}, steps, "canceling an install works");
+
+ let addons = yield promiseAddonsByIDs([ID]);
+ is(addons[0], null, "The addon was not installed");
+
+ ok(AddonManager.webAPI.installs.size > 0, "webAPI is tracking the AddonInstall");
+}));
+
+add_task(makeInstallTest(function* (browser) {
+ let steps = [
+ {action: "install"},
+ {
+ event: "onDownloadStarted",
+ props: {state: "STATE_DOWNLOADING"},
+ },
+ {event: "onDownloadProgress"},
+ {
+ event: "onDownloadFailed",
+ props: {
+ state: "STATE_DOWNLOAD_FAILED",
+ error: "ERROR_NETWORK_FAILURE",
+ },
+ }
+ ];
+
+ yield testInstall(browser, {url: XPI_URL + "bogus"}, steps, "install of a bad url fails");
+
+ let addons = yield promiseAddonsByIDs([ID]);
+ is(addons[0], null, "The addon was not installed");
+
+ ok(AddonManager.webAPI.installs.size > 0, "webAPI is tracking the AddonInstall");
+}));
+
+add_task(makeInstallTest(function* (browser) {
+ let steps = [
+ {action: "install"},
+ {
+ event: "onDownloadStarted",
+ props: {state: "STATE_DOWNLOADING"},
+ },
+ {event: "onDownloadProgress"},
+ {
+ event: "onDownloadFailed",
+ props: {
+ state: "STATE_DOWNLOAD_FAILED",
+ error: "ERROR_INCORRECT_HASH",
+ },
+ }
+ ];
+
+ yield testInstall(browser, {url: XPI_URL, hash: "sha256:bogus"}, steps, "install with bad hash fails");
+
+ let addons = yield promiseAddonsByIDs([ID]);
+ is(addons[0], null, "The addon was not installed");
+
+ ok(AddonManager.webAPI.installs.size > 0, "webAPI is tracking the AddonInstall");
+}));
+
+add_task(function* test_permissions() {
+ function testBadUrl(url, pattern, successMessage) {
+ return BrowserTestUtils.withNewTab(TESTPAGE, function* (browser) {
+ let result = yield ContentTask.spawn(browser, {url, pattern}, function (opts) {
+ return new Promise(resolve => {
+ content.navigator.mozAddonManager.createInstall({url: opts.url})
+ .then(() => {
+ resolve({success: false, message: "createInstall should not have succeeded"});
+ }, err => {
+ if (err.message.match(new RegExp(opts.pattern))) {
+ resolve({success: true});
+ }
+ resolve({success: false, message: `Wrong error message: ${err.message}`});
+ });
+ });
+ });
+ is(result.success, true, result.message || successMessage);
+ });
+ }
+
+ yield testBadUrl("i am not a url", "NS_ERROR_MALFORMED_URI",
+ "Installing from an unparseable URL fails");
+
+ yield testBadUrl("https://addons.not-really-mozilla.org/impostor.xpi",
+ "not permitted",
+ "Installing from non-approved URL fails");
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webapi_uninstall.js b/toolkit/mozapps/webextensions/test/browser/browser_webapi_uninstall.js
new file mode 100644
index 000000000..724f6fefe
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webapi_uninstall.js
@@ -0,0 +1,51 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const TESTPAGE = `${SECURE_TESTROOT}webapi_checkavailable.html`;
+
+Services.prefs.setBoolPref("extensions.webapi.testing", true);
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webapi.testing");
+});
+
+function testWithAPI(task) {
+ return function*() {
+ yield BrowserTestUtils.withNewTab(TESTPAGE, task);
+ }
+}
+
+function API_uninstallByID(browser, id) {
+ return ContentTask.spawn(browser, id, function*(id) {
+ let addon = yield content.navigator.mozAddonManager.getAddonByID(id);
+
+ let result = yield addon.uninstall();
+ return result;
+ });
+}
+
+add_task(testWithAPI(function*(browser) {
+ const ID1 = "addon1@tests.mozilla.org";
+ const ID2 = "addon2@tests.mozilla.org";
+
+ let provider = new MockProvider();
+
+ provider.addAddon(new MockAddon(ID1, "Test add-on 1", "extension", 0));
+ provider.addAddon(new MockAddon(ID2, "Test add-on 2", "extension", 0));
+
+ let [a1, a2] = yield promiseAddonsByIDs([ID1, ID2]);
+ isnot(a1, null, "addon1 is installed");
+ isnot(a2, null, "addon2 is installed");
+
+ let result = yield API_uninstallByID(browser, ID1);
+ is(result, true, "uninstall of addon1 succeeded");
+
+ [a1, a2] = yield promiseAddonsByIDs([ID1, ID2]);
+ is(a1, null, "addon1 is uninstalled");
+ isnot(a2, null, "addon2 is still installed");
+
+ result = yield API_uninstallByID(browser, ID2);
+ is(result, true, "uninstall of addon2 succeeded");
+ [a2] = yield promiseAddonsByIDs([ID2]);
+ is(a2, null, "addon2 is uninstalled");
+}));
diff --git a/toolkit/mozapps/webextensions/test/browser/browser_webext_options.js b/toolkit/mozapps/webextensions/test/browser/browser_webext_options.js
new file mode 100644
index 000000000..b13213f0b
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/browser_webext_options.js
@@ -0,0 +1,70 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Wrapper to run a test that consists of:
+// 1. opening the add-ons manager viewing the list of extensions
+// 2. installing an extension (using the provider installer callable)
+// 3. opening the preferences panel for the new extension and verifying
+// that it opens cleanly
+function* runTest(installer) {
+ let mgrWindow = yield open_manager("addons://list/extension");
+
+ let {addon, id} = yield* installer();
+ isnot(addon, null, "Extension is installed");
+
+ let element = get_addon_element(mgrWindow, id);
+ element.parentNode.ensureElementIsVisible(element);
+
+ let button = mgrWindow.document.getAnonymousElementByAttribute(element, "anonid", "preferences-btn");
+ is_element_visible(button, "Preferences button should be visible");
+
+ EventUtils.synthesizeMouseAtCenter(button, {clickCount: 1}, mgrWindow);
+
+ yield TestUtils.topicObserved(AddonManager.OPTIONS_NOTIFICATION_DISPLAYED,
+ (subject, data) => data == id);
+
+ is(mgrWindow.gViewController.currentViewId,
+ `addons://detail/${encodeURIComponent(id)}/preferences`,
+ "Current view should scroll to preferences");
+
+ var browser = mgrWindow.document.querySelector("#detail-grid > rows > .inline-options-browser");
+ var rows = browser.parentNode;
+
+ ok(browser, "Grid should have a browser child");
+ is(browser.localName, "browser", "Grid should have a browser child");
+ is(browser.currentURI.spec, element.mAddon.optionsURL, "Browser has the expected options URL loaded")
+
+ is(browser.clientWidth, rows.clientWidth,
+ "Browser should be the same width as its parent node");
+
+ button = mgrWindow.document.getElementById("detail-prefs-btn");
+ is_element_hidden(button, "Preferences button should not be visible");
+
+ yield close_manager(mgrWindow);
+
+ addon.uninstall();
+}
+
+// Test that deferred handling of optionsURL works for a signed webextension
+add_task(function* test_options_signed() {
+ yield* runTest(function*() {
+ // The extension in-tree is signed with this ID:
+ const ID = "{9792932b-32b2-4567-998c-e7bf6c4c5e35}";
+
+ yield install_addon("addons/options_signed.xpi");
+ let addon = yield promiseAddonByID(ID);
+
+ return {addon, id: ID};
+ });
+});
+
+add_task(function* test_options_temporary() {
+ yield* runTest(function*() {
+ let dir = get_addon_file_url("options_signed").file;
+ let addon = yield AddonManager.installTemporaryAddon(dir);
+ isnot(addon, null, "Extension is installed (temporarily)");
+
+ return {addon, id: addon.id};
+ });
+});
diff --git a/toolkit/mozapps/webextensions/test/browser/cancelCompatCheck.sjs b/toolkit/mozapps/webextensions/test/browser/cancelCompatCheck.sjs
new file mode 100644
index 000000000..38bc25d08
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/cancelCompatCheck.sjs
@@ -0,0 +1,43 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Delay before responding to an HTTP call attempting to read
+// an addon update RDF file
+
+function handleRequest(req, resp) {
+ resp.processAsync();
+ resp.setHeader("Cache-Control", "no-cache, no-store", false);
+ resp.setHeader("Content-Type", "text/xml;charset=utf-8", false);
+
+ let file = null;
+ getObjectState("SERVER_ROOT", function(serverRoot)
+ {
+ file = serverRoot.getFile("browser/toolkit/mozapps/extensions/test/browser/browser_bug557956.rdf");
+ });
+ dump("*** cancelCompatCheck.sjs: " + file.path + "\n");
+ let fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
+ createInstance(Components.interfaces.nsIFileInputStream);
+ fstream.init(file, -1, 0, 0);
+ let cstream = null;
+ cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
+ createInstance(Components.interfaces.nsIConverterInputStream);
+ cstream.init(fstream, "UTF-8", 0, 0);
+
+ // The delay can be passed on the query string
+ let delay = req.queryString + 0;
+
+ timer = Components.classes["@mozilla.org/timer;1"].
+ createInstance(Components.interfaces.nsITimer);
+ timer.init(function sendFile() {
+ dump("cancelCompatCheck: starting to send file\n");
+ let str = {};
+ let read = 0;
+ do {
+ // read as much as we can and put it in str.value
+ read = cstream.readString(0xffffffff, str);
+ resp.write(str.value);
+ } while (read != 0);
+ cstream.close();
+ resp.finish();
+ }, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/discovery.html b/toolkit/mozapps/webextensions/test/browser/discovery.html
new file mode 100644
index 000000000..72f4fe374
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/discovery.html
@@ -0,0 +1,10 @@
+<html>
+<body>
+ <h1>Test page for the discovery pane</h1>
+ <p><a id="link-normal" href="https://example.com/browser/toolkit/mozapps/extensions/test/browser/discovery.html">Load normal</a></p>
+ <p><a id="link-http" href="http://example.com/browser/toolkit/mozapps/extensions/test/browser/discovery.html">Load insecure</a></p>
+ <p><a id="link-domain" href="https://test1.example.com/browser/toolkit/mozapps/extensions/test/browser/discovery.html">Load other domain</a></p>
+ <p><a id="link-bad" href="https://example.com/browser/toolkit/mozapps/extensions/test/browser/foo.html">Load missing page</a></p>
+ <p><a id="link-good" href="https://example.com/browser/toolkit/mozapps/extensions/test/browser/releaseNotes.xhtml">Load other page</a></p>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/discovery_frame.html b/toolkit/mozapps/webextensions/test/browser/discovery_frame.html
new file mode 100644
index 000000000..8ec722812
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/discovery_frame.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+
+<html>
+<body>
+<iframe id="frame" width="100%" height="100%" src="https://example.com/browser/toolkit/mozapps/extensions/test/browser/discovery_install.html"></iframe>
+</body>
diff --git a/toolkit/mozapps/webextensions/test/browser/discovery_install.html b/toolkit/mozapps/webextensions/test/browser/discovery_install.html
new file mode 100644
index 000000000..c6499ec03
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/discovery_install.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+<script type="text/javascript">
+/* globals InstallTrigger */
+function install() {
+ InstallTrigger.install({
+ "Test Add-on": {
+ URL: "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi"
+ }
+ });
+}
+</script>
+</head>
+<body>
+ <h1>Test page for the discovery pane</h1>
+ <p><a id="install-direct" href="https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi">Direct install</a></p>
+ <p><a id="install-js" href="javascript:install()">JS install</a></p>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/head.js b/toolkit/mozapps/webextensions/test/browser/head.js
new file mode 100644
index 000000000..5a749099d
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/head.js
@@ -0,0 +1,1468 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+/* globals end_test*/
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
+var tmp = {};
+Components.utils.import("resource://gre/modules/AddonManager.jsm", tmp);
+Components.utils.import("resource://gre/modules/Log.jsm", tmp);
+var AddonManager = tmp.AddonManager;
+var AddonManagerPrivate = tmp.AddonManagerPrivate;
+var Log = tmp.Log;
+
+var pathParts = gTestPath.split("/");
+// Drop the test filename
+pathParts.splice(pathParts.length - 1, pathParts.length);
+
+var gTestInWindow = /-window$/.test(pathParts[pathParts.length - 1]);
+
+// Drop the UI type
+if (gTestInWindow) {
+ pathParts.splice(pathParts.length - 1, pathParts.length);
+}
+
+const RELATIVE_DIR = pathParts.slice(4).join("/") + "/";
+
+const TESTROOT = "http://example.com/" + RELATIVE_DIR;
+const SECURE_TESTROOT = "https://example.com/" + RELATIVE_DIR;
+const TESTROOT2 = "http://example.org/" + RELATIVE_DIR;
+const SECURE_TESTROOT2 = "https://example.org/" + RELATIVE_DIR;
+const CHROMEROOT = pathParts.join("/") + "/";
+const PREF_DISCOVERURL = "extensions.webservice.discoverURL";
+const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane";
+const PREF_XPI_ENABLED = "xpinstall.enabled";
+const PREF_UPDATEURL = "extensions.update.url";
+const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
+const PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI = "xpinstall.customConfirmationUI";
+const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory";
+
+const MANAGER_URI = "about:addons";
+const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
+const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
+const PREF_SEARCH_MAXRESULTS = "extensions.getAddons.maxResults";
+const PREF_STRICT_COMPAT = "extensions.strictCompatibility";
+
+var PREF_CHECK_COMPATIBILITY;
+(function() {
+ var channel = "default";
+ try {
+ channel = Services.prefs.getCharPref("app.update.channel");
+ } catch (e) { }
+ if (channel != "aurora" &&
+ channel != "beta" &&
+ channel != "release" &&
+ channel != "esr") {
+ var version = "nightly";
+ } else {
+ version = Services.appinfo.version.replace(/^([^\.]+\.[0-9]+[a-z]*).*/gi, "$1");
+ }
+ PREF_CHECK_COMPATIBILITY = "extensions.checkCompatibility." + version;
+})();
+
+var gPendingTests = [];
+var gTestsRun = 0;
+var gTestStart = null;
+
+var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window);
+
+var gRestorePrefs = [{name: PREF_LOGGING_ENABLED},
+ {name: PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI},
+ {name: "extensions.webservice.discoverURL"},
+ {name: "extensions.update.url"},
+ {name: "extensions.update.background.url"},
+ {name: "extensions.update.enabled"},
+ {name: "extensions.update.autoUpdateDefault"},
+ {name: "extensions.getAddons.get.url"},
+ {name: "extensions.getAddons.getWithPerformance.url"},
+ {name: "extensions.getAddons.search.browseURL"},
+ {name: "extensions.getAddons.search.url"},
+ {name: "extensions.getAddons.cache.enabled"},
+ {name: "devtools.chrome.enabled"},
+ {name: PREF_SEARCH_MAXRESULTS},
+ {name: PREF_STRICT_COMPAT},
+ {name: PREF_CHECK_COMPATIBILITY}];
+
+for (let pref of gRestorePrefs) {
+ if (!Services.prefs.prefHasUserValue(pref.name)) {
+ pref.type = "clear";
+ continue;
+ }
+ pref.type = Services.prefs.getPrefType(pref.name);
+ if (pref.type == Services.prefs.PREF_BOOL)
+ pref.value = Services.prefs.getBoolPref(pref.name);
+ else if (pref.type == Services.prefs.PREF_INT)
+ pref.value = Services.prefs.getIntPref(pref.name);
+ else if (pref.type == Services.prefs.PREF_STRING)
+ pref.value = Services.prefs.getCharPref(pref.name);
+}
+
+// Turn logging on for all tests
+Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
+
+Services.prefs.setBoolPref(PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI, false);
+
+// Helper to register test failures and close windows if any are left open
+function checkOpenWindows(aWindowID) {
+ let windows = Services.wm.getEnumerator(aWindowID);
+ let found = false;
+ while (windows.hasMoreElements()) {
+ let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ if (!win.closed) {
+ found = true;
+ win.close();
+ }
+ }
+ if (found)
+ ok(false, "Found unexpected " + aWindowID + " window still open");
+}
+
+// Tools to disable and re-enable the background update and blocklist timers
+// so that tests can protect themselves from unwanted timer events.
+var gCatMan = Components.classes["@mozilla.org/categorymanager;1"]
+ .getService(Components.interfaces.nsICategoryManager);
+// Default values from toolkit/mozapps/extensions/extensions.manifest, but disable*UpdateTimer()
+// records the actual value so we can put it back in enable*UpdateTimer()
+var backgroundUpdateConfig = "@mozilla.org/addons/integration;1,getService,addon-background-update-timer,extensions.update.interval,86400";
+var blocklistUpdateConfig = "@mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400";
+
+var UTIMER = "update-timer";
+var AMANAGER = "addonManager";
+var BLOCKLIST = "nsBlocklistService";
+
+function disableBackgroundUpdateTimer() {
+ info("Disabling " + UTIMER + " " + AMANAGER);
+ backgroundUpdateConfig = gCatMan.getCategoryEntry(UTIMER, AMANAGER);
+ gCatMan.deleteCategoryEntry(UTIMER, AMANAGER, true);
+}
+
+function enableBackgroundUpdateTimer() {
+ info("Enabling " + UTIMER + " " + AMANAGER);
+ gCatMan.addCategoryEntry(UTIMER, AMANAGER, backgroundUpdateConfig, false, true);
+}
+
+function disableBlocklistUpdateTimer() {
+ info("Disabling " + UTIMER + " " + BLOCKLIST);
+ blocklistUpdateConfig = gCatMan.getCategoryEntry(UTIMER, BLOCKLIST);
+ gCatMan.deleteCategoryEntry(UTIMER, BLOCKLIST, true);
+}
+
+function enableBlocklistUpdateTimer() {
+ info("Enabling " + UTIMER + " " + BLOCKLIST);
+ gCatMan.addCategoryEntry(UTIMER, BLOCKLIST, blocklistUpdateConfig, false, true);
+}
+
+registerCleanupFunction(function() {
+ // Restore prefs
+ for (let pref of gRestorePrefs) {
+ if (pref.type == "clear")
+ Services.prefs.clearUserPref(pref.name);
+ else if (pref.type == Services.prefs.PREF_BOOL)
+ Services.prefs.setBoolPref(pref.name, pref.value);
+ else if (pref.type == Services.prefs.PREF_INT)
+ Services.prefs.setIntPref(pref.name, pref.value);
+ else if (pref.type == Services.prefs.PREF_STRING)
+ Services.prefs.setCharPref(pref.name, pref.value);
+ }
+
+ // Throw an error if the add-ons manager window is open anywhere
+ checkOpenWindows("Addons:Manager");
+ checkOpenWindows("Addons:Compatibility");
+ checkOpenWindows("Addons:Install");
+
+ return new Promise((resolve, reject) => AddonManager.getAllInstalls(resolve))
+ .then(aInstalls => {
+ for (let install of aInstalls) {
+ if (install instanceof MockInstall)
+ continue;
+
+ ok(false, "Should not have seen an install of " + install.sourceURI.spec + " in state " + install.state);
+ install.cancel();
+ }
+ });
+});
+
+function log_exceptions(aCallback, ...aArgs) {
+ try {
+ return aCallback.apply(null, aArgs);
+ }
+ catch (e) {
+ info("Exception thrown: " + e);
+ throw e;
+ }
+}
+
+function log_callback(aPromise, aCallback) {
+ aPromise.then(aCallback)
+ .then(null, e => info("Exception thrown: " + e));
+ return aPromise;
+}
+
+function add_test(test) {
+ gPendingTests.push(test);
+}
+
+function run_next_test() {
+ // Make sure we're not calling run_next_test from inside an add_task() test
+ // We're inside the browser_test.js 'testScope' here
+ if (this.__tasks) {
+ throw new Error("run_next_test() called from an add_task() test function. " +
+ "run_next_test() should not be called from inside add_task() " +
+ "under any circumstances!");
+ }
+ if (gTestsRun > 0)
+ info("Test " + gTestsRun + " took " + (Date.now() - gTestStart) + "ms");
+
+ if (gPendingTests.length == 0) {
+ executeSoon(end_test);
+ return;
+ }
+
+ gTestsRun++;
+ var test = gPendingTests.shift();
+ if (test.name)
+ info("Running test " + gTestsRun + " (" + test.name + ")");
+ else
+ info("Running test " + gTestsRun);
+
+ gTestStart = Date.now();
+ executeSoon(() => log_exceptions(test));
+}
+
+var get_tooltip_info = Task.async(function*(addon) {
+ let managerWindow = addon.ownerDocument.defaultView;
+
+ // The popup code uses a triggering event's target to set the
+ // document.tooltipNode property.
+ let nameNode = addon.ownerDocument.getAnonymousElementByAttribute(addon, "anonid", "name");
+ let event = new managerWindow.CustomEvent("TriggerEvent");
+ nameNode.dispatchEvent(event);
+
+ let tooltip = managerWindow.document.getElementById("addonitem-tooltip");
+
+ let promise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
+ tooltip.openPopup(nameNode, "after_start", 0, 0, false, false, event);
+ yield promise;
+
+ let tiptext = tooltip.label;
+
+ promise = BrowserTestUtils.waitForEvent(tooltip, "popuphidden");
+ tooltip.hidePopup();
+ yield promise;
+
+ let expectedName = addon.getAttribute("name");
+ ok(tiptext.substring(0, expectedName.length), expectedName,
+ "Tooltip should always start with the expected name");
+
+ if (expectedName.length == tiptext.length) {
+ return {
+ name: tiptext,
+ version: undefined
+ };
+ }
+ return {
+ name: tiptext.substring(0, expectedName.length),
+ version: tiptext.substring(expectedName.length + 1)
+ };
+});
+
+function get_addon_file_url(aFilename) {
+ try {
+ var cr = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIChromeRegistry);
+ var fileurl = cr.convertChromeURL(makeURI(CHROMEROOT + "addons/" + aFilename));
+ return fileurl.QueryInterface(Ci.nsIFileURL);
+ } catch (ex) {
+ var jar = getJar(CHROMEROOT + "addons/" + aFilename);
+ var tmpDir = extractJarToTmp(jar);
+ tmpDir.append(aFilename);
+
+ return Services.io.newFileURI(tmpDir).QueryInterface(Ci.nsIFileURL);
+ }
+}
+
+function get_current_view(aManager) {
+ let view = aManager.document.getElementById("view-port").selectedPanel;
+ if (view.id == "headered-views") {
+ view = aManager.document.getElementById("headered-views-content").selectedPanel;
+ }
+ is(view, aManager.gViewController.displayedView, "view controller is tracking the displayed view correctly");
+ return view;
+}
+
+function get_test_items_in_list(aManager) {
+ var tests = "@tests.mozilla.org";
+
+ let view = get_current_view(aManager);
+ let listid = view.id == "search-view" ? "search-list" : "addon-list";
+ let item = aManager.document.getElementById(listid).firstChild;
+ let items = [];
+
+ while (item) {
+ if (item.localName != "richlistitem") {
+ item = item.nextSibling;
+ continue;
+ }
+
+ if (!item.mAddon || item.mAddon.id.substring(item.mAddon.id.length - tests.length) == tests)
+ items.push(item);
+ item = item.nextSibling;
+ }
+
+ return items;
+}
+
+function check_all_in_list(aManager, aIds, aIgnoreExtras) {
+ var doc = aManager.document;
+ var view = get_current_view(aManager);
+ var listid = view.id == "search-view" ? "search-list" : "addon-list";
+ var list = doc.getElementById(listid);
+
+ var inlist = [];
+ var node = list.firstChild;
+ while (node) {
+ if (node.value)
+ inlist.push(node.value);
+ node = node.nextSibling;
+ }
+
+ for (let id of aIds) {
+ if (inlist.indexOf(id) == -1)
+ ok(false, "Should find " + id + " in the list");
+ }
+
+ if (aIgnoreExtras)
+ return;
+
+ for (let inlistItem of inlist) {
+ if (aIds.indexOf(inlistItem) == -1)
+ ok(false, "Shouldn't have seen " + inlistItem + " in the list");
+ }
+}
+
+function get_addon_element(aManager, aId) {
+ var doc = aManager.document;
+ var view = get_current_view(aManager);
+ var listid = "addon-list";
+ if (view.id == "search-view")
+ listid = "search-list";
+ else if (view.id == "updates-view")
+ listid = "updates-list";
+ var list = doc.getElementById(listid);
+
+ var node = list.firstChild;
+ while (node) {
+ if (node.value == aId)
+ return node;
+ node = node.nextSibling;
+ }
+ return null;
+}
+
+function wait_for_view_load(aManagerWindow, aCallback, aForceWait, aLongerTimeout) {
+ requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
+
+ if (!aForceWait && !aManagerWindow.gViewController.isLoading) {
+ log_exceptions(aCallback, aManagerWindow);
+ return;
+ }
+
+ aManagerWindow.document.addEventListener("ViewChanged", function() {
+ aManagerWindow.document.removeEventListener("ViewChanged", arguments.callee, false);
+ log_exceptions(aCallback, aManagerWindow);
+ }, false);
+}
+
+function wait_for_manager_load(aManagerWindow, aCallback) {
+ if (!aManagerWindow.gIsInitializing) {
+ log_exceptions(aCallback, aManagerWindow);
+ return;
+ }
+
+ info("Waiting for initialization");
+ aManagerWindow.document.addEventListener("Initialized", function() {
+ aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false);
+ log_exceptions(aCallback, aManagerWindow);
+ }, false);
+}
+
+function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) {
+ let p = new Promise((resolve, reject) => {
+
+ function setup_manager(aManagerWindow) {
+ if (aLoadCallback)
+ log_exceptions(aLoadCallback, aManagerWindow);
+
+ if (aView)
+ aManagerWindow.loadView(aView);
+
+ ok(aManagerWindow != null, "Should have an add-ons manager window");
+ is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
+
+ waitForFocus(function() {
+ info("window has focus, waiting for manager load");
+ wait_for_manager_load(aManagerWindow, function() {
+ info("Manager waiting for view load");
+ wait_for_view_load(aManagerWindow, function() {
+ resolve(aManagerWindow);
+ }, null, aLongerTimeout);
+ });
+ }, aManagerWindow);
+ }
+
+ if (gUseInContentUI) {
+ info("Loading manager window in tab");
+ Services.obs.addObserver(function (aSubject, aTopic, aData) {
+ Services.obs.removeObserver(arguments.callee, aTopic);
+ if (aSubject.location.href != MANAGER_URI) {
+ info("Ignoring load event for " + aSubject.location.href);
+ return;
+ }
+ setup_manager(aSubject);
+ }, "EM-loaded", false);
+
+ gBrowser.selectedTab = gBrowser.addTab();
+ switchToTabHavingURI(MANAGER_URI, true);
+ } else {
+ info("Loading manager window in dialog");
+ Services.obs.addObserver(function (aSubject, aTopic, aData) {
+ Services.obs.removeObserver(arguments.callee, aTopic);
+ setup_manager(aSubject);
+ }, "EM-loaded", false);
+
+ openDialog(MANAGER_URI);
+ }
+ });
+
+ // The promise resolves with the manager window, so it is passed to the callback
+ return log_callback(p, aCallback);
+}
+
+function close_manager(aManagerWindow, aCallback, aLongerTimeout) {
+ let p = new Promise((resolve, reject) => {
+ requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
+
+ ok(aManagerWindow != null, "Should have an add-ons manager window to close");
+ is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
+
+ aManagerWindow.addEventListener("unload", function() {
+ try {
+ dump("Manager window unload handler\n");
+ this.removeEventListener("unload", arguments.callee, false);
+ resolve();
+ } catch (e) {
+ reject(e);
+ }
+ }, false);
+ });
+
+ info("Telling manager window to close");
+ aManagerWindow.close();
+ info("Manager window close() call returned");
+
+ return log_callback(p, aCallback);
+}
+
+function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) {
+ if (!aManagerWindow) {
+ return open_manager(aView, aCallback, aLoadCallback);
+ }
+
+ return close_manager(aManagerWindow)
+ .then(() => open_manager(aView, aCallback, aLoadCallback));
+}
+
+function wait_for_window_open(aCallback) {
+ Services.wm.addListener({
+ onOpenWindow: function(aWindow) {
+ Services.wm.removeListener(this);
+
+ let domwindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ domwindow.addEventListener("load", function() {
+ domwindow.removeEventListener("load", arguments.callee, false);
+ executeSoon(function() {
+ aCallback(domwindow);
+ });
+ }, false);
+ },
+
+ onCloseWindow: function(aWindow) {
+ },
+
+ onWindowTitleChange: function(aWindow, aTitle) {
+ }
+ });
+}
+
+function get_string(aName, ...aArgs) {
+ var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
+ if (aArgs.length == 0)
+ return bundle.GetStringFromName(aName);
+ return bundle.formatStringFromName(aName, aArgs, aArgs.length);
+}
+
+function formatDate(aDate) {
+ const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
+ .getService(Ci.nsIXULChromeRegistry)
+ .getSelectedLocale("global", true);
+ const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' };
+ return aDate.toLocaleDateString(locale, dtOptions);
+}
+
+function is_hidden(aElement) {
+ var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, "");
+ if (style.display == "none")
+ return true;
+ if (style.visibility != "visible")
+ return true;
+
+ // Hiding a parent element will hide all its children
+ if (aElement.parentNode != aElement.ownerDocument)
+ return is_hidden(aElement.parentNode);
+
+ return false;
+}
+
+function is_element_visible(aElement, aMsg) {
+ isnot(aElement, null, "Element should not be null, when checking visibility");
+ ok(!is_hidden(aElement), aMsg || (aElement + " should be visible"));
+}
+
+function is_element_hidden(aElement, aMsg) {
+ isnot(aElement, null, "Element should not be null, when checking visibility");
+ ok(is_hidden(aElement), aMsg || (aElement + " should be hidden"));
+}
+
+function promiseAddonByID(aId) {
+ return new Promise(resolve => {
+ AddonManager.getAddonByID(aId, resolve);
+ });
+}
+
+function promiseAddonsByIDs(aIDs) {
+ return new Promise(resolve => {
+ AddonManager.getAddonsByIDs(aIDs, resolve);
+ });
+}
+/**
+ * Install an add-on and call a callback when complete.
+ *
+ * The callback will receive the Addon for the installed add-on.
+ */
+function install_addon(path, cb, pathPrefix=TESTROOT) {
+ let p = new Promise((resolve, reject) => {
+ AddonManager.getInstallForURL(pathPrefix + path, (install) => {
+ install.addListener({
+ onInstallEnded: () => resolve(install.addon),
+ });
+
+ install.install();
+ }, "application/x-xpinstall");
+ });
+
+ return log_callback(p, cb);
+}
+
+function CategoryUtilities(aManagerWindow) {
+ this.window = aManagerWindow;
+
+ var self = this;
+ this.window.addEventListener("unload", function() {
+ self.window.removeEventListener("unload", arguments.callee, false);
+ self.window = null;
+ }, false);
+}
+
+CategoryUtilities.prototype = {
+ window: null,
+
+ get selectedCategory() {
+ isnot(this.window, null, "Should not get selected category when manager window is not loaded");
+ var selectedItem = this.window.document.getElementById("categories").selectedItem;
+ isnot(selectedItem, null, "A category should be selected");
+ var view = this.window.gViewController.parseViewId(selectedItem.value);
+ return (view.type == "list") ? view.param : view.type;
+ },
+
+ get: function(aCategoryType, aAllowMissing) {
+ isnot(this.window, null, "Should not get category when manager window is not loaded");
+ var categories = this.window.document.getElementById("categories");
+
+ var viewId = "addons://list/" + aCategoryType;
+ var items = categories.getElementsByAttribute("value", viewId);
+ if (items.length)
+ return items[0];
+
+ viewId = "addons://" + aCategoryType + "/";
+ items = categories.getElementsByAttribute("value", viewId);
+ if (items.length)
+ return items[0];
+
+ if (!aAllowMissing)
+ ok(false, "Should have found a category with type " + aCategoryType);
+ return null;
+ },
+
+ getViewId: function(aCategoryType) {
+ isnot(this.window, null, "Should not get view id when manager window is not loaded");
+ return this.get(aCategoryType).value;
+ },
+
+ isVisible: function(aCategory) {
+ isnot(this.window, null, "Should not check visible state when manager window is not loaded");
+ if (aCategory.hasAttribute("disabled") &&
+ aCategory.getAttribute("disabled") == "true")
+ return false;
+
+ return !is_hidden(aCategory);
+ },
+
+ isTypeVisible: function(aCategoryType) {
+ return this.isVisible(this.get(aCategoryType));
+ },
+
+ open: function(aCategory, aCallback) {
+
+ isnot(this.window, null, "Should not open category when manager window is not loaded");
+ ok(this.isVisible(aCategory), "Category should be visible if attempting to open it");
+
+ EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window);
+ let p = new Promise((resolve, reject) => wait_for_view_load(this.window, resolve));
+
+ return log_callback(p, aCallback);
+ },
+
+ openType: function(aCategoryType, aCallback) {
+ return this.open(this.get(aCategoryType), aCallback);
+ }
+}
+
+function CertOverrideListener(host, bits) {
+ this.host = host;
+ this.bits = bits;
+}
+
+CertOverrideListener.prototype = {
+ host: null,
+ bits: null,
+
+ getInterface: function (aIID) {
+ return this.QueryInterface(aIID);
+ },
+
+ QueryInterface: function(aIID) {
+ if (aIID.equals(Ci.nsIBadCertListener2) ||
+ aIID.equals(Ci.nsIInterfaceRequestor) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+
+ throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE);
+ },
+
+ notifyCertProblem: function (socketInfo, sslStatus, targetHost) {
+ var cert = sslStatus.QueryInterface(Components.interfaces.nsISSLStatus)
+ .serverCert;
+ var cos = Cc["@mozilla.org/security/certoverride;1"].
+ getService(Ci.nsICertOverrideService);
+ cos.rememberValidityOverride(this.host, -1, cert, this.bits, false);
+ return true;
+ }
+}
+
+// Add overrides for the bad certificates
+function addCertOverride(host, bits) {
+ var req = new XMLHttpRequest();
+ try {
+ req.open("GET", "https://" + host + "/", false);
+ req.channel.notificationCallbacks = new CertOverrideListener(host, bits);
+ req.send(null);
+ }
+ catch (e) {
+ // This request will fail since the SSL server is not trusted yet
+ }
+}
+
+/** *** Mock Provider *****/
+
+function MockProvider(aUseAsyncCallbacks, aTypes) {
+ this.addons = [];
+ this.installs = [];
+ this.callbackTimers = [];
+ this.timerLocations = new Map();
+ this.useAsyncCallbacks = (aUseAsyncCallbacks === undefined) ? true : aUseAsyncCallbacks;
+ this.types = (aTypes === undefined) ? [{
+ id: "extension",
+ name: "Extensions",
+ uiPriority: 4000,
+ flags: AddonManager.TYPE_UI_VIEW_LIST |
+ AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL,
+ }] : aTypes;
+
+ var self = this;
+ registerCleanupFunction(function() {
+ if (self.started)
+ self.unregister();
+ });
+
+ this.register();
+}
+
+MockProvider.prototype = {
+ addons: null,
+ installs: null,
+ started: null,
+ apiDelay: 10,
+ callbackTimers: null,
+ timerLocations: null,
+ useAsyncCallbacks: null,
+ types: null,
+
+ /** *** Utility functions *****/
+
+ /**
+ * Register this provider with the AddonManager
+ */
+ register: function MP_register() {
+ info("Registering mock add-on provider");
+ AddonManagerPrivate.registerProvider(this, this.types);
+ },
+
+ /**
+ * Unregister this provider with the AddonManager
+ */
+ unregister: function MP_unregister() {
+ info("Unregistering mock add-on provider");
+ AddonManagerPrivate.unregisterProvider(this);
+ },
+
+ /**
+ * Adds an add-on to the list of add-ons that this provider exposes to the
+ * AddonManager, dispatching appropriate events in the process.
+ *
+ * @param aAddon
+ * The add-on to add
+ */
+ addAddon: function MP_addAddon(aAddon) {
+ var oldAddons = this.addons.filter(aOldAddon => aOldAddon.id == aAddon.id);
+ var oldAddon = oldAddons.length > 0 ? oldAddons[0] : null;
+
+ this.addons = this.addons.filter(aOldAddon => aOldAddon.id != aAddon.id);
+
+ this.addons.push(aAddon);
+ aAddon._provider = this;
+
+ if (!this.started)
+ return;
+
+ let requiresRestart = (aAddon.operationsRequiringRestart &
+ AddonManager.OP_NEEDS_RESTART_INSTALL) != 0;
+ AddonManagerPrivate.callInstallListeners("onExternalInstall", null, aAddon,
+ oldAddon, requiresRestart)
+ },
+
+ /**
+ * Removes an add-on from the list of add-ons that this provider exposes to
+ * the AddonManager, dispatching the onUninstalled event in the process.
+ *
+ * @param aAddon
+ * The add-on to add
+ */
+ removeAddon: function MP_removeAddon(aAddon) {
+ var pos = this.addons.indexOf(aAddon);
+ if (pos == -1) {
+ ok(false, "Tried to remove an add-on that wasn't registered with the mock provider");
+ return;
+ }
+
+ this.addons.splice(pos, 1);
+
+ if (!this.started)
+ return;
+
+ AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon);
+ },
+
+ /**
+ * Adds an add-on install to the list of installs that this provider exposes
+ * to the AddonManager, dispatching appropriate events in the process.
+ *
+ * @param aInstall
+ * The add-on install to add
+ */
+ addInstall: function MP_addInstall(aInstall) {
+ this.installs.push(aInstall);
+ aInstall._provider = this;
+
+ if (!this.started)
+ return;
+
+ aInstall.callListeners("onNewInstall");
+ },
+
+ removeInstall: function MP_removeInstall(aInstall) {
+ var pos = this.installs.indexOf(aInstall);
+ if (pos == -1) {
+ ok(false, "Tried to remove an install that wasn't registered with the mock provider");
+ return;
+ }
+
+ this.installs.splice(pos, 1);
+ },
+
+ /**
+ * Creates a set of mock add-on objects and adds them to the list of add-ons
+ * managed by this provider.
+ *
+ * @param aAddonProperties
+ * An array of objects containing properties describing the add-ons
+ * @return Array of the new MockAddons
+ */
+ createAddons: function MP_createAddons(aAddonProperties) {
+ var newAddons = [];
+ for (let addonProp of aAddonProperties) {
+ let addon = new MockAddon(addonProp.id);
+ for (let prop in addonProp) {
+ if (prop == "id")
+ continue;
+ if (prop == "applyBackgroundUpdates") {
+ addon._applyBackgroundUpdates = addonProp[prop];
+ continue;
+ }
+ if (prop == "appDisabled") {
+ addon._appDisabled = addonProp[prop];
+ continue;
+ }
+ addon[prop] = addonProp[prop];
+ }
+ if (!addon.optionsType && !!addon.optionsURL)
+ addon.optionsType = AddonManager.OPTIONS_TYPE_DIALOG;
+
+ // Make sure the active state matches the passed in properties
+ addon.isActive = addon.shouldBeActive;
+
+ this.addAddon(addon);
+ newAddons.push(addon);
+ }
+
+ return newAddons;
+ },
+
+ /**
+ * Creates a set of mock add-on install objects and adds them to the list
+ * of installs managed by this provider.
+ *
+ * @param aInstallProperties
+ * An array of objects containing properties describing the installs
+ * @return Array of the new MockInstalls
+ */
+ createInstalls: function MP_createInstalls(aInstallProperties) {
+ var newInstalls = [];
+ for (let installProp of aInstallProperties) {
+ let install = new MockInstall(installProp.name || null,
+ installProp.type || null,
+ null);
+ for (let prop in installProp) {
+ switch (prop) {
+ case "name":
+ case "type":
+ break;
+ case "sourceURI":
+ install[prop] = NetUtil.newURI(installProp[prop]);
+ break;
+ default:
+ install[prop] = installProp[prop];
+ }
+ }
+ this.addInstall(install);
+ newInstalls.push(install);
+ }
+
+ return newInstalls;
+ },
+
+ /** *** AddonProvider implementation *****/
+
+ /**
+ * Called to initialize the provider.
+ */
+ startup: function MP_startup() {
+ this.started = true;
+ },
+
+ /**
+ * Called when the provider should shutdown.
+ */
+ shutdown: function MP_shutdown() {
+ if (this.callbackTimers.length) {
+ info("MockProvider: pending callbacks at shutdown(): calling immediately");
+ }
+ while (this.callbackTimers.length > 0) {
+ // When we notify the callback timer, it removes itself from our array
+ let timer = this.callbackTimers[0];
+ try {
+ let setAt = this.timerLocations.get(timer);
+ info("Notifying timer set at " + (setAt || "unknown location"));
+ timer.callback.notify(timer);
+ timer.cancel();
+ } catch (e) {
+ info("Timer notify failed: " + e);
+ }
+ }
+ this.callbackTimers = [];
+ this.timerLocations = null;
+
+ this.started = false;
+ },
+
+ /**
+ * Called to get an Addon with a particular ID.
+ *
+ * @param aId
+ * The ID of the add-on to retrieve
+ * @param aCallback
+ * A callback to pass the Addon to
+ */
+ getAddonByID: function MP_getAddon(aId, aCallback) {
+ for (let addon of this.addons) {
+ if (addon.id == aId) {
+ this._delayCallback(aCallback, addon);
+ return;
+ }
+ }
+
+ aCallback(null);
+ },
+
+ /**
+ * Called to get Addons of a particular type.
+ *
+ * @param aTypes
+ * An array of types to fetch. Can be null to get all types.
+ * @param callback
+ * A callback to pass an array of Addons to
+ */
+ getAddonsByTypes: function MP_getAddonsByTypes(aTypes, aCallback) {
+ var addons = this.addons.filter(function(aAddon) {
+ if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1)
+ return false;
+ return true;
+ });
+ this._delayCallback(aCallback, addons);
+ },
+
+ /**
+ * Called to get Addons that have pending operations.
+ *
+ * @param aTypes
+ * An array of types to fetch. Can be null to get all types
+ * @param aCallback
+ * A callback to pass an array of Addons to
+ */
+ getAddonsWithOperationsByTypes: function MP_getAddonsWithOperationsByTypes(aTypes, aCallback) {
+ var addons = this.addons.filter(function(aAddon) {
+ if (aTypes && aTypes.length > 0 && aTypes.indexOf(aAddon.type) == -1)
+ return false;
+ return aAddon.pendingOperations != 0;
+ });
+ this._delayCallback(aCallback, addons);
+ },
+
+ /**
+ * Called to get the current AddonInstalls, optionally restricting by type.
+ *
+ * @param aTypes
+ * An array of types or null to get all types
+ * @param aCallback
+ * A callback to pass the array of AddonInstalls to
+ */
+ getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) {
+ var installs = this.installs.filter(function(aInstall) {
+ // Appear to have actually removed cancelled installs from the provider
+ if (aInstall.state == AddonManager.STATE_CANCELLED)
+ return false;
+
+ if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1)
+ return false;
+
+ return true;
+ });
+ this._delayCallback(aCallback, installs);
+ },
+
+ /**
+ * Called when a new add-on has been enabled when only one add-on of that type
+ * can be enabled.
+ *
+ * @param aId
+ * The ID of the newly enabled add-on
+ * @param aType
+ * The type of the newly enabled add-on
+ * @param aPendingRestart
+ * true if the newly enabled add-on will only become enabled after a
+ * restart
+ */
+ addonChanged: function MP_addonChanged(aId, aType, aPendingRestart) {
+ // Not implemented
+ },
+
+ /**
+ * Update the appDisabled property for all add-ons.
+ */
+ updateAddonAppDisabledStates: function MP_updateAddonAppDisabledStates() {
+ // Not needed
+ },
+
+ /**
+ * Called to get an AddonInstall to download and install an add-on from a URL.
+ *
+ * @param aUrl
+ * The URL to be installed
+ * @param aHash
+ * A hash for the install
+ * @param aName
+ * A name for the install
+ * @param aIconURL
+ * An icon URL for the install
+ * @param aVersion
+ * A version for the install
+ * @param aLoadGroup
+ * An nsILoadGroup to associate requests with
+ * @param aCallback
+ * A callback to pass the AddonInstall to
+ */
+ getInstallForURL: function MP_getInstallForURL(aUrl, aHash, aName, aIconURL,
+ aVersion, aLoadGroup, aCallback) {
+ // Not yet implemented
+ },
+
+ /**
+ * Called to get an AddonInstall to install an add-on from a local file.
+ *
+ * @param aFile
+ * The file to be installed
+ * @param aCallback
+ * A callback to pass the AddonInstall to
+ */
+ getInstallForFile: function MP_getInstallForFile(aFile, aCallback) {
+ // Not yet implemented
+ },
+
+ /**
+ * Called to test whether installing add-ons is enabled.
+ *
+ * @return true if installing is enabled
+ */
+ isInstallEnabled: function MP_isInstallEnabled() {
+ return false;
+ },
+
+ /**
+ * Called to test whether this provider supports installing a particular
+ * mimetype.
+ *
+ * @param aMimetype
+ * The mimetype to check for
+ * @return true if the mimetype is supported
+ */
+ supportsMimetype: function MP_supportsMimetype(aMimetype) {
+ return false;
+ },
+
+ /**
+ * Called to test whether installing add-ons from a URI is allowed.
+ *
+ * @param aUri
+ * The URI being installed from
+ * @return true if installing is allowed
+ */
+ isInstallAllowed: function MP_isInstallAllowed(aUri) {
+ return false;
+ },
+
+
+ /** *** Internal functions *****/
+
+ /**
+ * Delay calling a callback to fake a time-consuming async operation.
+ * The delay is specified by the apiDelay property, in milliseconds.
+ * Parameters to send to the callback should be specified as arguments after
+ * the aCallback argument.
+ *
+ * @param aCallback Callback to eventually call
+ */
+ _delayCallback: function MP_delayCallback(aCallback, ...aArgs) {
+ if (!this.useAsyncCallbacks) {
+ aCallback(...aArgs);
+ return;
+ }
+
+ let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+ // Need to keep a reference to the timer, so it doesn't get GC'ed
+ this.callbackTimers.push(timer);
+ // Capture a stack trace where the timer was set
+ // needs the 'new Error' hack until bug 1007656
+ this.timerLocations.set(timer, Log.stackTrace(new Error("dummy")));
+ timer.initWithCallback(() => {
+ let idx = this.callbackTimers.indexOf(timer);
+ if (idx == -1) {
+ dump("MockProvider._delayCallback lost track of timer set at "
+ + (this.timerLocations.get(timer) || "unknown location") + "\n");
+ } else {
+ this.callbackTimers.splice(idx, 1);
+ }
+ this.timerLocations.delete(timer);
+ aCallback(...aArgs);
+ }, this.apiDelay, timer.TYPE_ONE_SHOT);
+ }
+};
+
+/** *** Mock Addon object for the Mock Provider *****/
+
+function MockAddon(aId, aName, aType, aOperationsRequiringRestart) {
+ // Only set required attributes.
+ this.id = aId || "";
+ this.name = aName || "";
+ this.type = aType || "extension";
+ this.version = "";
+ this.isCompatible = true;
+ this.providesUpdatesSecurely = true;
+ this.blocklistState = 0;
+ this._appDisabled = false;
+ this._userDisabled = false;
+ this._applyBackgroundUpdates = AddonManager.AUTOUPDATE_ENABLE;
+ this.scope = AddonManager.SCOPE_PROFILE;
+ this.isActive = true;
+ this.creator = "";
+ this.pendingOperations = 0;
+ this._permissions = AddonManager.PERM_CAN_UNINSTALL |
+ AddonManager.PERM_CAN_ENABLE |
+ AddonManager.PERM_CAN_DISABLE |
+ AddonManager.PERM_CAN_UPGRADE;
+ this.operationsRequiringRestart = (aOperationsRequiringRestart != undefined) ?
+ aOperationsRequiringRestart :
+ (AddonManager.OP_NEEDS_RESTART_INSTALL |
+ AddonManager.OP_NEEDS_RESTART_UNINSTALL |
+ AddonManager.OP_NEEDS_RESTART_ENABLE |
+ AddonManager.OP_NEEDS_RESTART_DISABLE);
+}
+
+MockAddon.prototype = {
+ get isCorrectlySigned() {
+ if (this.signedState === AddonManager.SIGNEDSTATE_NOT_REQUIRED)
+ return true;
+ return this.signedState > AddonManager.SIGNEDSTATE_MISSING;
+ },
+
+ get shouldBeActive() {
+ return !this.appDisabled && !this._userDisabled &&
+ !(this.pendingOperations & AddonManager.PENDING_UNINSTALL);
+ },
+
+ get appDisabled() {
+ return this._appDisabled;
+ },
+
+ set appDisabled(val) {
+ if (val == this._appDisabled)
+ return val;
+
+ AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["appDisabled"]);
+
+ var currentActive = this.shouldBeActive;
+ this._appDisabled = val;
+ var newActive = this.shouldBeActive;
+ this._updateActiveState(currentActive, newActive);
+
+ return val;
+ },
+
+ get userDisabled() {
+ return this._userDisabled;
+ },
+
+ set userDisabled(val) {
+ if (val == this._userDisabled)
+ return val;
+
+ var currentActive = this.shouldBeActive;
+ this._userDisabled = val;
+ var newActive = this.shouldBeActive;
+ this._updateActiveState(currentActive, newActive);
+
+ return val;
+ },
+
+ get permissions() {
+ let permissions = this._permissions;
+ if (this.appDisabled || !this._userDisabled)
+ permissions &= ~AddonManager.PERM_CAN_ENABLE;
+ if (this.appDisabled || this._userDisabled)
+ permissions &= ~AddonManager.PERM_CAN_DISABLE;
+ return permissions;
+ },
+
+ set permissions(val) {
+ return this._permissions = val;
+ },
+
+ get applyBackgroundUpdates() {
+ return this._applyBackgroundUpdates;
+ },
+
+ set applyBackgroundUpdates(val) {
+ if (val != AddonManager.AUTOUPDATE_DEFAULT &&
+ val != AddonManager.AUTOUPDATE_DISABLE &&
+ val != AddonManager.AUTOUPDATE_ENABLE) {
+ ok(false, "addon.applyBackgroundUpdates set to an invalid value: " + val);
+ }
+ this._applyBackgroundUpdates = val;
+ AddonManagerPrivate.callAddonListeners("onPropertyChanged", this, ["applyBackgroundUpdates"]);
+ },
+
+ isCompatibleWith: function(aAppVersion, aPlatformVersion) {
+ return true;
+ },
+
+ findUpdates: function(aListener, aReason, aAppVersion, aPlatformVersion) {
+ // Tests can implement this if they need to
+ },
+
+ uninstall: function(aAlwaysAllowUndo = false) {
+ if ((this.operationsRequiringRestart & AddonManager.OP_NEED_RESTART_UNINSTALL)
+ && this.pendingOperations & AddonManager.PENDING_UNINSTALL)
+ throw Components.Exception("Add-on is already pending uninstall");
+
+ var needsRestart = aAlwaysAllowUndo || !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL);
+ this.pendingOperations |= AddonManager.PENDING_UNINSTALL;
+ AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart);
+ if (!needsRestart) {
+ this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
+ this._provider.removeAddon(this);
+ } else if (!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE)) {
+ this.isActive = false;
+ }
+ },
+
+ cancelUninstall: function() {
+ if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL))
+ throw Components.Exception("Add-on is not pending uninstall");
+
+ this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
+ this.isActive = this.shouldBeActive;
+ AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
+ },
+
+ markAsSeen: function() {
+ this.seen = true;
+ },
+
+ _updateActiveState: function(currentActive, newActive) {
+ if (currentActive == newActive)
+ return;
+
+ if (newActive == this.isActive) {
+ this.pendingOperations -= (newActive ? AddonManager.PENDING_DISABLE : AddonManager.PENDING_ENABLE);
+ AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
+ }
+ else if (newActive) {
+ let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE);
+ this.pendingOperations |= AddonManager.PENDING_ENABLE;
+ AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart);
+ if (!needsRestart) {
+ this.isActive = newActive;
+ this.pendingOperations -= AddonManager.PENDING_ENABLE;
+ AddonManagerPrivate.callAddonListeners("onEnabled", this);
+ }
+ }
+ else {
+ let needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE);
+ this.pendingOperations |= AddonManager.PENDING_DISABLE;
+ AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart);
+ if (!needsRestart) {
+ this.isActive = newActive;
+ this.pendingOperations -= AddonManager.PENDING_DISABLE;
+ AddonManagerPrivate.callAddonListeners("onDisabled", this);
+ }
+ }
+ }
+};
+
+/** *** Mock AddonInstall object for the Mock Provider *****/
+
+function MockInstall(aName, aType, aAddonToInstall) {
+ this.name = aName || "";
+ // Don't expose type until download completed
+ this._type = aType || "extension";
+ this.type = null;
+ this.version = "1.0";
+ this.iconURL = "";
+ this.infoURL = "";
+ this.state = AddonManager.STATE_AVAILABLE;
+ this.error = 0;
+ this.sourceURI = null;
+ this.file = null;
+ this.progress = 0;
+ this.maxProgress = -1;
+ this.certificate = null;
+ this.certName = "";
+ this.existingAddon = null;
+ this.addon = null;
+ this._addonToInstall = aAddonToInstall;
+ this.listeners = [];
+
+ // Another type of install listener for tests that want to check the results
+ // of code run from standard install listeners
+ this.testListeners = [];
+}
+
+MockInstall.prototype = {
+ install: function() {
+ switch (this.state) {
+ case AddonManager.STATE_AVAILABLE:
+ this.state = AddonManager.STATE_DOWNLOADING;
+ if (!this.callListeners("onDownloadStarted")) {
+ this.state = AddonManager.STATE_CANCELLED;
+ this.callListeners("onDownloadCancelled");
+ return;
+ }
+
+ this.type = this._type;
+
+ // Adding addon to MockProvider to be implemented when needed
+ if (this._addonToInstall)
+ this.addon = this._addonToInstall;
+ else {
+ this.addon = new MockAddon("", this.name, this.type);
+ this.addon.version = this.version;
+ this.addon.pendingOperations = AddonManager.PENDING_INSTALL;
+ }
+ this.addon.install = this;
+ if (this.existingAddon) {
+ if (!this.addon.id)
+ this.addon.id = this.existingAddon.id;
+ this.existingAddon.pendingUpgrade = this.addon;
+ this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE;
+ }
+
+ this.state = AddonManager.STATE_DOWNLOADED;
+ this.callListeners("onDownloadEnded");
+
+ case AddonManager.STATE_DOWNLOADED:
+ this.state = AddonManager.STATE_INSTALLING;
+ if (!this.callListeners("onInstallStarted")) {
+ this.state = AddonManager.STATE_CANCELLED;
+ this.callListeners("onInstallCancelled");
+ return;
+ }
+
+ let needsRestart = (this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_INSTALL);
+ AddonManagerPrivate.callAddonListeners("onInstalling", this.addon, needsRestart);
+ if (!needsRestart) {
+ AddonManagerPrivate.callAddonListeners("onInstalled", this.addon);
+ }
+
+ this.state = AddonManager.STATE_INSTALLED;
+ this.callListeners("onInstallEnded");
+ break;
+ case AddonManager.STATE_DOWNLOADING:
+ case AddonManager.STATE_CHECKING:
+ case AddonManager.STATE_INSTALLING:
+ // Installation is already running
+ return;
+ default:
+ ok(false, "Cannot start installing when state = " + this.state);
+ }
+ },
+
+ cancel: function() {
+ switch (this.state) {
+ case AddonManager.STATE_AVAILABLE:
+ this.state = AddonManager.STATE_CANCELLED;
+ break;
+ case AddonManager.STATE_INSTALLED:
+ this.state = AddonManager.STATE_CANCELLED;
+ this._provider.removeInstall(this);
+ this.callListeners("onInstallCancelled");
+ break;
+ default:
+ // Handling cancelling when downloading to be implemented when needed
+ ok(false, "Cannot cancel when state = " + this.state);
+ }
+ },
+
+
+ addListener: function(aListener) {
+ if (!this.listeners.some(i => i == aListener))
+ this.listeners.push(aListener);
+ },
+
+ removeListener: function(aListener) {
+ this.listeners = this.listeners.filter(i => i != aListener);
+ },
+
+ addTestListener: function(aListener) {
+ if (!this.testListeners.some(i => i == aListener))
+ this.testListeners.push(aListener);
+ },
+
+ removeTestListener: function(aListener) {
+ this.testListeners = this.testListeners.filter(i => i != aListener);
+ },
+
+ callListeners: function(aMethod) {
+ var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners,
+ this, this.addon);
+
+ // Call test listeners after standard listeners to remove race condition
+ // between standard and test listeners
+ for (let listener of this.testListeners) {
+ try {
+ if (aMethod in listener)
+ if (listener[aMethod].call(listener, this, this.addon) === false)
+ result = false;
+ }
+ catch (e) {
+ ok(false, "Test listener threw exception: " + e);
+ }
+ }
+
+ return result;
+ }
+};
+
+function waitForCondition(condition, nextTest, errorMsg) {
+ let tries = 0;
+ let interval = setInterval(function() {
+ if (tries >= 30) {
+ ok(false, errorMsg);
+ moveOn();
+ }
+ var conditionPassed;
+ try {
+ conditionPassed = condition();
+ } catch (e) {
+ ok(false, e + "\n" + e.stack);
+ conditionPassed = false;
+ }
+ if (conditionPassed) {
+ moveOn();
+ }
+ tries++;
+ }, 100);
+ let moveOn = function() { clearInterval(interval); nextTest(); };
+}
+
+function getTestPluginTag() {
+ let ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+ let tags = ph.getPluginTags();
+
+ // Find the test plugin
+ for (let i = 0; i < tags.length; i++) {
+ if (tags[i].name == "Test Plug-in")
+ return tags[i];
+ }
+ ok(false, "Unable to find plugin");
+ return null;
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/more_options.xul b/toolkit/mozapps/webextensions/test/browser/more_options.xul
new file mode 100644
index 000000000..28dbb0a2e
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/more_options.xul
@@ -0,0 +1,32 @@
+<?xml version="1.0" ?>
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting pref="extensions.inlinesettings3.radioBool" type="radio" title="Radio">
+ <radiogroup>
+ <radio label="Delta" value="true" />
+ <radio label="Echo" value="false" />
+ </radiogroup>
+ </setting>
+ <setting pref="extensions.inlinesettings3.radioInt" type="radio" title="Radio">
+ <radiogroup>
+ <radio label="Foxtrot" value="4" />
+ <radio label="Golf" value="5" />
+ <radio label="Hotel" value="6" />
+ </radiogroup>
+ </setting>
+ <setting pref="extensions.inlinesettings3.radioString" type="radio" title="Radio">
+ <radiogroup>
+ <radio label="India" value="india" />
+ <radio label="Juliet" value="juliet" />
+ <radio label="Kilo &#x338F;" value="kilo &#x338F;" />
+ </radiogroup>
+ </setting>
+ <setting pref="extensions.inlinesettings3.menulist" type="menulist" title="Menulist">
+ <menulist sizetopopup="always">
+ <menupopup>
+ <menuitem label="Lima" value="7" />
+ <menuitem label="Mike" value="8" />
+ <menuitem label="November" value="9" />
+ </menupopup>
+ </menulist>
+ </setting>
+</vbox>
diff --git a/toolkit/mozapps/webextensions/test/browser/moz.build b/toolkit/mozapps/webextensions/test/browser/moz.build
new file mode 100644
index 000000000..af04aaeef
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/moz.build
@@ -0,0 +1,10 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += [
+ 'browser-window.ini',
+ 'browser.ini',
+]
diff --git a/toolkit/mozapps/webextensions/test/browser/options.xul b/toolkit/mozapps/webextensions/test/browser/options.xul
new file mode 100644
index 000000000..1b6827915
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/options.xul
@@ -0,0 +1,12 @@
+<?xml version="1.0" ?>
+<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <setting />
+ <setting pref="extensions.inlinesettings2.bool1" type="bool" title="Bool 1" desc="Description Attribute"/>
+ <setting pref="extensions.inlinesettings2.bool2" type="bool" title="Bool 2">Description Text Node</setting>
+ <setting type="control" title="Button">
+ This is a test, <button label="button" />all this text should be visible
+ </setting>
+ <setting type="unsupported">
+ This setting should never appear
+ </setting>
+</vbox>
diff --git a/toolkit/mozapps/webextensions/test/browser/plugin_test.html b/toolkit/mozapps/webextensions/test/browser/plugin_test.html
new file mode 100644
index 000000000..0709eda06
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/plugin_test.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+<head><meta charset="utf-8"></head>
+<body>
+<object id="test" width=200 height=200 type="application/x-test"></object>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/redirect.sjs b/toolkit/mozapps/webextensions/test/browser/redirect.sjs
new file mode 100644
index 000000000..8f9d1c08a
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/redirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response) {
+ dump("*** Received redirect for " + request.queryString + "\n");
+ response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
+ response.setHeader("Location", request.queryString, false);
+}
diff --git a/toolkit/mozapps/webextensions/test/browser/releaseNotes.xhtml b/toolkit/mozapps/webextensions/test/browser/releaseNotes.xhtml
new file mode 100644
index 000000000..63ae07901
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/releaseNotes.xhtml
@@ -0,0 +1,15 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html lang="en-US" dir="ltr" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <title></title>
+</head>
+
+<body>
+ <h1>OMG, an update!!!!</h1>
+ <ul>
+ <li>Made everything more awesome</li>
+ <li>Added hot sauce</li>
+ </ul>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/signed_hotfix.rdf b/toolkit/mozapps/webextensions/test/browser/signed_hotfix.rdf
new file mode 100644
index 000000000..39bd936c9
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/signed_hotfix.rdf
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:extension:hotfix@tests.mozilla.org">
+ <em:updates>
+ <Seq>
+ <li>
+ <Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>https://example.com/browser/toolkit/mozapps/extensions/test/browser/signed_hotfix.xpi</em:updateLink>
+ </Description>
+ </em:targetApplication>
+ </Description>
+ </li>
+ </Seq>
+ </em:updates>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpi b/toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpi
new file mode 100644
index 000000000..bd1890573
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.rdf b/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.rdf
new file mode 100644
index 000000000..2b4ba9362
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.rdf
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:extension:hotfix@tests.mozilla.org">
+ <em:updates>
+ <Seq>
+ <li>
+ <Description>
+ <em:version>1.0</em:version>
+ <em:targetApplication>
+ <Description>
+ <em:id>toolkit@mozilla.org</em:id>
+ <em:minVersion>0</em:minVersion>
+ <em:maxVersion>*</em:maxVersion>
+ <em:updateLink>https://example.com/browser/toolkit/mozapps/extensions/test/browser/unsigned_hotfix.xpi</em:updateLink>
+ </Description>
+ </em:targetApplication>
+ </Description>
+ </li>
+ </Seq>
+ </em:updates>
+ </Description>
+
+</RDF>
diff --git a/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpi b/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpi
new file mode 100644
index 000000000..f2d475bd2
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpi
Binary files differ
diff --git a/toolkit/mozapps/webextensions/test/browser/webapi_addon_listener.html b/toolkit/mozapps/webextensions/test/browser/webapi_addon_listener.html
new file mode 100644
index 000000000..56128fd9c
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/webapi_addon_listener.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<p id="result"></p>
+<script type="text/javascript">
+let events = [];
+let resultEl = document.getElementById("result");
+[ "onEnabling",
+ "onEnabled",
+ "onDisabling",
+ "onDisabled",
+ "onInstalling",
+ "onInstalled",
+ "onUninstalling",
+ "onUninstalled",
+ "onOperationCancelled",
+].forEach(event => {
+ navigator.mozAddonManager.addEventListener(event, data => {
+ let obj = {event, id: data.id, needsRestart: data.needsRestart};
+ events.push(JSON.stringify(obj));
+ resultEl.textContent = events.join('\n');
+ });
+});
+</script>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/webapi_checkavailable.html b/toolkit/mozapps/webextensions/test/browser/webapi_checkavailable.html
new file mode 100644
index 000000000..141f09cc6
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/webapi_checkavailable.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <meta charset="utf-8">
+</head>
+<body>
+<p id="result"></p>
+<script type="text/javascript">
+document.getElementById("result").textContent = ("mozAddonManager" in window.navigator);
+</script>
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/webapi_checkchromeframe.xul b/toolkit/mozapps/webextensions/test/browser/webapi_checkchromeframe.xul
new file mode 100644
index 000000000..76e642604
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/webapi_checkchromeframe.xul
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <browser id="frame" disablehistory="true" flex="1" type="content"
+ src="https://example.com/browser/toolkit/mozapps/extensions/test/browser/webapi_checkavailable.html"/>
+</window>
diff --git a/toolkit/mozapps/webextensions/test/browser/webapi_checkframed.html b/toolkit/mozapps/webextensions/test/browser/webapi_checkframed.html
new file mode 100644
index 000000000..146769978
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/webapi_checkframed.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+
+<html>
+<body>
+<iframe id="frame" height="200" width="200" src="https://example.com/browser/toolkit/mozapps/extensions/test/browser/webapi_checkavailable.html">
+</body>
+</html>
diff --git a/toolkit/mozapps/webextensions/test/browser/webapi_checknavigatedwindow.html b/toolkit/mozapps/webextensions/test/browser/webapi_checknavigatedwindow.html
new file mode 100644
index 000000000..ba3653310
--- /dev/null
+++ b/toolkit/mozapps/webextensions/test/browser/webapi_checknavigatedwindow.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<body>
+<script type="text/javascript">
+var nav, win;
+
+function openWindow() {
+ return new Promise(resolve => {
+ win = window.open(window.location);
+
+ win.addEventListener("load", function listener() {
+ nav = win.navigator;
+ resolve();
+ }, false);
+ });
+}
+
+function navigate() {
+ win.location = "http://example.com/";
+}
+
+function check() {
+ return "mozAddonManager" in nav;
+}
+</script>
+</body>
+</html>