1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-selection.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,997 @@ 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 +module.metadata = { 1.11 + 'engines': { 1.12 + 'Firefox': '*' 1.13 + } 1.14 +}; 1.15 + 1.16 +const HTML = "<html>\ 1.17 + <body>\ 1.18 + <div>foo</div>\ 1.19 + <div>and</div>\ 1.20 + <textarea>noodles</textarea>\ 1.21 + </body>\ 1.22 +</html>"; 1.23 + 1.24 +const URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML); 1.25 + 1.26 +const FRAME_HTML = "<iframe src='" + URL + "'><iframe>"; 1.27 +const FRAME_URL = "data:text/html;charset=utf-8," + encodeURIComponent(FRAME_HTML); 1.28 + 1.29 +const { defer } = require("sdk/core/promise"); 1.30 +const tabs = require("sdk/tabs"); 1.31 +const { setTabURL } = require("sdk/tabs/utils"); 1.32 +const { getActiveTab, getTabContentWindow, closeTab } = require("sdk/tabs/utils") 1.33 +const { getMostRecentBrowserWindow } = require("sdk/window/utils"); 1.34 +const { open: openNewWindow } = require("sdk/window/helpers"); 1.35 +const { Loader } = require("sdk/test/loader"); 1.36 +const { setTimeout } = require("sdk/timers"); 1.37 +const { Cu } = require("chrome"); 1.38 +const { merge } = require("sdk/util/object"); 1.39 +const { isPrivate } = require("sdk/private-browsing"); 1.40 +const events = require("sdk/system/events"); 1.41 +// General purpose utility functions 1.42 + 1.43 +/** 1.44 + * Opens the url given and return a promise, that will be resolved with the 1.45 + * content window when the document is ready. 1.46 + * 1.47 + * I believe this approach could be useful in most of our unit test, that 1.48 + * requires to open a tab and need to access to its content. 1.49 + */ 1.50 +function open(url, options) { 1.51 + let { promise, resolve } = defer(); 1.52 + 1.53 + if (options && typeof(options) === "object") { 1.54 + openNewWindow("", { 1.55 + features: merge({ toolbar: true }, options) 1.56 + }).then(function(chromeWindow) { 1.57 + if (isPrivate(chromeWindow) !== !!options.private) 1.58 + throw new Error("Window should have Private set to " + !!options.private); 1.59 + 1.60 + let tab = getActiveTab(chromeWindow); 1.61 + 1.62 + tab.linkedBrowser.addEventListener("load", function ready(event) { 1.63 + let { document } = getTabContentWindow(tab); 1.64 + 1.65 + if (document.readyState === "complete" && document.URL === url) { 1.66 + this.removeEventListener(event.type, ready); 1.67 + 1.68 + resolve(document.defaultView); 1.69 + } 1.70 + }, true); 1.71 + 1.72 + setTabURL(tab, url); 1.73 + }); 1.74 + 1.75 + return promise; 1.76 + }; 1.77 + 1.78 + tabs.open({ 1.79 + url: url, 1.80 + onReady: function(tab) { 1.81 + // Unfortunately there is no way to get a XUL Tab from SDK Tab on Firefox, 1.82 + // only on Fennec. We should implement `tabNS` also on Firefox in order 1.83 + // to have that. 1.84 + 1.85 + // Here we assuming that the most recent browser window is the one we're 1.86 + // doing the test, and the active tab is the one we just opened. 1.87 + let window = getTabContentWindow(getActiveTab(getMostRecentBrowserWindow())); 1.88 + 1.89 + resolve(window); 1.90 + } 1.91 + }); 1.92 + 1.93 + return promise; 1.94 +}; 1.95 + 1.96 +/** 1.97 + * Close the Active Tab 1.98 + */ 1.99 +function close(window) { 1.100 + if (window && window.top && typeof(window.top).close === "function") { 1.101 + window.top.close(); 1.102 + } else { 1.103 + // Here we assuming that the most recent browser window is the one we're 1.104 + // doing the test, and the active tab is the one we just opened. 1.105 + let tab = getActiveTab(getMostRecentBrowserWindow()); 1.106 + 1.107 + closeTab(tab); 1.108 + } 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 + * Returns the frame's window once the document is loaded 1.135 + */ 1.136 +function getFrameWindow(window) { 1.137 + let { promise, resolve } = defer(); 1.138 + 1.139 + let frame = window.frames[0]; 1.140 + let { document } = frame; 1.141 + 1.142 + frame.focus(); 1.143 + 1.144 + if (document.readyState === "complete") 1.145 + return frame; 1.146 + 1.147 + document.addEventListener("readystatechange", function readystate() { 1.148 + if (this.readyState === "complete") { 1.149 + this.removeEventListener("readystatechange", readystate); 1.150 + frame.focus(); 1.151 + resolve(frame); 1.152 + } 1.153 + }); 1.154 + 1.155 + return promise; 1.156 +} 1.157 + 1.158 +/** 1.159 + * Hide the frame in order to destroy the selection object, and show it again 1.160 + * after ~500 msec, to give time to attach the code on `document-shown` 1.161 + * notification. 1.162 + * In the process, call `Cu.forgeGC` to ensure that the `document-shown` code 1.163 + * is not garbaged. 1.164 + */ 1.165 +function hideAndShowFrame(window) { 1.166 + let { promise, resolve } = defer(); 1.167 + let iframe = window.document.querySelector("iframe"); 1.168 + 1.169 + iframe.style.display = "none"; 1.170 + 1.171 + Cu.schedulePreciseGC(function() { 1.172 + events.on("document-shown", function shown(event) { 1.173 + if (iframe.contentWindow !== event.subject.defaultView) 1.174 + return; 1.175 + 1.176 + events.off("document-shown", shown); 1.177 + setTimeout(resolve, 0, window); 1.178 + }, true); 1.179 + 1.180 + iframe.style.display = ""; 1.181 + }); 1.182 + 1.183 + return promise; 1.184 +} 1.185 + 1.186 +/** 1.187 + * Select the first div in the page, adding the range to the selection. 1.188 + */ 1.189 +function selectFirstDiv(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.selectNode(div); 1.198 + selection.addRange(range); 1.199 + 1.200 + return window; 1.201 +} 1.202 + 1.203 +/** 1.204 + * Select all divs in the page, adding the ranges to the selection. 1.205 + */ 1.206 +function selectAllDivs(window) { 1.207 + let divs = window.document.getElementsByTagName("div"); 1.208 + let selection = window.getSelection(); 1.209 + 1.210 + if (selection.rangeCount > 0) 1.211 + selection.removeAllRanges(); 1.212 + 1.213 + for (let i = 0; i < divs.length; i++) { 1.214 + let range = window.document.createRange(); 1.215 + 1.216 + range.selectNode(divs[i]); 1.217 + selection.addRange(range); 1.218 + } 1.219 + 1.220 + return window; 1.221 +} 1.222 + 1.223 +/** 1.224 + * Select the textarea content 1.225 + */ 1.226 +function selectTextarea(window) { 1.227 + let selection = window.getSelection(); 1.228 + let textarea = window.document.querySelector("textarea"); 1.229 + 1.230 + if (selection.rangeCount > 0) 1.231 + selection.removeAllRanges(); 1.232 + 1.233 + textarea.setSelectionRange(0, textarea.value.length); 1.234 + textarea.focus(); 1.235 + 1.236 + return window; 1.237 +} 1.238 + 1.239 +/** 1.240 + * Select the content of the first div 1.241 + */ 1.242 +function selectContentFirstDiv(window) { 1.243 + let div = window.document.querySelector("div"); 1.244 + let selection = window.getSelection(); 1.245 + let range = window.document.createRange(); 1.246 + 1.247 + if (selection.rangeCount > 0) 1.248 + selection.removeAllRanges(); 1.249 + 1.250 + range.selectNodeContents(div); 1.251 + selection.addRange(range); 1.252 + 1.253 + return window; 1.254 +} 1.255 + 1.256 +/** 1.257 + * Dispatch the selection event for the selection listener added by 1.258 + * `nsISelectionPrivate.addSelectionListener` 1.259 + */ 1.260 +function dispatchSelectionEvent(window) { 1.261 + // We modify the selection in order to dispatch the selection's event, by 1.262 + // contract the selection by one character. So if the text selected is "foo" 1.263 + // will be "fo". 1.264 + window.getSelection().modify("extend", "backward", "character"); 1.265 + 1.266 + return window; 1.267 +} 1.268 + 1.269 +/** 1.270 + * Dispatch the selection event for the selection listener added by 1.271 + * `window.onselect` / `window.addEventListener` 1.272 + */ 1.273 +function dispatchOnSelectEvent(window) { 1.274 + let { document } = window; 1.275 + let textarea = document.querySelector("textarea"); 1.276 + let event = document.createEvent("UIEvents"); 1.277 + 1.278 + event.initUIEvent("select", true, true, window, 1); 1.279 + 1.280 + textarea.dispatchEvent(event); 1.281 + 1.282 + return window; 1.283 +} 1.284 + 1.285 +/** 1.286 + * Creates empty ranges and add them to selections 1.287 + */ 1.288 +function createEmptySelections(window) { 1.289 + selectAllDivs(window); 1.290 + 1.291 + let selection = window.getSelection(); 1.292 + 1.293 + for (let i = 0; i < selection.rangeCount; i++) 1.294 + selection.getRangeAt(i).collapse(true); 1.295 +} 1.296 + 1.297 +// Test cases 1.298 + 1.299 +exports["test No Selection"] = function(assert, done) { 1.300 + let loader = Loader(module); 1.301 + let selection = loader.require("sdk/selection"); 1.302 + 1.303 + open(URL).then(function() { 1.304 + 1.305 + assert.equal(selection.isContiguous, false, 1.306 + "selection.isContiguous without selection works."); 1.307 + 1.308 + assert.strictEqual(selection.text, null, 1.309 + "selection.text without selection works."); 1.310 + 1.311 + assert.strictEqual(selection.html, null, 1.312 + "selection.html without 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(selectionCount, 0, 1.319 + "No iterable selections"); 1.320 + 1.321 + }).then(close).then(loader.unload).then(done, assert.fail); 1.322 +}; 1.323 + 1.324 +exports["test Single DOM Selection"] = function(assert, done) { 1.325 + let loader = Loader(module); 1.326 + let selection = loader.require("sdk/selection"); 1.327 + 1.328 + open(URL).then(selectFirstDiv).then(function() { 1.329 + 1.330 + assert.equal(selection.isContiguous, true, 1.331 + "selection.isContiguous with single DOM Selection works."); 1.332 + 1.333 + assert.equal(selection.text, "foo", 1.334 + "selection.text with single DOM Selection works."); 1.335 + 1.336 + assert.equal(selection.html, "<div>foo</div>", 1.337 + "selection.html with single DOM Selection works."); 1.338 + 1.339 + let selectionCount = 0; 1.340 + for each (let sel in selection) { 1.341 + selectionCount++; 1.342 + 1.343 + assert.equal(sel.text, "foo", 1.344 + "iterable selection.text with single DOM Selection works."); 1.345 + 1.346 + assert.equal(sel.html, "<div>foo</div>", 1.347 + "iterable selection.html with single DOM Selection works."); 1.348 + } 1.349 + 1.350 + assert.equal(selectionCount, 1, 1.351 + "One iterable selection"); 1.352 + 1.353 + }).then(close).then(loader.unload).then(done, assert.fail); 1.354 +}; 1.355 + 1.356 +exports["test Multiple DOM Selection"] = function(assert, done) { 1.357 + let loader = Loader(module); 1.358 + let selection = loader.require("sdk/selection"); 1.359 + 1.360 + open(URL).then(selectAllDivs).then(function() { 1.361 + let expectedText = ["foo", "and"]; 1.362 + let expectedHTML = ["<div>foo</div>", "<div>and</div>"]; 1.363 + 1.364 + assert.equal(selection.isContiguous, false, 1.365 + "selection.isContiguous with multiple DOM Selection works."); 1.366 + 1.367 + assert.equal(selection.text, expectedText[0], 1.368 + "selection.text with multiple DOM Selection works."); 1.369 + 1.370 + assert.equal(selection.html, expectedHTML[0], 1.371 + "selection.html with multiple DOM Selection works."); 1.372 + 1.373 + let selectionCount = 0; 1.374 + for each (let sel in selection) { 1.375 + assert.equal(sel.text, expectedText[selectionCount], 1.376 + "iterable selection.text with multiple DOM Selection works."); 1.377 + 1.378 + assert.equal(sel.html, expectedHTML[selectionCount], 1.379 + "iterable selection.text with multiple DOM Selection works."); 1.380 + 1.381 + selectionCount++; 1.382 + } 1.383 + 1.384 + assert.equal(selectionCount, 2, 1.385 + "Two iterable selections"); 1.386 + 1.387 + }).then(close).then(loader.unload).then(done, assert.fail); 1.388 +}; 1.389 + 1.390 +exports["test Textarea Selection"] = function(assert, done) { 1.391 + let loader = Loader(module); 1.392 + let selection = loader.require("sdk/selection"); 1.393 + 1.394 + open(URL).then(selectTextarea).then(function() { 1.395 + 1.396 + assert.equal(selection.isContiguous, true, 1.397 + "selection.isContiguous with Textarea Selection works."); 1.398 + 1.399 + assert.equal(selection.text, "noodles", 1.400 + "selection.text with Textarea Selection works."); 1.401 + 1.402 + assert.strictEqual(selection.html, null, 1.403 + "selection.html with Textarea Selection works."); 1.404 + 1.405 + let selectionCount = 0; 1.406 + for each (let sel in selection) { 1.407 + selectionCount++; 1.408 + 1.409 + assert.equal(sel.text, "noodles", 1.410 + "iterable selection.text with Textarea Selection works."); 1.411 + 1.412 + assert.strictEqual(sel.html, null, 1.413 + "iterable selection.html with Textarea Selection works."); 1.414 + } 1.415 + 1.416 + assert.equal(selectionCount, 1, 1.417 + "One iterable selection"); 1.418 + 1.419 + }).then(close).then(loader.unload).then(done, assert.fail); 1.420 +}; 1.421 + 1.422 +exports["test Set Text in Multiple DOM Selection"] = function(assert, done) { 1.423 + let loader = Loader(module); 1.424 + let selection = loader.require("sdk/selection"); 1.425 + 1.426 + open(URL).then(selectAllDivs).then(function() { 1.427 + let expectedText = ["bar", "and"]; 1.428 + let expectedHTML = ["bar", "<div>and</div>"]; 1.429 + 1.430 + selection.text = "bar"; 1.431 + 1.432 + assert.equal(selection.text, expectedText[0], 1.433 + "set selection.text with single DOM Selection works."); 1.434 + 1.435 + assert.equal(selection.html, expectedHTML[0], 1.436 + "selection.html with single DOM Selection works."); 1.437 + 1.438 + let selectionCount = 0; 1.439 + for each (let sel in selection) { 1.440 + 1.441 + assert.equal(sel.text, expectedText[selectionCount], 1.442 + "iterable selection.text with multiple DOM Selection works."); 1.443 + 1.444 + assert.equal(sel.html, expectedHTML[selectionCount], 1.445 + "iterable selection.html with multiple DOM Selection works."); 1.446 + 1.447 + selectionCount++; 1.448 + } 1.449 + 1.450 + assert.equal(selectionCount, 2, 1.451 + "Two iterable selections"); 1.452 + 1.453 + }).then(close).then(loader.unload).then(done, assert.fail); 1.454 +}; 1.455 + 1.456 +exports["test Set HTML in Multiple DOM Selection"] = function(assert, done) { 1.457 + let loader = Loader(module); 1.458 + let selection = loader.require("sdk/selection"); 1.459 + 1.460 + open(URL).then(selectAllDivs).then(function() { 1.461 + let html = "<span>b<b>a</b>r</span>"; 1.462 + 1.463 + let expectedText = ["bar", "and"]; 1.464 + let expectedHTML = [html, "<div>and</div>"]; 1.465 + 1.466 + selection.html = html; 1.467 + 1.468 + assert.equal(selection.text, expectedText[0], 1.469 + "set selection.text with DOM Selection works."); 1.470 + 1.471 + assert.equal(selection.html, expectedHTML[0], 1.472 + "selection.html with DOM Selection works."); 1.473 + 1.474 + let selectionCount = 0; 1.475 + for each (let sel in selection) { 1.476 + 1.477 + assert.equal(sel.text, expectedText[selectionCount], 1.478 + "iterable selection.text with multiple DOM Selection works."); 1.479 + 1.480 + assert.equal(sel.html, expectedHTML[selectionCount], 1.481 + "iterable selection.html with multiple DOM Selection works."); 1.482 + 1.483 + selectionCount++; 1.484 + } 1.485 + 1.486 + assert.equal(selectionCount, 2, 1.487 + "Two iterable selections"); 1.488 + 1.489 + }).then(close).then(loader.unload).then(done, assert.fail); 1.490 +}; 1.491 + 1.492 +exports["test Set HTML as text in Multiple DOM Selection"] = function(assert, done) { 1.493 + let loader = Loader(module); 1.494 + let selection = loader.require("sdk/selection"); 1.495 + 1.496 + open(URL).then(selectAllDivs).then(function() { 1.497 + let text = "<span>b<b>a</b>r</span>"; 1.498 + let html = "<span>b<b>a</b>r</span>"; 1.499 + 1.500 + let expectedText = [text, "and"]; 1.501 + let expectedHTML = [html, "<div>and</div>"]; 1.502 + 1.503 + selection.text = text; 1.504 + 1.505 + assert.equal(selection.text, expectedText[0], 1.506 + "set selection.text with DOM Selection works."); 1.507 + 1.508 + assert.equal(selection.html, expectedHTML[0], 1.509 + "selection.html with DOM Selection works."); 1.510 + 1.511 + let selectionCount = 0; 1.512 + for each (let sel in selection) { 1.513 + 1.514 + assert.equal(sel.text, expectedText[selectionCount], 1.515 + "iterable selection.text with multiple DOM Selection works."); 1.516 + 1.517 + assert.equal(sel.html, expectedHTML[selectionCount], 1.518 + "iterable selection.html with multiple DOM Selection works."); 1.519 + 1.520 + selectionCount++; 1.521 + } 1.522 + 1.523 + assert.equal(selectionCount, 2, 1.524 + "Two iterable selections"); 1.525 + 1.526 + }).then(close).then(loader.unload).then(done, assert.fail); 1.527 +}; 1.528 + 1.529 +exports["test Set Text in Textarea Selection"] = function(assert, done) { 1.530 + let loader = Loader(module); 1.531 + let selection = loader.require("sdk/selection"); 1.532 + 1.533 + open(URL).then(selectTextarea).then(function() { 1.534 + 1.535 + let text = "bar"; 1.536 + 1.537 + selection.text = text; 1.538 + 1.539 + assert.equal(selection.text, text, 1.540 + "set selection.text with Textarea Selection works."); 1.541 + 1.542 + assert.strictEqual(selection.html, null, 1.543 + "selection.html with Textarea Selection works."); 1.544 + 1.545 + let selectionCount = 0; 1.546 + for each (let sel in selection) { 1.547 + selectionCount++; 1.548 + 1.549 + assert.equal(sel.text, text, 1.550 + "iterable selection.text with Textarea Selection works."); 1.551 + 1.552 + assert.strictEqual(sel.html, null, 1.553 + "iterable selection.html with Textarea Selection works."); 1.554 + } 1.555 + 1.556 + assert.equal(selectionCount, 1, 1.557 + "One iterable selection"); 1.558 + 1.559 + }).then(close).then(loader.unload).then(done, assert.fail); 1.560 +}; 1.561 + 1.562 +exports["test Set HTML in Textarea Selection"] = function(assert, done) { 1.563 + let loader = Loader(module); 1.564 + let selection = loader.require("sdk/selection"); 1.565 + 1.566 + open(URL).then(selectTextarea).then(function() { 1.567 + 1.568 + let html = "<span>b<b>a</b>r</span>"; 1.569 + 1.570 + // Textarea can't have HTML so set `html` property is equals to set `text` 1.571 + // property 1.572 + selection.html = html; 1.573 + 1.574 + assert.equal(selection.text, html, 1.575 + "set selection.text with Textarea Selection works."); 1.576 + 1.577 + assert.strictEqual(selection.html, null, 1.578 + "selection.html with Textarea Selection works."); 1.579 + 1.580 + let selectionCount = 0; 1.581 + for each (let sel in selection) { 1.582 + selectionCount++; 1.583 + 1.584 + assert.equal(sel.text, html, 1.585 + "iterable selection.text with Textarea Selection works."); 1.586 + 1.587 + assert.strictEqual(sel.html, null, 1.588 + "iterable selection.html with Textarea Selection works."); 1.589 + } 1.590 + 1.591 + assert.equal(selectionCount, 1, 1.592 + "One iterable selection"); 1.593 + 1.594 + }).then(close).then(loader.unload).then(done, assert.fail); 1.595 +}; 1.596 + 1.597 +exports["test Empty Selections"] = function(assert, done) { 1.598 + let loader = Loader(module); 1.599 + let selection = loader.require("sdk/selection"); 1.600 + 1.601 + open(URL).then(createEmptySelections).then(function(){ 1.602 + assert.equal(selection.isContiguous, false, 1.603 + "selection.isContiguous with empty selections works."); 1.604 + 1.605 + assert.strictEqual(selection.text, null, 1.606 + "selection.text with empty selections works."); 1.607 + 1.608 + assert.strictEqual(selection.html, null, 1.609 + "selection.html with empty selections works."); 1.610 + 1.611 + let selectionCount = 0; 1.612 + for each (let sel in selection) 1.613 + selectionCount++; 1.614 + 1.615 + assert.equal(selectionCount, 0, 1.616 + "No iterable selections"); 1.617 + 1.618 + }).then(close).then(loader.unload).then(done, assert.fail); 1.619 +} 1.620 + 1.621 + 1.622 +exports["test No Selection Exception"] = function(assert, done) { 1.623 + const NO_SELECTION = /It isn't possible to change the selection/; 1.624 + 1.625 + let loader = Loader(module); 1.626 + let selection = loader.require("sdk/selection"); 1.627 + 1.628 + open(URL).then(function() { 1.629 + 1.630 + // We're trying to change a selection when there is no selection 1.631 + assert.throws(function() { 1.632 + selection.text = "bar"; 1.633 + }, NO_SELECTION); 1.634 + 1.635 + assert.throws(function() { 1.636 + selection.html = "bar"; 1.637 + }, NO_SELECTION); 1.638 + 1.639 + }).then(close).then(loader.unload).then(done, assert.fail); 1.640 +}; 1.641 + 1.642 +exports["test for...of without selections"] = function(assert, done) { 1.643 + let loader = Loader(module); 1.644 + let selection = loader.require("sdk/selection"); 1.645 + 1.646 + open(URL).then(function() { 1.647 + let selectionCount = 0; 1.648 + 1.649 + for (let sel of selection) 1.650 + selectionCount++; 1.651 + 1.652 + assert.equal(selectionCount, 0, 1.653 + "No iterable selections"); 1.654 + 1.655 + }).then(close).then(loader.unload).then(null, function(error) { 1.656 + // iterable are not supported yet in Firefox 16, for example, but 1.657 + // they are in Firefox 17. 1.658 + if (error.message.indexOf("is not iterable") > -1) 1.659 + assert.pass("`iterable` method not supported in this application"); 1.660 + else 1.661 + assert.fail(error); 1.662 + }).then(done, assert.fail); 1.663 +} 1.664 + 1.665 +exports["test for...of with selections"] = function(assert, done) { 1.666 + let loader = Loader(module); 1.667 + let selection = loader.require("sdk/selection"); 1.668 + 1.669 + open(URL).then(selectAllDivs).then(function(){ 1.670 + let expectedText = ["foo", "and"]; 1.671 + let expectedHTML = ["<div>foo</div>", "<div>and</div>"]; 1.672 + 1.673 + let selectionCount = 0; 1.674 + 1.675 + for (let sel of selection) { 1.676 + assert.equal(sel.text, expectedText[selectionCount], 1.677 + "iterable selection.text with for...of works."); 1.678 + 1.679 + assert.equal(sel.html, expectedHTML[selectionCount], 1.680 + "iterable selection.text with for...of works."); 1.681 + 1.682 + selectionCount++; 1.683 + } 1.684 + 1.685 + assert.equal(selectionCount, 2, 1.686 + "Two iterable selections"); 1.687 + 1.688 + }).then(close).then(loader.unload).then(null, function(error) { 1.689 + // iterable are not supported yet in Firefox 16, for example, but 1.690 + // they are in Firefox 17. 1.691 + if (error.message.indexOf("is not iterable") > -1) 1.692 + assert.pass("`iterable` method not supported in this application"); 1.693 + else 1.694 + assert.fail(error); 1.695 + }).then(done, assert.fail) 1.696 +} 1.697 + 1.698 +exports["test Selection Listener"] = function(assert, done) { 1.699 + let loader = Loader(module); 1.700 + let selection = loader.require("sdk/selection"); 1.701 + 1.702 + selection.once("select", function() { 1.703 + assert.equal(selection.text, "fo"); 1.704 + done(); 1.705 + }); 1.706 + 1.707 + open(URL).then(selectContentFirstDiv). 1.708 + then(dispatchSelectionEvent). 1.709 + then(close). 1.710 + then(loader.unload, assert.fail); 1.711 +}; 1.712 + 1.713 +exports["test Textarea OnSelect Listener"] = function(assert, done) { 1.714 + let loader = Loader(module); 1.715 + let selection = loader.require("sdk/selection"); 1.716 + 1.717 + selection.once("select", function() { 1.718 + assert.equal(selection.text, "noodles"); 1.719 + done(); 1.720 + }); 1.721 + 1.722 + open(URL).then(selectTextarea). 1.723 + then(dispatchOnSelectEvent). 1.724 + then(close). 1.725 + then(loader.unload, assert.fail); 1.726 +}; 1.727 + 1.728 +exports["test Selection listener removed on unload"] = function(assert, done) { 1.729 + let loader = Loader(module); 1.730 + let selection = loader.require("sdk/selection"); 1.731 + 1.732 + selection.once("select", function() { 1.733 + assert.fail("Shouldn't be never called"); 1.734 + }); 1.735 + 1.736 + loader.unload(); 1.737 + 1.738 + assert.pass(); 1.739 + 1.740 + open(URL). 1.741 + then(selectContentFirstDiv). 1.742 + then(dispatchSelectionEvent). 1.743 + then(close). 1.744 + then(done, assert.fail); 1.745 +}; 1.746 + 1.747 +exports["test Textarea onSelect Listener removed on unload"] = function(assert, done) { 1.748 + let loader = Loader(module); 1.749 + let selection = loader.require("sdk/selection"); 1.750 + 1.751 + selection.once("select", function() { 1.752 + assert.fail("Shouldn't be never called"); 1.753 + }); 1.754 + 1.755 + loader.unload(); 1.756 + 1.757 + assert.pass(); 1.758 + 1.759 + open(URL). 1.760 + then(selectTextarea). 1.761 + then(dispatchOnSelectEvent). 1.762 + then(close). 1.763 + then(done, assert.fail); 1.764 +}; 1.765 + 1.766 + 1.767 +exports["test Selection Listener on existing document"] = function(assert, done) { 1.768 + let loader = Loader(module); 1.769 + 1.770 + open(URL).then(function(window){ 1.771 + let selection = loader.require("sdk/selection"); 1.772 + 1.773 + selection.once("select", function() { 1.774 + assert.equal(selection.text, "fo"); 1.775 + done(); 1.776 + }); 1.777 + 1.778 + return window; 1.779 + }).then(selectContentFirstDiv). 1.780 + then(dispatchSelectionEvent). 1.781 + then(close). 1.782 + then(loader.unload, assert.fail); 1.783 +}; 1.784 + 1.785 + 1.786 +exports["test Textarea OnSelect Listener on existing document"] = function(assert, done) { 1.787 + let loader = Loader(module); 1.788 + 1.789 + open(URL).then(function(window){ 1.790 + let selection = loader.require("sdk/selection"); 1.791 + 1.792 + selection.once("select", function() { 1.793 + assert.equal(selection.text, "noodles"); 1.794 + done(); 1.795 + }); 1.796 + 1.797 + return window; 1.798 + }).then(selectTextarea). 1.799 + then(dispatchOnSelectEvent). 1.800 + then(close). 1.801 + then(loader.unload, assert.fail); 1.802 +}; 1.803 + 1.804 +exports["test Selection Listener on document reload"] = function(assert, done) { 1.805 + let loader = Loader(module); 1.806 + let selection = loader.require("sdk/selection"); 1.807 + 1.808 + selection.once("select", function() { 1.809 + assert.equal(selection.text, "fo"); 1.810 + done(); 1.811 + }); 1.812 + 1.813 + open(URL). 1.814 + then(reload). 1.815 + then(selectContentFirstDiv). 1.816 + then(dispatchSelectionEvent). 1.817 + then(close). 1.818 + then(loader.unload, assert.fail); 1.819 +}; 1.820 + 1.821 +exports["test Textarea OnSelect Listener on document reload"] = function(assert, done) { 1.822 + let loader = Loader(module); 1.823 + let selection = loader.require("sdk/selection"); 1.824 + 1.825 + selection.once("select", function() { 1.826 + assert.equal(selection.text, "noodles"); 1.827 + done(); 1.828 + }); 1.829 + 1.830 + open(URL). 1.831 + then(reload). 1.832 + then(selectTextarea). 1.833 + then(dispatchOnSelectEvent). 1.834 + then(close). 1.835 + then(loader.unload, assert.fail); 1.836 +}; 1.837 + 1.838 +exports["test Selection Listener on frame"] = function(assert, done) { 1.839 + let loader = Loader(module); 1.840 + let selection = loader.require("sdk/selection"); 1.841 + 1.842 + selection.once("select", function() { 1.843 + assert.equal(selection.text, "fo"); 1.844 + close(); 1.845 + loader.unload(); 1.846 + done(); 1.847 + }); 1.848 + 1.849 + open(FRAME_URL). 1.850 + then(hideAndShowFrame). 1.851 + then(getFrameWindow). 1.852 + then(selectContentFirstDiv). 1.853 + then(dispatchSelectionEvent). 1.854 + then(null, assert.fail); 1.855 +}; 1.856 + 1.857 +exports["test Textarea onSelect Listener on frame"] = function(assert, done) { 1.858 + let loader = Loader(module); 1.859 + let selection = loader.require("sdk/selection"); 1.860 + 1.861 + selection.once("select", function() { 1.862 + assert.equal(selection.text, "noodles"); 1.863 + close(); 1.864 + loader.unload(); 1.865 + done(); 1.866 + }); 1.867 + 1.868 + open(FRAME_URL). 1.869 + then(hideAndShowFrame). 1.870 + then(getFrameWindow). 1.871 + then(selectTextarea). 1.872 + then(dispatchOnSelectEvent). 1.873 + then(null, assert.fail); 1.874 +}; 1.875 + 1.876 + 1.877 +exports["test PBPW Selection Listener"] = function(assert, done) { 1.878 + let loader = Loader(module); 1.879 + let selection = loader.require("sdk/selection"); 1.880 + 1.881 + selection.once("select", function() { 1.882 + assert.fail("Shouldn't be never called"); 1.883 + }); 1.884 + 1.885 + assert.pass(); 1.886 + 1.887 + open(URL, {private: true}). 1.888 + then(selectContentFirstDiv). 1.889 + then(dispatchSelectionEvent). 1.890 + then(close). 1.891 + then(loader.unload). 1.892 + then(done, assert.fail); 1.893 +}; 1.894 + 1.895 +exports["test PBPW Textarea OnSelect Listener"] = function(assert, done) { 1.896 + let loader = Loader(module); 1.897 + let selection = loader.require("sdk/selection"); 1.898 + 1.899 + selection.once("select", function() { 1.900 + assert.fail("Shouldn't be never called"); 1.901 + }); 1.902 + 1.903 + assert.pass(); 1.904 + 1.905 + open(URL, {private: true}). 1.906 + then(selectTextarea). 1.907 + then(dispatchOnSelectEvent). 1.908 + then(close). 1.909 + then(loader.unload). 1.910 + then(done, assert.fail); 1.911 +}; 1.912 + 1.913 + 1.914 +exports["test PBPW Single DOM Selection"] = function(assert, done) { 1.915 + let loader = Loader(module); 1.916 + let selection = loader.require("sdk/selection"); 1.917 + 1.918 + open(URL, {private: true}).then(selectFirstDiv).then(function(window) { 1.919 + 1.920 + assert.equal(selection.isContiguous, false, 1.921 + "selection.isContiguous with single DOM Selection in PBPW works."); 1.922 + 1.923 + assert.equal(selection.text, null, 1.924 + "selection.text with single DOM Selection in PBPW works."); 1.925 + 1.926 + assert.equal(selection.html, null, 1.927 + "selection.html with single DOM Selection in PBPW works."); 1.928 + 1.929 + let selectionCount = 0; 1.930 + for each (let sel in selection) 1.931 + selectionCount++; 1.932 + 1.933 + assert.equal(selectionCount, 0, 1.934 + "No iterable selection in PBPW"); 1.935 + 1.936 + return window; 1.937 + }).then(close).then(loader.unload).then(done, assert.fail); 1.938 +}; 1.939 + 1.940 +exports["test PBPW Textarea Selection"] = function(assert, done) { 1.941 + let loader = Loader(module); 1.942 + let selection = loader.require("sdk/selection"); 1.943 + 1.944 + open(URL, {private: true}).then(selectTextarea).then(function(window) { 1.945 + 1.946 + assert.equal(selection.isContiguous, false, 1.947 + "selection.isContiguous with Textarea Selection in PBPW works."); 1.948 + 1.949 + assert.equal(selection.text, null, 1.950 + "selection.text with Textarea Selection in PBPW works."); 1.951 + 1.952 + assert.strictEqual(selection.html, null, 1.953 + "selection.html with Textarea Selection in PBPW works."); 1.954 + 1.955 + let selectionCount = 0; 1.956 + for each (let sel in selection) { 1.957 + selectionCount++; 1.958 + 1.959 + assert.equal(sel.text, null, 1.960 + "iterable selection.text with Textarea Selection in PBPW works."); 1.961 + 1.962 + assert.strictEqual(sel.html, null, 1.963 + "iterable selection.html with Textarea Selection in PBPW works."); 1.964 + } 1.965 + 1.966 + assert.equal(selectionCount, 0, 1.967 + "No iterable selection in PBPW"); 1.968 + 1.969 + return window; 1.970 + }).then(close).then(loader.unload).then(done, assert.fail); 1.971 +}; 1.972 + 1.973 +// TODO: test Selection Listener on long-held connection (Bug 661884) 1.974 +// 1.975 +// I didn't find a way to do so with httpd, using `processAsync` I'm able to 1.976 +// Keep the connection but not to flush the buffer to the client in two steps, 1.977 +// that is what I need for this test (e.g. flush "Hello" to the client, makes 1.978 +// selection when the connection is still hold, and check that the listener 1.979 +// is executed before the server send "World" and close the connection). 1.980 +// 1.981 +// Because this test is needed to the refactoring of context-menu as well, I 1.982 +// believe we will find a proper solution quickly. 1.983 +/* 1.984 +exports["test Selection Listener on long-held connection"] = function(assert, done) { 1.985 + 1.986 +}; 1.987 +*/ 1.988 + 1.989 +// If the platform doesn't support the PBPW, we're replacing PBPW tests 1.990 +if (!require("sdk/private-browsing/utils").isWindowPBSupported) { 1.991 + Object.keys(module.exports).forEach(function(key) { 1.992 + if (key.indexOf("test PBPW") === 0) { 1.993 + module.exports[key] = function Unsupported (assert) { 1.994 + assert.pass("Private Window Per Browsing is not supported on this platform."); 1.995 + } 1.996 + } 1.997 + }); 1.998 +} 1.999 + 1.1000 +require("test").run(exports)