diff options
author | Matt A. Tobin <email@mattatobin.com> | 2018-02-10 02:51:36 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2018-02-10 02:51:36 -0500 |
commit | 37d5300335d81cecbecc99812747a657588c63eb (patch) | |
tree | 765efa3b6a56bb715d9813a8697473e120436278 /toolkit/mozapps/webextensions/test/browser | |
parent | b2bdac20c02b12f2057b9ef70b0a946113a00e00 (diff) | |
parent | 4fb11cd5966461bccc3ed1599b808237be6b0de9 (diff) | |
download | UXP-37d5300335d81cecbecc99812747a657588c63eb.tar UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.gz UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.lz UXP-37d5300335d81cecbecc99812747a657588c63eb.tar.xz UXP-37d5300335d81cecbecc99812747a657588c63eb.zip |
Merge branch 'ext-work'
Diffstat (limited to 'toolkit/mozapps/webextensions/test/browser')
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 Binary files differnew file mode 100644 index 000000000..d13e5d66e --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_1.xpi 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 Binary files differnew file mode 100644 index 000000000..e1d6ac586 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_10.xpi 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 Binary files differnew file mode 100644 index 000000000..1380e7b5b --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_2.xpi 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 Binary files differnew file mode 100644 index 000000000..46326b04c --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_3.xpi 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 Binary files differnew file mode 100644 index 000000000..95de79b79 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_4.xpi 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 Binary files differnew file mode 100644 index 000000000..005d7ef21 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_5.xpi 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 Binary files differnew file mode 100644 index 000000000..89f751a03 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_6.xpi 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 Binary files differnew file mode 100644 index 000000000..77de37c2a --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_7.xpi 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 Binary files differnew file mode 100644 index 000000000..666ae0910 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_8_1.xpi 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 Binary files differnew file mode 100644 index 000000000..ad9367dc1 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug557956_9_1.xpi 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 Binary files differnew file mode 100644 index 000000000..20ae35539 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_1.xpi 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 Binary files differnew file mode 100644 index 000000000..3c99022cf --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug567127_2.xpi 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 Binary files differnew file mode 100644 index 000000000..c438cbd0b --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_1.xpi 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 Binary files differnew file mode 100644 index 000000000..a87191efe --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_bug596336_2.xpi 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 Binary files differnew file mode 100644 index 000000000..d8b4d083c --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop1.xpi 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 Binary files differnew file mode 100644 index 000000000..e4441cb19 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_dragdrop2.xpi 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 Binary files differnew file mode 100644 index 000000000..1c2b793f1 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_experiment1.xpi 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 Binary files differnew file mode 100644 index 000000000..be453ce9c --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1.xpi 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 Binary files differnew file mode 100644 index 000000000..6e937c5cc --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_custom.xpi 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 Binary files differnew file mode 100644 index 000000000..4c939c05b --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_inlinesettings1_info.xpi 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 Binary files differnew file mode 100644 index 000000000..d6df8f9d0 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_1.xpi 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 Binary files differnew file mode 100644 index 000000000..5468e6cb0 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_install1_2.xpi 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 Binary files differnew file mode 100644 index 000000000..999535a97 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_installssl.xpi 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 Binary files differnew file mode 100644 index 000000000..efef815aa --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_searching.xpi 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 Binary files differnew file mode 100644 index 000000000..956812aaa --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_1.xpi 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 Binary files differnew file mode 100644 index 000000000..7ef3db940 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_update1_2.xpi 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 Binary files differnew file mode 100644 index 000000000..4fa7b8bfa --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/browser_webapi_install.xpi 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 Binary files differnew file mode 100644 index 000000000..a063fd1c4 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/addons/options_signed.xpi 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 Binary files differnew file mode 100644 index 000000000..e99f3c3bd --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_8_2.xpi diff --git a/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi Binary files differnew file mode 100644 index 000000000..23686b608 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/browser_bug557956_9_2.xpi 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 Binary files differnew file mode 100644 index 000000000..de3c90353 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/browser_install1_3.xpi 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 ㎏" value="kilo ㎏" /> + </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 Binary files differnew file mode 100644 index 000000000..bd1890573 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/signed_hotfix.xpi 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 Binary files differnew file mode 100644 index 000000000..f2d475bd2 --- /dev/null +++ b/toolkit/mozapps/webextensions/test/browser/unsigned_hotfix.xpi 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> |