diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/frontend/specs/automatic_reconnect.js | 71 | ||||
-rw-r--r-- | tests/frontend/specs/drag_and_drop.js | 12 | ||||
-rw-r--r-- | tests/frontend/specs/helper.js | 41 | ||||
-rw-r--r-- | tests/frontend/specs/ordered_list.js | 98 | ||||
-rw-r--r-- | tests/frontend/specs/pad_modal.js | 131 | ||||
-rwxr-xr-x | tests/frontend/travis/sauce_tunnel.sh | 14 |
6 files changed, 331 insertions, 36 deletions
diff --git a/tests/frontend/specs/automatic_reconnect.js b/tests/frontend/specs/automatic_reconnect.js new file mode 100644 index 00000000..e2d2df36 --- /dev/null +++ b/tests/frontend/specs/automatic_reconnect.js @@ -0,0 +1,71 @@ +describe('Automatic pad reload on Force Reconnect message', function() { + var padId, $originalPadFrame; + + beforeEach(function(done) { + padId = helper.newPad(function() { + // enable userdup error to have timer to force reconnect + var $errorMessageModal = helper.padChrome$('#connectivity .userdup'); + $errorMessageModal.addClass('with_reconnect_timer'); + + // make sure there's a timeout set, otherwise automatic reconnect won't be enabled + helper.padChrome$.window.clientVars.automaticReconnectionTimeout = 2; + + // open same pad on another iframe, to force userdup error + var $otherIframeWithSamePad = $('<iframe src="/p/' + padId + '" style="height: 1px;"></iframe>'); + $originalPadFrame = $('#iframe-container iframe'); + $otherIframeWithSamePad.insertAfter($originalPadFrame); + + // wait for modal to be displayed + helper.waitFor(function() { + return $errorMessageModal.is(':visible'); + }, 50000).done(done); + }); + + this.timeout(60000); + }); + + it('displays a count down timer to automatically reconnect', function(done) { + var $errorMessageModal = helper.padChrome$('#connectivity .userdup'); + var $countDownTimer = $errorMessageModal.find('.reconnecttimer'); + + expect($countDownTimer.is(':visible')).to.be(true); + + done(); + }); + + context('and user clicks on Cancel', function() { + beforeEach(function() { + var $errorMessageModal = helper.padChrome$('#connectivity .userdup'); + $errorMessageModal.find('#cancelreconnect').click(); + }); + + it('does not show Cancel button nor timer anymore', function(done) { + var $errorMessageModal = helper.padChrome$('#connectivity .userdup'); + var $countDownTimer = $errorMessageModal.find('.reconnecttimer'); + var $cancelButton = $errorMessageModal.find('#cancelreconnect'); + + expect($countDownTimer.is(':visible')).to.be(false); + expect($cancelButton.is(':visible')).to.be(false); + + done(); + }); + }); + + context('and user does not click on Cancel until timer expires', function() { + var padWasReloaded = false; + + beforeEach(function() { + $originalPadFrame.one('load', function() { + padWasReloaded = true; + }); + }); + + it('reloads the pad', function(done) { + helper.waitFor(function() { + return padWasReloaded; + }, 5000).done(done); + + this.timeout(5000); + }); + }); +}); diff --git a/tests/frontend/specs/drag_and_drop.js b/tests/frontend/specs/drag_and_drop.js index bcec0bd2..821d3aac 100644 --- a/tests/frontend/specs/drag_and_drop.js +++ b/tests/frontend/specs/drag_and_drop.js @@ -154,7 +154,15 @@ describe('drag and drop', function() { var $target = getLine(targetLineNumber); $target.sendkeys('{selectall}{rightarrow}{leftarrow}'); - // insert content - innerDocument.execCommand('insertHTML', false, draggedHtml); + // Insert content. + // Based on http://stackoverflow.com/a/6691294, to be IE-compatible + var range = innerDocument.getSelection().getRangeAt(0); + var frag = innerDocument.createDocumentFragment(); + var el = innerDocument.createElement('div'); + el.innerHTML = draggedHtml; + while (el.firstChild) { + frag.appendChild(el.firstChild); + } + range.insertNode(frag); } }); diff --git a/tests/frontend/specs/helper.js b/tests/frontend/specs/helper.js index bb47f4dc..8520769a 100644 --- a/tests/frontend/specs/helper.js +++ b/tests/frontend/specs/helper.js @@ -101,20 +101,21 @@ describe("the test helper", 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 + // IE replaces line breaks with a whitespace, so we need to unify its behavior + // for other browsers, to have all tests running for all browsers + .replace(/\n/gi, "") + .replace(/\s/gi, " "); } 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}"); + $firstLine.sendkeys("{selectall}some{enter}short{enter}lines{enter}to test{enter}{enter}"); // wait for lines to be split helper.waitFor(function(){ - var $fourthLine = helper.padInner$("div").slice(3,4); + var $fourthLine = helper.padInner$("div").eq(3); return $fourthLine.text() === "to test"; }).done(done); }); @@ -129,13 +130,13 @@ describe("the test helper", function(){ var endOffset = 4; var $lines = inner$("div"); - var $startLine = $lines.slice(1,2); - var $endLine = $lines.slice(3,4); + var $startLine = $lines.eq(1); + var $endLine = $lines.eq(3); helper.selectLines($startLine, $endLine, startOffset, endOffset); var selection = inner$.document.getSelection(); - expect(cleanText(selection.toString())).to.be("ort \nlines \nto t"); + expect(cleanText(selection.toString())).to.be("ort lines to t"); done(); }); @@ -147,13 +148,13 @@ describe("the test helper", function(){ var endOffset = 1; var $lines = inner$("div"); - var $startLine = $lines.slice(1,2); - var $endLine = $lines.slice(4,5); + var $startLine = $lines.eq(1); + var $endLine = $lines.eq(4); helper.selectLines($startLine, $endLine, startOffset, endOffset); var selection = inner$.document.getSelection(); - expect(cleanText(selection.toString())).to.be("ort \nlines \nto test\n"); + expect(cleanText(selection.toString())).to.be("ort lines to test"); done(); }); @@ -165,13 +166,13 @@ describe("the test helper", function(){ var endOffset = 0; var $lines = inner$("div"); - var $startLine = $lines.slice(1,2); - var $endLine = $lines.slice(3,4); + var $startLine = $lines.eq(1); + var $endLine = $lines.eq(3); helper.selectLines($startLine, $endLine, startOffset, endOffset); var selection = inner$.document.getSelection(); - expect(cleanText(selection.toString())).to.be("ort \nlines \n"); + expect(cleanText(selection.toString())).to.be("ort lines "); done(); }); @@ -183,13 +184,13 @@ describe("the test helper", function(){ var endOffset = 50; var $lines = inner$("div"); - var $startLine = $lines.slice(1,2); - var $endLine = $lines.slice(3,4); + var $startLine = $lines.eq(1); + var $endLine = $lines.eq(3); helper.selectLines($startLine, $endLine, startOffset, endOffset); var selection = inner$.document.getSelection(); - expect(cleanText(selection.toString())).to.be("ort \nlines \nto test"); + expect(cleanText(selection.toString())).to.be("ort lines to test"); done(); }); @@ -198,13 +199,13 @@ describe("the test helper", function(){ var inner$ = helper.padInner$; var $lines = inner$("div"); - var $startLine = $lines.slice(1,2); - var $endLine = $lines.slice(3,4); + var $startLine = $lines.eq(1); + var $endLine = $lines.eq(3); helper.selectLines($startLine, $endLine); var selection = inner$.document.getSelection(); - expect(cleanText(selection.toString())).to.be("short \nlines \nto test"); + expect(cleanText(selection.toString())).to.be("short lines to test"); done(); }); diff --git a/tests/frontend/specs/ordered_list.js b/tests/frontend/specs/ordered_list.js index ca7d755e..57196fef 100644 --- a/tests/frontend/specs/ordered_list.js +++ b/tests/frontend/specs/ordered_list.js @@ -5,8 +5,8 @@ describe("assign ordered list", function(){ this.timeout(60000); }); - it("insert ordered list text", function(done){ - var inner$ = helper.padInner$; + it("inserts ordered list text", function(done){ + var inner$ = helper.padInner$; var chrome$ = helper.padChrome$; var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist"); @@ -17,8 +17,72 @@ describe("assign ordered list", function(){ }).done(done); }); + context('when user presses Ctrl+Shift+N', function() { + context('and pad shortcut is enabled', function() { + beforeEach(function() { + makeSureShortcutIsEnabled('cmdShiftN'); + triggerCtrlShiftShortcut('N'); + }); + + it('inserts unordered list', function(done) { + helper.waitFor(function() { + return helper.padInner$('div').first().find('ol li').length === 1; + }).done(done); + }); + }); + + context('and pad shortcut is disabled', function() { + beforeEach(function() { + makeSureShortcutIsDisabled('cmdShiftN'); + triggerCtrlShiftShortcut('N'); + }); + + it('does not insert unordered list', function(done) { + helper.waitFor(function() { + return helper.padInner$('div').first().find('ol li').length === 1; + }).done(function() { + expect().fail(function() { return 'Unordered list inserted, should ignore shortcut' }); + }).fail(function() { + done(); + }); + }); + }); + }); + + context('when user presses Ctrl+Shift+1', function() { + context('and pad shortcut is enabled', function() { + beforeEach(function() { + makeSureShortcutIsEnabled('cmdShift1'); + triggerCtrlShiftShortcut('1'); + }); + + it('inserts unordered list', function(done) { + helper.waitFor(function() { + return helper.padInner$('div').first().find('ol li').length === 1; + }).done(done); + }); + }); + + context('and pad shortcut is disabled', function() { + beforeEach(function() { + makeSureShortcutIsDisabled('cmdShift1'); + triggerCtrlShiftShortcut('1'); + }); + + it('does not insert unordered list', function(done) { + helper.waitFor(function() { + return helper.padInner$('div').first().find('ol li').length === 1; + }).done(function() { + expect().fail(function() { return 'Unordered list inserted, should ignore shortcut' }); + }).fail(function() { + done(); + }); + }); + }); + }); + xit("issue #1125 keeps the numbered list on enter for the new line - EMULATES PASTING INTO A PAD", function(done){ - var inner$ = helper.padInner$; + var inner$ = helper.padInner$; var chrome$ = helper.padChrome$; var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist"); @@ -26,9 +90,9 @@ describe("assign ordered list", function(){ //type a bit, make a line break and type again var $firstTextElement = inner$("div span").first(); - $firstTextElement.sendkeys('line 1'); - $firstTextElement.sendkeys('{enter}'); - $firstTextElement.sendkeys('line 2'); + $firstTextElement.sendkeys('line 1'); + $firstTextElement.sendkeys('{enter}'); + $firstTextElement.sendkeys('line 2'); $firstTextElement.sendkeys('{enter}'); helper.waitFor(function(){ @@ -44,4 +108,26 @@ describe("assign ordered list", function(){ done(); }); }); + + var triggerCtrlShiftShortcut = function(shortcutChar) { + var inner$ = helper.padInner$; + if(inner$(window)[0].bowser.firefox || inner$(window)[0].bowser.modernIE) { // if it's a mozilla or IE + var evtType = "keypress"; + }else{ + var evtType = "keydown"; + } + var e = inner$.Event(evtType); + e.ctrlKey = true; + e.shiftKey = true; + e.which = shortcutChar.toString().charCodeAt(0); + inner$("#innerdocbody").trigger(e); + } + + var makeSureShortcutIsDisabled = function(shortcut) { + helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = false; + } + var makeSureShortcutIsEnabled = function(shortcut) { + helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = true; + } + }); diff --git a/tests/frontend/specs/pad_modal.js b/tests/frontend/specs/pad_modal.js new file mode 100644 index 00000000..80752e4b --- /dev/null +++ b/tests/frontend/specs/pad_modal.js @@ -0,0 +1,131 @@ +describe('Pad modal', function() { + context('when modal is a "force reconnect" message', function() { + var MODAL_SELECTOR = '#connectivity .slowcommit'; + + beforeEach(function(done) { + helper.newPad(function() { + // force a "slowcommit" error + helper.padChrome$.window.pad.handleChannelStateChange('DISCONNECTED', 'slowcommit'); + + // wait for modal to be displayed + var $modal = helper.padChrome$(MODAL_SELECTOR); + helper.waitFor(function() { + return $modal.is(':visible'); + }, 50000).done(done); + }); + + this.timeout(60000); + }); + + it('disables editor', function(done) { + expect(isEditorDisabled()).to.be(true); + + done(); + }); + + context('and user clicks on editor', function() { + beforeEach(function() { + clickOnPadInner(); + }); + + it('does not close the modal', function(done) { + var $modal = helper.padChrome$(MODAL_SELECTOR); + var modalIsVisible = $modal.is(':visible'); + + expect(modalIsVisible).to.be(true); + + done(); + }); + }); + + context('and user clicks on pad outer', function() { + beforeEach(function() { + clickOnPadOuter(); + }); + + it('does not close the modal', function(done) { + var $modal = helper.padChrome$(MODAL_SELECTOR); + var modalIsVisible = $modal.is(':visible'); + + expect(modalIsVisible).to.be(true); + + done(); + }); + }); + }); + + // we use "settings" here, but other modals have the same behaviour + context('when modal is not an error message', function() { + var MODAL_SELECTOR = '#settings'; + + beforeEach(function(done) { + helper.newPad(function() { + openSettingsAndWaitForModalToBeVisible(done); + }); + + this.timeout(60000); + }); + + it('does not disable editor', function(done) { + expect(isEditorDisabled()).to.be(false); + done(); + }); + + context('and user clicks on editor', function() { + beforeEach(function() { + clickOnPadInner(); + }); + + it('closes the modal', function(done) { + expect(isModalOpened(MODAL_SELECTOR)).to.be(false); + done(); + }); + }); + + context('and user clicks on pad outer', function() { + beforeEach(function() { + clickOnPadOuter(); + }); + + it('closes the modal', function(done) { + expect(isModalOpened(MODAL_SELECTOR)).to.be(false); + done(); + }); + }); + }); + + var clickOnPadInner = function() { + var $editor = helper.padInner$('#innerdocbody'); + $editor.click(); + } + + var clickOnPadOuter = function() { + var $lineNumbersColumn = helper.padOuter$('#sidedivinner'); + $lineNumbersColumn.click(); + } + + var openSettingsAndWaitForModalToBeVisible = function(done) { + helper.padChrome$('.buttonicon-settings').click(); + + // wait for modal to be displayed + var modalSelector = '#settings'; + helper.waitFor(function() { + return isModalOpened(modalSelector); + }, 10000).done(done); + } + + var isEditorDisabled = function() { + var editorDocument = helper.padOuter$("iframe[name='ace_inner']").get(0).contentDocument; + var editorBody = editorDocument.getElementById('innerdocbody'); + + var editorIsDisabled = editorBody.contentEditable === 'false' // IE/Safari + || editorDocument.designMode === 'off'; // other browsers + + return editorIsDisabled; + } + + var isModalOpened = function(modalSelector) { + var $modal = helper.padChrome$(modalSelector); + return $modal.is(':visible'); + } +}); diff --git a/tests/frontend/travis/sauce_tunnel.sh b/tests/frontend/travis/sauce_tunnel.sh index f519f8d9..b19268d0 100755 --- a/tests/frontend/travis/sauce_tunnel.sh +++ b/tests/frontend/travis/sauce_tunnel.sh @@ -1,16 +1,14 @@ #!/bin/bash # download and unzip the sauce connector -curl http://saucelabs.com/downloads/Sauce-Connect-latest.zip > /tmp/sauce.zip -unzip /tmp/sauce.zip -d /tmp +curl https://saucelabs.com/downloads/sc-latest-linux.tar.gz > /tmp/sauce.tar.gz +tar zxf /tmp/sauce.tar.gz --directory /tmp +mv /tmp/sc-*-linux /tmp/sauce_connect # start the sauce connector in background and make sure it doesn't output the secret key -(java -jar /tmp/Sauce-Connect.jar $SAUCE_USERNAME $SAUCE_ACCESS_KEY -f /tmp/tunnel > /dev/null )& - -# save the sauce pid in a file -echo $! > /tmp/sauce.pid +(/tmp/sauce_connect/bin/sc --user $SAUCE_USERNAME --key $SAUCE_ACCESS_KEY --pidfile /tmp/sauce.pid --readyfile /tmp/tunnel > /dev/null )& # wait for the tunnel to build up while [ ! -e "/tmp/tunnel" ] do - sleep 1 -done
\ No newline at end of file + sleep 1 +done |