mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-28 11:26:16 -04:00
add tests from origin/develop
This commit is contained in:
parent
6a3e4c69b8
commit
2df2d7d60a
71 changed files with 18931 additions and 4032 deletions
|
@ -1,11 +1,9 @@
|
|||
var helper = {};
|
||||
|
||||
(function(){
|
||||
var $iframeContainer, $iframe, jsLibraries = {};
|
||||
var $iframe, jsLibraries = {};
|
||||
|
||||
helper.init = function(cb){
|
||||
$iframeContainer = $("#iframe-container");
|
||||
|
||||
$.get('/static/js/jquery.js').done(function(code){
|
||||
// make sure we don't override existing jquery
|
||||
jsLibraries["jquery"] = "if(typeof $ === 'undefined') {\n" + code + "\n}";
|
||||
|
@ -52,10 +50,49 @@ var helper = {};
|
|||
return win.$;
|
||||
}
|
||||
|
||||
helper.clearCookies = function(){
|
||||
window.document.cookie = "";
|
||||
helper.clearSessionCookies = function(){
|
||||
// Expire cookies, so author and language are changed after reloading the pad.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie
|
||||
window.document.cookie = 'token=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
||||
window.document.cookie = 'language=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
||||
}
|
||||
|
||||
// Can only happen when the iframe exists, so we're doing it separately from other cookies
|
||||
helper.clearPadPrefCookie = function(){
|
||||
helper.padChrome$.document.cookie = 'prefsHttp=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
||||
}
|
||||
|
||||
// Overwrite all prefs in pad cookie. Assumes http, not https.
|
||||
//
|
||||
// `helper.padChrome$.document.cookie` (the iframe) and `window.document.cookie`
|
||||
// seem to have independent cookies, UNLESS we put path=/ here (which we don't).
|
||||
// I don't fully understand it, but this function seems to properly simulate
|
||||
// padCookie.setPref in the client code
|
||||
helper.setPadPrefCookie = function(prefs){
|
||||
helper.padChrome$.document.cookie = ("prefsHttp=" + escape(JSON.stringify(prefs)) + ";expires=Thu, 01 Jan 3000 00:00:00 GMT");
|
||||
}
|
||||
|
||||
// Functionality for knowing what key event type is required for tests
|
||||
var evtType = "keydown";
|
||||
// if it's IE require keypress
|
||||
if(window.navigator.userAgent.indexOf("MSIE") > -1){
|
||||
evtType = "keypress";
|
||||
}
|
||||
// Edge also requires keypress.
|
||||
if(window.navigator.userAgent.indexOf("Edge") > -1){
|
||||
evtType = "keypress";
|
||||
}
|
||||
// Opera also requires keypress.
|
||||
if(window.navigator.userAgent.indexOf("OPR") > -1){
|
||||
evtType = "keypress";
|
||||
}
|
||||
helper.evtType = evtType;
|
||||
|
||||
// @todo needs fixing asap
|
||||
// newPad occasionally timeouts, might be a problem with ready/onload code during page setup
|
||||
// This ensures that tests run regardless of this problem
|
||||
helper.retry = 0
|
||||
|
||||
helper.newPad = function(cb, padName){
|
||||
//build opts object
|
||||
var opts = {clearCookies: true}
|
||||
|
@ -65,38 +102,56 @@ var helper = {};
|
|||
opts = _.defaults(cb, opts);
|
||||
}
|
||||
|
||||
// if opts.params is set we manipulate the URL to include URL parameters IE ?foo=Bah.
|
||||
if(opts.params){
|
||||
var encodedParams = "?" + $.param(opts.params);
|
||||
}
|
||||
|
||||
//clear cookies
|
||||
if(opts.clearCookies){
|
||||
helper.clearCookies();
|
||||
helper.clearSessionCookies();
|
||||
}
|
||||
|
||||
if(!padName)
|
||||
padName = "FRONTEND_TEST_" + helper.randomString(20);
|
||||
$iframe = $("<iframe src='/p/" + padName + "'></iframe>");
|
||||
$iframe = $("<iframe src='/p/" + padName + (encodedParams || '') + "'></iframe>");
|
||||
|
||||
// needed for retry
|
||||
let origPadName = padName;
|
||||
|
||||
//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(){
|
||||
helper.waitFor(function(){
|
||||
return !$iframe.contents().find("#editorloadingbox").is(":visible");
|
||||
}, 50000).done(function(){
|
||||
helper.padChrome$ = getFrameJQuery( $('#iframe-container iframe'));
|
||||
helper.padOuter$ = getFrameJQuery(helper.padChrome$('iframe[name="ace_outer"]'));
|
||||
helper.padInner$ = getFrameJQuery( helper.padOuter$('iframe[name="ace_inner"]'));
|
||||
//remove old iframe
|
||||
$("#iframe-container iframe").remove();
|
||||
//set new iframe
|
||||
$("#iframe-container").append($iframe);
|
||||
$iframe.one('load', function(){
|
||||
helper.padChrome$ = getFrameJQuery($('#iframe-container iframe'));
|
||||
if (opts.clearCookies) {
|
||||
helper.clearPadPrefCookie();
|
||||
}
|
||||
if (opts.padPrefs) {
|
||||
helper.setPadPrefCookie(opts.padPrefs);
|
||||
}
|
||||
helper.waitFor(function(){
|
||||
return !$iframe.contents().find("#editorloadingbox").is(":visible");
|
||||
}, 10000).done(function(){
|
||||
helper.padOuter$ = getFrameJQuery(helper.padChrome$('iframe[name="ace_outer"]'));
|
||||
helper.padInner$ = getFrameJQuery( helper.padOuter$('iframe[name="ace_inner"]'));
|
||||
|
||||
//disable all animations, this makes tests faster and easier
|
||||
helper.padChrome$.fx.off = true;
|
||||
helper.padOuter$.fx.off = true;
|
||||
helper.padInner$.fx.off = true;
|
||||
//disable all animations, this makes tests faster and easier
|
||||
helper.padChrome$.fx.off = true;
|
||||
helper.padOuter$.fx.off = true;
|
||||
helper.padInner$.fx.off = true;
|
||||
|
||||
opts.cb();
|
||||
}).fail(function(){
|
||||
opts.cb();
|
||||
}).fail(function(){
|
||||
if (helper.retry > 3) {
|
||||
throw new Error("Pad never loaded");
|
||||
});
|
||||
}
|
||||
helper.retry++;
|
||||
helper.newPad(cb,origPadName);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -104,7 +159,7 @@ var helper = {};
|
|||
}
|
||||
|
||||
helper.waitFor = function(conditionFunc, _timeoutTime, _intervalTime){
|
||||
var timeoutTime = _timeoutTime || 1000;
|
||||
var timeoutTime = _timeoutTime || 1900;
|
||||
var intervalTime = _intervalTime || 10;
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
@ -216,4 +271,4 @@ var helper = {};
|
|||
|
||||
_it(name, func);
|
||||
}
|
||||
})()
|
||||
})()
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
<script src="lib/underscore.js"></script>
|
||||
|
||||
<script src="lib/mocha.js"></script>
|
||||
<script> mocha.setup('bdd') </script>
|
||||
<script> mocha.setup({ui: 'bdd', ignoreLeaks: true}) </script>
|
||||
<script src="lib/expect.js"></script>
|
||||
|
||||
<script src="lib/sendkeys.js"></script>
|
||||
<script src="lib/jquery.iframe.js"></script>
|
||||
<script src="helper.js"></script>
|
||||
|
||||
<script src="specs_list.js"></script>
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
var name = $flags[i]
|
||||
, assertion = new Assertion(this.obj, name, this)
|
||||
|
||||
|
||||
if ('function' == typeof Assertion.prototype[name]) {
|
||||
// clone the function, make sure we dont touch the prot reference
|
||||
var old = this[name];
|
||||
|
@ -148,7 +148,7 @@
|
|||
if ('object' == typeof fn && not) {
|
||||
// in the presence of a matcher, ensure the `not` only applies to
|
||||
// the matching.
|
||||
this.flags.not = false;
|
||||
this.flags.not = false;
|
||||
}
|
||||
|
||||
var name = this.obj.name || 'fn';
|
||||
|
@ -219,7 +219,7 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* Assert within start to finish (inclusive).
|
||||
* Assert within start to finish (inclusive).
|
||||
*
|
||||
* @param {Number} start
|
||||
* @param {Number} finish
|
||||
|
@ -298,7 +298,7 @@
|
|||
, function(){ return 'expected ' + i(this.obj) + ' to be above ' + n });
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Assert string value matches _regexp_.
|
||||
*
|
||||
|
@ -359,13 +359,13 @@
|
|||
} catch (e) {
|
||||
hasProp = undefined !== this.obj[name]
|
||||
}
|
||||
|
||||
|
||||
this.assert(
|
||||
hasProp
|
||||
, function(){ return 'expected ' + i(this.obj) + ' to have a property ' + i(name) }
|
||||
, function(){ return 'expected ' + i(this.obj) + ' to not have a property ' + i(name) });
|
||||
}
|
||||
|
||||
|
||||
if (undefined !== val) {
|
||||
this.assert(
|
||||
val === this.obj[name]
|
||||
|
@ -537,7 +537,7 @@
|
|||
return html;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Returns true if object is a DOM element.
|
||||
var isDOMElement = function (object) {
|
||||
if (typeof HTMLElement === 'object') {
|
||||
|
@ -843,9 +843,9 @@
|
|||
|
||||
expect.eql = function eql (actual, expected) {
|
||||
// 7.1. All identical values are equivalent, as determined by ===.
|
||||
if (actual === expected) {
|
||||
if (actual === expected) {
|
||||
return true;
|
||||
} else if ('undefined' != typeof Buffer
|
||||
} else if ('undefined' != typeof Buffer
|
||||
&& Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
|
||||
if (actual.length != expected.length) return false;
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
//copied from http://stackoverflow.com/questions/8407946/is-it-possible-to-use-iframes-in-ie-without-memory-leaks
|
||||
(function($) {
|
||||
$.fn.purgeFrame = function() {
|
||||
var deferred;
|
||||
var browser = bowser;
|
||||
|
||||
if (browser.msie && parseFloat(browser.version, 10) < 9) {
|
||||
deferred = purge(this);
|
||||
} else {
|
||||
this.remove();
|
||||
deferred = $.Deferred();
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
function purge($frame) {
|
||||
var sem = $frame.length
|
||||
, deferred = $.Deferred();
|
||||
|
||||
$frame.load(function() {
|
||||
var frame = this;
|
||||
frame.contentWindow.document.innerHTML = '';
|
||||
|
||||
sem -= 1;
|
||||
if (sem <= 0) {
|
||||
$frame.remove();
|
||||
deferred.resolve();
|
||||
}
|
||||
});
|
||||
$frame.attr('src', 'about:blank');
|
||||
|
||||
if ($frame.length === 0) {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
})(jQuery);
|
File diff suppressed because one or more lines are too long
|
@ -305,11 +305,11 @@ var START_TO_END = 1;
|
|||
var END_TO_END = 2;
|
||||
var END_TO_START = 3;
|
||||
// from the Mozilla documentation, for range.compareBoundaryPoints(how, sourceRange)
|
||||
// -1, 0, or 1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange.
|
||||
// -1, 0, or 1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange.
|
||||
// * Range.END_TO_END compares the end boundary-point of sourceRange to the end boundary-point of range.
|
||||
// * Range.END_TO_START compares the end boundary-point of sourceRange to the start boundary-point of range.
|
||||
// * Range.START_TO_END compares the start boundary-point of sourceRange to the end boundary-point of range.
|
||||
// * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range.
|
||||
// * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range.
|
||||
function w3cstart(rng, constraint){
|
||||
if (rng.compareBoundaryPoints (START_TO_START, constraint) <= 0) return 0; // at or before the beginning
|
||||
if (rng.compareBoundaryPoints (END_TO_START, constraint) >= 0) return constraint.toString().length;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
html {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#console {
|
||||
|
@ -13,34 +16,34 @@ body {
|
|||
}
|
||||
|
||||
#iframe-container {
|
||||
width: 50%;
|
||||
width: 80%;
|
||||
min-width: 820px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#iframe-container iframe {
|
||||
height: 100%;
|
||||
position:absolute;
|
||||
min-width:500px;
|
||||
max-width:800px;
|
||||
left:50%;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
#mocha {
|
||||
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
border-right: 2px solid #999;
|
||||
width: 50%;
|
||||
flex: 1 auto;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
overflow: auto;
|
||||
float:left;
|
||||
width:20%;
|
||||
font-size:80%;
|
||||
|
||||
}
|
||||
|
||||
#mocha #report {
|
||||
margin-top: 50px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#mocha ul, #mocha li {
|
||||
#mocha li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -60,7 +63,7 @@ body {
|
|||
}
|
||||
|
||||
#mocha h1 a:visited
|
||||
{
|
||||
{
|
||||
color: #00E;
|
||||
}
|
||||
|
||||
|
@ -76,11 +79,11 @@ body {
|
|||
}
|
||||
|
||||
#mocha .suite {
|
||||
margin-left: 15px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
#mocha .test {
|
||||
margin-left: 15px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#mocha .test:hover h2::after {
|
||||
|
@ -175,6 +178,10 @@ body {
|
|||
-webkit-box-shadow: 0 1px 3px #eee;
|
||||
}
|
||||
|
||||
#report ul {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#report.pass .test.fail {
|
||||
display: none;
|
||||
}
|
||||
|
@ -191,17 +198,21 @@ body {
|
|||
}
|
||||
|
||||
#stats {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 52%;
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
color: #888;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#stats .progress {
|
||||
#mocha-stats {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
#mocha-stats .progress {
|
||||
float: right;
|
||||
padding-top: 0;
|
||||
margin-right:5px;
|
||||
}
|
||||
|
||||
#stats em {
|
||||
|
@ -229,3 +240,7 @@ code .init { color: #2F6FAD }
|
|||
code .string { color: #5890AD }
|
||||
code .keyword { color: #8A6343 }
|
||||
code .number { color: #2F6FAD }
|
||||
|
||||
ul{
|
||||
padding-left:5px;
|
||||
}
|
||||
|
|
|
@ -1,28 +1,68 @@
|
|||
$(function(){
|
||||
function Base(runner) {
|
||||
var self = this
|
||||
, stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
|
||||
, failures = this.failures = [];
|
||||
|
||||
function stringifyException(exception){
|
||||
var err = exception.stack || exception.toString();
|
||||
|
||||
// FF / Opera do not add the message
|
||||
if (!~err.indexOf(exception.message)) {
|
||||
err = exception.message + '\n' + err;
|
||||
}
|
||||
|
||||
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
||||
// check for the result of the stringifying.
|
||||
if ('[object Error]' == err) err = exception.message;
|
||||
|
||||
// Safari doesn't give you a stack. Let's at least provide a source line.
|
||||
if (!exception.stack && exception.sourceURL && exception.line !== undefined) {
|
||||
err += "\n(" + exception.sourceURL + ":" + exception.line + ")";
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
function CustomRunner(runner) {
|
||||
var stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 };
|
||||
|
||||
if (!runner) return;
|
||||
this.runner = runner;
|
||||
|
||||
runner.on('start', function(){
|
||||
stats.start = new Date;
|
||||
});
|
||||
|
||||
runner.on('suite', function(suite){
|
||||
stats.suites = stats.suites || 0;
|
||||
suite.root || stats.suites++;
|
||||
if (suite.root) return;
|
||||
append(suite.title);
|
||||
level++;
|
||||
});
|
||||
|
||||
runner.on('test end', function(test){
|
||||
stats.tests = stats.tests || 0;
|
||||
runner.on('suite end', function(suite){
|
||||
if (suite.root) return;
|
||||
level--;
|
||||
|
||||
if(level == 0) {
|
||||
append("");
|
||||
}
|
||||
});
|
||||
|
||||
// Scroll down test display after each test
|
||||
let mochaEl = $('#mocha')[0];
|
||||
runner.on('test', function(){
|
||||
mochaEl.scrollTop = mochaEl.scrollHeight;
|
||||
});
|
||||
|
||||
// max time a test is allowed to run
|
||||
// TODO this should be lowered once timeslider_revision.js is faster
|
||||
var killTimeout;
|
||||
runner.on('test end', function(){
|
||||
stats.tests++;
|
||||
});
|
||||
|
||||
runner.on('pass', function(test){
|
||||
stats.passes = stats.passes || 0;
|
||||
if(killTimeout) clearTimeout(killTimeout);
|
||||
killTimeout = setTimeout(function(){
|
||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
||||
}, 60000 * 3);
|
||||
|
||||
var medium = test.slow() / 2;
|
||||
test.speed = test.duration > test.slow()
|
||||
|
@ -32,43 +72,31 @@ $(function(){
|
|||
: 'fast';
|
||||
|
||||
stats.passes++;
|
||||
append("->","[green]PASSED[clear] :", test.title," ",test.duration,"ms");
|
||||
});
|
||||
|
||||
runner.on('fail', function(test, err){
|
||||
stats.failures = stats.failures || 0;
|
||||
if(killTimeout) clearTimeout(killTimeout);
|
||||
killTimeout = setTimeout(function(){
|
||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
||||
}, 60000 * 3);
|
||||
|
||||
stats.failures++;
|
||||
test.err = err;
|
||||
failures.push(test);
|
||||
append("->","[red]FAILED[clear] :", test.title, stringifyException(test.err));
|
||||
});
|
||||
|
||||
runner.on('end', function(){
|
||||
stats.end = new Date;
|
||||
stats.duration = new Date - stats.start;
|
||||
});
|
||||
runner.on('pending', function(test){
|
||||
if(killTimeout) clearTimeout(killTimeout);
|
||||
killTimeout = setTimeout(function(){
|
||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
||||
}, 60000 * 3);
|
||||
|
||||
runner.on('pending', function(){
|
||||
stats.pending++;
|
||||
append("->","[yellow]PENDING[clear]:", test.title);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
This reporter wraps the original html reporter plus reports plain text into a hidden div.
|
||||
This allows the webdriver client to pick up the test results
|
||||
*/
|
||||
var WebdriverAndHtmlReporter = function(html_reporter){
|
||||
return function(runner){
|
||||
Base.call(this, runner);
|
||||
|
||||
// Scroll down test display after each test
|
||||
mocha = $('#mocha')[0];
|
||||
runner.on('test', function(){
|
||||
mocha.scrollTop = mocha.scrollHeight;
|
||||
});
|
||||
|
||||
//initalize the html reporter first
|
||||
html_reporter(runner);
|
||||
|
||||
var $console = $("#console");
|
||||
var $console = $("#console");
|
||||
var level = 0;
|
||||
var append = function(){
|
||||
var text = Array.prototype.join.apply(arguments, [" "]);
|
||||
|
@ -97,68 +125,23 @@ $(function(){
|
|||
$console.text(oldText + newText + "\\n");
|
||||
}
|
||||
|
||||
runner.on('suite', function(suite){
|
||||
if (suite.root) return;
|
||||
|
||||
append(suite.title);
|
||||
level++;
|
||||
});
|
||||
|
||||
runner.on('suite end', function(suite){
|
||||
if (suite.root) return;
|
||||
level--;
|
||||
|
||||
if(level == 0) {
|
||||
append("");
|
||||
}
|
||||
});
|
||||
|
||||
var stringifyException = function(exception){
|
||||
var err = exception.stack || exception.toString();
|
||||
|
||||
// FF / Opera do not add the message
|
||||
if (!~err.indexOf(exception.message)) {
|
||||
err = exception.message + '\n' + err;
|
||||
}
|
||||
|
||||
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
||||
// check for the result of the stringifying.
|
||||
if ('[object Error]' == err) err = exception.message;
|
||||
|
||||
// Safari doesn't give you a stack. Let's at least provide a source line.
|
||||
if (!exception.stack && exception.sourceURL && exception.line !== undefined) {
|
||||
err += "\n(" + exception.sourceURL + ":" + exception.line + ")";
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
var killTimeout;
|
||||
runner.on('test end', function(test){
|
||||
if ('passed' == test.state) {
|
||||
append("->","[green]PASSED[clear] :", test.title);
|
||||
} else if (test.pending) {
|
||||
append("->","[yellow]PENDING[clear]:", test.title);
|
||||
} else {
|
||||
append("->","[red]FAILED[clear] :", test.title, stringifyException(test.err));
|
||||
}
|
||||
|
||||
if(killTimeout) clearTimeout(killTimeout);
|
||||
killTimeout = setTimeout(function(){
|
||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
||||
}, 60000 * 3);
|
||||
});
|
||||
|
||||
var total = runner.total;
|
||||
runner.on('end', function(){
|
||||
if(stats.tests >= total){
|
||||
var minutes = Math.floor(stats.duration / 1000 / 60);
|
||||
var seconds = Math.round((stats.duration / 1000) % 60);
|
||||
|
||||
append("FINISHED -", stats.passes, "tests passed,", stats.failures, "tests failed, duration: " + minutes + ":" + seconds);
|
||||
stats.end = new Date;
|
||||
stats.duration = stats.end - stats.start;
|
||||
var minutes = Math.floor(stats.duration / 1000 / 60);
|
||||
var seconds = Math.round((stats.duration / 1000) % 60) // chrome < 57 does not like this .toString().padStart("2","0");
|
||||
if(stats.tests === total){
|
||||
append("FINISHED -", stats.passes, "tests passed,", stats.failures, "tests failed,", stats.pending," pending, duration: " + minutes + ":" + seconds);
|
||||
} else if (stats.tests > total) {
|
||||
append("FINISHED - but more tests than planned returned", stats.passes, "tests passed,", stats.failures, "tests failed,", stats.pending," pending, duration: " + minutes + ":" + seconds);
|
||||
append(total,"tests, but",stats.tests,"returned. There is probably a problem with your async code or error handling, see https://github.com/mochajs/mocha/issues/1327");
|
||||
}
|
||||
else {
|
||||
append("FINISHED - but not all tests returned", stats.passes, "tests passed,", stats.failures, "tests failed,", stats.pending, "tests pending, duration: " + minutes + ":" + seconds);
|
||||
append(total,"tests, but only",stats.tests,"returned. Check for failed before/beforeEach-hooks (no `test end` is called for them and subsequent tests of the same suite are skipped), see https://github.com/mochajs/mocha/pull/1043");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
|
||||
|
@ -170,7 +153,7 @@ $(function(){
|
|||
|
||||
//get the list of specs and filter it if requested
|
||||
var specs = specs_list.slice();
|
||||
|
||||
|
||||
//inject spec scripts into the dom
|
||||
var $body = $('body');
|
||||
$.each(specs, function(i, spec){
|
||||
|
@ -189,10 +172,7 @@ $(function(){
|
|||
mocha.grep(grep);
|
||||
}
|
||||
|
||||
mocha.ignoreLeaks();
|
||||
|
||||
mocha.reporter(WebdriverAndHtmlReporter(mocha._reporter));
|
||||
|
||||
mocha.run();
|
||||
var runner = mocha.run();
|
||||
CustomRunner(runner)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,12 +8,12 @@ describe("All the alphabet works n stuff", function(){
|
|||
});
|
||||
|
||||
it("when you enter any char it appears right", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// simulate key presses to delete content
|
||||
firstTextElement.sendkeys('{selectall}'); // select all
|
||||
firstTextElement.sendkeys('{del}'); // clear the first line
|
||||
|
|
|
@ -6,22 +6,22 @@ describe("bold button", function(){
|
|||
});
|
||||
|
||||
it("makes text bold on click", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
//get the bold button and click it
|
||||
var $boldButton = chrome$(".buttonicon-bold");
|
||||
$boldButton.click();
|
||||
|
||||
|
||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// is there a <b> element now?
|
||||
var isBold = $newFirstTextElement.find("b").length === 1;
|
||||
|
||||
|
@ -44,13 +44,7 @@ describe("bold button", function(){
|
|||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 66; // b
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
|
|
@ -198,9 +198,9 @@ console.log(inner$);
|
|||
/*
|
||||
it("Creates N rows, changes height of rows, updates UI by caret key events", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var numberOfRows = 50;
|
||||
|
||||
|
||||
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
var originalDivHeight = inner$("div").first().css("height");
|
||||
|
@ -211,7 +211,7 @@ console.log(inner$);
|
|||
}).done(function(){ // Once the DOM has registered the items
|
||||
inner$("div").each(function(index){ // Randomize the item heights (replicates images / headings etc)
|
||||
var random = Math.floor(Math.random() * (50)) + 20;
|
||||
$(this).css("height", random+"px");
|
||||
$(this).css("height", random+"px");
|
||||
});
|
||||
|
||||
console.log(caretPosition(inner$));
|
||||
|
@ -253,7 +253,7 @@ console.log(inner$);
|
|||
keyEvent(inner$, 33, false, false); // doesn't work
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
// Does scrolling back up the pad with the up arrow show the correct contents?
|
||||
helper.waitFor(function(){ // Wait for the new position to be in place
|
||||
try{
|
||||
|
@ -280,7 +280,7 @@ console.log(inner$);
|
|||
helper.waitFor(function(){ // Wait for the new position to be in place
|
||||
return isScrolledIntoView(inner$("div:nth-child(1)"), inner$); // Wait for the DOM to scroll into place
|
||||
}).done(function(){ // Once the DOM has registered the items
|
||||
expect(true).to.be(true);
|
||||
expect(true).to.be(true);
|
||||
done();
|
||||
});
|
||||
*/
|
||||
|
@ -297,20 +297,15 @@ function prepareDocument(n, target){ // generates a random document with random
|
|||
}
|
||||
|
||||
function keyEvent(target, charCode, ctrl, shift){ // sends a charCode to the window
|
||||
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 = target.Event(evtType);
|
||||
console.log(e);
|
||||
|
||||
var e = target.Event(helper.evtType);
|
||||
if(ctrl){
|
||||
e.ctrlKey = true; // Control key
|
||||
}
|
||||
if(shift){
|
||||
e.shiftKey = true; // Shift Key
|
||||
}
|
||||
e.which = charCode;
|
||||
e.which = charCode;
|
||||
e.keyCode = charCode;
|
||||
target("#innerdocbody").trigger(e);
|
||||
}
|
||||
|
@ -339,6 +334,5 @@ function caretPosition($){
|
|||
var pos = doc.getSelection();
|
||||
pos.y = pos.anchorNode.parentElement.offsetTop;
|
||||
pos.x = pos.anchorNode.parentElement.offsetLeft;
|
||||
console.log(pos);
|
||||
return pos;
|
||||
}
|
||||
|
|
104
tests/frontend/specs/change_user_color.js
Normal file
104
tests/frontend/specs/change_user_color.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
describe("change user color", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("Color picker matches original color and remembers the user color after a refresh", function(done) {
|
||||
this.timeout(60000);
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
var $userSwatch = chrome$("#myswatch");
|
||||
$userSwatch.click();
|
||||
|
||||
var fb = chrome$.farbtastic('#colorpicker')
|
||||
var $colorPickerSave = chrome$("#mycolorpickersave");
|
||||
var $colorPickerPreview = chrome$("#mycolorpickerpreview");
|
||||
|
||||
// Same color represented in two different ways
|
||||
const testColorHash = '#abcdef'
|
||||
const testColorRGB = 'rgb(171, 205, 239)'
|
||||
|
||||
// Check that the color picker matches the automatically assigned random color on the swatch.
|
||||
// NOTE: This has a tiny chance of creating a false positive for passing in the
|
||||
// off-chance the randomly assigned color is the same as the test color.
|
||||
expect($colorPickerPreview.css('background-color')).to.be($userSwatch.css('background-color'))
|
||||
|
||||
// The swatch updates as the test color is picked.
|
||||
fb.setColor(testColorHash)
|
||||
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB)
|
||||
$colorPickerSave.click();
|
||||
expect($userSwatch.css('background-color')).to.be(testColorRGB)
|
||||
|
||||
setTimeout(function(){ //give it a second to save the color on the server side
|
||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||
clearCookies: false
|
||||
, cb: function(){
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
var $userSwatch = chrome$("#myswatch");
|
||||
$userSwatch.click();
|
||||
|
||||
var $colorPickerPreview = chrome$("#mycolorpickerpreview");
|
||||
|
||||
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB)
|
||||
expect($userSwatch.css('background-color')).to.be(testColorRGB)
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it("Own user color is shown when you enter a chat", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var $colorOption = helper.padChrome$('#options-colorscheck');
|
||||
if (!$colorOption.is(':checked')) {
|
||||
$colorOption.click();
|
||||
}
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
var $userSwatch = chrome$("#myswatch");
|
||||
$userSwatch.click();
|
||||
|
||||
var fb = chrome$.farbtastic('#colorpicker')
|
||||
var $colorPickerSave = chrome$("#mycolorpickersave");
|
||||
|
||||
// Same color represented in two different ways
|
||||
const testColorHash = '#abcdef'
|
||||
const testColorRGB = 'rgb(171, 205, 239)'
|
||||
|
||||
fb.setColor(testColorHash)
|
||||
$colorPickerSave.click();
|
||||
|
||||
//click on the chat button to make chat visible
|
||||
var $chatButton = chrome$("#chaticon");
|
||||
$chatButton.click();
|
||||
var $chatInput = chrome$("#chatinput");
|
||||
$chatInput.sendkeys('O hi'); // simulate a keypress of typing user
|
||||
$chatInput.sendkeys('{enter}'); // simulate a keypress of enter actually does evt.which = 10 not 13
|
||||
|
||||
//check if chat shows up
|
||||
helper.waitFor(function(){
|
||||
return chrome$("#chattext").children("p").length !== 0; // wait until the chat message shows up
|
||||
}).done(function(){
|
||||
var $firstChatMessage = chrome$("#chattext").children("p");
|
||||
expect($firstChatMessage.css('background-color')).to.be(testColorRGB); // expect the first chat message to be of the user's color
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -12,7 +12,7 @@ describe("change username value", function(){
|
|||
//click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
|
||||
var $usernameInput = chrome$("#myusernameedit");
|
||||
$usernameInput.click();
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe("change username value", function(){
|
|||
//click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
|
||||
var $usernameInput = chrome$("#myusernameedit");
|
||||
$usernameInput.click();
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ describe("Chat messages and UI", function(){
|
|||
});
|
||||
|
||||
it("opens chat, sends a message and makes sure it exists on the page", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chatValue = "JohnMcLear";
|
||||
|
||||
//click on the chat button to make chat visible
|
||||
|
@ -39,8 +39,8 @@ describe("Chat messages and UI", function(){
|
|||
});
|
||||
|
||||
it("makes sure that an empty message can't be sent", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the chat button to make chat visible
|
||||
var $chatButton = chrome$("#chaticon");
|
||||
|
@ -65,8 +65,8 @@ describe("Chat messages and UI", function(){
|
|||
});
|
||||
|
||||
it("makes chat stick to right side of the screen", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $settingsButton = chrome$(".buttonicon-settings");
|
||||
|
@ -75,56 +75,96 @@ describe("Chat messages and UI", function(){
|
|||
//get the chat selector
|
||||
var $stickychatCheckbox = chrome$("#options-stickychat");
|
||||
|
||||
//select chat always on screen and fire change event
|
||||
$stickychatCheckbox.attr('selected','selected');
|
||||
$stickychatCheckbox.change();
|
||||
$stickychatCheckbox.click();
|
||||
//select chat always on screen
|
||||
if (!$stickychatCheckbox.is(':checked')) {
|
||||
$stickychatCheckbox.click();
|
||||
}
|
||||
|
||||
//check if chat changed to get the stickychat Class
|
||||
var $chatbox = chrome$("#chatbox");
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(true);
|
||||
// due to animation, we need to make some timeout...
|
||||
setTimeout(function() {
|
||||
//check if chat changed to get the stickychat Class
|
||||
var $chatbox = chrome$("#chatbox");
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(true);
|
||||
|
||||
//select chat always on screen and fire change event
|
||||
$stickychatCheckbox.attr('selected','selected');
|
||||
$stickychatCheckbox.change();
|
||||
$stickychatCheckbox.click();
|
||||
// select chat always on screen and fire change event
|
||||
$stickychatCheckbox.click();
|
||||
|
||||
setTimeout(function() {
|
||||
//check if chat changed to remove the stickychat Class
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(false);
|
||||
|
||||
done();
|
||||
}, 10)
|
||||
}, 10)
|
||||
|
||||
//check if chat changed to remove the stickychat Class
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(false);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it("makes chat stick to right side of the screen then makes it one step smaller", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $settingsButton = chrome$(".buttonicon-settings");
|
||||
$settingsButton.click();
|
||||
// open chat
|
||||
chrome$('#chaticon').click();
|
||||
|
||||
//get the chat selector
|
||||
var $stickychatCheckbox = chrome$("#options-stickychat");
|
||||
// select chat always on screen from chatbox
|
||||
chrome$('.stick-to-screen-btn').click();
|
||||
|
||||
//select chat always on screen and fire change event
|
||||
$stickychatCheckbox.attr('selected','selected');
|
||||
$stickychatCheckbox.change();
|
||||
$stickychatCheckbox.click();
|
||||
// due to animation, we need to make some timeout...
|
||||
setTimeout(function() {
|
||||
//check if chat changed to get the stickychat Class
|
||||
var $chatbox = chrome$("#chatbox");
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(true);
|
||||
|
||||
//check if chat changed to get the stickychat Class
|
||||
var $chatbox = chrome$("#chatbox");
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(true);
|
||||
// select chat always on screen and fire change event
|
||||
chrome$('#titlecross').click();
|
||||
|
||||
//select chat always on screen and fire change event
|
||||
chrome$('#titlecross').click();
|
||||
setTimeout(function() {
|
||||
//check if chat changed to remove the stickychat Class
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(false);
|
||||
|
||||
//check if chat changed to remove the stickychat Class
|
||||
var hasStickyChatClass = $chatbox.hasClass("stickyChat");
|
||||
expect(hasStickyChatClass).to.be(false);
|
||||
|
||||
done();
|
||||
done();
|
||||
}, 10)
|
||||
}, 10)
|
||||
});
|
||||
|
||||
xit("Checks showChat=false URL Parameter hides chat then when removed it shows chat", function(done) {
|
||||
this.timeout(60000);
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
setTimeout(function(){ //give it a second to save the username on the server side
|
||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||
clearCookies: false,
|
||||
params:{
|
||||
showChat: "false"
|
||||
}, cb: function(){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chaticon = chrome$("#chaticon");
|
||||
// chat should be hidden.
|
||||
expect(chaticon.is(":visible")).to.be(false);
|
||||
|
||||
setTimeout(function(){ //give it a second to save the username on the server side
|
||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||
clearCookies: false
|
||||
, cb: function(){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chaticon = chrome$("#chaticon");
|
||||
// chat should be visible.
|
||||
expect(chaticon.is(":visible")).to.be(true);
|
||||
done();
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
describe("chat-load-messages", function(){
|
||||
var padName;
|
||||
|
||||
|
||||
it("creates a pad", function(done) {
|
||||
padName = helper.newPad(done);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("adds a lot of messages", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chatButton = chrome$("#chaticon");
|
||||
chatButton.click();
|
||||
var chatInput = chrome$("#chatinput");
|
||||
var chatText = chrome$("#chattext");
|
||||
|
||||
|
||||
this.timeout(60000);
|
||||
|
||||
|
||||
var messages = 140;
|
||||
for(var i=1; i <= messages; i++) {
|
||||
var num = ''+i;
|
||||
|
@ -33,7 +33,7 @@ describe("chat-load-messages", function(){
|
|||
helper.newPad(done, padName);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("checks initial message count", function(done) {
|
||||
var chatText;
|
||||
var expectedCount = 101;
|
||||
|
@ -48,7 +48,7 @@ describe("chat-load-messages", function(){
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("loads more messages", function(done) {
|
||||
var expectedCount = 122;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
@ -56,7 +56,7 @@ describe("chat-load-messages", function(){
|
|||
chatButton.click();
|
||||
var chatText = chrome$("#chattext");
|
||||
var loadMsgBtn = chrome$("#chatloadmessagesbutton");
|
||||
|
||||
|
||||
loadMsgBtn.click();
|
||||
helper.waitFor(function(){
|
||||
return chatText.children("p").length == expectedCount;
|
||||
|
@ -65,7 +65,7 @@ describe("chat-load-messages", function(){
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("checks for button vanishing", function(done) {
|
||||
var expectedDisplay = 'none';
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
|
|
@ -6,8 +6,8 @@ describe("clear authorship colors button", function(){
|
|||
});
|
||||
|
||||
it("makes text clear authorship colors", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// override the confirm dialogue functioon
|
||||
helper.padChrome$.window.confirm = function(){
|
||||
|
@ -19,7 +19,7 @@ describe("clear authorship colors button", function(){
|
|||
|
||||
// Get the original text
|
||||
var originalText = inner$("div").first().text();
|
||||
|
||||
|
||||
// Set some new text
|
||||
var sentText = "Hello";
|
||||
|
||||
|
@ -39,7 +39,6 @@ describe("clear authorship colors button", function(){
|
|||
$clearauthorshipcolorsButton.click();
|
||||
|
||||
// does the first divs span include an author class?
|
||||
console.log(inner$("div span").first().attr("class"));
|
||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
||||
//expect(hasAuthorClass).to.be(false);
|
||||
|
||||
|
@ -47,13 +46,88 @@ describe("clear authorship colors button", function(){
|
|||
var hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
||||
expect(hasAuthorClass).to.be(false);
|
||||
|
||||
setTimeout(function(){
|
||||
helper.waitFor(function(){
|
||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
||||
expect(disconnectVisible).to.be(true);
|
||||
},1000);
|
||||
return (disconnectVisible === true)
|
||||
});
|
||||
|
||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
||||
expect(disconnectVisible).to.be(true);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("makes text clear authorship colors and checks it can't be undone", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// override the confirm dialogue functioon
|
||||
helper.padChrome$.window.confirm = function(){
|
||||
return true;
|
||||
}
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
// Get the original text
|
||||
var originalText = inner$("div").first().text();
|
||||
|
||||
// Set some new text
|
||||
var sentText = "Hello";
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
$firstTextElement.sendkeys(sentText);
|
||||
$firstTextElement.sendkeys('{rightarrow}');
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div span").first().attr("class").indexOf("author") !== -1; // wait until we have the full value available
|
||||
}).done(function(){
|
||||
//IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
|
||||
inner$("div").first().focus();
|
||||
|
||||
//get the clear authorship colors button and click it
|
||||
var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship");
|
||||
$clearauthorshipcolorsButton.click();
|
||||
|
||||
// does the first divs span include an author class?
|
||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
||||
//expect(hasAuthorClass).to.be(false);
|
||||
|
||||
// does the first div include an author class?
|
||||
var hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
||||
expect(hasAuthorClass).to.be(false);
|
||||
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 90; // z
|
||||
inner$("#innerdocbody").trigger(e); // shouldn't od anything
|
||||
|
||||
// does the first div include an author class?
|
||||
hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
||||
expect(hasAuthorClass).to.be(false);
|
||||
|
||||
// get undo and redo buttons
|
||||
var $undoButton = chrome$(".buttonicon-undo");
|
||||
|
||||
// click the button
|
||||
$undoButton.click(); // shouldn't do anything
|
||||
hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
||||
expect(hasAuthorClass).to.be(false);
|
||||
|
||||
helper.waitFor(function(){
|
||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
||||
return (disconnectVisible === true)
|
||||
});
|
||||
|
||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
||||
expect(disconnectVisible).to.be(true);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -6,12 +6,12 @@ describe("delete keystroke", function(){
|
|||
});
|
||||
|
||||
it("makes text delete", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// get the original length of this element
|
||||
var elementLength = $firstTextElement.text().length;
|
||||
|
||||
|
@ -25,7 +25,7 @@ describe("delete keystroke", function(){
|
|||
|
||||
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// get the new length of this element
|
||||
var newElementLength = $newFirstTextElement.text().length;
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ describe("embed links", function(){
|
|||
var $embediFrame = $(embedCode);
|
||||
|
||||
//read and check the frame attributes
|
||||
var width = $embediFrame.attr("width");
|
||||
var height = $embediFrame.attr("height");
|
||||
var name = $embediFrame.attr("name");
|
||||
expect(width).to.be('600');
|
||||
expect(height).to.be('400');
|
||||
var width = $embediFrame.attr("width");
|
||||
var height = $embediFrame.attr("height");
|
||||
var name = $embediFrame.attr("name");
|
||||
expect(width).to.be('100%');
|
||||
expect(height).to.be('600');
|
||||
expect(name).to.be(readonly ? "embed_readonly" : "embed_readwrite");
|
||||
|
||||
//parse the url
|
||||
|
@ -43,7 +43,7 @@ describe("embed links", function(){
|
|||
} else {
|
||||
expect(url).to.be(helper.padChrome$.window.location.href);
|
||||
}
|
||||
|
||||
|
||||
//check if all parts of the url are like expected
|
||||
expect(params).to.eql(expectedParams);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ describe("embed links", function(){
|
|||
|
||||
describe("the share link", function(){
|
||||
it("is the actual pad url", function(done){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//open share dropdown
|
||||
chrome$(".buttonicon-embed").click();
|
||||
|
@ -73,14 +73,14 @@ describe("embed links", function(){
|
|||
|
||||
describe("the embed as iframe code", function(){
|
||||
it("is an iframe with the the correct url parameters and correct size", function(done){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//open share dropdown
|
||||
chrome$(".buttonicon-embed").click();
|
||||
|
||||
//get the link of the share field + the actual pad url and compare them
|
||||
var embedCode = chrome$("#embedinput").val();
|
||||
|
||||
|
||||
checkiFrameCode(embedCode, false)
|
||||
|
||||
done();
|
||||
|
@ -96,7 +96,7 @@ describe("embed links", function(){
|
|||
|
||||
describe("the share link", function(){
|
||||
it("shows a read only url", function(done){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//open share dropdown
|
||||
chrome$(".buttonicon-embed").click();
|
||||
|
@ -114,7 +114,7 @@ describe("embed links", function(){
|
|||
|
||||
describe("the embed as iframe code", function(){
|
||||
it("is an iframe with the the correct url parameters and correct size", function(done){
|
||||
var chrome$ = helper.padChrome$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//open share dropdown
|
||||
chrome$(".buttonicon-embed").click();
|
||||
|
@ -125,9 +125,9 @@ describe("embed links", function(){
|
|||
|
||||
//get the link of the share field + the actual pad url and compare them
|
||||
var embedCode = chrome$("#embedinput").val();
|
||||
|
||||
|
||||
checkiFrameCode(embedCode, true);
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,12 +6,12 @@ describe("enter keystroke", function(){
|
|||
});
|
||||
|
||||
it("creates a new line & puts cursor onto a new line", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// get the original string value minus the last char
|
||||
var originalTextValue = $firstTextElement.text();
|
||||
|
||||
|
@ -20,7 +20,7 @@ describe("enter keystroke", function(){
|
|||
|
||||
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().text() === "";
|
||||
}).done(function(){
|
||||
|
|
|
@ -5,26 +5,27 @@ describe("font select", function(){
|
|||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("makes text monospace", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
it("makes text RobotoMono", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//click on the settings button to make settings visible
|
||||
var $settingsButton = chrome$(".buttonicon-settings");
|
||||
$settingsButton.click();
|
||||
|
||||
//get the font menu and monospace option
|
||||
//get the font menu and RobotoMono option
|
||||
var $viewfontmenu = chrome$("#viewfontmenu");
|
||||
var $monospaceoption = $viewfontmenu.find("[value=monospace]");
|
||||
var $RobotoMonooption = $viewfontmenu.find("[value=RobotoMono]");
|
||||
|
||||
//select monospace and fire change event
|
||||
$monospaceoption.attr('selected','selected');
|
||||
$viewfontmenu.val("monospace");
|
||||
//select RobotoMono and fire change event
|
||||
// $RobotoMonooption.attr('selected','selected');
|
||||
// commenting out above will break safari test
|
||||
$viewfontmenu.val("RobotoMono");
|
||||
$viewfontmenu.change();
|
||||
|
||||
//check if font changed to monospace
|
||||
//check if font changed to RobotoMono
|
||||
var fontFamily = inner$("body").css("font-family").toLowerCase();
|
||||
var containsStr = fontFamily.indexOf("monospace");
|
||||
var containsStr = fontFamily.indexOf("robotomono");
|
||||
expect(containsStr).to.not.be(-1);
|
||||
|
||||
done();
|
||||
|
|
|
@ -20,7 +20,7 @@ describe("the test helper", function(){
|
|||
});
|
||||
|
||||
it("gives me 3 jquery instances of chrome, outer and inner", function(done){
|
||||
this.timeout(5000);
|
||||
this.timeout(10000);
|
||||
|
||||
helper.newPad(function(){
|
||||
//check if the jquery selectors have the desired elements
|
||||
|
@ -36,17 +36,106 @@ describe("the test helper", function(){
|
|||
done();
|
||||
});
|
||||
});
|
||||
// Make sure the cookies are cleared, and make sure that the cookie
|
||||
// clearing has taken effect at this point in the code. It has been
|
||||
// observed that the former can happen without the latter if there
|
||||
// isn't a timeout (within `newPad`) after clearing the cookies.
|
||||
// However this doesn't seem to always be easily replicated, so this
|
||||
// timeout may or may end up in the code. None the less, we test here
|
||||
// to catch it if the bug comes up again.
|
||||
it("clears cookies", function(done) {
|
||||
this.timeout(60000);
|
||||
|
||||
// set cookies far into the future to make sure they're not expired yet
|
||||
window.document.cookie = 'token=foo;expires=Thu, 01 Jan 3030 00:00:00 GMT; path=/';
|
||||
window.document.cookie = 'language=bar;expires=Thu, 01 Jan 3030 00:00:00 GMT; path=/';
|
||||
|
||||
expect(window.document.cookie).to.contain('token=foo');
|
||||
expect(window.document.cookie).to.contain('language=bar');
|
||||
|
||||
helper.newPad(function(){
|
||||
// helper function seems to have cleared cookies
|
||||
// NOTE: this doesn't yet mean it's proven to have taken effect by this point in execution
|
||||
var firstCookie = window.document.cookie
|
||||
expect(firstCookie).to.not.contain('token=foo');
|
||||
expect(firstCookie).to.not.contain('language=bar');
|
||||
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
var $usernameInput = chrome$("#myusernameedit");
|
||||
$usernameInput.click();
|
||||
|
||||
$usernameInput.val('John McLear');
|
||||
$usernameInput.blur();
|
||||
|
||||
// Before refreshing, make sure the name is there
|
||||
expect($usernameInput.val()).to.be('John McLear');
|
||||
|
||||
// Now that we have a chrome, we can set a pad cookie, so we can confirm it gets wiped as well
|
||||
chrome$.document.cookie = 'prefsHtml=baz;expires=Thu, 01 Jan 3030 00:00:00 GMT';
|
||||
expect(chrome$.document.cookie).to.contain('prefsHtml=baz');
|
||||
|
||||
// Cookies are weird. Because it's attached to chrome$ (as helper.setPadCookies does), AND we
|
||||
// didn't put path=/, we shouldn't expect it to be visible on window.document.cookie. Let's just
|
||||
// be sure.
|
||||
expect(window.document.cookie).to.not.contain('prefsHtml=baz');
|
||||
|
||||
setTimeout(function(){ //give it a second to save the username on the server side
|
||||
helper.newPad(function(){ // get a new pad, let it clear the cookies
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// helper function seems to have cleared cookies
|
||||
// NOTE: this doesn't yet mean cookies were cleared effectively.
|
||||
// We still need to test below that we're in a new session
|
||||
expect(window.document.cookie).to.not.contain('token=foo');
|
||||
expect(window.document.cookie).to.not.contain('language=bar');
|
||||
expect(chrome$.document.cookie).to.contain('prefsHtml=baz');
|
||||
expect(window.document.cookie).to.not.contain('prefsHtml=baz');
|
||||
|
||||
expect(window.document.cookie).to.not.be(firstCookie);
|
||||
|
||||
// click on the settings button to make settings visible
|
||||
var $userButton = chrome$(".buttonicon-showusers");
|
||||
$userButton.click();
|
||||
|
||||
// confirm that the session was actually cleared
|
||||
var $usernameInput = chrome$("#myusernameedit");
|
||||
expect($usernameInput.val()).to.be('');
|
||||
|
||||
done();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it("sets pad prefs cookie", function(done) {
|
||||
this.timeout(60000);
|
||||
|
||||
helper.newPad({
|
||||
padPrefs: {foo:"bar"},
|
||||
cb: function(){
|
||||
var chrome$ = helper.padChrome$;
|
||||
expect(chrome$.document.cookie).to.contain('prefsHttp=%7B%22');
|
||||
expect(chrome$.document.cookie).to.contain('foo%22%3A%22bar');
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("the waitFor method", function(){
|
||||
it("takes a timeout and waits long enough", function(done){
|
||||
this.timeout(2000);
|
||||
var startTime = new Date().getTime();
|
||||
var startTime = Date.now();
|
||||
|
||||
helper.waitFor(function(){
|
||||
return false;
|
||||
}, 1500).fail(function(){
|
||||
var duration = new Date().getTime() - startTime;
|
||||
var duration = Date.now() - startTime;
|
||||
expect(duration).to.be.greaterThan(1400);
|
||||
done();
|
||||
});
|
||||
|
@ -136,7 +225,15 @@ describe("the test helper", function(){
|
|||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||
|
||||
var selection = inner$.document.getSelection();
|
||||
expect(cleanText(selection.toString())).to.be("ort lines to t");
|
||||
|
||||
/*
|
||||
* replace() is required here because Firefox keeps the line breaks.
|
||||
*
|
||||
* I'm not sure this is ideal behavior of getSelection() where the text
|
||||
* is not consistent between browsers but that's the situation so that's
|
||||
* how I'm covering it in this test.
|
||||
*/
|
||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to t");
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -154,7 +251,15 @@ describe("the test helper", function(){
|
|||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||
|
||||
var selection = inner$.document.getSelection();
|
||||
expect(cleanText(selection.toString())).to.be("ort lines to test");
|
||||
|
||||
/*
|
||||
* replace() is required here because Firefox keeps the line breaks.
|
||||
*
|
||||
* I'm not sure this is ideal behavior of getSelection() where the text
|
||||
* is not consistent between browsers but that's the situation so that's
|
||||
* how I'm covering it in this test.
|
||||
*/
|
||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to test");
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -172,7 +277,15 @@ describe("the test helper", function(){
|
|||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||
|
||||
var selection = inner$.document.getSelection();
|
||||
expect(cleanText(selection.toString())).to.be("ort lines ");
|
||||
|
||||
/*
|
||||
* replace() is required here because Firefox keeps the line breaks.
|
||||
*
|
||||
* I'm not sure this is ideal behavior of getSelection() where the text
|
||||
* is not consistent between browsers but that's the situation so that's
|
||||
* how I'm covering it in this test.
|
||||
*/
|
||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines ");
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -190,7 +303,15 @@ describe("the test helper", function(){
|
|||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||
|
||||
var selection = inner$.document.getSelection();
|
||||
expect(cleanText(selection.toString())).to.be("ort lines to test");
|
||||
|
||||
/*
|
||||
* replace() is required here because Firefox keeps the line breaks.
|
||||
*
|
||||
* I'm not sure this is ideal behavior of getSelection() where the text
|
||||
* is not consistent between browsers but that's the situation so that's
|
||||
* how I'm covering it in this test.
|
||||
*/
|
||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to test");
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -205,7 +326,15 @@ describe("the test helper", function(){
|
|||
helper.selectLines($startLine, $endLine);
|
||||
|
||||
var selection = inner$.document.getSelection();
|
||||
expect(cleanText(selection.toString())).to.be("short lines to test");
|
||||
|
||||
/*
|
||||
* replace() is required here because Firefox keeps the line breaks.
|
||||
*
|
||||
* I'm not sure this is ideal behavior of getSelection() where the text
|
||||
* is not consistent between browsers but that's the situation so that's
|
||||
* how I'm covering it in this test.
|
||||
*/
|
||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("short lines to test");
|
||||
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -159,7 +159,7 @@ describe("import functionality", function(){
|
|||
//<ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
||||
//<br>\n')
|
||||
})
|
||||
|
||||
|
||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
||||
expect(results[0][1]).to.be('<ul class="bullet"><li>bullet line 1</li><li>bullet line 2</li><ul class="bullet"><li>bullet2 line 1</li><ul><ul class="bullet"><li>bullet4 line 2</li><li>bullet4 line 2</li><li>bullet4 line 2</li></ul><li>bullet3 line 1</li></ul></ul><li>bullet2 line 1</li></ul><br>')
|
||||
expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t* bullet3 line 1\n\t* bullet2 line 1\n\n')
|
||||
|
@ -183,11 +183,11 @@ describe("import functionality", function(){
|
|||
<br>\n')
|
||||
})
|
||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
||||
expect(results[0][1]).to.be('<ul class="bullet"><li>bullet line 1</li></ul><br><ul class="bullet"><li>bullet line 2</li><ul class="bullet"><li>bullet2 line 1</li></ul></ul><br><ul><ul><ul><ul class="bullet"><li><strong><em><s><u>bullet4 line 2 bisu</u></s></em></strong></li><li><strong><s>bullet4 line 2 bs</s></strong></li><li><u>bullet4 line 2 u<em><s>uis</s></em></u></li><ul><ul><ul><ul class="bullet"><li>foo</li><li><strong><s>foobar bs</s></strong></li></ul></ul></ul><li>foobar</li></ul></ul></ul></ul></ul><br>')
|
||||
expect(results[0][1]).to.be('<ul class="bullet"><li>bullet line 1</li></ul><br><ul class="bullet"><li>bullet line 2</li><ul class="bullet"><li>bullet2 line 1</li></ul></ul><br><ul><ul><ul><ul class="bullet"><li><strong><em><s><u>bullet4 line 2 bisu</u></s></em></strong></li><li><strong><s>bullet4 line 2 bs</s></strong></li><li><u>bullet4 line 2 u<em><s>uis</s></em></u></li><ul><ul><ul><ul class="bullet"><li>foo</li><li><strong><s>foobar bs</s></strong></li></ul></ul></ul><li>foobar</li></ul></ul></ul></ul></ul><br>')
|
||||
expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\t\t\t\t\t\t\t\t* foo\n\t\t\t\t\t\t\t\t* foobar bs\n\t\t\t\t\t* foobar\n\n')
|
||||
done()
|
||||
})
|
||||
|
||||
|
||||
xit("import a pad with ordered lists from html", function(done){
|
||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
||||
var htmlWithBullets = '<html><body><ol class="list-number1" start="1"><li>number 1 line 1</li></ol><ol class="list-number1" start="2"><li>number 2 line 2</li></ol></body></html>'
|
||||
|
|
|
@ -66,7 +66,7 @@ describe("import indents functionality", function(){
|
|||
expect(results[1][1]).to.be('\tindent line 1\n\tindent line 2\n\t\tindent2 line 1\n\t\tindent2 line 2\n\n')
|
||||
done()
|
||||
})
|
||||
|
||||
|
||||
xit("import a pad with indented lists and newlines from html", function(done){
|
||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
||||
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li></ul><br/><ul class="list-indent1"><li>indent 1 line 2</li><ul class="list-indent2"><li>indent 2 times line 1</li></ul></ul><br/><ul class="list-indent1"><ul class="list-indent2"><li>indent 2 times line 2</li></ul></ul></body></html>'
|
||||
|
@ -104,7 +104,7 @@ describe("import indents functionality", function(){
|
|||
<br>\n')
|
||||
})
|
||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
||||
expect(results[0][1]).to.be('<ul class="indent"><li>indent line 1</li></ul><br><ul class="indent"><li>indent line 2</li><ul class="indent"><li>indent2 line 1</li></ul></ul><br><ul><ul><ul><ul class="indent"><li><strong><em><s><u>indent4 line 2 bisu</u></s></em></strong></li><li><strong><s>indent4 line 2 bs</s></strong></li><li><u>indent4 line 2 u<em><s>uis</s></em></u></li><ul><ul><ul><ul class="indent"><li>foo</li><li><strong><s>foobar bs</s></strong></li></ul></ul></ul><li>foobar</li></ul></ul></ul></ul></ul><br>')
|
||||
expect(results[0][1]).to.be('<ul class="indent"><li>indent line 1</li></ul><br><ul class="indent"><li>indent line 2</li><ul class="indent"><li>indent2 line 1</li></ul></ul><br><ul><ul><ul><ul class="indent"><li><strong><em><s><u>indent4 line 2 bisu</u></s></em></strong></li><li><strong><s>indent4 line 2 bs</s></strong></li><li><u>indent4 line 2 u<em><s>uis</s></em></u></li><ul><ul><ul><ul class="indent"><li>foo</li><li><strong><s>foobar bs</s></strong></li></ul></ul></ul><li>foobar</li></ul></ul></ul></ul></ul><br>')
|
||||
expect(results[1][1]).to.be('\tindent line 1\n\n\tindent line 2\n\t\tindent2 line 1\n\n\t\t\t\tindent4 line 2 bisu\n\t\t\t\tindent4 line 2 bs\n\t\t\t\tindent4 line 2 uuis\n\t\t\t\t\t\t\t\tfoo\n\t\t\t\t\t\t\t\tfoobar bs\n\t\t\t\t\tfoobar\n\n')
|
||||
done()
|
||||
})
|
||||
|
|
|
@ -15,13 +15,7 @@ describe("indentation button", function(){
|
|||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.keyCode = 9; // tab :|
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
|
@ -325,12 +319,7 @@ describe("indentation button", function(){
|
|||
|
||||
function pressEnter(){
|
||||
var inner$ = helper.padInner$;
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.keyCode = 13; // enter :|
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
}
|
||||
|
|
|
@ -6,22 +6,22 @@ describe("italic some text", function(){
|
|||
});
|
||||
|
||||
it("makes text italic using button", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
//get the bold button and click it
|
||||
var $boldButton = chrome$(".buttonicon-italic");
|
||||
$boldButton.click();
|
||||
|
||||
|
||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// is there a <i> element now?
|
||||
var isItalic = $newFirstTextElement.find("i").length === 1;
|
||||
|
||||
|
@ -44,13 +44,7 @@ describe("italic some text", function(){
|
|||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 105; // i
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
|
51
tests/frontend/specs/multiple_authors_clear_authorship_colors.js
Executable file
51
tests/frontend/specs/multiple_authors_clear_authorship_colors.js
Executable file
|
@ -0,0 +1,51 @@
|
|||
describe('author of pad edition', function() {
|
||||
// author 1 creates a new pad with some content (regular lines and lists)
|
||||
before(function(done) {
|
||||
var padId = helper.newPad(function() {
|
||||
// make sure pad has at least 3 lines
|
||||
var $firstLine = helper.padInner$('div').first();
|
||||
$firstLine.html("Hello World");
|
||||
|
||||
// wait for lines to be processed by Etherpad
|
||||
helper.waitFor(function() {
|
||||
return $firstLine.text() === 'Hello World';
|
||||
}).done(function() {
|
||||
// Reload pad, to make changes as a second user. Need a timeout here to make sure
|
||||
// all changes were saved before reloading
|
||||
setTimeout(function() {
|
||||
// Expire cookie, so author is changed after reloading the pad.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie
|
||||
helper.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
||||
|
||||
helper.newPad(done, padId);
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
// author 2 makes some changes on the pad
|
||||
it('Clears Authorship by second user', function(done) {
|
||||
clearAuthorship(done);
|
||||
});
|
||||
|
||||
var clearAuthorship = function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// override the confirm dialogue functioon
|
||||
helper.padChrome$.window.confirm = function(){
|
||||
return true;
|
||||
}
|
||||
|
||||
//get the clear authorship colors button and click it
|
||||
var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship");
|
||||
$clearauthorshipcolorsButton.click();
|
||||
|
||||
// does the first divs span include an author class?
|
||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
||||
|
||||
expect(hasAuthorClass).to.be(false)
|
||||
done();
|
||||
}
|
||||
});
|
|
@ -100,7 +100,6 @@ describe("assign ordered list", function(){
|
|||
}).done(function(){
|
||||
var $newSecondLine = inner$("div").first().next();
|
||||
var hasOLElement = $newSecondLine.find("ol li").length === 1;
|
||||
console.log($newSecondLine.find("ol"));
|
||||
expect(hasOLElement).to.be(true);
|
||||
expect($newSecondLine.text()).to.be("line 2");
|
||||
var hasLineNumber = $newSecondLine.find("ol").attr("start") === 2;
|
||||
|
@ -111,12 +110,7 @@ describe("assign ordered list", function(){
|
|||
|
||||
var triggerCtrlShiftShortcut = function(shortcutChar) {
|
||||
var inner$ = helper.padInner$;
|
||||
if(inner$(window)[0].bowser.modernIE) { // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true;
|
||||
e.shiftKey = true;
|
||||
e.which = shortcutChar.toString().charCodeAt(0);
|
||||
|
@ -131,3 +125,80 @@ describe("assign ordered list", function(){
|
|||
}
|
||||
|
||||
});
|
||||
|
||||
describe("Pressing Tab in an OL increases and decreases indentation", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("indent and de-indent list item with keypress", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
||||
$insertorderedlistButton.click();
|
||||
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.keyCode = 9; // tab
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
expect(inner$("div").first().find(".list-number2").length === 1).to.be(true);
|
||||
e.shiftKey = true; // shift
|
||||
e.keyCode = 9; // tab
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().find(".list-number1").length === 1;
|
||||
}).done(done);
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("Pressing indent/outdent button in an OL increases and decreases indentation and bullet / ol formatting", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("indent and de-indent list item with indent button", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
||||
$insertorderedlistButton.click();
|
||||
|
||||
var $indentButton = chrome$(".buttonicon-indent");
|
||||
$indentButton.click(); // make it indented twice
|
||||
|
||||
expect(inner$("div").first().find(".list-number2").length === 1).to.be(true);
|
||||
|
||||
var $outdentButton = chrome$(".buttonicon-outdent");
|
||||
$outdentButton.click(); // make it deindented to 1
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().find(".list-number1").length === 1;
|
||||
}).done(done);
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
describe('Pad modal', function() {
|
||||
context('when modal is a "force reconnect" message', function() {
|
||||
var MODAL_SELECTOR = '#connectivity .slowcommit';
|
||||
var MODAL_SELECTOR = '#connectivity';
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.newPad(function() {
|
||||
|
@ -10,7 +10,7 @@ describe('Pad modal', function() {
|
|||
// wait for modal to be displayed
|
||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||
helper.waitFor(function() {
|
||||
return $modal.is(':visible');
|
||||
return $modal.hasClass('popup-show');
|
||||
}, 50000).done(done);
|
||||
});
|
||||
|
||||
|
@ -30,7 +30,7 @@ describe('Pad modal', function() {
|
|||
|
||||
it('does not close the modal', function(done) {
|
||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||
var modalIsVisible = $modal.is(':visible');
|
||||
var modalIsVisible = $modal.hasClass('popup-show');
|
||||
|
||||
expect(modalIsVisible).to.be(true);
|
||||
|
||||
|
@ -45,7 +45,7 @@ describe('Pad modal', function() {
|
|||
|
||||
it('does not close the modal', function(done) {
|
||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||
var modalIsVisible = $modal.is(':visible');
|
||||
var modalIsVisible = $modal.hasClass('popup-show');
|
||||
|
||||
expect(modalIsVisible).to.be(true);
|
||||
|
||||
|
@ -65,12 +65,13 @@ describe('Pad modal', function() {
|
|||
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
// This test breaks safari testing
|
||||
/*
|
||||
it('does not disable editor', function(done) {
|
||||
expect(isEditorDisabled()).to.be(false);
|
||||
done();
|
||||
});
|
||||
|
||||
*/
|
||||
context('and user clicks on editor', function() {
|
||||
beforeEach(function() {
|
||||
clickOnPadInner();
|
||||
|
@ -126,6 +127,7 @@ describe('Pad modal', function() {
|
|||
|
||||
var isModalOpened = function(modalSelector) {
|
||||
var $modal = helper.padChrome$(modalSelector);
|
||||
return $modal.is(':visible');
|
||||
|
||||
return $modal.hasClass('popup-show');
|
||||
}
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("undo button then redo button", function(){
|
|||
it("redo some typing with button", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
|
||||
// get the first text element inside the editable space
|
||||
var $firstTextElement = inner$("div span").first();
|
||||
var originalValue = $firstTextElement.text(); // get the original value
|
||||
|
@ -25,7 +25,6 @@ describe("undo button then redo button", function(){
|
|||
$redoButton.click(); // resends foo
|
||||
|
||||
helper.waitFor(function(){
|
||||
console.log(inner$("div span").first().text());
|
||||
return inner$("div span").first().text() === newString;
|
||||
}).done(function(){
|
||||
var finalValue = inner$("div").first().text();
|
||||
|
@ -47,24 +46,17 @@ describe("undo button then redo button", function(){
|
|||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
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);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 90; // z
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 121; // y
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
helper.waitFor(function(){
|
||||
console.log(inner$("div span").first().text());
|
||||
return inner$("div span").first().text() === newString;
|
||||
}).done(function(){
|
||||
var finalValue = inner$("div").first().text();
|
||||
|
|
|
@ -49,7 +49,7 @@ describe('Responsiveness of Editor', function() {
|
|||
}).done(function(){
|
||||
|
||||
expect( inner$('div').text().length ).to.be.greaterThan( length ); // has the text changed?
|
||||
var start = new Date().getTime(); // get the start time
|
||||
var start = Date.now(); // get the start time
|
||||
|
||||
// send some new text to the screen (ensure all 3 key events are sent)
|
||||
var el = inner$('div').first();
|
||||
|
@ -65,11 +65,10 @@ describe('Responsiveness of Editor', function() {
|
|||
helper.waitFor(function(){ // Wait for the ability to process
|
||||
return true; // Ghetto but works for now
|
||||
}).done(function(){
|
||||
var end = new Date().getTime(); // get the current time
|
||||
var end = Date.now(); // get the current time
|
||||
var delay = end - start; // get the delay as the current time minus the start time
|
||||
|
||||
console.log('delay:', delay);
|
||||
expect(delay).to.be.below(200);
|
||||
expect(delay).to.be.below(300);
|
||||
done();
|
||||
}, 1000);
|
||||
|
||||
|
|
|
@ -1,649 +0,0 @@
|
|||
describe('scroll when focus line is out of viewport', function () {
|
||||
before(function (done) {
|
||||
helper.newPad(function(){
|
||||
cleanPad(function(){
|
||||
forceUseMonospacedFont();
|
||||
scrollWhenPlaceCaretInTheLastLineOfViewport();
|
||||
createPadWithSeveralLines(function(){
|
||||
resizeEditorHeight();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
this.timeout(20000);
|
||||
});
|
||||
|
||||
context('when user presses any arrow keys on a line above the viewport', function(){
|
||||
context('and scroll percentage config is set to 0.2 on settings.json', function(){
|
||||
var lineCloseOfTopOfPad = 10;
|
||||
before(function (done) {
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true);
|
||||
scrollEditorToBottomOfPad();
|
||||
|
||||
placeCaretInTheBeginningOfLine(lineCloseOfTopOfPad, function(){ // place caret in the 10th line
|
||||
// warning: even pressing right arrow, the caret does not change of position
|
||||
// the column where the caret is, it has not importance, only the line
|
||||
pressAndReleaseRightArrow();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps the focus line scrolled 20% from the top of the viewport', function (done) {
|
||||
// default behavior is to put the line in the top of viewport, but as
|
||||
// scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
|
||||
// (2 lines, which are the 20% of the 10 that are visible on viewport)
|
||||
var firstLineOfViewport = getFirstLineVisibileOfViewport();
|
||||
expect(lineCloseOfTopOfPad).to.be(firstLineOfViewport + 2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when user presses any arrow keys on a line below the viewport', function(){
|
||||
context('and scroll percentage config is set to 0.7 on settings.json', function(){
|
||||
var lineCloseToBottomOfPad = 50;
|
||||
before(function (done) {
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.7);
|
||||
|
||||
// firstly, scroll to make the lineCloseToBottomOfPad visible. After that, scroll to make it out of viewport
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lineCloseToBottomOfPad); // place caret in the 50th line
|
||||
setTimeout(function() {
|
||||
// warning: even pressing right arrow, the caret does not change of position
|
||||
pressAndReleaseLeftArrow();
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('keeps the focus line scrolled 70% from the bottom of the viewport', function (done) {
|
||||
// default behavior is to put the line in the top of viewport, but as
|
||||
// scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.7, we have an extra 70% of lines scrolled
|
||||
// (7 lines, which are the 70% of the 10 that are visible on viewport)
|
||||
var lastLineOfViewport = getLastLineVisibleOfViewport();
|
||||
expect(lineCloseToBottomOfPad).to.be(lastLineOfViewport - 7);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when user presses arrow up on the first line of the viewport', function(){
|
||||
context('and percentageToScrollWhenUserPressesArrowUp is set to 0.3', function () {
|
||||
var lineOnTopOfViewportWhenThePadIsScrolledDown;
|
||||
before(function (done) {
|
||||
setPercentageToScrollWhenUserPressesArrowUp(0.3);
|
||||
|
||||
// we need some room to make the scroll up
|
||||
scrollEditorToBottomOfPad();
|
||||
lineOnTopOfViewportWhenThePadIsScrolledDown = 91;
|
||||
placeCaretAtTheEndOfLine(lineOnTopOfViewportWhenThePadIsScrolledDown);
|
||||
setTimeout(function() {
|
||||
// warning: even pressing up arrow, the caret does not change of position
|
||||
pressAndReleaseUpArrow();
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it('keeps the focus line scrolled 30% of the top of the viewport', function (done) {
|
||||
// default behavior is to put the line in the top of viewport, but as
|
||||
// PercentageToScrollWhenUserPressesArrowUp is set to 0.3, we have an extra 30% of lines scrolled
|
||||
// (3 lines, which are the 30% of the 10 that are visible on viewport)
|
||||
var firstLineOfViewport = getFirstLineVisibileOfViewport();
|
||||
expect(firstLineOfViewport).to.be(lineOnTopOfViewportWhenThePadIsScrolledDown - 3);
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
context('when user edits the last line of viewport', function(){
|
||||
context('and scroll percentage config is set to 0 on settings.json', function(){
|
||||
var lastLineOfViewportBeforeEnter = 10;
|
||||
before(function () {
|
||||
// the default value
|
||||
resetScrollPercentageWhenFocusLineIsOutOfViewport();
|
||||
|
||||
// make sure the last line on viewport is the 10th one
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
|
||||
pressEnter();
|
||||
});
|
||||
|
||||
it('keeps the focus line on the bottom of the viewport', function (done) {
|
||||
var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
|
||||
expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3', function(){ // this value is arbitrary
|
||||
var lastLineOfViewportBeforeEnter = 9;
|
||||
before(function () {
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.3);
|
||||
|
||||
// make sure the last line on viewport is the 10th one
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
|
||||
pressBackspace();
|
||||
});
|
||||
|
||||
it('scrolls 30% of viewport up', function (done) {
|
||||
var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
|
||||
// default behavior is to scroll one line at the bottom of viewport, but as
|
||||
// scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3, we have an extra 30% of lines scrolled
|
||||
// (3 lines, which are the 30% of the 10 that are visible on viewport)
|
||||
expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
context('and it is set to a value that overflow the interval [0, 1]', function(){
|
||||
var lastLineOfViewportBeforeEnter = 10;
|
||||
before(function(){
|
||||
var scrollPercentageWhenFocusLineIsOutOfViewport = 1.5;
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(scrollPercentageWhenFocusLineIsOutOfViewport);
|
||||
pressEnter();
|
||||
});
|
||||
|
||||
it('keeps the default behavior of moving the focus line on the bottom of the viewport', function (done) {
|
||||
var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
|
||||
expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when user edits a line above the viewport', function(){
|
||||
context('and scroll percentage config is set to 0 on settings.json', function(){
|
||||
var lineCloseOfTopOfPad = 10;
|
||||
before(function () {
|
||||
// the default value
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0);
|
||||
|
||||
// firstly, scroll to make the lineCloseOfTopOfPad visible. After that, scroll to make it out of viewport
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lineCloseOfTopOfPad); // place caret in the 10th line
|
||||
scrollEditorToBottomOfPad();
|
||||
pressBackspace(); // edit the line where the caret is, which is above the viewport
|
||||
});
|
||||
|
||||
it('keeps the focus line on the top of the viewport', function (done) {
|
||||
var firstLineOfViewportAfterEnter = getFirstLineVisibileOfViewport();
|
||||
expect(firstLineOfViewportAfterEnter).to.be(lineCloseOfTopOfPad);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2', function(){ // this value is arbitrary
|
||||
var lineCloseToBottomOfPad = 50;
|
||||
before(function () {
|
||||
// we force the line edited to be above the top of the viewport
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true); // set scroll jump to 20%
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretAtTheEndOfLine(lineCloseToBottomOfPad);
|
||||
scrollEditorToBottomOfPad();
|
||||
pressBackspace(); // edit line
|
||||
});
|
||||
|
||||
it('scrolls 20% of viewport down', function (done) {
|
||||
// default behavior is to scroll one line at the top of viewport, but as
|
||||
// scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
|
||||
// (2 lines, which are the 20% of the 10 that are visible on viewport)
|
||||
var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
|
||||
expect(lineCloseToBottomOfPad).to.be(firstLineVisibileOfViewport + 2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when user places the caret at the last line visible of viewport', function(){
|
||||
var lastLineVisible;
|
||||
context('and scroll percentage config is set to 0 on settings.json', function(){
|
||||
before(function (done) {
|
||||
// reset to the default value
|
||||
resetScrollPercentageWhenFocusLineIsOutOfViewport();
|
||||
|
||||
placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
|
||||
scrollEditorToTopOfPad();
|
||||
lastLineVisible = getLastLineVisibleOfViewport();
|
||||
placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('does not scroll', function(done){
|
||||
setTimeout(function() {
|
||||
var lastLineOfViewport = getLastLineVisibleOfViewport();
|
||||
var lineDoesNotScroll = lastLineOfViewport === lastLineVisible;
|
||||
expect(lineDoesNotScroll).to.be(true);
|
||||
done();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
context('and scroll percentage config is set to 0.5 on settings.json', function(){
|
||||
before(function (done) {
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.5);
|
||||
scrollEditorToTopOfPad();
|
||||
placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
|
||||
// this timeout inside a callback is ugly but it necessary to give time to aceSelectionChange
|
||||
// realizes that the selection has been changed
|
||||
setTimeout(function() {
|
||||
lastLineVisible = getLastLineVisibleOfViewport();
|
||||
placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it('scrolls line to 50% of the viewport', function(done){
|
||||
helper.waitFor(function(){
|
||||
var lastLineOfViewport = getLastLineVisibleOfViewport();
|
||||
var lastLinesScrolledFiveLinesUp = lastLineOfViewport - 5 === lastLineVisible;
|
||||
return lastLinesScrolledFiveLinesUp;
|
||||
}).done(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// This is a special case. When user is selecting a text with arrow down or arrow left we have
|
||||
// to keep the last line selected on focus
|
||||
context('when the first line selected is out of the viewport and user presses shift arrow down', function(){
|
||||
var lastLineOfPad = 99;
|
||||
before(function (done) {
|
||||
scrollEditorToTopOfPad();
|
||||
|
||||
// make a selection bigger than the viewport height
|
||||
var $firstLineOfSelection = getLine(0);
|
||||
var $lastLineOfSelection = getLine(lastLineOfPad);
|
||||
var lengthOfLastLine = $lastLineOfSelection.text().length;
|
||||
helper.selectLines($firstLineOfSelection, $lastLineOfSelection, 0, lengthOfLastLine);
|
||||
|
||||
// place the last line selected on the viewport
|
||||
scrollEditorToBottomOfPad();
|
||||
|
||||
// press a key to make the selection goes down
|
||||
// although we can't simulate the extending of selection. It's possible to send a key event
|
||||
// which is captured on ace2_inner scroll function.
|
||||
pressAndReleaseLeftArrow(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('keeps the last line selected on focus', function (done) {
|
||||
var lastLineOfSelectionIsVisible = isLineOnViewport(lastLineOfPad);
|
||||
expect(lastLineOfSelectionIsVisible).to.be(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// In this scenario we avoid the bouncing scroll. E.g Let's suppose we have a big line that is
|
||||
// the size of the viewport, and its top is above the viewport. When user presses '<-', this line
|
||||
// will scroll down because the top is out of the viewport. When it scrolls down, the bottom of
|
||||
// line gets below the viewport so when user presses '<-' again it scrolls up to make the bottom
|
||||
// of line visible. If user presses arrow keys more than one time, the editor will keep scrolling up and down
|
||||
context('when the line height is bigger than the scroll amount percentage * viewport height', function(){
|
||||
var scrollOfEditorBeforePressKey;
|
||||
var BIG_LINE_NUMBER = 0;
|
||||
var MIDDLE_OF_BIG_LINE = 51;
|
||||
before(function (done) {
|
||||
createPadWithALineHigherThanViewportHeight(this, BIG_LINE_NUMBER, function(){
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(0.5); // set any value to force scroll to outside to viewport
|
||||
var $bigLine = getLine(BIG_LINE_NUMBER);
|
||||
|
||||
// each line has about 5 chars, we place the caret in the middle of the line
|
||||
helper.selectLines($bigLine, $bigLine, MIDDLE_OF_BIG_LINE, MIDDLE_OF_BIG_LINE);
|
||||
|
||||
scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport($bigLine);
|
||||
scrollOfEditorBeforePressKey = getEditorScroll();
|
||||
|
||||
// press a key to force to scroll
|
||||
pressAndReleaseRightArrow();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// reset pad to the original text
|
||||
after(function (done) {
|
||||
this.timeout(5000);
|
||||
cleanPad(function(){
|
||||
createPadWithSeveralLines(function(){
|
||||
resetEditorWidth();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// as the editor.line is inside of the viewport, it should not scroll
|
||||
it('should not scroll', function (done) {
|
||||
var scrollOfEditorAfterPressKey = getEditorScroll();
|
||||
expect(scrollOfEditorAfterPressKey).to.be(scrollOfEditorBeforePressKey);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Some plugins, for example the ep_page_view, change the editor dimensions. This plugin, for example,
|
||||
// adds padding-top to the ace_outer, which changes the viewport height
|
||||
describe('integration with plugins which changes the margin of editor', function(){
|
||||
context('when editor dimensions changes', function(){
|
||||
before(function () {
|
||||
// reset the size of editor. Now we show more than 10 lines as in the other tests
|
||||
resetResizeOfEditorHeight();
|
||||
scrollEditorToTopOfPad();
|
||||
|
||||
// height of the editor viewport
|
||||
var editorHeight = getEditorHeight();
|
||||
|
||||
// add a big padding-top, 50% of the viewport
|
||||
var paddingTopOfAceOuter = editorHeight/2;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var $outerIframe = chrome$('iframe');
|
||||
$outerIframe.css('padding-top', paddingTopOfAceOuter);
|
||||
|
||||
// we set a big value to check if the scroll is made
|
||||
setScrollPercentageWhenFocusLineIsOutOfViewport(1);
|
||||
});
|
||||
|
||||
context('and user places the caret in the last line visible of the pad', function(){
|
||||
var lastLineVisible;
|
||||
beforeEach(function (done) {
|
||||
lastLineVisible = getLastLineVisibleOfViewport();
|
||||
placeCaretInTheBeginningOfLine(lastLineVisible, done);
|
||||
});
|
||||
|
||||
it('scrolls the line where caret is', function(done){
|
||||
helper.waitFor(function(){
|
||||
var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
|
||||
var linesScrolled = firstLineVisibileOfViewport !== 0;
|
||||
return linesScrolled;
|
||||
}).done(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* ********************* Helper functions/constants ********************* */
|
||||
var TOP_OF_PAGE = 0;
|
||||
var BOTTOM_OF_PAGE = 5000; // we use a big value to force the page to be scrolled all the way down
|
||||
var LINES_OF_PAD = 100;
|
||||
var ENTER = 13;
|
||||
var BACKSPACE = 8;
|
||||
var LEFT_ARROW = 37;
|
||||
var UP_ARROW = 38;
|
||||
var RIGHT_ARROW = 39;
|
||||
var LINES_ON_VIEWPORT = 10;
|
||||
var WIDTH_OF_EDITOR_RESIZED = 100;
|
||||
var LONG_TEXT_CHARS = 100;
|
||||
|
||||
var cleanPad = function(callback) {
|
||||
var inner$ = helper.padInner$;
|
||||
var $padContent = inner$('#innerdocbody');
|
||||
$padContent.html('');
|
||||
|
||||
// wait for Etherpad to re-create first line
|
||||
helper.waitFor(function(){
|
||||
var lineNumber = inner$('div').length;
|
||||
return lineNumber === 1;
|
||||
}, 2000).done(callback);
|
||||
};
|
||||
|
||||
var createPadWithSeveralLines = function(done) {
|
||||
var line = '<span>a</span><br>';
|
||||
var $firstLine = helper.padInner$('div').first();
|
||||
var lines = line.repeat(LINES_OF_PAD); //arbitrary number, we need to create lines that is over the viewport
|
||||
$firstLine.html(lines);
|
||||
|
||||
helper.waitFor(function(){
|
||||
var linesCreated = helper.padInner$('div').length;
|
||||
return linesCreated === LINES_OF_PAD;
|
||||
}, 4000).done(done);
|
||||
};
|
||||
|
||||
var createPadWithALineHigherThanViewportHeight = function(test, line, done) {
|
||||
var viewportHeight = 160; //10 lines * 16px (height of line)
|
||||
test.timeout(5000);
|
||||
cleanPad(function(){
|
||||
// make the editor smaller to make test easier
|
||||
// with that width the each line has about 5 chars
|
||||
resizeEditorWidth();
|
||||
|
||||
// we create a line with 100 chars, which makes about 20 lines
|
||||
setLongTextOnLine(line);
|
||||
helper.waitFor(function () {
|
||||
var $firstLine = getLine(line);
|
||||
|
||||
var heightOfLine = $firstLine.get(0).getBoundingClientRect().height;
|
||||
return heightOfLine >= viewportHeight;
|
||||
}, 4000).done(done);
|
||||
});
|
||||
};
|
||||
|
||||
var setLongTextOnLine = function(line) {
|
||||
var $line = getLine(line);
|
||||
var longText = 'a'.repeat(LONG_TEXT_CHARS);
|
||||
$line.html(longText);
|
||||
};
|
||||
|
||||
// resize the editor to make the tests easier
|
||||
var resizeEditorHeight = function() {
|
||||
var chrome$ = helper.padChrome$;
|
||||
chrome$('#editorcontainer').css('height', getSizeOfViewport());
|
||||
};
|
||||
|
||||
// this makes about 5 chars per line
|
||||
var resizeEditorWidth = function() {
|
||||
var chrome$ = helper.padChrome$;
|
||||
chrome$('#editorcontainer').css('width', WIDTH_OF_EDITOR_RESIZED);
|
||||
};
|
||||
|
||||
var resetResizeOfEditorHeight = function() {
|
||||
var chrome$ = helper.padChrome$;
|
||||
chrome$('#editorcontainer').css('height', '');
|
||||
};
|
||||
|
||||
var resetEditorWidth = function () {
|
||||
var chrome$ = helper.padChrome$;
|
||||
chrome$('#editorcontainer').css('width', '');
|
||||
};
|
||||
|
||||
var getEditorHeight = function() {
|
||||
var chrome$ = helper.padChrome$;
|
||||
var $editor = chrome$('#editorcontainer');
|
||||
var editorHeight = $editor.get(0).clientHeight;
|
||||
return editorHeight;
|
||||
};
|
||||
|
||||
var getSizeOfViewport = function() {
|
||||
return getLinePositionOnViewport(LINES_ON_VIEWPORT) - getLinePositionOnViewport(0);
|
||||
};
|
||||
|
||||
var scrollPageTo = function(value) {
|
||||
var outer$ = helper.padOuter$;
|
||||
var $ace_outer = outer$('#outerdocbody').parent();
|
||||
$ace_outer.parent().scrollTop(value);
|
||||
};
|
||||
|
||||
var scrollEditorToTopOfPad = function() {
|
||||
scrollPageTo(TOP_OF_PAGE);
|
||||
};
|
||||
|
||||
var scrollEditorToBottomOfPad = function() {
|
||||
scrollPageTo(BOTTOM_OF_PAGE);
|
||||
};
|
||||
|
||||
var scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport = function ($bigLine) {
|
||||
var lineHeight = $bigLine.get(0).getBoundingClientRect().height;
|
||||
var middleOfLine = lineHeight/2;
|
||||
scrollPageTo(middleOfLine);
|
||||
};
|
||||
|
||||
var getLine = function(lineNum) {
|
||||
var inner$ = helper.padInner$;
|
||||
var $line = inner$('div').eq(lineNum);
|
||||
return $line;
|
||||
};
|
||||
|
||||
var placeCaretAtTheEndOfLine = function(lineNum) {
|
||||
var $targetLine = getLine(lineNum);
|
||||
var lineLength = $targetLine.text().length;
|
||||
helper.selectLines($targetLine, $targetLine, lineLength, lineLength);
|
||||
};
|
||||
|
||||
var placeCaretInTheBeginningOfLine = function(lineNum, cb) {
|
||||
var $targetLine = getLine(lineNum);
|
||||
helper.selectLines($targetLine, $targetLine, 0, 0);
|
||||
helper.waitFor(function() {
|
||||
var $lineWhereCaretIs = getLineWhereCaretIs();
|
||||
return $targetLine.get(0) === $lineWhereCaretIs.get(0);
|
||||
}).done(cb);
|
||||
};
|
||||
|
||||
var getLineWhereCaretIs = function() {
|
||||
var inner$ = helper.padInner$;
|
||||
var nodeWhereCaretIs = inner$.document.getSelection().anchorNode;
|
||||
var $lineWhereCaretIs = $(nodeWhereCaretIs).closest('div');
|
||||
return $lineWhereCaretIs;
|
||||
};
|
||||
|
||||
var getFirstLineVisibileOfViewport = function() {
|
||||
return _.find(_.range(0, LINES_OF_PAD - 1), isLineOnViewport);
|
||||
};
|
||||
|
||||
var getLastLineVisibleOfViewport = function() {
|
||||
return _.find(_.range(LINES_OF_PAD - 1, 0, -1), isLineOnViewport);
|
||||
};
|
||||
|
||||
var pressKey = function(keyCode, shiftIsPressed){
|
||||
var inner$ = helper.padInner$;
|
||||
var evtType;
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
evtType = 'keypress';
|
||||
}else{
|
||||
evtType = 'keydown';
|
||||
}
|
||||
var e = inner$.Event(evtType);
|
||||
e.shiftKey = shiftIsPressed;
|
||||
e.keyCode = keyCode;
|
||||
e.which = keyCode; // etherpad listens to 'which'
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
};
|
||||
|
||||
var releaseKey = function(keyCode){
|
||||
var inner$ = helper.padInner$;
|
||||
var evtType = 'keyup';
|
||||
var e = inner$.Event(evtType);
|
||||
e.keyCode = keyCode;
|
||||
e.which = keyCode; // etherpad listens to 'which'
|
||||
inner$('#innerdocbody').trigger(e);
|
||||
};
|
||||
|
||||
var pressEnter = function() {
|
||||
pressKey(ENTER);
|
||||
};
|
||||
|
||||
var pressBackspace = function() {
|
||||
pressKey(BACKSPACE);
|
||||
};
|
||||
|
||||
var pressAndReleaseUpArrow = function() {
|
||||
pressKey(UP_ARROW);
|
||||
releaseKey(UP_ARROW);
|
||||
};
|
||||
|
||||
var pressAndReleaseRightArrow = function() {
|
||||
pressKey(RIGHT_ARROW);
|
||||
releaseKey(RIGHT_ARROW);
|
||||
};
|
||||
|
||||
var pressAndReleaseLeftArrow = function(shiftIsPressed) {
|
||||
pressKey(LEFT_ARROW, shiftIsPressed);
|
||||
releaseKey(LEFT_ARROW);
|
||||
};
|
||||
|
||||
var isLineOnViewport = function(lineNumber) {
|
||||
// in the function scrollNodeVerticallyIntoView from ace2_inner.js, iframePadTop is used to calculate
|
||||
// how much scroll is needed. Although the name refers to padding-top, this value is not set on the
|
||||
// padding-top.
|
||||
var iframePadTop = 8;
|
||||
var $line = getLine(lineNumber);
|
||||
var linePosition = $line.get(0).getBoundingClientRect();
|
||||
|
||||
// position relative to the current viewport
|
||||
var linePositionTopOnViewport = linePosition.top - getEditorScroll() + iframePadTop;
|
||||
var linePositionBottomOnViewport = linePosition.bottom - getEditorScroll();
|
||||
|
||||
var lineBellowTop = linePositionBottomOnViewport > 0;
|
||||
var lineAboveBottom = linePositionTopOnViewport < getClientHeightVisible();
|
||||
var isVisible = lineBellowTop && lineAboveBottom;
|
||||
|
||||
return isVisible;
|
||||
};
|
||||
|
||||
var getEditorScroll = function () {
|
||||
var outer$ = helper.padOuter$;
|
||||
var scrollTopFirefox = outer$('#outerdocbody').parent().scrollTop(); // works only on firefox
|
||||
var scrollTop = outer$('#outerdocbody').scrollTop() || scrollTopFirefox;
|
||||
return scrollTop;
|
||||
};
|
||||
|
||||
// clientHeight includes padding, so we have to subtract it and consider only the visible viewport
|
||||
var getClientHeightVisible = function () {
|
||||
var outer$ = helper.padOuter$;
|
||||
var $ace_outer = outer$('#outerdocbody').parent();
|
||||
var ace_outerHeight = $ace_outer.get(0).clientHeight;
|
||||
var ace_outerPaddingTop = getIntValueOfCSSProperty($ace_outer, 'padding-top');
|
||||
var paddingAddedWhenPageViewIsEnable = getPaddingAddedWhenPageViewIsEnable();
|
||||
var clientHeight = ace_outerHeight - ( ace_outerPaddingTop + paddingAddedWhenPageViewIsEnable);
|
||||
|
||||
return clientHeight;
|
||||
};
|
||||
|
||||
// ep_page_view changes the dimensions of the editor. We have to guarantee
|
||||
// the viewport height is calculated right
|
||||
var getPaddingAddedWhenPageViewIsEnable = function () {
|
||||
var chrome$ = helper.padChrome$;
|
||||
var $outerIframe = chrome$('iframe');
|
||||
var paddingAddedWhenPageViewIsEnable = parseInt($outerIframe.css('padding-top'));
|
||||
return paddingAddedWhenPageViewIsEnable;
|
||||
};
|
||||
|
||||
var getIntValueOfCSSProperty = function($element, property){
|
||||
var valueString = $element.css(property);
|
||||
return parseInt(valueString) || 0;
|
||||
};
|
||||
|
||||
var forceUseMonospacedFont = function () {
|
||||
helper.padChrome$.window.clientVars.padOptions.useMonospaceFont = true;
|
||||
};
|
||||
|
||||
var setScrollPercentageWhenFocusLineIsOutOfViewport = function(value, editionAboveViewport) {
|
||||
var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
||||
if (editionAboveViewport) {
|
||||
scrollSettings.percentage.editionAboveViewport = value;
|
||||
}else{
|
||||
scrollSettings.percentage.editionBelowViewport = value;
|
||||
}
|
||||
};
|
||||
|
||||
var resetScrollPercentageWhenFocusLineIsOutOfViewport = function() {
|
||||
var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
||||
scrollSettings.percentage.editionAboveViewport = 0;
|
||||
scrollSettings.percentage.editionBelowViewport = 0;
|
||||
};
|
||||
|
||||
var setPercentageToScrollWhenUserPressesArrowUp = function (value) {
|
||||
var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
||||
scrollSettings.percentageToScrollWhenUserPressesArrowUp = value;
|
||||
};
|
||||
|
||||
var scrollWhenPlaceCaretInTheLastLineOfViewport = function() {
|
||||
var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
|
||||
scrollSettings.scrollWhenCaretIsInTheLastLineOfViewport = true;
|
||||
};
|
||||
|
||||
var getLinePositionOnViewport = function(lineNumber) {
|
||||
var $line = getLine(lineNumber);
|
||||
var linePosition = $line.get(0).getBoundingClientRect();
|
||||
|
||||
// position relative to the current viewport
|
||||
return linePosition.top - getEditorScroll();
|
||||
};
|
||||
});
|
||||
|
|
@ -63,19 +63,23 @@ describe("select formatting buttons when selection has style applied", function(
|
|||
}
|
||||
|
||||
var applyStyleOnLineOnFullLineAndRemoveSelection = function(line, style, selectTarget, cb) {
|
||||
// see if line html has changed
|
||||
var inner$ = helper.padInner$;
|
||||
var oldLineHTML = inner$.find("div")[line];
|
||||
applyStyleOnLine(style, line);
|
||||
|
||||
// we have to give some time to Etherpad detects the selection changed
|
||||
setTimeout(function() {
|
||||
helper.waitFor(function(){
|
||||
var lineHTML = inner$.find("div")[line];
|
||||
return lineHTML !== oldLineHTML;
|
||||
});
|
||||
// remove selection from previous line
|
||||
selectLine(line + 1);
|
||||
setTimeout(function() {
|
||||
// select the text or place the caret on a position that
|
||||
// has the formatting text applied previously
|
||||
selectTarget(line);
|
||||
cb();
|
||||
}, 1000);
|
||||
}, 1000);
|
||||
selectLine(line + 1);
|
||||
//setTimeout(function() {
|
||||
// select the text or place the caret on a position that
|
||||
// has the formatting text applied previously
|
||||
selectTarget(line);
|
||||
cb();
|
||||
//}, 1000);
|
||||
}
|
||||
|
||||
var pressFormattingShortcutOnSelection = function(key) {
|
||||
|
@ -88,13 +92,7 @@ describe("select formatting buttons when selection has style applied", function(
|
|||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
if(inner$(window)[0].bowser.modernIE){ // if it's IE
|
||||
var evtType = "keypress";
|
||||
}else{
|
||||
var evtType = "keydown";
|
||||
}
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = key.charCodeAt(0); // I, U, B, 5
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
|
|
@ -6,22 +6,22 @@ describe("strikethrough button", function(){
|
|||
});
|
||||
|
||||
it("makes text strikethrough", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
//get the strikethrough button and click it
|
||||
var $strikethroughButton = chrome$(".buttonicon-strikethrough");
|
||||
$strikethroughButton.click();
|
||||
|
||||
|
||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
||||
var $newFirstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// is there a <i> element now?
|
||||
var isstrikethrough = $newFirstTextElement.find("s").length === 1;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ xdescribe("timeslider button takes you to the timeslider of a pad", function(){
|
|||
it("timeslider contained in URL", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
|
||||
// get the first text element inside the editable space
|
||||
var $firstTextElement = inner$("div span").first();
|
||||
var originalValue = $firstTextElement.text(); // get the original value
|
||||
|
|
55
tests/frontend/specs/timeslider_follow.js
Normal file
55
tests/frontend/specs/timeslider_follow.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
describe("timeslider", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(6000);
|
||||
});
|
||||
|
||||
it("follow content as it's added to timeslider", function(done) { // passes
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// make some changes to produce 100 revisions
|
||||
var timePerRev = 900
|
||||
, revs = 10;
|
||||
this.timeout(revs*timePerRev+10000);
|
||||
for(var i=0; i < revs; i++) {
|
||||
setTimeout(function() {
|
||||
// enter 'a' in the first text element
|
||||
inner$("div").last().sendkeys('a\n');
|
||||
inner$("div").last().sendkeys('{enter}');
|
||||
inner$("div").last().sendkeys('{enter}');
|
||||
inner$("div").last().sendkeys('{enter}');
|
||||
inner$("div").last().sendkeys('{enter}');
|
||||
}, timePerRev*i);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0');
|
||||
|
||||
setTimeout(function() {
|
||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
||||
|
||||
var latestContents = timeslider$('#innerdocbody').text();
|
||||
|
||||
// set to follow contents as it arrives
|
||||
timeslider$('#options-followContents').prop("checked", true);
|
||||
|
||||
var originalTop = timeslider$('#innerdocbody').offset();
|
||||
timeslider$('#playpause_button_icon').click();
|
||||
|
||||
setTimeout(function() {
|
||||
//make sure the text has changed
|
||||
var newTop = timeslider$('#innerdocbody').offset();
|
||||
expect( originalTop ).not.to.eql( newTop );
|
||||
done();
|
||||
}, 1000);
|
||||
|
||||
}, 2000);
|
||||
}, revs*timePerRev);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -6,9 +6,9 @@ describe("timeslider", function(){
|
|||
});
|
||||
|
||||
it("Shows a date and time in the timeslider and make sure it doesn't include NaN", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// make some changes to produce 100 revisions
|
||||
var revs = 10;
|
||||
this.timeout(60000);
|
||||
|
@ -18,15 +18,15 @@ describe("timeslider", function(){
|
|||
inner$("div").first().sendkeys('a');
|
||||
}, 200);
|
||||
}
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
||||
|
||||
|
||||
var latestContents = timeslider$('#padcontent').text();
|
||||
|
||||
// Expect the date and time to be shown
|
||||
|
@ -36,17 +36,17 @@ describe("timeslider", function(){
|
|||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 45;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 40;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 50;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
$sliderBar.trigger('mouseup')
|
||||
|
||||
setTimeout(function() {
|
||||
|
|
67
tests/frontend/specs/timeslider_numeric_padID.js
Normal file
67
tests/frontend/specs/timeslider_numeric_padID.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
describe("timeslider", function(){
|
||||
var padId = 735773577357+(Math.round(Math.random()*1000));
|
||||
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb, padId);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("Makes sure the export URIs are as expected when the padID is numeric", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// make some changes to produce 100 revisions
|
||||
var revs = 10;
|
||||
this.timeout(60000);
|
||||
for(var i=0; i < revs; i++) {
|
||||
setTimeout(function() {
|
||||
// enter 'a' in the first text element
|
||||
inner$("div").first().sendkeys('a');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
||||
|
||||
setTimeout(function() {
|
||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
||||
|
||||
var latestContents = timeslider$('#padcontent').text();
|
||||
|
||||
// Expect the date and time to be shown
|
||||
|
||||
// Click somewhere on the timeslider
|
||||
var e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 45;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 40;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 50;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
$sliderBar.trigger('mouseup')
|
||||
|
||||
setTimeout(function() {
|
||||
// expect URI to be similar to
|
||||
// http://192.168.1.48:9001/p/2/2/export/html
|
||||
// http://192.168.1.48:9001/p/735773577399/0/export/html
|
||||
var exportLink = timeslider$('#exporthtmla').attr('href');
|
||||
var checkVal = padId + "/0/export/html";
|
||||
var includesCorrectURI = exportLink.indexOf(checkVal);
|
||||
expect(includesCorrectURI).to.not.be(-1);
|
||||
done();
|
||||
}, 400);
|
||||
}, 2000);
|
||||
}, 2000);
|
||||
});
|
||||
});
|
|
@ -6,12 +6,12 @@ describe("timeslider", function(){
|
|||
});
|
||||
|
||||
it("loads adds a hundred revisions", function(done) { // passes
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// make some changes to produce 100 revisions
|
||||
var timePerRev = 900
|
||||
, revs = 100;
|
||||
, revs = 99;
|
||||
this.timeout(revs*timePerRev+10000);
|
||||
for(var i=0; i < revs; i++) {
|
||||
setTimeout(function() {
|
||||
|
@ -20,43 +20,45 @@ describe("timeslider", function(){
|
|||
}, timePerRev*i);
|
||||
}
|
||||
chrome$('.buttonicon-savedRevision').click();
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
||||
|
||||
var latestContents = timeslider$('#padcontent').text();
|
||||
|
||||
var latestContents = timeslider$('#innerdocbody').text();
|
||||
|
||||
// Click somewhere on the timeslider
|
||||
var e = new jQuery.Event('mousedown');
|
||||
// sets y co-ordinate of the pad slider modal.
|
||||
var base = (timeslider$('#ui-slider-bar').offset().top - 24)
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 45;
|
||||
e.clientY = e.pageY = base+5;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 40;
|
||||
e.clientY = e.pageY = base;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 50;
|
||||
e.clientY = e.pageY = base-5;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
$sliderBar.trigger('mouseup')
|
||||
|
||||
setTimeout(function() {
|
||||
//make sure the text has changed
|
||||
expect( timeslider$('#padcontent').text() ).not.to.eql( latestContents );
|
||||
expect( timeslider$('#innerdocbody').text() ).not.to.eql( latestContents );
|
||||
var starIsVisible = timeslider$('.star').is(":visible");
|
||||
expect( starIsVisible ).to.eql( true );
|
||||
done();
|
||||
}, 1000);
|
||||
|
||||
|
||||
}, 6000);
|
||||
}, revs*timePerRev);
|
||||
});
|
||||
|
@ -64,9 +66,9 @@ describe("timeslider", function(){
|
|||
|
||||
// Disabled as jquery trigger no longer works properly
|
||||
xit("changes the url when clicking on the timeslider", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
// make some changes to produce 7 revisions
|
||||
var timePerRev = 1000
|
||||
, revs = 20;
|
||||
|
@ -77,24 +79,24 @@ describe("timeslider", function(){
|
|||
inner$("div").first().sendkeys('a');
|
||||
}, timePerRev*i);
|
||||
}
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
||||
|
||||
var latestContents = timeslider$('#padcontent').text();
|
||||
|
||||
var latestContents = timeslider$('#innerdocbody').text();
|
||||
var oldUrl = $('#iframe-container iframe')[0].contentWindow.location.hash;
|
||||
|
||||
|
||||
// Click somewhere on the timeslider
|
||||
var e = new jQuery.Event('mousedown');
|
||||
e.clientX = e.pageX = 150;
|
||||
e.clientY = e.pageY = 60;
|
||||
$sliderBar.trigger(e);
|
||||
|
||||
|
||||
helper.waitFor(function(){
|
||||
return $('#iframe-container iframe')[0].contentWindow.location.hash != oldUrl;
|
||||
}, 6000).always(function(){
|
||||
|
@ -105,7 +107,7 @@ describe("timeslider", function(){
|
|||
}, revs*timePerRev);
|
||||
});
|
||||
it("jumps to a revision given in the url", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
this.timeout(20000);
|
||||
|
||||
|
@ -118,7 +120,7 @@ describe("timeslider", function(){
|
|||
expect( oldLength ).to.not.eql( 0 );
|
||||
inner$("div").first().sendkeys('a');
|
||||
var timeslider$;
|
||||
|
||||
|
||||
// wait for our additional revision to be added
|
||||
helper.waitFor(function(){
|
||||
// newLines takes the new lines into account which are strippen when using
|
||||
|
@ -131,17 +133,17 @@ describe("timeslider", function(){
|
|||
}, 6000).always(function() {
|
||||
// go to timeslider with a specific revision set
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0');
|
||||
|
||||
|
||||
// wait for the timeslider to be loaded
|
||||
helper.waitFor(function(){
|
||||
try {
|
||||
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
} catch(e){}
|
||||
if(timeslider$){
|
||||
return timeslider$('#padcontent').text().length == oldLength;
|
||||
return timeslider$('#innerdocbody').text().length == oldLength;
|
||||
}
|
||||
}, 6000).always(function(){
|
||||
expect( timeslider$('#padcontent').text().length ).to.eql( oldLength );
|
||||
expect( timeslider$('#innerdocbody').text().length ).to.eql( oldLength );
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -149,17 +151,17 @@ describe("timeslider", function(){
|
|||
});
|
||||
|
||||
it("checks the export url", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
this.timeout(11000);
|
||||
inner$("div").first().sendkeys('a');
|
||||
|
||||
|
||||
setTimeout(function() {
|
||||
// go to timeslider
|
||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0');
|
||||
var timeslider$;
|
||||
var exportLink;
|
||||
|
||||
|
||||
helper.waitFor(function(){
|
||||
try{
|
||||
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||
|
|
|
@ -4,11 +4,10 @@ describe("undo button", function(){
|
|||
this.timeout(60000);
|
||||
});
|
||||
|
||||
/*
|
||||
it("undo some typing by clicking undo button", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
|
||||
// get the first text element inside the editable space
|
||||
var $firstTextElement = inner$("div span").first();
|
||||
var originalValue = $firstTextElement.text(); // get the original value
|
||||
|
@ -30,7 +29,6 @@ describe("undo button", function(){
|
|||
done();
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
it("undo some typing using a keypress", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
|
@ -44,13 +42,7 @@ describe("undo button", function(){
|
|||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||
|
||||
/*
|
||||
* ACHTUNG: this is the only place in the test codebase in which a keydown
|
||||
* is sent for IE. Everywhere else IE uses keypress.
|
||||
*/
|
||||
var evtType = "keydown";
|
||||
|
||||
var e = inner$.Event(evtType);
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.ctrlKey = true; // Control key
|
||||
e.which = 90; // z
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
|
|
@ -6,7 +6,7 @@ describe("assign unordered list", function(){
|
|||
});
|
||||
|
||||
it("insert unordered list text then removes by outdent", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var originalText = inner$("div").first().text();
|
||||
|
||||
|
@ -33,3 +33,145 @@ describe("assign unordered list", function(){
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
describe("unassign unordered list", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("insert unordered list text then remove by clicking list again", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
var originalText = inner$("div").first().text();
|
||||
|
||||
var $insertunorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
||||
$insertunorderedlistButton.click();
|
||||
|
||||
helper.waitFor(function(){
|
||||
var newText = inner$("div").first().text();
|
||||
if(newText === originalText){
|
||||
return inner$("div").first().find("ul li").length === 1;
|
||||
}
|
||||
}).done(function(){
|
||||
|
||||
// remove indentation by bullet and ensure text string remains the same
|
||||
$insertunorderedlistButton.click();
|
||||
helper.waitFor(function(){
|
||||
var isList = inner$("div").find("ul").length === 1;
|
||||
// sohuldn't be list
|
||||
return (isList === false);
|
||||
}).done(function(){
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("keep unordered list on enter key", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("Keeps the unordered list on enter for the new line", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var $insertorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
||||
$insertorderedlistButton.click();
|
||||
|
||||
//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('{enter}');
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div span").first().text().indexOf("line 2") === -1;
|
||||
}).done(function(){
|
||||
var $newSecondLine = inner$("div").first().next();
|
||||
var hasULElement = $newSecondLine.find("ul li").length === 1;
|
||||
expect(hasULElement).to.be(true);
|
||||
expect($newSecondLine.text()).to.be("line 2");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Pressing Tab in an UL increases and decreases indentation", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("indent and de-indent list item with keypress", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
var $insertorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
||||
$insertorderedlistButton.click();
|
||||
|
||||
var e = inner$.Event(helper.evtType);
|
||||
e.keyCode = 9; // tab
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
expect(inner$("div").first().find(".list-bullet2").length === 1).to.be(true);
|
||||
e.shiftKey = true; // shift
|
||||
e.keyCode = 9; // tab
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().find(".list-bullet1").length === 1;
|
||||
}).done(done);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Pressing indent/outdent button in an UL increases and decreases indentation and bullet / ol formatting", function(){
|
||||
//create a new pad before each test run
|
||||
beforeEach(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
it("indent and de-indent list item with indent button", function(done){
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
var $insertunorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
||||
$insertunorderedlistButton.click();
|
||||
|
||||
var $indentButton = chrome$(".buttonicon-indent");
|
||||
$indentButton.click(); // make it indented twice
|
||||
|
||||
expect(inner$("div").first().find(".list-bullet2").length === 1).to.be(true);
|
||||
var $outdentButton = chrome$(".buttonicon-outdent");
|
||||
$outdentButton.click(); // make it deindented to 1
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().find(".list-bullet1").length === 1;
|
||||
}).done(done);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -6,16 +6,16 @@ describe("urls", function(){
|
|||
});
|
||||
|
||||
it("when you enter an url, it becomes clickable", function(done) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var firstTextElement = inner$("div").first();
|
||||
|
||||
|
||||
// simulate key presses to delete content
|
||||
firstTextElement.sendkeys('{selectall}'); // select all
|
||||
firstTextElement.sendkeys('{del}'); // clear the first line
|
||||
firstTextElement.sendkeys('http://etherpad.org'); // insert a URL
|
||||
firstTextElement.sendkeys('https://etherpad.org'); // insert a URL
|
||||
|
||||
helper.waitFor(function(){
|
||||
return inner$("div").first().find("a").length === 1;
|
||||
|
@ -28,7 +28,7 @@ describe("urls", function(){
|
|||
|
||||
//get the first text element out of the inner iframe
|
||||
var firstTextElement = inner$("div").first();
|
||||
var url = "http://etherpad.org/!foo";
|
||||
var url = "https://etherpad.org/!foo";
|
||||
|
||||
// simulate key presses to delete content
|
||||
firstTextElement.sendkeys('{selectall}'); // select all
|
||||
|
@ -50,7 +50,7 @@ describe("urls", function(){
|
|||
|
||||
//get the first text element out of the inner iframe
|
||||
var firstTextElement = inner$("div").first();
|
||||
var url = "http://etherpad.org/";
|
||||
var url = "https://etherpad.org/";
|
||||
|
||||
// simulate key presses to delete content
|
||||
firstTextElement.sendkeys('{selectall}'); // select all
|
||||
|
|
|
@ -17,95 +17,125 @@ var sauceTestWorker = async.queue(function (testSettings, callback) {
|
|||
testSettings.name = name;
|
||||
testSettings["public"] = true;
|
||||
testSettings["build"] = process.env.GIT_HASH;
|
||||
testSettings["extendedDebugging"] = true; // console.json can be downloaded via saucelabs, don't know how to print them into output of the tests
|
||||
testSettings["tunnelIdentifier"] = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
browser.init(testSettings).get("http://localhost:9001/tests/frontend/", function(){
|
||||
var url = "https://saucelabs.com/jobs/" + browser.sessionID;
|
||||
console.log("Remote sauce test '" + name + "' started! " + url);
|
||||
browser.init(testSettings).get("http://localhost:9001/tests/frontend/", function(){
|
||||
var url = "https://saucelabs.com/jobs/" + browser.sessionID;
|
||||
console.log("Remote sauce test '" + name + "' started! " + url);
|
||||
|
||||
//tear down the test excecution
|
||||
var stopSauce = function(success){
|
||||
getStatusInterval && clearInterval(getStatusInterval);
|
||||
clearTimeout(timeout);
|
||||
//tear down the test excecution
|
||||
var stopSauce = function(success,timesup){
|
||||
clearInterval(getStatusInterval);
|
||||
clearTimeout(timeout);
|
||||
|
||||
browser.quit();
|
||||
browser.quit(function(){
|
||||
if(!success){
|
||||
allTestsPassed = false;
|
||||
}
|
||||
|
||||
if(!success){
|
||||
allTestsPassed = false;
|
||||
// if stopSauce is called via timeout (in contrast to via getStatusInterval) than the log of up to the last
|
||||
// five seconds may not be available here. It's an error anyway, so don't care about it.
|
||||
var testResult = knownConsoleText.replace(/\[red\]/g,'\x1B[31m').replace(/\[yellow\]/g,'\x1B[33m')
|
||||
.replace(/\[green\]/g,'\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
|
||||
testResult = testResult.split("\\n").map(function(line){
|
||||
return "[" + testSettings.browserName + " " + testSettings.platform + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] " + line;
|
||||
}).join("\n");
|
||||
|
||||
console.log(testResult);
|
||||
if (timesup) {
|
||||
console.log("[" + testSettings.browserName + " " + testSettings.platform + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] allowed test duration exceeded");
|
||||
}
|
||||
console.log("Remote sauce test '" + name + "' finished! " + url);
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
var testResult = knownConsoleText.replace(/\[red\]/g,'\x1B[31m').replace(/\[yellow\]/g,'\x1B[33m')
|
||||
.replace(/\[green\]/g,'\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
|
||||
testResult = testResult.split("\\n").map(function(line){
|
||||
return "[" + testSettings.browserName + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] " + line;
|
||||
}).join("\n");
|
||||
/**
|
||||
* timeout if a test hangs or the job exceeds 9.5 minutes
|
||||
* It's necessary because if travis kills the saucelabs session due to inactivity, we don't get any output
|
||||
* @todo this should be configured in testSettings, see https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts
|
||||
*/
|
||||
var timeout = setTimeout(function(){
|
||||
stopSauce(false,true);
|
||||
}, 570000); // travis timeout is 10 minutes, set this to a slightly lower value
|
||||
|
||||
console.log(testResult);
|
||||
console.log("Remote sauce test '" + name + "' finished! " + url);
|
||||
var knownConsoleText = "";
|
||||
var getStatusInterval = setInterval(function(){
|
||||
browser.eval("$('#console').text()", function(err, consoleText){
|
||||
if(!consoleText || err){
|
||||
return;
|
||||
}
|
||||
knownConsoleText = consoleText;
|
||||
|
||||
callback();
|
||||
}
|
||||
if(knownConsoleText.indexOf("FINISHED") > 0){
|
||||
let match = knownConsoleText.match(/FINISHED.*([0-9]+) tests passed, ([0-9]+) tests failed/);
|
||||
// finished without failures
|
||||
if (match[2] && match[2] == '0'){
|
||||
stopSauce(true);
|
||||
|
||||
//timeout for the case the test hangs
|
||||
var timeout = setTimeout(function(){
|
||||
stopSauce(false);
|
||||
}, 60000 * 10);
|
||||
// finished but some tests did not return or some tests failed
|
||||
} else {
|
||||
stopSauce(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
var knownConsoleText = "";
|
||||
var getStatusInterval = setInterval(function(){
|
||||
browser.eval("$('#console').text()", function(err, consoleText){
|
||||
if(!consoleText || err){
|
||||
return;
|
||||
}
|
||||
knownConsoleText = consoleText;
|
||||
}, 6); //run 6 tests in parrallel
|
||||
|
||||
if(knownConsoleText.indexOf("FINISHED") > 0){
|
||||
var success = knownConsoleText.indexOf("FAILED") === -1;
|
||||
stopSauce(success);
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
});
|
||||
}, 5); //run 5 tests in parrallel
|
||||
|
||||
// Firefox
|
||||
// 1) Firefox on Linux
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Linux'
|
||||
'platform' : 'Windows 7'
|
||||
, 'browserName' : 'firefox'
|
||||
, 'version' : ''
|
||||
, 'version' : '52.0'
|
||||
});
|
||||
|
||||
// Chrome
|
||||
// 2) Chrome on Linux
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Linux'
|
||||
, 'browserName' : 'googlechrome'
|
||||
, 'version' : ''
|
||||
'platform' : 'Windows 7'
|
||||
, 'browserName' : 'chrome'
|
||||
, 'version' : '55.0'
|
||||
, 'args' : ['--use-fake-device-for-media-stream']
|
||||
});
|
||||
|
||||
// 3) Safari on OSX 10.15
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'OS X 10.15'
|
||||
, 'browserName' : 'safari'
|
||||
, 'version' : '13.1'
|
||||
});
|
||||
|
||||
// 4) Safari on OSX 10.14
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'OS X 10.14'
|
||||
, 'browserName' : 'safari'
|
||||
, 'version' : '12.0'
|
||||
});
|
||||
// IE 10 doesn't appear to be working anyway
|
||||
/*
|
||||
// IE 8
|
||||
// 4) IE 10 on Win 8
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Windows 2003'
|
||||
'platform' : 'Windows 8'
|
||||
, 'browserName' : 'iexplore'
|
||||
, 'version' : '8'
|
||||
, 'version' : '10.0'
|
||||
});
|
||||
*/
|
||||
|
||||
// IE 9
|
||||
// 5) Edge on Win 10
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Windows XP'
|
||||
, 'browserName' : 'iexplore'
|
||||
, 'version' : '9'
|
||||
'platform' : 'Windows 10'
|
||||
, 'browserName' : 'microsoftedge'
|
||||
, 'version' : '83.0'
|
||||
});
|
||||
// 6) Firefox on Win 7
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Windows 7'
|
||||
, 'browserName' : 'firefox'
|
||||
, 'version' : '78.0'
|
||||
});
|
||||
|
||||
// IE 10
|
||||
sauceTestWorker.push({
|
||||
'platform' : 'Windows 2012'
|
||||
, 'browserName' : 'iexplore'
|
||||
, 'version' : '10'
|
||||
sauceTestWorker.drain(function() {
|
||||
process.exit(allTestsPassed ? 0 : 1);
|
||||
});
|
||||
|
||||
sauceTestWorker.drain = function() {
|
||||
setTimeout(function(){
|
||||
process.exit(allTestsPassed ? 0 : 1);
|
||||
}, 3000);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,48 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
if [ -z "${SAUCE_USERNAME}" ]; then echo "SAUCE_USERNAME is unset - exiting"; exit 1; fi
|
||||
if [ -z "${SAUCE_ACCESS_KEY}" ]; then echo "SAUCE_ACCESS_KEY is unset - exiting"; exit 1; fi
|
||||
|
||||
#Move to the base folder
|
||||
cd `dirname $0`
|
||||
# do not continue if there is an error
|
||||
set -eu
|
||||
|
||||
#start Etherpad
|
||||
../../../bin/run.sh > /dev/null &
|
||||
sleep 10
|
||||
# source: https://stackoverflow.com/questions/59895/get-the-source-directory-of-a-bash-script-from-within-the-script-itself#246128
|
||||
MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
#start remote runner
|
||||
# reliably move to the etherpad base folder before running it
|
||||
cd "${MY_DIR}/../../../"
|
||||
|
||||
# start Etherpad, assuming all dependencies are already installed.
|
||||
#
|
||||
# This is possible because the "install" section of .travis.yml already contains
|
||||
# a call to bin/installDeps.sh
|
||||
echo "Running Etherpad directly, assuming bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js "${@}" &
|
||||
|
||||
echo "Now I will try for 15 seconds to connect to Etherpad on http://localhost:9001"
|
||||
|
||||
# wait for at most 15 seconds until Etherpad starts accepting connections
|
||||
#
|
||||
# modified from:
|
||||
# https://unix.stackexchange.com/questions/5277/how-do-i-tell-a-script-to-wait-for-a-process-to-start-accepting-requests-on-a-po#349138
|
||||
#
|
||||
(timeout 15 bash -c 'until echo > /dev/tcp/localhost/9001; do sleep 0.5; done') || \
|
||||
(echo "Could not connect to Etherpad on http://localhost:9001" ; exit 1)
|
||||
|
||||
echo "Successfully connected to Etherpad on http://localhost:9001"
|
||||
|
||||
# On the Travis VM, remote_runner.js is found at
|
||||
# /home/travis/build/ether/[secure]/tests/frontend/travis/remote_runner.js
|
||||
# which is the same directory that contains this script.
|
||||
# Let's move back there.
|
||||
#
|
||||
# Probably remote_runner.js is injected by Saucelabs.
|
||||
cd "${MY_DIR}"
|
||||
|
||||
# start the remote runner
|
||||
echo "Now starting the remote runner"
|
||||
node remote_runner.js
|
||||
exit_code=$?
|
||||
|
||||
kill $!
|
||||
kill $(cat /tmp/sauce.pid)
|
||||
sleep 30
|
||||
|
||||
exit $exit_code
|
||||
exit $exit_code
|
||||
|
|
51
tests/frontend/travis/runnerBackend.sh
Executable file
51
tests/frontend/travis/runnerBackend.sh
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/bin/bash
|
||||
|
||||
# do not continue if there is an error
|
||||
set -u
|
||||
|
||||
# source: https://stackoverflow.com/questions/59895/get-the-source-directory-of-a-bash-script-from-within-the-script-itself#246128
|
||||
MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# reliably move to the etherpad base folder before running it
|
||||
cd "${MY_DIR}/../../../"
|
||||
|
||||
# Set soffice to /usr/bin/soffice
|
||||
sed 's#\"soffice\": null,#\"soffice\":\"/usr/bin/soffice\",#g' settings.json.template > settings.json.soffice
|
||||
|
||||
# Set allowAnyoneToImport to true
|
||||
sed 's/\"allowAnyoneToImport\": false,/\"allowAnyoneToImport\": true,/g' settings.json.soffice > settings.json.allowImport
|
||||
|
||||
# Set "max": 10 to 100 to not agressively rate limit
|
||||
sed 's/\"max\": 10/\"max\": 100/g' settings.json.allowImport > settings.json.rateLimit
|
||||
|
||||
# Set "points": 10 to 1000 to not agressively rate limit commits
|
||||
sed 's/\"points\": 10/\"points\": 1000/g' settings.json.rateLimit > settings.json
|
||||
|
||||
# start Etherpad, assuming all dependencies are already installed.
|
||||
#
|
||||
# This is possible because the "install" section of .travis.yml already contains
|
||||
# a call to bin/installDeps.sh
|
||||
echo "Running Etherpad directly, assuming bin/installDeps.sh has already been run"
|
||||
node node_modules/ep_etherpad-lite/node/server.js "${@}" > /dev/null &
|
||||
|
||||
echo "Now I will try for 15 seconds to connect to Etherpad on http://localhost:9001"
|
||||
|
||||
# wait for at most 15 seconds until Etherpad starts accepting connections
|
||||
#
|
||||
# modified from:
|
||||
# https://unix.stackexchange.com/questions/5277/how-do-i-tell-a-script-to-wait-for-a-process-to-start-accepting-requests-on-a-po#349138
|
||||
#
|
||||
(timeout 15 bash -c 'until echo > /dev/tcp/localhost/9001; do sleep 0.5; done') || \
|
||||
(echo "Could not connect to Etherpad on http://localhost:9001" ; exit 1)
|
||||
|
||||
echo "Successfully connected to Etherpad on http://localhost:9001"
|
||||
|
||||
# run the backend tests
|
||||
echo "Now run the backend tests"
|
||||
cd src
|
||||
|
||||
failed=0
|
||||
npm run test || failed=1
|
||||
npm run test-contentcollector || failed=1
|
||||
|
||||
exit $failed
|
51
tests/frontend/travis/runnerLoadTest.sh
Executable file
51
tests/frontend/travis/runnerLoadTest.sh
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/bin/bash
|
||||
|
||||
# do not continue if there is an error
|
||||
set -eu
|
||||
|
||||
# source: https://stackoverflow.com/questions/59895/get-the-source-directory-of-a-bash-script-from-within-the-script-itself#246128
|
||||
MY_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# reliably move to the etherpad base folder before running it
|
||||
cd "${MY_DIR}/../../../"
|
||||
|
||||
# Set "points": 10 to 1000 to not agressively rate limit commits
|
||||
sed 's/\"points\": 10/\"points\": 1000/g' settings.json.template > settings.json.points
|
||||
# And enable loadTest
|
||||
sed 's/\"loadTest\": false,/\"loadTest\": true,/g' settings.json.points > settings.json
|
||||
|
||||
# start Etherpad, assuming all dependencies are already installed.
|
||||
#
|
||||
# This is possible because the "install" section of .travis.yml already contains
|
||||
# a call to bin/installDeps.sh
|
||||
echo "Running Etherpad directly, assuming bin/installDeps.sh has already been run"
|
||||
|
||||
node node_modules/ep_etherpad-lite/node/server.js "${@}" > /dev/null &
|
||||
|
||||
echo "Now I will try for 15 seconds to connect to Etherpad on http://localhost:9001"
|
||||
|
||||
# wait for at most 15 seconds until Etherpad starts accepting connections
|
||||
#
|
||||
# modified from:
|
||||
# https://unix.stackexchange.com/questions/5277/how-do-i-tell-a-script-to-wait-for-a-process-to-start-accepting-requests-on-a-po#349138
|
||||
#
|
||||
(timeout 15 bash -c 'until echo > /dev/tcp/localhost/9001; do sleep 0.5; done') || \
|
||||
(echo "Could not connect to Etherpad on http://localhost:9001" ; exit 1)
|
||||
|
||||
echo "Successfully connected to Etherpad on http://localhost:9001"
|
||||
|
||||
# Build the minified files?
|
||||
curl http://localhost:9001/p/minifyme -f -s > /dev/null
|
||||
|
||||
# just in case, let's wait for another 10 seconds before going on
|
||||
sleep 10
|
||||
|
||||
# run the backend tests
|
||||
echo "Now run the load tests for 30 seconds and if it stalls before 100 then error"
|
||||
etherpad-loadtest -d 30
|
||||
exit_code=$?
|
||||
|
||||
kill $!
|
||||
sleep 5
|
||||
|
||||
exit $exit_code
|
|
@ -1,11 +1,20 @@
|
|||
#!/bin/bash
|
||||
# download and unzip the sauce connector
|
||||
curl https://saucelabs.com/downloads/sc-latest-linux.tar.gz > /tmp/sauce.tar.gz
|
||||
#
|
||||
# ACHTUNG: as of 2019-12-21, downloading sc-latest-linux.tar.gz does not work.
|
||||
# It is necessary to explicitly download a specific version, for
|
||||
# example https://saucelabs.com/downloads/sc-4.5.4-linux.tar.gz
|
||||
# Supported versions are currently listed at:
|
||||
# https://wiki.saucelabs.com/display/DOCS/Downloading+Sauce+Connect+Proxy
|
||||
if [ -z "${SAUCE_USERNAME}" ]; then echo "SAUCE_USERNAME is unset - exiting"; exit 1; fi
|
||||
if [ -z "${SAUCE_ACCESS_KEY}" ]; then echo "SAUCE_ACCESS_KEY is unset - exiting"; exit 1; fi
|
||||
|
||||
curl https://saucelabs.com/downloads/sc-4.6.2-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
|
||||
(/tmp/sauce_connect/bin/sc --user $SAUCE_USERNAME --key $SAUCE_ACCESS_KEY --pidfile /tmp/sauce.pid --readyfile /tmp/tunnel > /dev/null )&
|
||||
(/tmp/sauce_connect/bin/sc --user "${SAUCE_USERNAME}" --key "${SAUCE_ACCESS_KEY}" -i "${TRAVIS_JOB_NUMBER}" --pidfile /tmp/sauce.pid --readyfile /tmp/tunnel > /dev/null )&
|
||||
|
||||
# wait for the tunnel to build up
|
||||
while [ ! -e "/tmp/tunnel" ]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue