Bumping manifests a=b2g-bump
[gecko.git] / addon-sdk / source / test / test-selection.js
blobf80301eeb61b9aac45a23cba831b9e772ed12ea7
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 'use strict';
7 module.metadata = {
8   'engines': {
9     'Firefox': '*'
10   }
13 const HTML = "<html>\
14   <body>\
15     <div>foo</div>\
16     <div>and</div>\
17     <textarea>noodles</textarea>\
18   </body>\
19 </html>";
21 const URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
23 const FRAME_HTML = "<iframe src='" + URL + "'><iframe>";
24 const FRAME_URL = "data:text/html;charset=utf-8," + encodeURIComponent(FRAME_HTML);
26 const { defer } = require("sdk/core/promise");
27 const tabs = require("sdk/tabs");
28 const { setTabURL } = require("sdk/tabs/utils");
29 const { getActiveTab, getTabContentWindow, closeTab } = require("sdk/tabs/utils")
30 const { getMostRecentBrowserWindow } = require("sdk/window/utils");
31 const { open: openNewWindow, close: closeWindow } = require("sdk/window/helpers");
32 const { Loader } = require("sdk/test/loader");
33 const { setTimeout } = require("sdk/timers");
34 const { Cu } = require("chrome");
35 const { merge } = require("sdk/util/object");
36 const { isPrivate } = require("sdk/private-browsing");
37 const events = require("sdk/system/events");
38 // General purpose utility functions
40 /**
41  * Opens the url given and return a promise, that will be resolved with the
42  * content window when the document is ready.
43  *
44  * I believe this approach could be useful in most of our unit test, that
45  * requires to open a tab and need to access to its content.
46  */
47 function open(url, options) {
48   let { promise, resolve } = defer();
50   if (options && typeof(options) === "object") {
51     openNewWindow("", {
52       features: merge({ toolbar: true }, options)
53     }).then(function(chromeWindow) {
54       if (isPrivate(chromeWindow) !== !!options.private)
55         throw new Error("Window should have Private set to " + !!options.private);
57       let tab = getActiveTab(chromeWindow);
59       tab.linkedBrowser.addEventListener("load", function ready(event) {
60         let { document } = getTabContentWindow(tab);
62         if (document.readyState === "complete" && document.URL === url) {
63           this.removeEventListener(event.type, ready);
65           resolve(document.defaultView);
66         }
67       }, true);
69       setTabURL(tab, url);
70     });
72     return promise;
73   };
75   tabs.open({
76     url: url,
77     onReady: function(tab) {
78       // Unfortunately there is no way to get a XUL Tab from SDK Tab on Firefox,
79       // only on Fennec. We should implement `tabNS` also on Firefox in order
80       // to have that.
82       // Here we assuming that the most recent browser window is the one we're
83       // doing the test, and the active tab is the one we just opened.
84       let window = getTabContentWindow(getActiveTab(getMostRecentBrowserWindow()));
86       resolve(window);
87     }
88   });
90   return promise;
93 /**
94  * Close the Active Tab
95  */
96 function close(window) {
97   if (window && window.top && typeof(window.top).close === "function") {
98     window.top.close();
99   } else {
100     // Here we assuming that the most recent browser window is the one we're
101     // doing the test, and the active tab is the one we just opened.
102     let tab = getActiveTab(getMostRecentBrowserWindow());
104     closeTab(tab);
105   }
109  * Reload the window given and return a promise, that will be resolved with the
110  * content window after a small delay.
111  */
112 function reload(window) {
113   let { promise, resolve } = defer();
115   // Here we assuming that the most recent browser window is the one we're
116   // doing the test, and the active tab is the one we just opened.
117   let tab = tabs.activeTab;
119   tab.once("ready", function () {
120     resolve(window);
121   });
123   window.location.reload(true);
125   return promise;
128 // Selection's unit test utility function
131  * Returns the frame's window once the document is loaded
132  */
133 function getFrameWindow(window) {
134   let { promise, resolve } = defer();
136   let frame = window.frames[0];
137   let { document } = frame;
139   frame.focus();
141   if (document.readyState === "complete")
142     return frame;
144   document.addEventListener("readystatechange", function readystate() {
145     if (this.readyState === "complete") {
146       this.removeEventListener("readystatechange", readystate);
147       frame.focus();
148       resolve(frame);
149     }
150   });
152   return promise;
156  * Hide the frame in order to destroy the selection object, and show it again
157  * after ~500 msec, to give time to attach the code on `document-shown`
158  * notification.
159  * In the process, call `Cu.forgeGC` to ensure that the `document-shown` code
160  * is not garbaged.
161  */
162 function hideAndShowFrame(window) {
163   let { promise, resolve } = defer();
164   let iframe = window.document.querySelector("iframe");
166   iframe.style.display = "none";
168   Cu.schedulePreciseGC(function() {
169     events.on("document-shown", function shown(event) {
170       if (iframe.contentWindow !== event.subject.defaultView)
171         return;
173       events.off("document-shown", shown);
174       setTimeout(resolve, 0, window);
175     }, true);
177     iframe.style.display = "";
178   });
180   return promise;
184  * Select the first div in the page, adding the range to the selection.
185  */
186 function selectFirstDiv(window) {
187   let div = window.document.querySelector("div");
188   let selection = window.getSelection();
189   let range = window.document.createRange();
191   if (selection.rangeCount > 0)
192     selection.removeAllRanges();
194   range.selectNode(div);
195   selection.addRange(range);
197   return window;
201  * Select all divs in the page, adding the ranges to the selection.
202  */
203 function selectAllDivs(window) {
204   let divs = window.document.getElementsByTagName("div");
205   let selection = window.getSelection();
207   if (selection.rangeCount > 0)
208     selection.removeAllRanges();
210   for (let i = 0; i < divs.length; i++) {
211     let range = window.document.createRange();
213     range.selectNode(divs[i]);
214     selection.addRange(range);
215   }
217   return window;
221  * Select the textarea content
222  */
223 function selectTextarea(window) {
224   let selection = window.getSelection();
225   let textarea = window.document.querySelector("textarea");
227   if (selection.rangeCount > 0)
228     selection.removeAllRanges();
230   textarea.setSelectionRange(0, textarea.value.length);
231   textarea.focus();
233   return window;
237  * Select the content of the first div
238  */
239 function selectContentFirstDiv(window) {
240   let div = window.document.querySelector("div");
241   let selection = window.getSelection();
242   let range = window.document.createRange();
244   if (selection.rangeCount > 0)
245     selection.removeAllRanges();
247   range.selectNodeContents(div);
248   selection.addRange(range);
250   return window;
254  * Dispatch the selection event for the selection listener added by
255  * `nsISelectionPrivate.addSelectionListener`
256  */
257 function dispatchSelectionEvent(window) {
258   // We modify the selection in order to dispatch the selection's event, by
259   // contract the selection by one character. So if the text selected is "foo"
260   // will be "fo".
261   window.getSelection().modify("extend", "backward", "character");
263   return window;
267  * Dispatch the selection event for the selection listener added by
268  * `window.onselect` / `window.addEventListener`
269  */
270 function dispatchOnSelectEvent(window) {
271   let { document } = window;
272   let textarea = document.querySelector("textarea");
273   let event = document.createEvent("UIEvents");
275   event.initUIEvent("select", true, true, window, 1);
277   textarea.dispatchEvent(event);
279   return window;
283  * Creates empty ranges and add them to selections
284  */
285 function createEmptySelections(window) {
286   selectAllDivs(window);
288   let selection = window.getSelection();
290   for (let i = 0; i < selection.rangeCount; i++)
291     selection.getRangeAt(i).collapse(true);
294 // Test cases
296 exports["test No Selection"] = function(assert, done) {
297   let loader = Loader(module);
298   let selection = loader.require("sdk/selection");
300   open(URL).then(function() {
302     assert.equal(selection.isContiguous, false,
303       "selection.isContiguous without selection works.");
305     assert.strictEqual(selection.text, null,
306       "selection.text without selection works.");
308     assert.strictEqual(selection.html, null,
309       "selection.html without selection works.");
311     let selectionCount = 0;
312     for each (let sel in selection)
313       selectionCount++;
315     assert.equal(selectionCount, 0,
316       "No iterable selections");
318   }).then(close).then(loader.unload).then(done, assert.fail);
321 exports["test Single DOM Selection"] = function(assert, done) {
322   let loader = Loader(module);
323   let selection = loader.require("sdk/selection");
325   open(URL).then(selectFirstDiv).then(function() {
327     assert.equal(selection.isContiguous, true,
328       "selection.isContiguous with single DOM Selection works.");
330     assert.equal(selection.text, "foo",
331       "selection.text with single DOM Selection works.");
333     assert.equal(selection.html, "<div>foo</div>",
334       "selection.html with single DOM Selection works.");
336     let selectionCount = 0;
337     for each (let sel in selection) {
338       selectionCount++;
340       assert.equal(sel.text, "foo",
341         "iterable selection.text with single DOM Selection works.");
343       assert.equal(sel.html, "<div>foo</div>",
344         "iterable selection.html with single DOM Selection works.");
345     }
347     assert.equal(selectionCount, 1,
348       "One iterable selection");
350   }).then(close).then(loader.unload).then(done, assert.fail);
353 exports["test Multiple DOM Selection"] = function(assert, done) {
354   let loader = Loader(module);
355   let selection = loader.require("sdk/selection");
357   open(URL).then(selectAllDivs).then(function() {
358     let expectedText = ["foo", "and"];
359     let expectedHTML = ["<div>foo</div>", "<div>and</div>"];
361     assert.equal(selection.isContiguous, false,
362       "selection.isContiguous with multiple DOM Selection works.");
364     assert.equal(selection.text, expectedText[0],
365       "selection.text with multiple DOM Selection works.");
367     assert.equal(selection.html, expectedHTML[0],
368       "selection.html with multiple DOM Selection works.");
370     let selectionCount = 0;
371     for each (let sel in selection) {
372       assert.equal(sel.text, expectedText[selectionCount],
373         "iterable selection.text with multiple DOM Selection works.");
375       assert.equal(sel.html, expectedHTML[selectionCount],
376         "iterable selection.text with multiple DOM Selection works.");
378       selectionCount++;
379     }
381     assert.equal(selectionCount, 2,
382       "Two iterable selections");
384   }).then(close).then(loader.unload).then(done, assert.fail);
387 exports["test Textarea Selection"] = function(assert, done) {
388   let loader = Loader(module);
389   let selection = loader.require("sdk/selection");
391   open(URL).then(selectTextarea).then(function() {
393     assert.equal(selection.isContiguous, true,
394       "selection.isContiguous with Textarea Selection works.");
396     assert.equal(selection.text, "noodles",
397       "selection.text with Textarea Selection works.");
399     assert.strictEqual(selection.html, null,
400       "selection.html with Textarea Selection works.");
402     let selectionCount = 0;
403     for each (let sel in selection) {
404       selectionCount++;
406       assert.equal(sel.text, "noodles",
407         "iterable selection.text with Textarea Selection works.");
409       assert.strictEqual(sel.html, null,
410         "iterable selection.html with Textarea Selection works.");
411     }
413     assert.equal(selectionCount, 1,
414       "One iterable selection");
416   }).then(close).then(loader.unload).then(done, assert.fail);
419 exports["test Set Text in Multiple DOM Selection"] = function(assert, done) {
420   let loader = Loader(module);
421   let selection = loader.require("sdk/selection");
423   open(URL).then(selectAllDivs).then(function() {
424     let expectedText = ["bar", "and"];
425     let expectedHTML = ["bar", "<div>and</div>"];
427     selection.text = "bar";
429     assert.equal(selection.text, expectedText[0],
430       "set selection.text with single DOM Selection works.");
432     assert.equal(selection.html, expectedHTML[0],
433       "selection.html with single DOM Selection works.");
435     let selectionCount = 0;
436     for each (let sel in selection) {
438       assert.equal(sel.text, expectedText[selectionCount],
439         "iterable selection.text with multiple DOM Selection works.");
441       assert.equal(sel.html, expectedHTML[selectionCount],
442         "iterable selection.html with multiple DOM Selection works.");
444       selectionCount++;
445     }
447     assert.equal(selectionCount, 2,
448       "Two iterable selections");
450   }).then(close).then(loader.unload).then(done, assert.fail);
453 exports["test Set HTML in Multiple DOM Selection"] = function(assert, done) {
454   let loader = Loader(module);
455   let selection = loader.require("sdk/selection");
457   open(URL).then(selectAllDivs).then(function() {
458     let html = "<span>b<b>a</b>r</span>";
460     let expectedText = ["bar", "and"];
461     let expectedHTML = [html, "<div>and</div>"];
463     selection.html = html;
465     assert.equal(selection.text, expectedText[0],
466       "set selection.text with DOM Selection works.");
468     assert.equal(selection.html, expectedHTML[0],
469       "selection.html with DOM Selection works.");
471     let selectionCount = 0;
472     for each (let sel in selection) {
474       assert.equal(sel.text, expectedText[selectionCount],
475         "iterable selection.text with multiple DOM Selection works.");
477       assert.equal(sel.html, expectedHTML[selectionCount],
478         "iterable selection.html with multiple DOM Selection works.");
480       selectionCount++;
481     }
483     assert.equal(selectionCount, 2,
484       "Two iterable selections");
486   }).then(close).then(loader.unload).then(done, assert.fail);
489 exports["test Set HTML as text in Multiple DOM Selection"] = function(assert, done) {
490   let loader = Loader(module);
491   let selection = loader.require("sdk/selection");
493   open(URL).then(selectAllDivs).then(function() {
494     let text = "<span>b<b>a</b>r</span>";
495     let html = "&lt;span&gt;b&lt;b&gt;a&lt;/b&gt;r&lt;/span&gt;";
497     let expectedText = [text, "and"];
498     let expectedHTML = [html, "<div>and</div>"];
500     selection.text = text;
502     assert.equal(selection.text, expectedText[0],
503       "set selection.text with DOM Selection works.");
505     assert.equal(selection.html, expectedHTML[0],
506       "selection.html with DOM Selection works.");
508     let selectionCount = 0;
509     for each (let sel in selection) {
511       assert.equal(sel.text, expectedText[selectionCount],
512         "iterable selection.text with multiple DOM Selection works.");
514       assert.equal(sel.html, expectedHTML[selectionCount],
515         "iterable selection.html with multiple DOM Selection works.");
517       selectionCount++;
518     }
520     assert.equal(selectionCount, 2,
521       "Two iterable selections");
523   }).then(close).then(loader.unload).then(done, assert.fail);
526 exports["test Set Text in Textarea Selection"] = function(assert, done) {
527   let loader = Loader(module);
528   let selection = loader.require("sdk/selection");
530   open(URL).then(selectTextarea).then(function() {
532     let text = "bar";
534     selection.text = text;
536     assert.equal(selection.text, text,
537       "set selection.text with Textarea Selection works.");
539     assert.strictEqual(selection.html, null,
540       "selection.html with Textarea Selection works.");
542     let selectionCount = 0;
543     for each (let sel in selection) {
544       selectionCount++;
546       assert.equal(sel.text, text,
547         "iterable selection.text with Textarea Selection works.");
549       assert.strictEqual(sel.html, null,
550         "iterable selection.html with Textarea Selection works.");
551     }
553     assert.equal(selectionCount, 1,
554       "One iterable selection");
556   }).then(close).then(loader.unload).then(done, assert.fail);
559 exports["test Set HTML in Textarea Selection"] = function(assert, done) {
560   let loader = Loader(module);
561   let selection = loader.require("sdk/selection");
563   open(URL).then(selectTextarea).then(function() {
565     let html = "<span>b<b>a</b>r</span>";
567     // Textarea can't have HTML so set `html` property is equals to set `text`
568     // property
569     selection.html = html;
571     assert.equal(selection.text, html,
572       "set selection.text with Textarea Selection works.");
574     assert.strictEqual(selection.html, null,
575       "selection.html with Textarea Selection works.");
577     let selectionCount = 0;
578     for each (let sel in selection) {
579       selectionCount++;
581       assert.equal(sel.text, html,
582         "iterable selection.text with Textarea Selection works.");
584       assert.strictEqual(sel.html, null,
585         "iterable selection.html with Textarea Selection works.");
586     }
588     assert.equal(selectionCount, 1,
589       "One iterable selection");
591   }).then(close).then(loader.unload).then(done, assert.fail);
594 exports["test Empty Selections"] = function(assert, done) {
595   let loader = Loader(module);
596   let selection = loader.require("sdk/selection");
598   open(URL).then(createEmptySelections).then(function(){
599     assert.equal(selection.isContiguous, false,
600       "selection.isContiguous with empty selections works.");
602     assert.strictEqual(selection.text, null,
603       "selection.text with empty selections works.");
605     assert.strictEqual(selection.html, null,
606       "selection.html with empty selections works.");
608     let selectionCount = 0;
609     for each (let sel in selection)
610       selectionCount++;
612     assert.equal(selectionCount, 0,
613       "No iterable selections");
615   }).then(close).then(loader.unload).then(done, assert.fail);
619 exports["test No Selection Exception"] = function(assert, done) {
620   const NO_SELECTION = /It isn't possible to change the selection/;
622   let loader = Loader(module);
623   let selection = loader.require("sdk/selection");
625   open(URL).then(function() {
627     // We're trying to change a selection when there is no selection
628     assert.throws(function() {
629       selection.text = "bar";
630     }, NO_SELECTION);
632     assert.throws(function() {
633       selection.html = "bar";
634     }, NO_SELECTION);
636   }).then(close).then(loader.unload).then(done, assert.fail);
639 exports["test for...of without selections"] = function(assert, done) {
640   let loader = Loader(module);
641   let selection = loader.require("sdk/selection");
643   open(URL).then(function() {
644     let selectionCount = 0;
646     for (let sel of selection)
647       selectionCount++;
649     assert.equal(selectionCount, 0,
650       "No iterable selections");
652   }).then(close).then(loader.unload).then(null, function(error) {
653     // iterable are not supported yet in Firefox 16, for example, but
654     // they are in Firefox 17.
655     if (error.message.indexOf("is not iterable") > -1)
656       assert.pass("`iterable` method not supported in this application");
657     else
658       assert.fail(error);
659   }).then(done, assert.fail);
662 exports["test for...of with selections"] = function(assert, done) {
663   let loader = Loader(module);
664   let selection = loader.require("sdk/selection");
666   open(URL).then(selectAllDivs).then(function(){
667     let expectedText = ["foo", "and"];
668     let expectedHTML = ["<div>foo</div>", "<div>and</div>"];
670     let selectionCount = 0;
672     for (let sel of selection) {
673       assert.equal(sel.text, expectedText[selectionCount],
674         "iterable selection.text with for...of works.");
676       assert.equal(sel.html, expectedHTML[selectionCount],
677         "iterable selection.text with for...of works.");
679       selectionCount++;
680     }
682     assert.equal(selectionCount, 2,
683       "Two iterable selections");
685   }).then(close).then(loader.unload).then(null, function(error) {
686     // iterable are not supported yet in Firefox 16, for example, but
687     // they are in Firefox 17.
688     if (error.message.indexOf("is not iterable") > -1)
689       assert.pass("`iterable` method not supported in this application");
690     else
691       assert.fail(error);
692   }).then(done, assert.fail)
695 exports["test Selection Listener"] = function(assert, done) {
696   let loader = Loader(module);
697   let selection = loader.require("sdk/selection");
699   selection.once("select", function() {
700     assert.equal(selection.text, "fo");
701     close();
702     loader.unload();
703     done();
704   });
706   open(URL).then(selectContentFirstDiv).
707     then(dispatchSelectionEvent, assert.fail);
710 exports["test Textarea OnSelect Listener"] = function(assert, done) {
711   let loader = Loader(module);
712   let selection = loader.require("sdk/selection");
714   selection.once("select", function() {
715     assert.equal(selection.text, "noodles");
716     close();
717     loader.unload();
718     done();
719   });
721   open(URL).then(selectTextarea).
722     then(dispatchOnSelectEvent, assert.fail);
725 exports["test Selection listener removed on unload"] = function(assert, done) {
726   let loader = Loader(module);
727   let selection = loader.require("sdk/selection");
729   selection.once("select", function() {
730     assert.fail("Shouldn't be never called");
731   });
733   loader.unload();
735   assert.pass();
737   open(URL).
738     then(selectContentFirstDiv).
739     then(dispatchSelectionEvent).
740     then(close).
741     then(done, assert.fail);
744 exports["test Textarea onSelect Listener removed on unload"] = function(assert, done) {
745   let loader = Loader(module);
746   let selection = loader.require("sdk/selection");
748   selection.once("select", function() {
749     assert.fail("Shouldn't be never called");
750   });
752   loader.unload();
754   assert.pass();
756   open(URL).
757     then(selectTextarea).
758     then(dispatchOnSelectEvent).
759     then(close).
760     then(done, assert.fail);
764 exports["test Selection Listener on existing document"] = function(assert, done) {
765   let loader = Loader(module);
767   open(URL).then(function(window){
768     let selection = loader.require("sdk/selection");
770     selection.once("select", function() {
771       assert.equal(selection.text, "fo");
772       close();
773       loader.unload();
774       done();
775     });
777     return window;
778   }).then(selectContentFirstDiv).
779     then(dispatchSelectionEvent, assert.fail);
783 exports["test Textarea OnSelect Listener on existing document"] = function(assert, done) {
784   let loader = Loader(module);
786   open(URL).then(function(window){
787     let selection = loader.require("sdk/selection");
789     selection.once("select", function() {
790       assert.equal(selection.text, "noodles");
791       close();
792       loader.unload();
793       done();
794     });
796     return window;
797   }).then(selectTextarea).
798     then(dispatchOnSelectEvent, assert.fail);
801 exports["test Selection Listener on document reload"] = function(assert, done) {
802   let loader = Loader(module);
803   let selection = loader.require("sdk/selection");
805   selection.once("select", function() {
806     assert.equal(selection.text, "fo");
807     close();
808     loader.unload();
809     done();
810   });
812   open(URL).
813     then(reload).
814     then(selectContentFirstDiv).
815     then(dispatchSelectionEvent, assert.fail);
818 exports["test Textarea OnSelect Listener on document reload"] = function(assert, done) {
819   let loader = Loader(module);
820   let selection = loader.require("sdk/selection");
822   selection.once("select", function() {
823     assert.equal(selection.text, "noodles");
824     close();
825     loader.unload();
826     done();
827   });
829   open(URL).
830     then(reload).
831     then(selectTextarea).
832     then(dispatchOnSelectEvent, assert.fail);
835 exports["test Selection Listener on frame"] = function(assert, done) {
836   let loader = Loader(module);
837   let selection = loader.require("sdk/selection");
839   selection.once("select", function() {
840     assert.equal(selection.text, "fo");
841     close();
842     loader.unload();
843     done();
844   });
846   open(FRAME_URL).
847     then(hideAndShowFrame).
848     then(getFrameWindow).
849     then(selectContentFirstDiv).
850     then(dispatchSelectionEvent).
851     then(null, assert.fail);
854 exports["test Textarea onSelect Listener on frame"] = function(assert, done) {
855   let loader = Loader(module);
856   let selection = loader.require("sdk/selection");
858   selection.once("select", function() {
859     assert.equal(selection.text, "noodles");
860     close();
861     loader.unload();
862     done();
863   });
865   open(FRAME_URL).
866     then(hideAndShowFrame).
867     then(getFrameWindow).
868     then(selectTextarea).
869     then(dispatchOnSelectEvent).
870     then(null, assert.fail);
874 exports["test PBPW Selection Listener"] = function(assert, done) {
875   let loader = Loader(module);
876   let selection = loader.require("sdk/selection");
878   selection.once("select", function() {
879     assert.fail("Shouldn't be never called");
880   });
882   assert.pass();
884   open(URL, {private: true}).
885     then(selectContentFirstDiv).
886     then(dispatchSelectionEvent).
887     then(closeWindow).
888     then(loader.unload).
889     then(done, assert.fail);
892 exports["test PBPW Textarea OnSelect Listener"] = function(assert, done) {
893   let loader = Loader(module);
894   let selection = loader.require("sdk/selection");
896   selection.once("select", function() {
897     assert.fail("Shouldn't be never called");
898   });
900   assert.pass();
902   open(URL, {private: true}).
903     then(selectTextarea).
904     then(dispatchOnSelectEvent).
905     then(closeWindow).
906     then(loader.unload).
907     then(done, assert.fail);
911 exports["test PBPW Single DOM Selection"] = function(assert, done) {
912   let loader = Loader(module);
913   let selection = loader.require("sdk/selection");
915   open(URL, {private: true}).then(selectFirstDiv).then(function(window) {
917     assert.equal(selection.isContiguous, false,
918       "selection.isContiguous with single DOM Selection in PBPW works.");
920     assert.equal(selection.text, null,
921       "selection.text with single DOM Selection in PBPW works.");
923     assert.equal(selection.html, null,
924       "selection.html with single DOM Selection in PBPW works.");
926     let selectionCount = 0;
927     for each (let sel in selection)
928       selectionCount++;
930     assert.equal(selectionCount, 0,
931       "No iterable selection in PBPW");
933     return window;
934   }).then(closeWindow).then(loader.unload).then(done, assert.fail);
937 exports["test PBPW Textarea Selection"] = function(assert, done) {
938   let loader = Loader(module);
939   let selection = loader.require("sdk/selection");
941   open(URL, {private: true}).then(selectTextarea).then(function(window) {
943     assert.equal(selection.isContiguous, false,
944       "selection.isContiguous with Textarea Selection in PBPW works.");
946     assert.equal(selection.text, null,
947       "selection.text with Textarea Selection in PBPW works.");
949     assert.strictEqual(selection.html, null,
950       "selection.html with Textarea Selection in PBPW works.");
952     let selectionCount = 0;
953     for each (let sel in selection) {
954       selectionCount++;
956       assert.equal(sel.text, null,
957         "iterable selection.text with Textarea Selection in PBPW works.");
959       assert.strictEqual(sel.html, null,
960         "iterable selection.html with Textarea Selection in PBPW works.");
961     }
963     assert.equal(selectionCount, 0,
964       "No iterable selection in PBPW");
966     return window;
967   }).then(closeWindow).then(loader.unload).then(done, assert.fail);
970 // TODO: test Selection Listener on long-held connection (Bug 661884)
972 //  I didn't find a way to do so with httpd, using `processAsync` I'm able to
973 //  Keep the connection but not to flush the buffer to the client in two steps,
974 //  that is what I need for this test (e.g. flush "Hello" to the client, makes
975 //  selection when the connection is still hold, and check that the listener
976 //  is executed before the server send "World" and close the connection).
978 //  Because this test is needed to the refactoring of context-menu as well, I
979 //  believe we will find a proper solution quickly.
981 exports["test Selection Listener on long-held connection"] = function(assert, done) {
986 // If the platform doesn't support the PBPW, we're replacing PBPW tests
987 if (!require("sdk/private-browsing/utils").isWindowPBSupported) {
988   Object.keys(module.exports).forEach(function(key) {
989     if (key.indexOf("test PBPW") === 0) {
990       module.exports[key] = function Unsupported (assert) {
991         assert.pass("Private Window Per Browsing is not supported on this platform.");
992       }
993     }
994   });
997 require("test").run(exports)