From 95dc9d031599dfa7fcf986f3ce976932049131d5 Mon Sep 17 00:00:00 2001 From: Luiza Pagliari Date: Tue, 21 Jun 2016 06:48:10 -0300 Subject: Enable multi-line selection on frontend tests --- tests/frontend/helper.js | 77 +++++++++++++++++++++++++---- tests/frontend/specs/helper.js | 97 ++++++++++++++++++++++++++++++++++++- tests/frontend/specs/indentation.js | 45 +++++++++++++++++ 3 files changed, 209 insertions(+), 10 deletions(-) diff --git a/tests/frontend/helper.js b/tests/frontend/helper.js index 7131119a..d8aa096f 100644 --- a/tests/frontend/helper.js +++ b/tests/frontend/helper.js @@ -6,11 +6,11 @@ var helper = {}; helper.init = function(cb){ $iframeContainer = $("#iframe-container"); - $.get('/static/js/jquery.js').done(function(code){ + $.get('/static/js/jquery.js').done(function(code){ // make sure we don't override existing jquery jsLibraries["jquery"] = "if(typeof $ === 'undefined') {\n" + code + "\n}"; - $.get('/tests/frontend/lib/sendkeys.js').done(function(code){ + $.get('/tests/frontend/lib/sendkeys.js').done(function(code){ jsLibraries["sendkeys"] = code; cb(); @@ -32,7 +32,7 @@ var helper = {}; var getFrameJQuery = function($iframe){ /* - I tried over 9000 ways to inject javascript into iframes. + I tried over 9000 ways to inject javascript into iframes. This is the only way I found that worked in IE 7+8+9, FF and Chrome */ @@ -45,7 +45,7 @@ var helper = {}; win.eval(jsLibraries["jquery"]); win.eval(jsLibraries["sendkeys"]); - + win.$.window = win; win.$.document = doc; @@ -73,14 +73,14 @@ var helper = {}; if(!padName) padName = "FRONTEND_TEST_" + helper.randomString(20); $iframe = $(""); - + //clean up inner iframe references helper.padChrome$ = helper.padOuter$ = helper.padInner$ = null; //clean up iframes properly to prevent IE from memoryleaking $iframeContainer.find("iframe").purgeFrame().done(function(){ $iframeContainer.append($iframe); - $iframe.one('load', function(){ + $iframe.one('load', function(){ helper.waitFor(function(){ return !$iframe.contents().find("#editorloadingbox").is(":visible"); }, 50000).done(function(){ @@ -92,13 +92,13 @@ var helper = {}; helper.padChrome$.fx.off = true; helper.padOuter$.fx.off = true; helper.padInner$.fx.off = true; - + opts.cb(); }).fail(function(){ throw new Error("Pad never loaded"); }); }); - }); + }); return padName; } @@ -108,7 +108,7 @@ var helper = {}; var intervalTime = _intervalTime || 10; var deferred = $.Deferred(); - + var _fail = deferred.fail; var listenForFail = false; deferred.fail = function(){ @@ -142,6 +142,65 @@ var helper = {}; return deferred; } + helper.selectLines = function($startLine, $endLine, startOffset, endOffset){ + // if no offset is provided, use beginning of start line and end of end line + startOffset = startOffset || 0; + endOffset = endOffset || $endLine.text().length; + + var inner$ = helper.padInner$; + var selection = inner$.document.getSelection(); + var range = selection.getRangeAt(0); + + var start = getTextNodeAndOffsetOf($startLine, startOffset); + var end = getTextNodeAndOffsetOf($endLine, endOffset); + + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + + selection.removeAllRanges(); + selection.addRange(range); + } + + var getTextNodeAndOffsetOf = function($targetLine, targetOffsetAtLine){ + var $textNodes = $targetLine.find('*').contents().filter(function(){ + return this.nodeType === Node.TEXT_NODE; + }); + + // search node where targetOffsetAtLine is reached, and its 'inner offset' + var textNodeWhereOffsetIs = null; + var offsetBeforeTextNode = 0; + var offsetInsideTextNode = 0; + $textNodes.each(function(index, element){ + var elementTotalOffset = element.textContent.length; + textNodeWhereOffsetIs = element; + offsetInsideTextNode = targetOffsetAtLine - offsetBeforeTextNode; + + var foundTextNode = offsetBeforeTextNode + elementTotalOffset >= targetOffsetAtLine; + if (foundTextNode){ + return false; //stop .each by returning false + } + + offsetBeforeTextNode += elementTotalOffset; + }); + + // edge cases + if (textNodeWhereOffsetIs === null){ + // there was no text node inside $targetLine, so it is an empty line (
). + // Use beginning of line + textNodeWhereOffsetIs = $targetLine.get(0); + offsetInsideTextNode = 0; + } + // avoid errors if provided targetOffsetAtLine is higher than line offset (maxOffset). + // Use max allowed instead + var maxOffset = textNodeWhereOffsetIs.textContent.length; + offsetInsideTextNode = Math.min(offsetInsideTextNode, maxOffset); + + return { + node: textNodeWhereOffsetIs, + offset: offsetInsideTextNode, + }; + } + /* Ensure console.log doesn't blow up in IE, ugly but ok for a test framework imho*/ window.console = window.console || {}; window.console.log = window.console.log || function(){} diff --git a/tests/frontend/specs/helper.js b/tests/frontend/specs/helper.js index d5bff629..d460a02b 100644 --- a/tests/frontend/specs/helper.js +++ b/tests/frontend/specs/helper.js @@ -55,7 +55,7 @@ describe("the test helper", function(){ it("takes an interval and checks on every interval", function(done){ this.timeout(4000); var checks = 0; - + helper.waitFor(function(){ checks++; return false; @@ -96,4 +96,99 @@ describe("the test helper", function(){ }); }); }); + + describe("the selectLines method", function(){ + // function to support tests, use a single way to represent whitespaces + var cleanText = function(text){ + return text + .replace(/\n/gi, "\\\\n") // avoid \n to be replaced by \s on next line + .replace(/\s/gi, " ") + .replace(/\\\\n/gi, "\n"); // move back \n to its original state + } + + before(function(done){ + helper.newPad(function() { + // create some lines to be used on the tests + var $firstLine = helper.padInner$("div").first(); + $firstLine.sendkeys("{selectall}some{enter}short{enter}lines{enter}to test{enter}"); + + // wait for lines to be split + helper.waitFor(function(){ + var $fourthLine = helper.padInner$("div").slice(3,4); + return $fourthLine.text() === "to test"; + }).done(done); + }); + + this.timeout(60000); + }); + + it("changes editor selection to be between startOffset of $startLine and endOffset of $endLine", function(done){ + var inner$ = helper.padInner$; + + var startOffset = 2; + var endOffset = 4; + + var $lines = inner$("div"); + var $startLine = $lines.slice(1,2); + var $endLine = $lines.slice(3,4); + + helper.selectLines($startLine, $endLine, startOffset, endOffset); + + var selection = inner$.document.getSelection(); + expect(cleanText(selection.toString())).to.be("ort \nlines \nto t"); + + done(); + }); + + it("ends selection at beginning of $endLine when it is an empty line", function(done){ + var inner$ = helper.padInner$; + + var startOffset = 2; + var endOffset = 1; + + var $lines = inner$("div"); + var $startLine = $lines.slice(1,2); + var $endLine = $lines.slice(4,5); + + helper.selectLines($startLine, $endLine, startOffset, endOffset); + + var selection = inner$.document.getSelection(); + expect(cleanText(selection.toString())).to.be("ort \nlines \nto test\n"); + + done(); + }); + + it("selects full line when offset is longer than line content", function(done){ + var inner$ = helper.padInner$; + + var startOffset = 2; + var endOffset = 50; + + var $lines = inner$("div"); + var $startLine = $lines.slice(1,2); + var $endLine = $lines.slice(3,4); + + helper.selectLines($startLine, $endLine, startOffset, endOffset); + + var selection = inner$.document.getSelection(); + expect(cleanText(selection.toString())).to.be("ort \nlines \nto test"); + + done(); + }); + + it("selects all text between beginning of $startLine and end of $endLine when no offset is provided", function(done){ + var inner$ = helper.padInner$; + + var $lines = inner$("div"); + var $startLine = $lines.slice(1,2); + var $endLine = $lines.slice(3,4); + + helper.selectLines($startLine, $endLine); + + var selection = inner$.document.getSelection(); + expect(cleanText(selection.toString())).to.be("short \nlines \nto test"); + + done(); + }); + }); }); diff --git a/tests/frontend/specs/indentation.js b/tests/frontend/specs/indentation.js index de92cc8f..9294cefb 100644 --- a/tests/frontend/specs/indentation.js +++ b/tests/frontend/specs/indentation.js @@ -142,6 +142,51 @@ describe("indentation button", function(){ }); }); + it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", function(done){ + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + // make sure pad has more than one line + inner$("div").first().sendkeys("First{enter}Second{enter}"); + helper.waitFor(function(){ + return inner$("div").first().text().trim() === "First"; + }).done(function(){ + // indent first 2 lines + var $lines = inner$("div"); + var $firstLine = $lines.first(); + var $secondLine = $lines.slice(1,2); + helper.selectLines($firstLine, $secondLine); + + var $indentButton = chrome$(".buttonicon-indent"); + $indentButton.click(); + + helper.waitFor(function(){ + return inner$("div").first().find("ul li").length === 1; + }).done(function(){ + // apply bold + var $boldButton = chrome$(".buttonicon-bold"); + $boldButton.click(); + + helper.waitFor(function(){ + return inner$("div").first().find("b").length === 1; + }).done(function(){ + // outdent first 2 lines + var $outdentButton = chrome$(".buttonicon-outdent"); + $outdentButton.click(); + helper.waitFor(function(){ + return inner$("div").first().find("ul li").length === 0; + }).done(function(){ + // check if '*' is displayed + var $secondLine = inner$("div").slice(1,2); + expect($secondLine.text().trim()).to.be("Second"); + + done(); + }); + }); + }); + }); + }); + /* it("makes text indented and outdented", function() { -- cgit v1.2.3