1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/addons/private-browsing-supported/test-selection.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,459 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const HTML = "<html>\ 1.11 + <body>\ 1.12 + <div>foo</div>\ 1.13 + <div>and</div>\ 1.14 + <textarea>noodles</textarea>\ 1.15 + </body>\ 1.16 +</html>"; 1.17 + 1.18 +const URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML); 1.19 + 1.20 +const FRAME_HTML = "<iframe src='" + URL + "'><iframe>"; 1.21 +const FRAME_URL = "data:text/html;charset=utf-8," + encodeURIComponent(FRAME_HTML); 1.22 + 1.23 +const { defer } = require("sdk/core/promise"); 1.24 +const { browserWindows } = require("sdk/windows"); 1.25 +const tabs = require("sdk/tabs"); 1.26 +const { setTabURL, getActiveTab, getTabContentWindow, closeTab, getTabs, 1.27 + getTabTitle } = require("sdk/tabs/utils"); 1.28 +const { getMostRecentBrowserWindow, isFocused } = require("sdk/window/utils"); 1.29 +const { open: openNewWindow, close: closeWindow, focus } = require("sdk/window/helpers"); 1.30 +const { Loader } = require("sdk/test/loader"); 1.31 +const { merge } = require("sdk/util/object"); 1.32 +const { isPrivate } = require("sdk/private-browsing"); 1.33 + 1.34 +// General purpose utility functions 1.35 + 1.36 +/** 1.37 + * Opens the url given and return a promise, that will be resolved with the 1.38 + * content window when the document is ready. 1.39 + * 1.40 + * I believe this approach could be useful in most of our unit test, that 1.41 + * requires to open a tab and need to access to its content. 1.42 + */ 1.43 +function open(url, options) { 1.44 + let { promise, resolve } = defer(); 1.45 + 1.46 + if (options && typeof(options) === "object") { 1.47 + openNewWindow("", { 1.48 + features: merge({ toolbar: true }, options) 1.49 + }).then(function(chromeWindow) { 1.50 + if (isPrivate(chromeWindow) !== !!options.private) 1.51 + throw new Error("Window should have Private set to " + !!options.private); 1.52 + 1.53 + let tab = getActiveTab(chromeWindow); 1.54 + 1.55 + tab.linkedBrowser.addEventListener("load", function ready(event) { 1.56 + let { document } = getTabContentWindow(tab); 1.57 + 1.58 + if (document.readyState === "complete" && document.URL === url) { 1.59 + this.removeEventListener(event.type, ready); 1.60 + 1.61 + if (options.title) 1.62 + document.title = options.title; 1.63 + 1.64 + resolve(document.defaultView); 1.65 + } 1.66 + }, true); 1.67 + 1.68 + setTabURL(tab, url); 1.69 + }); 1.70 + 1.71 + return promise; 1.72 + }; 1.73 + 1.74 + tabs.open({ 1.75 + url: url, 1.76 + onReady: function(tab) { 1.77 + // Unfortunately there is no way to get a XUL Tab from SDK Tab on Firefox, 1.78 + // only on Fennec. We should implement `tabNS` also on Firefox in order 1.79 + // to have that. 1.80 + 1.81 + // Here we assuming that the most recent browser window is the one we're 1.82 + // doing the test, and the active tab is the one we just opened. 1.83 + let window = getTabContentWindow(getActiveTab(getMostRecentBrowserWindow())); 1.84 + 1.85 + resolve(window); 1.86 + } 1.87 + }); 1.88 + 1.89 + return promise; 1.90 +}; 1.91 + 1.92 +/** 1.93 + * Close the Active Tab 1.94 + */ 1.95 +function close(window) { 1.96 + let { promise, resolve } = defer(); 1.97 + 1.98 + if (window && typeof(window.close) === "function") { 1.99 + closeWindow(window).then(function() resolve()); 1.100 + } 1.101 + else { 1.102 + // Here we assuming that the most recent browser window is the one we're 1.103 + // doing the test, and the active tab is the one we just opened. 1.104 + closeTab(getActiveTab(getMostRecentBrowserWindow())); 1.105 + resolve(); 1.106 + } 1.107 + 1.108 + return promise; 1.109 +} 1.110 + 1.111 +/** 1.112 + * Reload the window given and return a promise, that will be resolved with the 1.113 + * content window after a small delay. 1.114 + */ 1.115 +function reload(window) { 1.116 + let { promise, resolve } = defer(); 1.117 + 1.118 + // Here we assuming that the most recent browser window is the one we're 1.119 + // doing the test, and the active tab is the one we just opened. 1.120 + let tab = tabs.activeTab; 1.121 + 1.122 + tab.once("ready", function () { 1.123 + resolve(window); 1.124 + }); 1.125 + 1.126 + window.location.reload(true); 1.127 + 1.128 + return promise; 1.129 +} 1.130 + 1.131 +// Selection's unit test utility function 1.132 + 1.133 +/** 1.134 + * Select the first div in the page, adding the range to the selection. 1.135 + */ 1.136 +function selectFirstDiv(window) { 1.137 + let div = window.document.querySelector("div"); 1.138 + let selection = window.getSelection(); 1.139 + let range = window.document.createRange(); 1.140 + 1.141 + if (selection.rangeCount > 0) 1.142 + selection.removeAllRanges(); 1.143 + 1.144 + range.selectNode(div); 1.145 + selection.addRange(range); 1.146 + 1.147 + return window; 1.148 +} 1.149 + 1.150 +/** 1.151 + * Select all divs in the page, adding the ranges to the selection. 1.152 + */ 1.153 +function selectAllDivs(window) { 1.154 + let divs = window.document.getElementsByTagName("div"); 1.155 + let selection = window.getSelection(); 1.156 + 1.157 + if (selection.rangeCount > 0) 1.158 + selection.removeAllRanges(); 1.159 + 1.160 + for (let i = 0; i < divs.length; i++) { 1.161 + let range = window.document.createRange(); 1.162 + 1.163 + range.selectNode(divs[i]); 1.164 + selection.addRange(range); 1.165 + } 1.166 + 1.167 + return window; 1.168 +} 1.169 + 1.170 +/** 1.171 + * Select the textarea content 1.172 + */ 1.173 +function selectTextarea(window) { 1.174 + let selection = window.getSelection(); 1.175 + let textarea = window.document.querySelector("textarea"); 1.176 + 1.177 + if (selection.rangeCount > 0) 1.178 + selection.removeAllRanges(); 1.179 + 1.180 + textarea.setSelectionRange(0, textarea.value.length); 1.181 + textarea.focus(); 1.182 + 1.183 + return window; 1.184 +} 1.185 + 1.186 +/** 1.187 + * Select the content of the first div 1.188 + */ 1.189 +function selectContentFirstDiv(window) { 1.190 + let div = window.document.querySelector("div"); 1.191 + let selection = window.getSelection(); 1.192 + let range = window.document.createRange(); 1.193 + 1.194 + if (selection.rangeCount > 0) 1.195 + selection.removeAllRanges(); 1.196 + 1.197 + range.selectNodeContents(div); 1.198 + selection.addRange(range); 1.199 + 1.200 + return window; 1.201 +} 1.202 + 1.203 +/** 1.204 + * Dispatch the selection event for the selection listener added by 1.205 + * `nsISelectionPrivate.addSelectionListener` 1.206 + */ 1.207 +function dispatchSelectionEvent(window) { 1.208 + // We modify the selection in order to dispatch the selection's event, by 1.209 + // contract the selection by one character. So if the text selected is "foo" 1.210 + // will be "fo". 1.211 + window.getSelection().modify("extend", "backward", "character"); 1.212 + 1.213 + return window; 1.214 +} 1.215 + 1.216 +/** 1.217 + * Dispatch the selection event for the selection listener added by 1.218 + * `window.onselect` / `window.addEventListener` 1.219 + */ 1.220 +function dispatchOnSelectEvent(window) { 1.221 + let { document } = window; 1.222 + let textarea = document.querySelector("textarea"); 1.223 + let event = document.createEvent("UIEvents"); 1.224 + 1.225 + event.initUIEvent("select", true, true, window, 1); 1.226 + 1.227 + textarea.dispatchEvent(event); 1.228 + 1.229 + return window; 1.230 +} 1.231 + 1.232 +// Test cases 1.233 + 1.234 +exports["test PWPB Selection Listener"] = function(assert, done) { 1.235 + let loader = Loader(module); 1.236 + let selection = loader.require("sdk/selection"); 1.237 + 1.238 + open(URL, {private: true, title: "PWPB Selection Listener"}). 1.239 + then(function(window) { 1.240 + selection.once("select", function() { 1.241 + assert.equal(browserWindows.length, 2, "there should be only two windows open."); 1.242 + assert.equal(getTabs().length, 2, "there should be only two tabs open: '" + 1.243 + getTabs().map(function(tab) getTabTitle(tab)).join("', '") + 1.244 + "'." 1.245 + ); 1.246 + 1.247 + // window should be focused, but force the focus anyhow.. see bug 841823 1.248 + focus(window).then(function() { 1.249 + // check state of window 1.250 + assert.ok(isFocused(window), "the window is focused"); 1.251 + assert.ok(isPrivate(window), "the window should be a private window"); 1.252 + 1.253 + assert.equal(selection.text, "fo"); 1.254 + 1.255 + close(window). 1.256 + then(loader.unload). 1.257 + then(done). 1.258 + then(null, assert.fail); 1.259 + }); 1.260 + }); 1.261 + return window; 1.262 + }). 1.263 + then(selectContentFirstDiv). 1.264 + then(dispatchSelectionEvent). 1.265 + then(null, assert.fail); 1.266 +}; 1.267 + 1.268 +exports["test PWPB Textarea OnSelect Listener"] = function(assert, done) { 1.269 + let loader = Loader(module); 1.270 + let selection = loader.require("sdk/selection"); 1.271 + 1.272 + open(URL, {private: true, title: "PWPB OnSelect Listener"}). 1.273 + then(function(window) { 1.274 + selection.once("select", function() { 1.275 + assert.equal(browserWindows.length, 2, "there should be only two windows open."); 1.276 + assert.equal(getTabs().length, 2, "there should be only two tabs open: '" + 1.277 + getTabs().map(function(tab) getTabTitle(tab)).join("', '") + 1.278 + "'." 1.279 + ); 1.280 + 1.281 + // window should be focused, but force the focus anyhow.. see bug 841823 1.282 + focus(window).then(function() { 1.283 + assert.equal(selection.text, "noodles"); 1.284 + 1.285 + close(window). 1.286 + then(loader.unload). 1.287 + then(done). 1.288 + then(null, assert.fail); 1.289 + }); 1.290 + }); 1.291 + return window; 1.292 + }). 1.293 + then(selectTextarea). 1.294 + then(dispatchOnSelectEvent). 1.295 + then(null, assert.fail); 1.296 +}; 1.297 + 1.298 +exports["test PWPB Single DOM Selection"] = function(assert, done) { 1.299 + let loader = Loader(module); 1.300 + let selection = loader.require("sdk/selection"); 1.301 + 1.302 + open(URL, {private: true, title: "PWPB Single DOM Selection"}). 1.303 + then(selectFirstDiv). 1.304 + then(focus).then(function() { 1.305 + assert.equal(selection.isContiguous, true, 1.306 + "selection.isContiguous with single DOM Selection works."); 1.307 + 1.308 + assert.equal(selection.text, "foo", 1.309 + "selection.text with single DOM Selection works."); 1.310 + 1.311 + assert.equal(selection.html, "<div>foo</div>", 1.312 + "selection.html with single DOM Selection works."); 1.313 + 1.314 + let selectionCount = 0; 1.315 + for each (let sel in selection) { 1.316 + selectionCount++; 1.317 + 1.318 + assert.equal(sel.text, "foo", 1.319 + "iterable selection.text with single DOM Selection works."); 1.320 + 1.321 + assert.equal(sel.html, "<div>foo</div>", 1.322 + "iterable selection.html with single DOM Selection works."); 1.323 + } 1.324 + 1.325 + assert.equal(selectionCount, 1, 1.326 + "One iterable selection"); 1.327 + }).then(close).then(loader.unload).then(done).then(null, assert.fail); 1.328 +} 1.329 + 1.330 +exports["test PWPB Textarea Selection"] = function(assert, done) { 1.331 + let loader = Loader(module); 1.332 + let selection = loader.require("sdk/selection"); 1.333 + 1.334 + open(URL, {private: true, title: "PWPB Textarea Listener"}). 1.335 + then(selectTextarea). 1.336 + then(focus). 1.337 + then(function() { 1.338 + 1.339 + assert.equal(selection.isContiguous, true, 1.340 + "selection.isContiguous with Textarea Selection works."); 1.341 + 1.342 + assert.equal(selection.text, "noodles", 1.343 + "selection.text with Textarea Selection works."); 1.344 + 1.345 + assert.strictEqual(selection.html, null, 1.346 + "selection.html with Textarea Selection works."); 1.347 + 1.348 + let selectionCount = 0; 1.349 + for each (let sel in selection) { 1.350 + selectionCount++; 1.351 + 1.352 + assert.equal(sel.text, "noodles", 1.353 + "iterable selection.text with Textarea Selection works."); 1.354 + 1.355 + assert.strictEqual(sel.html, null, 1.356 + "iterable selection.html with Textarea Selection works."); 1.357 + } 1.358 + 1.359 + assert.equal(selectionCount, 1, 1.360 + "One iterable selection"); 1.361 + }).then(close).then(loader.unload).then(done).then(null, assert.fail); 1.362 +}; 1.363 + 1.364 +exports["test PWPB Set HTML in Multiple DOM Selection"] = function(assert, done) { 1.365 + let loader = Loader(module); 1.366 + let selection = loader.require("sdk/selection"); 1.367 + 1.368 + open(URL, {private: true, title: "PWPB Set HTML in Multiple DOM Selection"}). 1.369 + then(selectAllDivs). 1.370 + then(focus). 1.371 + then(function() { 1.372 + let html = "<span>b<b>a</b>r</span>"; 1.373 + 1.374 + let expectedText = ["bar", "and"]; 1.375 + let expectedHTML = [html, "<div>and</div>"]; 1.376 + 1.377 + selection.html = html; 1.378 + 1.379 + assert.equal(selection.text, expectedText[0], 1.380 + "set selection.text with DOM Selection works."); 1.381 + 1.382 + assert.equal(selection.html, expectedHTML[0], 1.383 + "selection.html with DOM Selection works."); 1.384 + 1.385 + let selectionCount = 0; 1.386 + for each (let sel in selection) { 1.387 + 1.388 + assert.equal(sel.text, expectedText[selectionCount], 1.389 + "iterable selection.text with multiple DOM Selection works."); 1.390 + 1.391 + assert.equal(sel.html, expectedHTML[selectionCount], 1.392 + "iterable selection.html with multiple DOM Selection works."); 1.393 + 1.394 + selectionCount++; 1.395 + } 1.396 + 1.397 + assert.equal(selectionCount, 2, 1.398 + "Two iterable selections"); 1.399 + }).then(close).then(loader.unload).then(done).then(null, assert.fail); 1.400 +}; 1.401 + 1.402 +exports["test PWPB Set Text in Textarea Selection"] = function(assert, done) { 1.403 + let loader = Loader(module); 1.404 + let selection = loader.require("sdk/selection"); 1.405 + 1.406 + open(URL, {private: true, title: "test PWPB Set Text in Textarea Selection"}). 1.407 + then(selectTextarea). 1.408 + then(focus). 1.409 + then(function() { 1.410 + 1.411 + let text = "bar"; 1.412 + 1.413 + selection.text = text; 1.414 + 1.415 + assert.equal(selection.text, text, 1.416 + "set selection.text with Textarea Selection works."); 1.417 + 1.418 + assert.strictEqual(selection.html, null, 1.419 + "selection.html with Textarea Selection works."); 1.420 + 1.421 + let selectionCount = 0; 1.422 + for each (let sel in selection) { 1.423 + selectionCount++; 1.424 + 1.425 + assert.equal(sel.text, text, 1.426 + "iterable selection.text with Textarea Selection works."); 1.427 + 1.428 + assert.strictEqual(sel.html, null, 1.429 + "iterable selection.html with Textarea Selection works."); 1.430 + } 1.431 + 1.432 + assert.equal(selectionCount, 1, 1.433 + "One iterable selection"); 1.434 + 1.435 + }).then(close).then(loader.unload).then(done).then(null, assert.fail); 1.436 +}; 1.437 + 1.438 +// If the platform doesn't support the PBPW, we're replacing PBPW tests 1.439 +if (!require("sdk/private-browsing/utils").isWindowPBSupported) { 1.440 + module.exports = { 1.441 + "test PBPW Unsupported": function Unsupported (assert) { 1.442 + assert.pass("Private Window Per Browsing is not supported on this platform."); 1.443 + } 1.444 + } 1.445 +} 1.446 + 1.447 +// If the module doesn't support the app we're being run in, require() will 1.448 +// throw. In that case, remove all tests above from exports, and add one dummy 1.449 +// test that passes. 1.450 +try { 1.451 + require("sdk/selection"); 1.452 +} 1.453 +catch (err) { 1.454 + if (!/^Unsupported Application/.test(err.message)) 1.455 + throw err; 1.456 + 1.457 + module.exports = { 1.458 + "test Unsupported Application": function Unsupported (assert) { 1.459 + assert.pass(err.message); 1.460 + } 1.461 + } 1.462 +}