mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +01:00
lint: Run eslint --fix
on bin/
and tests/
This commit is contained in:
parent
0625739cb8
commit
b8d07a42eb
78 changed files with 4319 additions and 4599 deletions
|
@ -3,88 +3,85 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (process.argv.length != 2) {
|
if (process.argv.length != 2) {
|
||||||
console.error("Use: node bin/checkAllPads.js");
|
console.error('Use: node bin/checkAllPads.js');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load and initialize NPM
|
// load and initialize NPM
|
||||||
let npm = require('../src/node_modules/npm');
|
const npm = require('../src/node_modules/npm');
|
||||||
npm.load({}, async function() {
|
npm.load({}, async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize the database
|
// initialize the database
|
||||||
let settings = require('../src/node/utils/Settings');
|
const settings = require('../src/node/utils/Settings');
|
||||||
let db = require('../src/node/db/DB');
|
const db = require('../src/node/db/DB');
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
// load modules
|
// load modules
|
||||||
let Changeset = require('../src/static/js/Changeset');
|
const Changeset = require('../src/static/js/Changeset');
|
||||||
let padManager = require('../src/node/db/PadManager');
|
const padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
// get all pads
|
// get all pads
|
||||||
let res = await padManager.listAllPads();
|
const res = await padManager.listAllPads();
|
||||||
|
|
||||||
for (let padId of res.padIDs) {
|
for (const padId of res.padIDs) {
|
||||||
|
const pad = await padManager.getPad(padId);
|
||||||
let pad = await padManager.getPad(padId);
|
|
||||||
|
|
||||||
// check if the pad has a pool
|
// check if the pad has a pool
|
||||||
if (pad.pool === undefined) {
|
if (pad.pool === undefined) {
|
||||||
console.error("[" + pad.id + "] Missing attribute pool");
|
console.error(`[${pad.id}] Missing attribute pool`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an array with key kevisions
|
// create an array with key kevisions
|
||||||
// key revisions always save the full pad atext
|
// key revisions always save the full pad atext
|
||||||
let head = pad.getHeadRevisionNumber();
|
const head = pad.getHeadRevisionNumber();
|
||||||
let keyRevisions = [];
|
const keyRevisions = [];
|
||||||
for (let rev = 0; rev < head; rev += 100) {
|
for (let rev = 0; rev < head; rev += 100) {
|
||||||
keyRevisions.push(rev);
|
keyRevisions.push(rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// run through all key revisions
|
// run through all key revisions
|
||||||
for (let keyRev of keyRevisions) {
|
for (const keyRev of keyRevisions) {
|
||||||
|
|
||||||
// create an array of revisions we need till the next keyRevision or the End
|
// create an array of revisions we need till the next keyRevision or the End
|
||||||
var revisionsNeeded = [];
|
const revisionsNeeded = [];
|
||||||
for (let rev = keyRev ; rev <= keyRev + 100 && rev <= head; rev++) {
|
for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) {
|
||||||
revisionsNeeded.push(rev);
|
revisionsNeeded.push(rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this array will hold all revision changesets
|
// this array will hold all revision changesets
|
||||||
var revisions = [];
|
const revisions = [];
|
||||||
|
|
||||||
// run through all needed revisions and get them from the database
|
// run through all needed revisions and get them from the database
|
||||||
for (let revNum of revisionsNeeded) {
|
for (const revNum of revisionsNeeded) {
|
||||||
let revision = await db.get("pad:" + pad.id + ":revs:" + revNum);
|
const revision = await db.get(`pad:${pad.id}:revs:${revNum}`);
|
||||||
revisions[revNum] = revision;
|
revisions[revNum] = revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the revision exists
|
// check if the revision exists
|
||||||
if (revisions[keyRev] == null) {
|
if (revisions[keyRev] == null) {
|
||||||
console.error("[" + pad.id + "] Missing revision " + keyRev);
|
console.error(`[${pad.id}] Missing revision ${keyRev}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is a atext in the keyRevisions
|
// check if there is a atext in the keyRevisions
|
||||||
if (revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
if (revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||||
console.error("[" + pad.id + "] Missing atext in revision " + keyRev);
|
console.error(`[${pad.id}] Missing atext in revision ${keyRev}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let apool = pad.pool;
|
const apool = pad.pool;
|
||||||
let atext = revisions[keyRev].meta.atext;
|
let atext = revisions[keyRev].meta.atext;
|
||||||
|
|
||||||
for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) {
|
for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) {
|
||||||
try {
|
try {
|
||||||
let cs = revisions[rev].changeset;
|
const cs = revisions[rev].changeset;
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("[" + pad.id + "] Bad changeset at revision " + i + " - " + e.message);
|
console.error(`[${pad.id}] Bad changeset at revision ${i} - ${e.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("finished");
|
console.log('finished');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.error("Use: node bin/checkPad.js $PADID");
|
console.error('Use: node bin/checkPad.js $PADID');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,83 +11,80 @@ if (process.argv.length != 3) {
|
||||||
const padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
|
|
||||||
// load and initialize NPM;
|
// load and initialize NPM;
|
||||||
let npm = require('../src/node_modules/npm');
|
const npm = require('../src/node_modules/npm');
|
||||||
npm.load({}, async function() {
|
npm.load({}, async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize database
|
// initialize database
|
||||||
let settings = require('../src/node/utils/Settings');
|
const settings = require('../src/node/utils/Settings');
|
||||||
let db = require('../src/node/db/DB');
|
const db = require('../src/node/db/DB');
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
// load modules
|
// load modules
|
||||||
let Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||||
let padManager = require('../src/node/db/PadManager');
|
const padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
let exists = await padManager.doesPadExists(padId);
|
const exists = await padManager.doesPadExists(padId);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
console.error("Pad does not exist");
|
console.error('Pad does not exist');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the pad
|
// get the pad
|
||||||
let pad = await padManager.getPad(padId);
|
const pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
// create an array with key revisions
|
// create an array with key revisions
|
||||||
// key revisions always save the full pad atext
|
// key revisions always save the full pad atext
|
||||||
let head = pad.getHeadRevisionNumber();
|
const head = pad.getHeadRevisionNumber();
|
||||||
let keyRevisions = [];
|
const keyRevisions = [];
|
||||||
for (let rev = 0; rev < head; rev += 100) {
|
for (let rev = 0; rev < head; rev += 100) {
|
||||||
keyRevisions.push(rev);
|
keyRevisions.push(rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// run through all key revisions
|
// run through all key revisions
|
||||||
for (let keyRev of keyRevisions) {
|
for (const keyRev of keyRevisions) {
|
||||||
|
|
||||||
// create an array of revisions we need till the next keyRevision or the End
|
// create an array of revisions we need till the next keyRevision or the End
|
||||||
let revisionsNeeded = [];
|
const revisionsNeeded = [];
|
||||||
for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) {
|
for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) {
|
||||||
revisionsNeeded.push(rev);
|
revisionsNeeded.push(rev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this array will hold all revision changesets
|
// this array will hold all revision changesets
|
||||||
var revisions = [];
|
const revisions = [];
|
||||||
|
|
||||||
// run through all needed revisions and get them from the database
|
// run through all needed revisions and get them from the database
|
||||||
for (let revNum of revisionsNeeded) {
|
for (const revNum of revisionsNeeded) {
|
||||||
let revision = await db.get("pad:" + padId + ":revs:" + revNum);
|
const revision = await db.get(`pad:${padId}:revs:${revNum}`);
|
||||||
revisions[revNum] = revision;
|
revisions[revNum] = revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if the pad has a pool
|
// check if the pad has a pool
|
||||||
if (pad.pool === undefined ) {
|
if (pad.pool === undefined) {
|
||||||
console.error("Attribute pool is missing");
|
console.error('Attribute pool is missing');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if there is an atext in the keyRevisions
|
// check if there is an atext in the keyRevisions
|
||||||
if (revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
if (revisions[keyRev] === undefined || revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) {
|
||||||
console.error("No atext in key revision " + keyRev);
|
console.error(`No atext in key revision ${keyRev}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let apool = pad.pool;
|
const apool = pad.pool;
|
||||||
let atext = revisions[keyRev].meta.atext;
|
let atext = revisions[keyRev].meta.atext;
|
||||||
|
|
||||||
for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) {
|
for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) {
|
||||||
try {
|
try {
|
||||||
// console.log("check revision " + rev);
|
// console.log("check revision " + rev);
|
||||||
let cs = revisions[rev].changeset;
|
const cs = revisions[rev].changeset;
|
||||||
atext = Changeset.applyToAText(cs, atext, apool);
|
atext = Changeset.applyToAText(cs, atext, apool);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error("Bad changeset at revision " + rev + " - " + e.message);
|
console.error(`Bad changeset at revision ${rev} - ${e.message}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("finished");
|
console.log('finished');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.trace(e);
|
console.trace(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.error("Use: node bin/checkPadDeltas.js $PADID");
|
console.error('Use: node bin/checkPadDeltas.js $PADID');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,108 +11,101 @@ if (process.argv.length != 3) {
|
||||||
const padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
|
|
||||||
// load and initialize NPM;
|
// load and initialize NPM;
|
||||||
var expect = require('expect.js')
|
const expect = require('expect.js');
|
||||||
var diff = require('diff')
|
const diff = require('diff');
|
||||||
var async = require('async')
|
var async = require('async');
|
||||||
|
|
||||||
let npm = require('../src/node_modules/npm');
|
const npm = require('../src/node_modules/npm');
|
||||||
var async = require("ep_etherpad-lite/node_modules/async");
|
var async = require('ep_etherpad-lite/node_modules/async');
|
||||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||||
|
|
||||||
npm.load({}, async function() {
|
|
||||||
|
|
||||||
|
npm.load({}, async () => {
|
||||||
try {
|
try {
|
||||||
// initialize database
|
// initialize database
|
||||||
let settings = require('../src/node/utils/Settings');
|
const settings = require('../src/node/utils/Settings');
|
||||||
let db = require('../src/node/db/DB');
|
const db = require('../src/node/db/DB');
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
// load modules
|
// load modules
|
||||||
let Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||||
let padManager = require('../src/node/db/PadManager');
|
const padManager = require('../src/node/db/PadManager');
|
||||||
|
|
||||||
let exists = await padManager.doesPadExists(padId);
|
const exists = await padManager.doesPadExists(padId);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
console.error("Pad does not exist");
|
console.error('Pad does not exist');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the pad
|
// get the pad
|
||||||
let pad = await padManager.getPad(padId);
|
const pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
//create an array with key revisions
|
// create an array with key revisions
|
||||||
//key revisions always save the full pad atext
|
// key revisions always save the full pad atext
|
||||||
var head = pad.getHeadRevisionNumber();
|
const head = pad.getHeadRevisionNumber();
|
||||||
var keyRevisions = [];
|
const keyRevisions = [];
|
||||||
for(var i=0;i<head;i+=100)
|
for (var i = 0; i < head; i += 100) {
|
||||||
{
|
|
||||||
keyRevisions.push(i);
|
keyRevisions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//create an array with all revisions
|
// create an array with all revisions
|
||||||
var revisions = [];
|
const revisions = [];
|
||||||
for(var i=0;i<=head;i++)
|
for (var i = 0; i <= head; i++) {
|
||||||
{
|
|
||||||
revisions.push(i);
|
revisions.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var atext = Changeset.makeAText("\n")
|
let atext = Changeset.makeAText('\n');
|
||||||
|
|
||||||
//run trough all revisions
|
// run trough all revisions
|
||||||
async.forEachSeries(revisions, function(revNum, callback) {
|
async.forEachSeries(revisions, (revNum, callback) => {
|
||||||
//console.log('Fetching', revNum)
|
// console.log('Fetching', revNum)
|
||||||
db.db.get("pad:"+padId+":revs:" + revNum, function(err, revision) {
|
db.db.get(`pad:${padId}:revs:${revNum}`, (err, revision) => {
|
||||||
if(err) return callback(err);
|
if (err) return callback(err);
|
||||||
|
|
||||||
//check if there is a atext in the keyRevisions
|
// check if there is a atext in the keyRevisions
|
||||||
if(~keyRevisions.indexOf(revNum) && (revision === undefined || revision.meta === undefined || revision.meta.atext === undefined)) {
|
if (~keyRevisions.indexOf(revNum) && (revision === undefined || revision.meta === undefined || revision.meta.atext === undefined)) {
|
||||||
console.error("No atext in key revision " + revNum);
|
console.error(`No atext in key revision ${revNum}`);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//console.log("check revision ", revNum);
|
// console.log("check revision ", revNum);
|
||||||
var cs = revision.changeset;
|
const cs = revision.changeset;
|
||||||
atext = Changeset.applyToAText(cs, atext, pad.pool);
|
atext = Changeset.applyToAText(cs, atext, pad.pool);
|
||||||
}
|
} catch (e) {
|
||||||
catch(e) {
|
console.error(`Bad changeset at revision ${revNum} - ${e.message}`);
|
||||||
console.error("Bad changeset at revision " + revNum + " - " + e.message);
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(~keyRevisions.indexOf(revNum)) {
|
if (~keyRevisions.indexOf(revNum)) {
|
||||||
try {
|
try {
|
||||||
expect(revision.meta.atext.text).to.eql(atext.text)
|
expect(revision.meta.atext.text).to.eql(atext.text);
|
||||||
expect(revision.meta.atext.attribs).to.eql(atext.attribs)
|
expect(revision.meta.atext.attribs).to.eql(atext.attribs);
|
||||||
}catch(e) {
|
} catch (e) {
|
||||||
console.error("Atext in key revision "+revNum+" doesn't match computed one.")
|
console.error(`Atext in key revision ${revNum} doesn't match computed one.`);
|
||||||
console.log(diff.diffChars(atext.text, revision.meta.atext.text).map(function(op) {if(!op.added && !op.removed) op.value = op.value.length; return op}))
|
console.log(diff.diffChars(atext.text, revision.meta.atext.text).map((op) => { if (!op.added && !op.removed) op.value = op.value.length; return op; }));
|
||||||
//console.error(e)
|
// console.error(e)
|
||||||
//console.log('KeyRev. :', revision.meta.atext)
|
// console.log('KeyRev. :', revision.meta.atext)
|
||||||
//console.log('Computed:', atext)
|
// console.log('Computed:', atext)
|
||||||
callback()
|
callback();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setImmediate(callback)
|
setImmediate(callback);
|
||||||
});
|
});
|
||||||
}, function(er) {
|
}, (er) => {
|
||||||
if(pad.atext.text == atext.text) console.log('ok')
|
if (pad.atext.text == atext.text) { console.log('ok'); } else {
|
||||||
else {
|
console.error('Pad AText doesn\'t match computed one! (Computed ', atext.text.length, ', db', pad.atext.text.length, ')');
|
||||||
console.error('Pad AText doesn\'t match computed one! (Computed ',atext.text.length, ', db', pad.atext.text.length,')')
|
console.log(diff.diffChars(atext.text, pad.atext.text).map((op) => { if (!op.added && !op.removed) op.value = op.value.length; return op; }));
|
||||||
console.log(diff.diffChars(atext.text, pad.atext.text).map(function(op) {if(!op.added && !op.removed) op.value = op.value.length; return op}))
|
|
||||||
}
|
}
|
||||||
callback(er)
|
callback(er);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.trace(e);
|
console.trace(e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
464
bin/convert.js
464
bin/convert.js
|
@ -1,120 +1,116 @@
|
||||||
var startTime = Date.now();
|
const startTime = Date.now();
|
||||||
var fs = require("fs");
|
const fs = require('fs');
|
||||||
var ueberDB = require("../src/node_modules/ueberdb2");
|
const ueberDB = require('../src/node_modules/ueberdb2');
|
||||||
var mysql = require("../src/node_modules/ueberdb2/node_modules/mysql");
|
const mysql = require('../src/node_modules/ueberdb2/node_modules/mysql');
|
||||||
var async = require("../src/node_modules/async");
|
const async = require('../src/node_modules/async');
|
||||||
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
const Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||||
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;
|
||||||
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
|
const AttributePool = require('ep_etherpad-lite/static/js/AttributePool');
|
||||||
|
|
||||||
var settingsFile = process.argv[2];
|
const settingsFile = process.argv[2];
|
||||||
var sqlOutputFile = process.argv[3];
|
const sqlOutputFile = process.argv[3];
|
||||||
|
|
||||||
//stop if the settings file is not set
|
// stop if the settings file is not set
|
||||||
if(!settingsFile || !sqlOutputFile)
|
if (!settingsFile || !sqlOutputFile) {
|
||||||
{
|
console.error('Use: node convert.js $SETTINGSFILE $SQLOUTPUT');
|
||||||
console.error("Use: node convert.js $SETTINGSFILE $SQLOUTPUT");
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
log("read settings file...");
|
log('read settings file...');
|
||||||
//read the settings file and parse the json
|
// read the settings file and parse the json
|
||||||
var settings = JSON.parse(fs.readFileSync(settingsFile, "utf8"));
|
const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
|
||||||
log("done");
|
log('done');
|
||||||
|
|
||||||
log("open output file...");
|
log('open output file...');
|
||||||
var sqlOutput = fs.openSync(sqlOutputFile, "w");
|
const sqlOutput = fs.openSync(sqlOutputFile, 'w');
|
||||||
var sql = "SET CHARACTER SET UTF8;\n" +
|
const sql = 'SET CHARACTER SET UTF8;\n' +
|
||||||
"CREATE TABLE IF NOT EXISTS `store` ( \n" +
|
'CREATE TABLE IF NOT EXISTS `store` ( \n' +
|
||||||
"`key` VARCHAR( 100 ) NOT NULL , \n" +
|
'`key` VARCHAR( 100 ) NOT NULL , \n' +
|
||||||
"`value` LONGTEXT NOT NULL , \n" +
|
'`value` LONGTEXT NOT NULL , \n' +
|
||||||
"PRIMARY KEY ( `key` ) \n" +
|
'PRIMARY KEY ( `key` ) \n' +
|
||||||
") ENGINE = INNODB;\n" +
|
') ENGINE = INNODB;\n' +
|
||||||
"START TRANSACTION;\n\n";
|
'START TRANSACTION;\n\n';
|
||||||
fs.writeSync(sqlOutput, sql);
|
fs.writeSync(sqlOutput, sql);
|
||||||
log("done");
|
log('done');
|
||||||
|
|
||||||
var etherpadDB = mysql.createConnection({
|
const etherpadDB = mysql.createConnection({
|
||||||
host : settings.etherpadDB.host,
|
host: settings.etherpadDB.host,
|
||||||
user : settings.etherpadDB.user,
|
user: settings.etherpadDB.user,
|
||||||
password : settings.etherpadDB.password,
|
password: settings.etherpadDB.password,
|
||||||
database : settings.etherpadDB.database,
|
database: settings.etherpadDB.database,
|
||||||
port : settings.etherpadDB.port
|
port: settings.etherpadDB.port,
|
||||||
});
|
});
|
||||||
|
|
||||||
//get the timestamp once
|
// get the timestamp once
|
||||||
var timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
|
|
||||||
var padIDs;
|
let padIDs;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get all padids out of the database...
|
// get all padids out of the database...
|
||||||
function(callback) {
|
function (callback) {
|
||||||
log("get all padIds out of the database...");
|
log('get all padIds out of the database...');
|
||||||
|
|
||||||
etherpadDB.query("SELECT ID FROM PAD_META", [], function(err, _padIDs) {
|
etherpadDB.query('SELECT ID FROM PAD_META', [], (err, _padIDs) => {
|
||||||
padIDs = _padIDs;
|
padIDs = _padIDs;
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(callback) {
|
function (callback) {
|
||||||
log("done");
|
log('done');
|
||||||
|
|
||||||
//create a queue with a concurrency 100
|
// create a queue with a concurrency 100
|
||||||
var queue = async.queue(function (padId, callback) {
|
const queue = async.queue((padId, callback) => {
|
||||||
convertPad(padId, function(err) {
|
convertPad(padId, (err) => {
|
||||||
incrementPadStats();
|
incrementPadStats();
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
//set the step callback as the queue callback
|
// set the step callback as the queue callback
|
||||||
queue.drain = callback;
|
queue.drain = callback;
|
||||||
|
|
||||||
//add the padids to the worker queue
|
// add the padids to the worker queue
|
||||||
for(var i=0,length=padIDs.length;i<length;i++)
|
for (let i = 0, length = padIDs.length; i < length; i++) {
|
||||||
{
|
|
||||||
queue.push(padIDs[i].ID);
|
queue.push(padIDs[i].ID);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
], function(err) {
|
], (err) => {
|
||||||
if(err) throw err;
|
if (err) throw err;
|
||||||
|
|
||||||
//write the groups
|
// write the groups
|
||||||
var sql = "";
|
let sql = '';
|
||||||
for(var proID in proID2groupID)
|
for (const proID in proID2groupID) {
|
||||||
{
|
const groupID = proID2groupID[proID];
|
||||||
var groupID = proID2groupID[proID];
|
const subdomain = proID2subdomain[proID];
|
||||||
var subdomain = proID2subdomain[proID];
|
|
||||||
|
|
||||||
sql+="REPLACE INTO store VALUES (" + etherpadDB.escape("group:" + groupID) + ", " + etherpadDB.escape(JSON.stringify(groups[groupID]))+ ");\n";
|
sql += `REPLACE INTO store VALUES (${etherpadDB.escape(`group:${groupID}`)}, ${etherpadDB.escape(JSON.stringify(groups[groupID]))});\n`;
|
||||||
sql+="REPLACE INTO store VALUES (" + etherpadDB.escape("mapper2group:subdomain:" + subdomain) + ", " + etherpadDB.escape(groupID)+ ");\n";
|
sql += `REPLACE INTO store VALUES (${etherpadDB.escape(`mapper2group:subdomain:${subdomain}`)}, ${etherpadDB.escape(groupID)});\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
//close transaction
|
// close transaction
|
||||||
sql+="COMMIT;";
|
sql += 'COMMIT;';
|
||||||
|
|
||||||
//end the sql file
|
// end the sql file
|
||||||
fs.writeSync(sqlOutput, sql, undefined, "utf-8");
|
fs.writeSync(sqlOutput, sql, undefined, 'utf-8');
|
||||||
fs.closeSync(sqlOutput);
|
fs.closeSync(sqlOutput);
|
||||||
|
|
||||||
log("finished.");
|
log('finished.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
function log(str) {
|
function log(str) {
|
||||||
console.log((Date.now() - startTime)/1000 + "\t" + str);
|
console.log(`${(Date.now() - startTime) / 1000}\t${str}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
var padsDone = 0;
|
let padsDone = 0;
|
||||||
|
|
||||||
function incrementPadStats() {
|
function incrementPadStats() {
|
||||||
padsDone++;
|
padsDone++;
|
||||||
|
|
||||||
if(padsDone%100 == 0)
|
if (padsDone % 100 == 0) {
|
||||||
{
|
const averageTime = Math.round(padsDone / ((Date.now() - startTime) / 1000));
|
||||||
var averageTime = Math.round(padsDone/((Date.now() - startTime)/1000));
|
log(`${padsDone}/${padIDs.length}\t${averageTime} pad/s`);
|
||||||
log(padsDone + "/" + padIDs.length + "\t" + averageTime + " pad/s")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,275 +119,245 @@ var proID2subdomain = {};
|
||||||
var groups = {};
|
var groups = {};
|
||||||
|
|
||||||
function convertPad(padId, callback) {
|
function convertPad(padId, callback) {
|
||||||
var changesets = [];
|
const changesets = [];
|
||||||
var changesetsMeta = [];
|
const changesetsMeta = [];
|
||||||
var chatMessages = [];
|
const chatMessages = [];
|
||||||
var authors = [];
|
const authors = [];
|
||||||
var apool;
|
let apool;
|
||||||
var subdomain;
|
let subdomain;
|
||||||
var padmeta;
|
let padmeta;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
//get all needed db values
|
// get all needed db values
|
||||||
function(callback) {
|
function (callback) {
|
||||||
async.parallel([
|
async.parallel([
|
||||||
//get the pad revisions
|
// get the pad revisions
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT * FROM `PAD_CHAT_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_CHAT_META` WHERE ID=?)";
|
const sql = 'SELECT * FROM `PAD_CHAT_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_CHAT_META` WHERE ID=?)';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
// parse the pages
|
||||||
{
|
for (let i = 0, length = results.length; i < length; i++) {
|
||||||
//parse the pages
|
|
||||||
for(var i=0,length=results.length;i<length;i++)
|
|
||||||
{
|
|
||||||
parsePage(chatMessages, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
parsePage(chatMessages, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
||||||
}
|
}
|
||||||
}catch(e) {err = e}
|
} catch (e) { err = e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the chat entries
|
// get the chat entries
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT * FROM `PAD_REVS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVS_META` WHERE ID=?)";
|
const sql = 'SELECT * FROM `PAD_REVS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVS_META` WHERE ID=?)';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
// parse the pages
|
||||||
{
|
for (let i = 0, length = results.length; i < length; i++) {
|
||||||
//parse the pages
|
|
||||||
for(var i=0,length=results.length;i<length;i++)
|
|
||||||
{
|
|
||||||
parsePage(changesets, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, false);
|
parsePage(changesets, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, false);
|
||||||
}
|
}
|
||||||
}catch(e) {err = e}
|
} catch (e) { err = e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the pad revisions meta data
|
// get the pad revisions meta data
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT * FROM `PAD_REVMETA_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVMETA_META` WHERE ID=?)";
|
const sql = 'SELECT * FROM `PAD_REVMETA_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVMETA_META` WHERE ID=?)';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
// parse the pages
|
||||||
{
|
for (let i = 0, length = results.length; i < length; i++) {
|
||||||
//parse the pages
|
|
||||||
for(var i=0,length=results.length;i<length;i++)
|
|
||||||
{
|
|
||||||
parsePage(changesetsMeta, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
parsePage(changesetsMeta, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
||||||
}
|
}
|
||||||
}catch(e) {err = e}
|
} catch (e) { err = e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the attribute pool of this pad
|
// get the attribute pool of this pad
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT `JSON` FROM `PAD_APOOL` WHERE `ID` = ?";
|
const sql = 'SELECT `JSON` FROM `PAD_APOOL` WHERE `ID` = ?';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
apool = JSON.parse(results[0].JSON).x;
|
||||||
{
|
} catch (e) { err = e; }
|
||||||
apool=JSON.parse(results[0].JSON).x;
|
|
||||||
}catch(e) {err = e}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the authors informations
|
// get the authors informations
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT * FROM `PAD_AUTHORS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_AUTHORS_META` WHERE ID=?)";
|
const sql = 'SELECT * FROM `PAD_AUTHORS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_AUTHORS_META` WHERE ID=?)';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
// parse the pages
|
||||||
{
|
for (let i = 0, length = results.length; i < length; i++) {
|
||||||
//parse the pages
|
|
||||||
for(var i=0, length=results.length;i<length;i++)
|
|
||||||
{
|
|
||||||
parsePage(authors, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
parsePage(authors, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true);
|
||||||
}
|
}
|
||||||
}catch(e) {err = e}
|
} catch (e) { err = e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the pad information
|
// get the pad information
|
||||||
function(callback) {
|
function (callback) {
|
||||||
var sql = "SELECT JSON FROM `PAD_META` WHERE ID=?";
|
const sql = 'SELECT JSON FROM `PAD_META` WHERE ID=?';
|
||||||
|
|
||||||
etherpadDB.query(sql, [padId], function(err, results) {
|
etherpadDB.query(sql, [padId], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
padmeta = JSON.parse(results[0].JSON).x;
|
padmeta = JSON.parse(results[0].JSON).x;
|
||||||
}catch(e) {err = e}
|
} catch (e) { err = e; }
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
//get the subdomain
|
// get the subdomain
|
||||||
function(callback) {
|
function (callback) {
|
||||||
//skip if this is no proPad
|
// skip if this is no proPad
|
||||||
if(padId.indexOf("$") == -1)
|
if (padId.indexOf('$') == -1) {
|
||||||
{
|
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the proID out of this padID
|
// get the proID out of this padID
|
||||||
var proID = padId.split("$")[0];
|
const proID = padId.split('$')[0];
|
||||||
|
|
||||||
var sql = "SELECT subDomain FROM pro_domains WHERE ID = ?";
|
const sql = 'SELECT subDomain FROM pro_domains WHERE ID = ?';
|
||||||
|
|
||||||
etherpadDB.query(sql, [proID], function(err, results) {
|
etherpadDB.query(sql, [proID], (err, results) => {
|
||||||
if(!err)
|
if (!err) {
|
||||||
{
|
|
||||||
subdomain = results[0].subDomain;
|
subdomain = results[0].subDomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
], callback);
|
], callback);
|
||||||
},
|
},
|
||||||
function(callback) {
|
function (callback) {
|
||||||
//saves all values that should be written to the database
|
// saves all values that should be written to the database
|
||||||
var values = {};
|
const values = {};
|
||||||
|
|
||||||
//this is a pro pad, let's convert it to a group pad
|
// this is a pro pad, let's convert it to a group pad
|
||||||
if(padId.indexOf("$") != -1)
|
if (padId.indexOf('$') != -1) {
|
||||||
{
|
const padIdParts = padId.split('$');
|
||||||
var padIdParts = padId.split("$");
|
const proID = padIdParts[0];
|
||||||
var proID = padIdParts[0];
|
const padName = padIdParts[1];
|
||||||
var padName = padIdParts[1];
|
|
||||||
|
|
||||||
var groupID
|
let groupID;
|
||||||
|
|
||||||
//this proID is not converted so far, do it
|
// this proID is not converted so far, do it
|
||||||
if(proID2groupID[proID] == null)
|
if (proID2groupID[proID] == null) {
|
||||||
{
|
groupID = `g.${randomString(16)}`;
|
||||||
groupID = "g." + randomString(16);
|
|
||||||
|
|
||||||
//create the mappers for this new group
|
// create the mappers for this new group
|
||||||
proID2groupID[proID] = groupID;
|
proID2groupID[proID] = groupID;
|
||||||
proID2subdomain[proID] = subdomain;
|
proID2subdomain[proID] = subdomain;
|
||||||
groups[groupID] = {pads: {}};
|
groups[groupID] = {pads: {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
//use the generated groupID;
|
// use the generated groupID;
|
||||||
groupID = proID2groupID[proID];
|
groupID = proID2groupID[proID];
|
||||||
|
|
||||||
//rename the pad
|
// rename the pad
|
||||||
padId = groupID + "$" + padName;
|
padId = `${groupID}$${padName}`;
|
||||||
|
|
||||||
//set the value for this pad in the group
|
// set the value for this pad in the group
|
||||||
groups[groupID].pads[padId] = 1;
|
groups[groupID].pads[padId] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try {
|
||||||
{
|
const newAuthorIDs = {};
|
||||||
var newAuthorIDs = {};
|
const oldName2newName = {};
|
||||||
var oldName2newName = {};
|
|
||||||
|
|
||||||
//replace the authors with generated authors
|
// replace the authors with generated authors
|
||||||
// we need to do that cause where the original etherpad saves pad local authors, the new (lite) etherpad uses them global
|
// we need to do that cause where the original etherpad saves pad local authors, the new (lite) etherpad uses them global
|
||||||
for(var i in apool.numToAttrib)
|
for (var i in apool.numToAttrib) {
|
||||||
{
|
|
||||||
var key = apool.numToAttrib[i][0];
|
var key = apool.numToAttrib[i][0];
|
||||||
var value = apool.numToAttrib[i][1];
|
const value = apool.numToAttrib[i][1];
|
||||||
|
|
||||||
//skip non authors and anonymous authors
|
// skip non authors and anonymous authors
|
||||||
if(key != "author" || value == "")
|
if (key != 'author' || value == '') continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
//generate new author values
|
// generate new author values
|
||||||
var authorID = "a." + randomString(16);
|
const authorID = `a.${randomString(16)}`;
|
||||||
var authorColorID = authors[i].colorId || Math.floor(Math.random()*(exports.getColorPalette().length));
|
const authorColorID = authors[i].colorId || Math.floor(Math.random() * (exports.getColorPalette().length));
|
||||||
var authorName = authors[i].name || null;
|
const authorName = authors[i].name || null;
|
||||||
|
|
||||||
//overwrite the authorID of the attribute pool
|
// overwrite the authorID of the attribute pool
|
||||||
apool.numToAttrib[i][1] = authorID;
|
apool.numToAttrib[i][1] = authorID;
|
||||||
|
|
||||||
//write the author to the database
|
// write the author to the database
|
||||||
values["globalAuthor:" + authorID] = {"colorId" : authorColorID, "name": authorName, "timestamp": timestamp};
|
values[`globalAuthor:${authorID}`] = {colorId: authorColorID, name: authorName, timestamp};
|
||||||
|
|
||||||
//save in mappers
|
// save in mappers
|
||||||
newAuthorIDs[i] = authorID;
|
newAuthorIDs[i] = authorID;
|
||||||
oldName2newName[value] = authorID;
|
oldName2newName[value] = authorID;
|
||||||
}
|
}
|
||||||
|
|
||||||
//save all revisions
|
// save all revisions
|
||||||
for(var i=0;i<changesets.length;i++)
|
for (var i = 0; i < changesets.length; i++) {
|
||||||
{
|
values[`pad:${padId}:revs:${i}`] = {changeset: changesets[i],
|
||||||
values["pad:" + padId + ":revs:" + i] = {changeset: changesets[i],
|
meta: {
|
||||||
meta : {
|
author: newAuthorIDs[changesetsMeta[i].a],
|
||||||
author: newAuthorIDs[changesetsMeta[i].a],
|
timestamp: changesetsMeta[i].t,
|
||||||
timestamp: changesetsMeta[i].t,
|
atext: changesetsMeta[i].atext || undefined,
|
||||||
atext: changesetsMeta[i].atext || undefined
|
}};
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//save all chat messages
|
// save all chat messages
|
||||||
for(var i=0;i<chatMessages.length;i++)
|
for (var i = 0; i < chatMessages.length; i++) {
|
||||||
{
|
values[`pad:${padId}:chat:${i}`] = {text: chatMessages[i].lineText,
|
||||||
values["pad:" + padId + ":chat:" + i] = {"text": chatMessages[i].lineText,
|
userId: oldName2newName[chatMessages[i].userId],
|
||||||
"userId": oldName2newName[chatMessages[i].userId],
|
time: chatMessages[i].time};
|
||||||
"time": chatMessages[i].time}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate the latest atext
|
// generate the latest atext
|
||||||
var fullAPool = (new AttributePool()).fromJsonable(apool);
|
const fullAPool = (new AttributePool()).fromJsonable(apool);
|
||||||
var keyRev = Math.floor(padmeta.head / padmeta.keyRevInterval) * padmeta.keyRevInterval;
|
const keyRev = Math.floor(padmeta.head / padmeta.keyRevInterval) * padmeta.keyRevInterval;
|
||||||
var atext = changesetsMeta[keyRev].atext;
|
let atext = changesetsMeta[keyRev].atext;
|
||||||
var curRev = keyRev;
|
let curRev = keyRev;
|
||||||
while (curRev < padmeta.head)
|
while (curRev < padmeta.head) {
|
||||||
{
|
|
||||||
curRev++;
|
curRev++;
|
||||||
var changeset = changesets[curRev];
|
const changeset = changesets[curRev];
|
||||||
atext = Changeset.applyToAText(changeset, atext, fullAPool);
|
atext = Changeset.applyToAText(changeset, atext, fullAPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
values["pad:" + padId] = {atext: atext,
|
values[`pad:${padId}`] = {atext,
|
||||||
pool: apool,
|
pool: apool,
|
||||||
head: padmeta.head,
|
head: padmeta.head,
|
||||||
chatHead: padmeta.numChatMessages }
|
chatHead: padmeta.numChatMessages};
|
||||||
|
} catch (e) {
|
||||||
}
|
console.error(`Error while converting pad ${padId}, pad skipped`);
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
console.error("Error while converting pad " + padId + ", pad skipped");
|
|
||||||
console.error(e.stack ? e.stack : JSON.stringify(e));
|
console.error(e.stack ? e.stack : JSON.stringify(e));
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sql = "";
|
let sql = '';
|
||||||
for(var key in values)
|
for (var key in values) {
|
||||||
{
|
sql += `REPLACE INTO store VALUES (${etherpadDB.escape(key)}, ${etherpadDB.escape(JSON.stringify(values[key]))});\n`;
|
||||||
sql+="REPLACE INTO store VALUES (" + etherpadDB.escape(key) + ", " + etherpadDB.escape(JSON.stringify(values[key]))+ ");\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeSync(sqlOutput, sql, undefined, "utf-8");
|
fs.writeSync(sqlOutput, sql, undefined, 'utf-8');
|
||||||
callback();
|
callback();
|
||||||
}
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,27 +367,25 @@ function convertPad(padId, callback) {
|
||||||
* all values behind each other
|
* all values behind each other
|
||||||
*/
|
*/
|
||||||
function parsePage(array, pageStart, offsets, data, json) {
|
function parsePage(array, pageStart, offsets, data, json) {
|
||||||
var start = 0;
|
let start = 0;
|
||||||
var lengths = offsets.split(",");
|
const lengths = offsets.split(',');
|
||||||
|
|
||||||
for(var i=0;i<lengths.length;i++)
|
for (let i = 0; i < lengths.length; i++) {
|
||||||
{
|
let unitLength = lengths[i];
|
||||||
var unitLength = lengths[i];
|
|
||||||
|
|
||||||
//skip empty units
|
// skip empty units
|
||||||
if(unitLength == "")
|
if (unitLength == '') continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
//parse the number
|
// parse the number
|
||||||
unitLength = Number(unitLength);
|
unitLength = Number(unitLength);
|
||||||
|
|
||||||
//cut the unit out of data
|
// cut the unit out of data
|
||||||
var unit = data.substr(start, unitLength);
|
const unit = data.substr(start, unitLength);
|
||||||
|
|
||||||
//put it into the array
|
// put it into the array
|
||||||
array[pageStart + i] = json ? JSON.parse(unit) : unit;
|
array[pageStart + i] = json ? JSON.parse(unit) : unit;
|
||||||
|
|
||||||
//update start
|
// update start
|
||||||
start+=unitLength;
|
start += unitLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* A tool for generating a test user session which can be used for debugging configs
|
* A tool for generating a test user session which can be used for debugging configs
|
||||||
* that require sessions.
|
* that require sessions.
|
||||||
*/
|
*/
|
||||||
const m = (f) => __dirname + '/../' + f;
|
const m = (f) => `${__dirname}/../${f}`;
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
@ -12,10 +12,10 @@ const settings = require(m('src/node/utils/Settings'));
|
||||||
const supertest = require(m('src/node_modules/supertest'));
|
const supertest = require(m('src/node_modules/supertest'));
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const api = supertest('http://'+settings.ip+':'+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
const filePath = path.join(__dirname, '../APIKEY.txt');
|
const filePath = path.join(__dirname, '../APIKEY.txt');
|
||||||
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
|
||||||
|
@ -43,5 +43,5 @@ const supertest = require(m('src/node_modules/supertest'));
|
||||||
res = await api.post(uri('createSession', {apikey, groupID, authorID, validUntil}));
|
res = await api.post(uri('createSession', {apikey, groupID, authorID, validUntil}));
|
||||||
if (res.body.code === 1) throw new Error(`Error creating session: ${res.body}`);
|
if (res.body.code === 1) throw new Error(`Error creating session: ${res.body}`);
|
||||||
console.log('Session made: ====> create a cookie named sessionID and set the value to',
|
console.log('Session made: ====> create a cookie named sessionID and set the value to',
|
||||||
res.body.data.sessionID);
|
res.body.data.sessionID);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -4,48 +4,48 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const request = require('../src/node_modules/request');
|
const request = require('../src/node_modules/request');
|
||||||
const settings = require(__dirname+'/../tests/container/loadSettings').loadSettings();
|
const settings = require(`${__dirname}/../tests/container/loadSettings`).loadSettings();
|
||||||
const supertest = require(__dirname+'/../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../src/node_modules/supertest`);
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
// get the API Key
|
// get the API Key
|
||||||
var filePath = path.join(__dirname, '../APIKEY.txt');
|
const filePath = path.join(__dirname, '../APIKEY.txt');
|
||||||
var apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
||||||
|
|
||||||
// Set apiVersion to base value, we change this later.
|
// Set apiVersion to base value, we change this later.
|
||||||
var apiVersion = 1;
|
let apiVersion = 1;
|
||||||
var guids;
|
let guids;
|
||||||
|
|
||||||
// Update the apiVersion
|
// Update the apiVersion
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
apiVersion = res.body.currentVersion;
|
apiVersion = res.body.currentVersion;
|
||||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
})
|
|
||||||
.then(function(){
|
|
||||||
let guri = '/api/'+apiVersion+'/listAllGroups?apikey='+apikey;
|
|
||||||
api.get(guri)
|
|
||||||
.then(function(res){
|
|
||||||
guids = res.body.data.groupIDs;
|
|
||||||
guids.forEach(function(groupID){
|
|
||||||
let luri = '/api/'+apiVersion+'/listSessionsOfGroup?apikey='+apikey + "&groupID="+groupID;
|
|
||||||
api.get(luri)
|
|
||||||
.then(function(res){
|
|
||||||
if(res.body.data){
|
|
||||||
Object.keys(res.body.data).forEach(function(sessionID){
|
|
||||||
if(sessionID){
|
|
||||||
console.log("Deleting", sessionID);
|
|
||||||
let duri = '/api/'+apiVersion+'/deleteSession?apikey='+apikey + "&sessionID="+sessionID;
|
|
||||||
api.post(duri); // deletes
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
// no session in this group.
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
.then(() => {
|
||||||
})
|
const guri = `/api/${apiVersion}/listAllGroups?apikey=${apikey}`;
|
||||||
|
api.get(guri)
|
||||||
|
.then((res) => {
|
||||||
|
guids = res.body.data.groupIDs;
|
||||||
|
guids.forEach((groupID) => {
|
||||||
|
const luri = `/api/${apiVersion}/listSessionsOfGroup?apikey=${apikey}&groupID=${groupID}`;
|
||||||
|
api.get(luri)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.body.data) {
|
||||||
|
Object.keys(res.body.data).forEach((sessionID) => {
|
||||||
|
if (sessionID) {
|
||||||
|
console.log('Deleting', sessionID);
|
||||||
|
const duri = `/api/${apiVersion}/deleteSession?apikey=${apikey}&sessionID=${sessionID}`;
|
||||||
|
api.post(duri); // deletes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// no session in this group.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -4,47 +4,45 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const request = require('../src/node_modules/request');
|
const request = require('../src/node_modules/request');
|
||||||
const settings = require(__dirname+'/../tests/container/loadSettings').loadSettings();
|
const settings = require(`${__dirname}/../tests/container/loadSettings`).loadSettings();
|
||||||
const supertest = require(__dirname+'/../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../src/node_modules/supertest`);
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.error("Use: node deletePad.js $PADID");
|
console.error('Use: node deletePad.js $PADID');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the padID
|
// get the padID
|
||||||
let padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
|
|
||||||
// get the API Key
|
// get the API Key
|
||||||
var filePath = path.join(__dirname, '../APIKEY.txt');
|
const filePath = path.join(__dirname, '../APIKEY.txt');
|
||||||
var apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
const apikey = fs.readFileSync(filePath, {encoding: 'utf-8'});
|
||||||
|
|
||||||
// Set apiVersion to base value, we change this later.
|
// Set apiVersion to base value, we change this later.
|
||||||
var apiVersion = 1;
|
let apiVersion = 1;
|
||||||
|
|
||||||
// Update the apiVersion
|
// Update the apiVersion
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
apiVersion = res.body.currentVersion;
|
apiVersion = res.body.currentVersion;
|
||||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.end(function(err, res){
|
.end((err, res) => {
|
||||||
|
|
||||||
// Now we know the latest API version, let's delete pad
|
// Now we know the latest API version, let's delete pad
|
||||||
var uri = '/api/'+apiVersion+'/deletePad?apikey='+apikey+'&padID='+padId;
|
const uri = `/api/${apiVersion}/deletePad?apikey=${apikey}&padID=${padId}`;
|
||||||
api.post(uri)
|
api.post(uri)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if (res.body.code === 1){
|
if (res.body.code === 1) {
|
||||||
console.error("Error deleting pad", res.body);
|
console.error('Error deleting pad', res.body);
|
||||||
}else{
|
} else {
|
||||||
console.log("Deleted pad", res.body);
|
console.log('Deleted pad', res.body);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.end(function(){})
|
.end(() => {});
|
||||||
});
|
});
|
||||||
// end
|
// end
|
||||||
|
|
||||||
|
|
|
@ -20,19 +20,19 @@
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
var marked = require('marked');
|
const marked = require('marked');
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
// parse the args.
|
// parse the args.
|
||||||
// Don't use nopt or whatever for this. It's simple enough.
|
// Don't use nopt or whatever for this. It's simple enough.
|
||||||
|
|
||||||
var args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
var format = 'json';
|
let format = 'json';
|
||||||
var template = null;
|
let template = null;
|
||||||
var inputFile = null;
|
let inputFile = null;
|
||||||
|
|
||||||
args.forEach(function (arg) {
|
args.forEach((arg) => {
|
||||||
if (!arg.match(/^\-\-/)) {
|
if (!arg.match(/^\-\-/)) {
|
||||||
inputFile = arg;
|
inputFile = arg;
|
||||||
} else if (arg.match(/^\-\-format=/)) {
|
} else if (arg.match(/^\-\-format=/)) {
|
||||||
|
@ -40,7 +40,7 @@ args.forEach(function (arg) {
|
||||||
} else if (arg.match(/^\-\-template=/)) {
|
} else if (arg.match(/^\-\-template=/)) {
|
||||||
template = arg.replace(/^\-\-template=/, '');
|
template = arg.replace(/^\-\-template=/, '');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
if (!inputFile) {
|
if (!inputFile) {
|
||||||
|
@ -49,25 +49,25 @@ if (!inputFile) {
|
||||||
|
|
||||||
|
|
||||||
console.error('Input file = %s', inputFile);
|
console.error('Input file = %s', inputFile);
|
||||||
fs.readFile(inputFile, 'utf8', function(er, input) {
|
fs.readFile(inputFile, 'utf8', (er, input) => {
|
||||||
if (er) throw er;
|
if (er) throw er;
|
||||||
// process the input for @include lines
|
// process the input for @include lines
|
||||||
processIncludes(inputFile, input, next);
|
processIncludes(inputFile, input, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var includeExpr = /^@include\s+([A-Za-z0-9-_\/]+)(?:\.)?([a-zA-Z]*)$/gmi;
|
const includeExpr = /^@include\s+([A-Za-z0-9-_\/]+)(?:\.)?([a-zA-Z]*)$/gmi;
|
||||||
var includeData = {};
|
const includeData = {};
|
||||||
function processIncludes(inputFile, input, cb) {
|
function processIncludes(inputFile, input, cb) {
|
||||||
var includes = input.match(includeExpr);
|
const includes = input.match(includeExpr);
|
||||||
if (includes === null) return cb(null, input);
|
if (includes === null) return cb(null, input);
|
||||||
var errState = null;
|
let errState = null;
|
||||||
console.error(includes);
|
console.error(includes);
|
||||||
var incCount = includes.length;
|
let incCount = includes.length;
|
||||||
if (incCount === 0) cb(null, input);
|
if (incCount === 0) cb(null, input);
|
||||||
|
|
||||||
includes.forEach(function(include) {
|
includes.forEach((include) => {
|
||||||
var fname = include.replace(/^@include\s+/, '');
|
let fname = include.replace(/^@include\s+/, '');
|
||||||
if (!fname.match(/\.md$/)) fname += '.md';
|
if (!fname.match(/\.md$/)) fname += '.md';
|
||||||
|
|
||||||
if (includeData.hasOwnProperty(fname)) {
|
if (includeData.hasOwnProperty(fname)) {
|
||||||
|
@ -78,11 +78,11 @@ function processIncludes(inputFile, input, cb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fullFname = path.resolve(path.dirname(inputFile), fname);
|
const fullFname = path.resolve(path.dirname(inputFile), fname);
|
||||||
fs.readFile(fullFname, 'utf8', function(er, inc) {
|
fs.readFile(fullFname, 'utf8', (er, inc) => {
|
||||||
if (errState) return;
|
if (errState) return;
|
||||||
if (er) return cb(errState = er);
|
if (er) return cb(errState = er);
|
||||||
processIncludes(fullFname, inc, function(er, inc) {
|
processIncludes(fullFname, inc, (er, inc) => {
|
||||||
if (errState) return;
|
if (errState) return;
|
||||||
if (er) return cb(errState = er);
|
if (er) return cb(errState = er);
|
||||||
incCount--;
|
incCount--;
|
||||||
|
@ -101,20 +101,20 @@ function next(er, input) {
|
||||||
if (er) throw er;
|
if (er) throw er;
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 'json':
|
case 'json':
|
||||||
require('./json.js')(input, inputFile, function(er, obj) {
|
require('./json.js')(input, inputFile, (er, obj) => {
|
||||||
console.log(JSON.stringify(obj, null, 2));
|
console.log(JSON.stringify(obj, null, 2));
|
||||||
if (er) throw er;
|
if (er) throw er;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'html':
|
case 'html':
|
||||||
require('./html.js')(input, inputFile, template, function(er, html) {
|
require('./html.js')(input, inputFile, template, (er, html) => {
|
||||||
if (er) throw er;
|
if (er) throw er;
|
||||||
console.log(html);
|
console.log(html);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid format: ' + format);
|
throw new Error(`Invalid format: ${format}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,15 @@
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
var fs = require('fs');
|
const fs = require('fs');
|
||||||
var marked = require('marked');
|
const marked = require('marked');
|
||||||
var path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = toHTML;
|
module.exports = toHTML;
|
||||||
|
|
||||||
function toHTML(input, filename, template, cb) {
|
function toHTML(input, filename, template, cb) {
|
||||||
var lexed = marked.lexer(input);
|
const lexed = marked.lexer(input);
|
||||||
fs.readFile(template, 'utf8', function(er, template) {
|
fs.readFile(template, 'utf8', (er, template) => {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
render(lexed, filename, template, cb);
|
render(lexed, filename, template, cb);
|
||||||
});
|
});
|
||||||
|
@ -35,7 +35,7 @@ function toHTML(input, filename, template, cb) {
|
||||||
|
|
||||||
function render(lexed, filename, template, cb) {
|
function render(lexed, filename, template, cb) {
|
||||||
// get the section
|
// get the section
|
||||||
var section = getSection(lexed);
|
const section = getSection(lexed);
|
||||||
|
|
||||||
filename = path.basename(filename, '.md');
|
filename = path.basename(filename, '.md');
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ function render(lexed, filename, template, cb) {
|
||||||
|
|
||||||
// generate the table of contents.
|
// generate the table of contents.
|
||||||
// this mutates the lexed contents in-place.
|
// this mutates the lexed contents in-place.
|
||||||
buildToc(lexed, filename, function(er, toc) {
|
buildToc(lexed, filename, (er, toc) => {
|
||||||
if (er) return cb(er);
|
if (er) return cb(er);
|
||||||
|
|
||||||
template = template.replace(/__FILENAME__/g, filename);
|
template = template.replace(/__FILENAME__/g, filename);
|
||||||
|
@ -63,11 +63,11 @@ function render(lexed, filename, template, cb) {
|
||||||
// just update the list item text in-place.
|
// just update the list item text in-place.
|
||||||
// lists that come right after a heading are what we're after.
|
// lists that come right after a heading are what we're after.
|
||||||
function parseLists(input) {
|
function parseLists(input) {
|
||||||
var state = null;
|
let state = null;
|
||||||
var depth = 0;
|
let depth = 0;
|
||||||
var output = [];
|
const output = [];
|
||||||
output.links = input.links;
|
output.links = input.links;
|
||||||
input.forEach(function(tok) {
|
input.forEach((tok) => {
|
||||||
if (state === null) {
|
if (state === null) {
|
||||||
if (tok.type === 'heading') {
|
if (tok.type === 'heading') {
|
||||||
state = 'AFTERHEADING';
|
state = 'AFTERHEADING';
|
||||||
|
@ -79,7 +79,7 @@ function parseLists(input) {
|
||||||
if (tok.type === 'list_start') {
|
if (tok.type === 'list_start') {
|
||||||
state = 'LIST';
|
state = 'LIST';
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
output.push({ type:'html', text: '<div class="signature">' });
|
output.push({type: 'html', text: '<div class="signature">'});
|
||||||
}
|
}
|
||||||
depth++;
|
depth++;
|
||||||
output.push(tok);
|
output.push(tok);
|
||||||
|
@ -99,7 +99,7 @@ function parseLists(input) {
|
||||||
depth--;
|
depth--;
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
state = null;
|
state = null;
|
||||||
output.push({ type:'html', text: '</div>' });
|
output.push({type: 'html', text: '</div>'});
|
||||||
}
|
}
|
||||||
output.push(tok);
|
output.push(tok);
|
||||||
return;
|
return;
|
||||||
|
@ -117,16 +117,16 @@ function parseLists(input) {
|
||||||
|
|
||||||
function parseListItem(text) {
|
function parseListItem(text) {
|
||||||
text = text.replace(/\{([^\}]+)\}/, '<span class="type">$1</span>');
|
text = text.replace(/\{([^\}]+)\}/, '<span class="type">$1</span>');
|
||||||
//XXX maybe put more stuff here?
|
// XXX maybe put more stuff here?
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// section is just the first heading
|
// section is just the first heading
|
||||||
function getSection(lexed) {
|
function getSection(lexed) {
|
||||||
var section = '';
|
const section = '';
|
||||||
for (var i = 0, l = lexed.length; i < l; i++) {
|
for (let i = 0, l = lexed.length; i < l; i++) {
|
||||||
var tok = lexed[i];
|
const tok = lexed[i];
|
||||||
if (tok.type === 'heading') return tok.text;
|
if (tok.type === 'heading') return tok.text;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -134,40 +134,39 @@ function getSection(lexed) {
|
||||||
|
|
||||||
|
|
||||||
function buildToc(lexed, filename, cb) {
|
function buildToc(lexed, filename, cb) {
|
||||||
var indent = 0;
|
const indent = 0;
|
||||||
var toc = [];
|
let toc = [];
|
||||||
var depth = 0;
|
let depth = 0;
|
||||||
lexed.forEach(function(tok) {
|
lexed.forEach((tok) => {
|
||||||
if (tok.type !== 'heading') return;
|
if (tok.type !== 'heading') return;
|
||||||
if (tok.depth - depth > 1) {
|
if (tok.depth - depth > 1) {
|
||||||
return cb(new Error('Inappropriate heading level\n' +
|
return cb(new Error(`Inappropriate heading level\n${
|
||||||
JSON.stringify(tok)));
|
JSON.stringify(tok)}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = tok.depth;
|
depth = tok.depth;
|
||||||
var id = getId(filename + '_' + tok.text.trim());
|
const id = getId(`${filename}_${tok.text.trim()}`);
|
||||||
toc.push(new Array((depth - 1) * 2 + 1).join(' ') +
|
toc.push(`${new Array((depth - 1) * 2 + 1).join(' ')
|
||||||
'* <a href="#' + id + '">' +
|
}* <a href="#${id}">${
|
||||||
tok.text + '</a>');
|
tok.text}</a>`);
|
||||||
tok.text += '<span><a class="mark" href="#' + id + '" ' +
|
tok.text += `<span><a class="mark" href="#${id}" ` +
|
||||||
'id="' + id + '">#</a></span>';
|
`id="${id}">#</a></span>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
toc = marked.parse(toc.join('\n'));
|
toc = marked.parse(toc.join('\n'));
|
||||||
cb(null, toc);
|
cb(null, toc);
|
||||||
}
|
}
|
||||||
|
|
||||||
var idCounters = {};
|
const idCounters = {};
|
||||||
function getId(text) {
|
function getId(text) {
|
||||||
text = text.toLowerCase();
|
text = text.toLowerCase();
|
||||||
text = text.replace(/[^a-z0-9]+/g, '_');
|
text = text.replace(/[^a-z0-9]+/g, '_');
|
||||||
text = text.replace(/^_+|_+$/, '');
|
text = text.replace(/^_+|_+$/, '');
|
||||||
text = text.replace(/^([^a-z])/, '_$1');
|
text = text.replace(/^([^a-z])/, '_$1');
|
||||||
if (idCounters.hasOwnProperty(text)) {
|
if (idCounters.hasOwnProperty(text)) {
|
||||||
text += '_' + (++idCounters[text]);
|
text += `_${++idCounters[text]}`;
|
||||||
} else {
|
} else {
|
||||||
idCounters[text] = 0;
|
idCounters[text] = 0;
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
165
bin/doc/json.js
165
bin/doc/json.js
|
@ -24,24 +24,24 @@ module.exports = doJSON;
|
||||||
// Take the lexed input, and return a JSON-encoded object
|
// Take the lexed input, and return a JSON-encoded object
|
||||||
// A module looks like this: https://gist.github.com/1777387
|
// A module looks like this: https://gist.github.com/1777387
|
||||||
|
|
||||||
var marked = require('marked');
|
const marked = require('marked');
|
||||||
|
|
||||||
function doJSON(input, filename, cb) {
|
function doJSON(input, filename, cb) {
|
||||||
var root = {source: filename};
|
const root = {source: filename};
|
||||||
var stack = [root];
|
const stack = [root];
|
||||||
var depth = 0;
|
let depth = 0;
|
||||||
var current = root;
|
let current = root;
|
||||||
var state = null;
|
let state = null;
|
||||||
var lexed = marked.lexer(input);
|
const lexed = marked.lexer(input);
|
||||||
lexed.forEach(function (tok) {
|
lexed.forEach((tok) => {
|
||||||
var type = tok.type;
|
const type = tok.type;
|
||||||
var text = tok.text;
|
let text = tok.text;
|
||||||
|
|
||||||
// <!-- type = module -->
|
// <!-- type = module -->
|
||||||
// This is for cases where the markdown semantic structure is lacking.
|
// This is for cases where the markdown semantic structure is lacking.
|
||||||
if (type === 'paragraph' || type === 'html') {
|
if (type === 'paragraph' || type === 'html') {
|
||||||
var metaExpr = /<!--([^=]+)=([^\-]+)-->\n*/g;
|
const metaExpr = /<!--([^=]+)=([^\-]+)-->\n*/g;
|
||||||
text = text.replace(metaExpr, function(_0, k, v) {
|
text = text.replace(metaExpr, (_0, k, v) => {
|
||||||
current[k.trim()] = v.trim();
|
current[k.trim()] = v.trim();
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
|
@ -52,8 +52,8 @@ function doJSON(input, filename, cb) {
|
||||||
if (type === 'heading' &&
|
if (type === 'heading' &&
|
||||||
!text.trim().match(/^example/i)) {
|
!text.trim().match(/^example/i)) {
|
||||||
if (tok.depth - depth > 1) {
|
if (tok.depth - depth > 1) {
|
||||||
return cb(new Error('Inappropriate heading level\n'+
|
return cb(new Error(`Inappropriate heading level\n${
|
||||||
JSON.stringify(tok)));
|
JSON.stringify(tok)}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes we have two headings with a single
|
// Sometimes we have two headings with a single
|
||||||
|
@ -61,7 +61,7 @@ function doJSON(input, filename, cb) {
|
||||||
if (current &&
|
if (current &&
|
||||||
state === 'AFTERHEADING' &&
|
state === 'AFTERHEADING' &&
|
||||||
depth === tok.depth) {
|
depth === tok.depth) {
|
||||||
var clone = current;
|
const clone = current;
|
||||||
current = newSection(tok);
|
current = newSection(tok);
|
||||||
current.clone = clone;
|
current.clone = clone;
|
||||||
// don't keep it around on the stack.
|
// don't keep it around on the stack.
|
||||||
|
@ -75,7 +75,7 @@ function doJSON(input, filename, cb) {
|
||||||
// root is always considered the level=0 section,
|
// root is always considered the level=0 section,
|
||||||
// and the lowest heading is 1, so this should always
|
// and the lowest heading is 1, so this should always
|
||||||
// result in having a valid parent node.
|
// result in having a valid parent node.
|
||||||
var d = tok.depth;
|
let d = tok.depth;
|
||||||
while (d <= depth) {
|
while (d <= depth) {
|
||||||
finishSection(stack.pop(), stack[stack.length - 1]);
|
finishSection(stack.pop(), stack[stack.length - 1]);
|
||||||
d++;
|
d++;
|
||||||
|
@ -98,7 +98,7 @@ function doJSON(input, filename, cb) {
|
||||||
//
|
//
|
||||||
// If one of these isn't found, then anything that comes between
|
// If one of these isn't found, then anything that comes between
|
||||||
// here and the next heading should be parsed as the desc.
|
// here and the next heading should be parsed as the desc.
|
||||||
var stability
|
let stability;
|
||||||
if (state === 'AFTERHEADING') {
|
if (state === 'AFTERHEADING') {
|
||||||
if (type === 'code' &&
|
if (type === 'code' &&
|
||||||
(stability = text.match(/^Stability: ([0-5])(?:\s*-\s*)?(.*)$/))) {
|
(stability = text.match(/^Stability: ([0-5])(?:\s*-\s*)?(.*)$/))) {
|
||||||
|
@ -138,7 +138,6 @@ function doJSON(input, filename, cb) {
|
||||||
|
|
||||||
current.desc = current.desc || [];
|
current.desc = current.desc || [];
|
||||||
current.desc.push(tok);
|
current.desc.push(tok);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// finish any sections left open
|
// finish any sections left open
|
||||||
|
@ -146,7 +145,7 @@ function doJSON(input, filename, cb) {
|
||||||
finishSection(current, stack[stack.length - 1]);
|
finishSection(current, stack[stack.length - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb(null, root)
|
return cb(null, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -193,14 +192,14 @@ function doJSON(input, filename, cb) {
|
||||||
// default: 'false' } ] } ]
|
// default: 'false' } ] } ]
|
||||||
|
|
||||||
function processList(section) {
|
function processList(section) {
|
||||||
var list = section.list;
|
const list = section.list;
|
||||||
var values = [];
|
const values = [];
|
||||||
var current;
|
let current;
|
||||||
var stack = [];
|
const stack = [];
|
||||||
|
|
||||||
// for now, *just* build the hierarchical list
|
// for now, *just* build the hierarchical list
|
||||||
list.forEach(function(tok) {
|
list.forEach((tok) => {
|
||||||
var type = tok.type;
|
const type = tok.type;
|
||||||
if (type === 'space') return;
|
if (type === 'space') return;
|
||||||
if (type === 'list_item_start') {
|
if (type === 'list_item_start') {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
|
@ -217,26 +216,26 @@ function processList(section) {
|
||||||
return;
|
return;
|
||||||
} else if (type === 'list_item_end') {
|
} else if (type === 'list_item_end') {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
throw new Error('invalid list - end without current item\n' +
|
throw new Error(`invalid list - end without current item\n${
|
||||||
JSON.stringify(tok) + '\n' +
|
JSON.stringify(tok)}\n${
|
||||||
JSON.stringify(list));
|
JSON.stringify(list)}`);
|
||||||
}
|
}
|
||||||
current = stack.pop();
|
current = stack.pop();
|
||||||
} else if (type === 'text') {
|
} else if (type === 'text') {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
throw new Error('invalid list - text without current item\n' +
|
throw new Error(`invalid list - text without current item\n${
|
||||||
JSON.stringify(tok) + '\n' +
|
JSON.stringify(tok)}\n${
|
||||||
JSON.stringify(list));
|
JSON.stringify(list)}`);
|
||||||
}
|
}
|
||||||
current.textRaw = current.textRaw || '';
|
current.textRaw = current.textRaw || '';
|
||||||
current.textRaw += tok.text + ' ';
|
current.textRaw += `${tok.text} `;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// shove the name in there for properties, since they are always
|
// shove the name in there for properties, since they are always
|
||||||
// just going to be the value etc.
|
// just going to be the value etc.
|
||||||
if (section.type === 'property' && values[0]) {
|
if (section.type === 'property' && values[0]) {
|
||||||
values[0].textRaw = '`' + section.name + '` ' + values[0].textRaw;
|
values[0].textRaw = `\`${section.name}\` ${values[0].textRaw}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now pull the actual values out of the text bits.
|
// now pull the actual values out of the text bits.
|
||||||
|
@ -252,9 +251,9 @@ function processList(section) {
|
||||||
// each item is an argument, unless the name is 'return',
|
// each item is an argument, unless the name is 'return',
|
||||||
// in which case it's the return value.
|
// in which case it's the return value.
|
||||||
section.signatures = section.signatures || [];
|
section.signatures = section.signatures || [];
|
||||||
var sig = {}
|
var sig = {};
|
||||||
section.signatures.push(sig);
|
section.signatures.push(sig);
|
||||||
sig.params = values.filter(function(v) {
|
sig.params = values.filter((v) => {
|
||||||
if (v.name === 'return') {
|
if (v.name === 'return') {
|
||||||
sig.return = v;
|
sig.return = v;
|
||||||
return false;
|
return false;
|
||||||
|
@ -271,7 +270,7 @@ function processList(section) {
|
||||||
delete value.name;
|
delete value.name;
|
||||||
section.typeof = value.type;
|
section.typeof = value.type;
|
||||||
delete value.type;
|
delete value.type;
|
||||||
Object.keys(value).forEach(function(k) {
|
Object.keys(value).forEach((k) => {
|
||||||
section[k] = value[k];
|
section[k] = value[k];
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -289,36 +288,36 @@ function processList(section) {
|
||||||
|
|
||||||
// textRaw = "someobject.someMethod(a, [b=100], [c])"
|
// textRaw = "someobject.someMethod(a, [b=100], [c])"
|
||||||
function parseSignature(text, sig) {
|
function parseSignature(text, sig) {
|
||||||
var params = text.match(paramExpr);
|
let params = text.match(paramExpr);
|
||||||
if (!params) return;
|
if (!params) return;
|
||||||
params = params[1];
|
params = params[1];
|
||||||
// the ] is irrelevant. [ indicates optionalness.
|
// the ] is irrelevant. [ indicates optionalness.
|
||||||
params = params.replace(/\]/g, '');
|
params = params.replace(/\]/g, '');
|
||||||
params = params.split(/,/)
|
params = params.split(/,/);
|
||||||
params.forEach(function(p, i, _) {
|
params.forEach((p, i, _) => {
|
||||||
p = p.trim();
|
p = p.trim();
|
||||||
if (!p) return;
|
if (!p) return;
|
||||||
var param = sig.params[i];
|
let param = sig.params[i];
|
||||||
var optional = false;
|
let optional = false;
|
||||||
var def;
|
let def;
|
||||||
// [foo] -> optional
|
// [foo] -> optional
|
||||||
if (p.charAt(0) === '[') {
|
if (p.charAt(0) === '[') {
|
||||||
optional = true;
|
optional = true;
|
||||||
p = p.substr(1);
|
p = p.substr(1);
|
||||||
}
|
}
|
||||||
var eq = p.indexOf('=');
|
const eq = p.indexOf('=');
|
||||||
if (eq !== -1) {
|
if (eq !== -1) {
|
||||||
def = p.substr(eq + 1);
|
def = p.substr(eq + 1);
|
||||||
p = p.substr(0, eq);
|
p = p.substr(0, eq);
|
||||||
}
|
}
|
||||||
if (!param) {
|
if (!param) {
|
||||||
param = sig.params[i] = { name: p };
|
param = sig.params[i] = {name: p};
|
||||||
}
|
}
|
||||||
// at this point, the name should match.
|
// at this point, the name should match.
|
||||||
if (p !== param.name) {
|
if (p !== param.name) {
|
||||||
console.error('Warning: invalid param "%s"', p);
|
console.error('Warning: invalid param "%s"', p);
|
||||||
console.error(' > ' + JSON.stringify(param));
|
console.error(` > ${JSON.stringify(param)}`);
|
||||||
console.error(' > ' + text);
|
console.error(` > ${text}`);
|
||||||
}
|
}
|
||||||
if (optional) param.optional = true;
|
if (optional) param.optional = true;
|
||||||
if (def !== undefined) param.default = def;
|
if (def !== undefined) param.default = def;
|
||||||
|
@ -332,18 +331,18 @@ function parseListItem(item) {
|
||||||
|
|
||||||
// the goal here is to find the name, type, default, and optional.
|
// the goal here is to find the name, type, default, and optional.
|
||||||
// anything left over is 'desc'
|
// anything left over is 'desc'
|
||||||
var text = item.textRaw.trim();
|
let text = item.textRaw.trim();
|
||||||
// text = text.replace(/^(Argument|Param)s?\s*:?\s*/i, '');
|
// text = text.replace(/^(Argument|Param)s?\s*:?\s*/i, '');
|
||||||
|
|
||||||
text = text.replace(/^, /, '').trim();
|
text = text.replace(/^, /, '').trim();
|
||||||
var retExpr = /^returns?\s*:?\s*/i;
|
const retExpr = /^returns?\s*:?\s*/i;
|
||||||
var ret = text.match(retExpr);
|
const ret = text.match(retExpr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
item.name = 'return';
|
item.name = 'return';
|
||||||
text = text.replace(retExpr, '');
|
text = text.replace(retExpr, '');
|
||||||
} else {
|
} else {
|
||||||
var nameExpr = /^['`"]?([^'`": \{]+)['`"]?\s*:?\s*/;
|
const nameExpr = /^['`"]?([^'`": \{]+)['`"]?\s*:?\s*/;
|
||||||
var name = text.match(nameExpr);
|
const name = text.match(nameExpr);
|
||||||
if (name) {
|
if (name) {
|
||||||
item.name = name[1];
|
item.name = name[1];
|
||||||
text = text.replace(nameExpr, '');
|
text = text.replace(nameExpr, '');
|
||||||
|
@ -351,24 +350,24 @@ function parseListItem(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
var defaultExpr = /\(default\s*[:=]?\s*['"`]?([^, '"`]*)['"`]?\)/i;
|
const defaultExpr = /\(default\s*[:=]?\s*['"`]?([^, '"`]*)['"`]?\)/i;
|
||||||
var def = text.match(defaultExpr);
|
const def = text.match(defaultExpr);
|
||||||
if (def) {
|
if (def) {
|
||||||
item.default = def[1];
|
item.default = def[1];
|
||||||
text = text.replace(defaultExpr, '');
|
text = text.replace(defaultExpr, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
var typeExpr = /^\{([^\}]+)\}/;
|
const typeExpr = /^\{([^\}]+)\}/;
|
||||||
var type = text.match(typeExpr);
|
const type = text.match(typeExpr);
|
||||||
if (type) {
|
if (type) {
|
||||||
item.type = type[1];
|
item.type = type[1];
|
||||||
text = text.replace(typeExpr, '');
|
text = text.replace(typeExpr, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
var optExpr = /^Optional\.|(?:, )?Optional$/;
|
const optExpr = /^Optional\.|(?:, )?Optional$/;
|
||||||
var optional = text.match(optExpr);
|
const optional = text.match(optExpr);
|
||||||
if (optional) {
|
if (optional) {
|
||||||
item.optional = true;
|
item.optional = true;
|
||||||
text = text.replace(optExpr, '');
|
text = text.replace(optExpr, '');
|
||||||
|
@ -382,9 +381,9 @@ function parseListItem(item) {
|
||||||
|
|
||||||
function finishSection(section, parent) {
|
function finishSection(section, parent) {
|
||||||
if (!section || !parent) {
|
if (!section || !parent) {
|
||||||
throw new Error('Invalid finishSection call\n'+
|
throw new Error(`Invalid finishSection call\n${
|
||||||
JSON.stringify(section) + '\n' +
|
JSON.stringify(section)}\n${
|
||||||
JSON.stringify(parent));
|
JSON.stringify(parent)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!section.type) {
|
if (!section.type) {
|
||||||
|
@ -394,7 +393,7 @@ function finishSection(section, parent) {
|
||||||
}
|
}
|
||||||
section.displayName = section.name;
|
section.displayName = section.name;
|
||||||
section.name = section.name.toLowerCase()
|
section.name = section.name.toLowerCase()
|
||||||
.trim().replace(/\s+/g, '_');
|
.trim().replace(/\s+/g, '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section.desc && Array.isArray(section.desc)) {
|
if (section.desc && Array.isArray(section.desc)) {
|
||||||
|
@ -411,10 +410,10 @@ function finishSection(section, parent) {
|
||||||
// Merge them into the parent.
|
// Merge them into the parent.
|
||||||
if (section.type === 'class' && section.ctors) {
|
if (section.type === 'class' && section.ctors) {
|
||||||
section.signatures = section.signatures || [];
|
section.signatures = section.signatures || [];
|
||||||
var sigs = section.signatures;
|
const sigs = section.signatures;
|
||||||
section.ctors.forEach(function(ctor) {
|
section.ctors.forEach((ctor) => {
|
||||||
ctor.signatures = ctor.signatures || [{}];
|
ctor.signatures = ctor.signatures || [{}];
|
||||||
ctor.signatures.forEach(function(sig) {
|
ctor.signatures.forEach((sig) => {
|
||||||
sig.desc = ctor.desc;
|
sig.desc = ctor.desc;
|
||||||
});
|
});
|
||||||
sigs.push.apply(sigs, ctor.signatures);
|
sigs.push.apply(sigs, ctor.signatures);
|
||||||
|
@ -425,7 +424,7 @@ function finishSection(section, parent) {
|
||||||
// properties are a bit special.
|
// properties are a bit special.
|
||||||
// their "type" is the type of object, not "property"
|
// their "type" is the type of object, not "property"
|
||||||
if (section.properties) {
|
if (section.properties) {
|
||||||
section.properties.forEach(function (p) {
|
section.properties.forEach((p) => {
|
||||||
if (p.typeof) p.type = p.typeof;
|
if (p.typeof) p.type = p.typeof;
|
||||||
else delete p.type;
|
else delete p.type;
|
||||||
delete p.typeof;
|
delete p.typeof;
|
||||||
|
@ -434,27 +433,27 @@ function finishSection(section, parent) {
|
||||||
|
|
||||||
// handle clones
|
// handle clones
|
||||||
if (section.clone) {
|
if (section.clone) {
|
||||||
var clone = section.clone;
|
const clone = section.clone;
|
||||||
delete section.clone;
|
delete section.clone;
|
||||||
delete clone.clone;
|
delete clone.clone;
|
||||||
deepCopy(section, clone);
|
deepCopy(section, clone);
|
||||||
finishSection(clone, parent);
|
finishSection(clone, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
var plur;
|
let plur;
|
||||||
if (section.type.slice(-1) === 's') {
|
if (section.type.slice(-1) === 's') {
|
||||||
plur = section.type + 'es';
|
plur = `${section.type}es`;
|
||||||
} else if (section.type.slice(-1) === 'y') {
|
} else if (section.type.slice(-1) === 'y') {
|
||||||
plur = section.type.replace(/y$/, 'ies');
|
plur = section.type.replace(/y$/, 'ies');
|
||||||
} else {
|
} else {
|
||||||
plur = section.type + 's';
|
plur = `${section.type}s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the parent's type is 'misc', then it's just a random
|
// if the parent's type is 'misc', then it's just a random
|
||||||
// collection of stuff, like the "globals" section.
|
// collection of stuff, like the "globals" section.
|
||||||
// Make the children top-level items.
|
// Make the children top-level items.
|
||||||
if (section.type === 'misc') {
|
if (section.type === 'misc') {
|
||||||
Object.keys(section).forEach(function(k) {
|
Object.keys(section).forEach((k) => {
|
||||||
switch (k) {
|
switch (k) {
|
||||||
case 'textRaw':
|
case 'textRaw':
|
||||||
case 'name':
|
case 'name':
|
||||||
|
@ -486,9 +485,7 @@ function finishSection(section, parent) {
|
||||||
// Not a general purpose deep copy.
|
// Not a general purpose deep copy.
|
||||||
// But sufficient for these basic things.
|
// But sufficient for these basic things.
|
||||||
function deepCopy(src, dest) {
|
function deepCopy(src, dest) {
|
||||||
Object.keys(src).filter(function(k) {
|
Object.keys(src).filter((k) => !dest.hasOwnProperty(k)).forEach((k) => {
|
||||||
return !dest.hasOwnProperty(k);
|
|
||||||
}).forEach(function(k) {
|
|
||||||
dest[k] = deepCopy_(src[k]);
|
dest[k] = deepCopy_(src[k]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -497,14 +494,14 @@ function deepCopy_(src) {
|
||||||
if (!src) return src;
|
if (!src) return src;
|
||||||
if (Array.isArray(src)) {
|
if (Array.isArray(src)) {
|
||||||
var c = new Array(src.length);
|
var c = new Array(src.length);
|
||||||
src.forEach(function(v, i) {
|
src.forEach((v, i) => {
|
||||||
c[i] = deepCopy_(v);
|
c[i] = deepCopy_(v);
|
||||||
});
|
});
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if (typeof src === 'object') {
|
if (typeof src === 'object') {
|
||||||
var c = {};
|
var c = {};
|
||||||
Object.keys(src).forEach(function(k) {
|
Object.keys(src).forEach((k) => {
|
||||||
c[k] = deepCopy_(src[k]);
|
c[k] = deepCopy_(src[k]);
|
||||||
});
|
});
|
||||||
return c;
|
return c;
|
||||||
|
@ -514,21 +511,21 @@ function deepCopy_(src) {
|
||||||
|
|
||||||
|
|
||||||
// these parse out the contents of an H# tag
|
// these parse out the contents of an H# tag
|
||||||
var eventExpr = /^Event(?::|\s)+['"]?([^"']+).*$/i;
|
const eventExpr = /^Event(?::|\s)+['"]?([^"']+).*$/i;
|
||||||
var classExpr = /^Class:\s*([^ ]+).*?$/i;
|
const classExpr = /^Class:\s*([^ ]+).*?$/i;
|
||||||
var propExpr = /^(?:property:?\s*)?[^\.]+\.([^ \.\(\)]+)\s*?$/i;
|
const propExpr = /^(?:property:?\s*)?[^\.]+\.([^ \.\(\)]+)\s*?$/i;
|
||||||
var braceExpr = /^(?:property:?\s*)?[^\.\[]+(\[[^\]]+\])\s*?$/i;
|
const braceExpr = /^(?:property:?\s*)?[^\.\[]+(\[[^\]]+\])\s*?$/i;
|
||||||
var classMethExpr =
|
const classMethExpr =
|
||||||
/^class\s*method\s*:?[^\.]+\.([^ \.\(\)]+)\([^\)]*\)\s*?$/i;
|
/^class\s*method\s*:?[^\.]+\.([^ \.\(\)]+)\([^\)]*\)\s*?$/i;
|
||||||
var methExpr =
|
const methExpr =
|
||||||
/^(?:method:?\s*)?(?:[^\.]+\.)?([^ \.\(\)]+)\([^\)]*\)\s*?$/i;
|
/^(?:method:?\s*)?(?:[^\.]+\.)?([^ \.\(\)]+)\([^\)]*\)\s*?$/i;
|
||||||
var newExpr = /^new ([A-Z][a-z]+)\([^\)]*\)\s*?$/;
|
const newExpr = /^new ([A-Z][a-z]+)\([^\)]*\)\s*?$/;
|
||||||
var paramExpr = /\((.*)\);?$/;
|
var paramExpr = /\((.*)\);?$/;
|
||||||
|
|
||||||
function newSection(tok) {
|
function newSection(tok) {
|
||||||
var section = {};
|
const section = {};
|
||||||
// infer the type from the text.
|
// infer the type from the text.
|
||||||
var text = section.textRaw = tok.text;
|
const text = section.textRaw = tok.text;
|
||||||
if (text.match(eventExpr)) {
|
if (text.match(eventExpr)) {
|
||||||
section.type = 'event';
|
section.type = 'event';
|
||||||
section.name = text.replace(eventExpr, '$1');
|
section.name = text.replace(eventExpr, '$1');
|
||||||
|
|
|
@ -5,60 +5,60 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.error("Use: node extractPadData.js $PADID");
|
console.error('Use: node extractPadData.js $PADID');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the padID
|
// get the padID
|
||||||
let padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
|
|
||||||
let npm = require('../src/node_modules/npm');
|
const npm = require('../src/node_modules/npm');
|
||||||
|
|
||||||
npm.load({}, async function(er) {
|
npm.load({}, async (er) => {
|
||||||
if (er) {
|
if (er) {
|
||||||
console.error("Could not load NPM: " + er)
|
console.error(`Could not load NPM: ${er}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// initialize database
|
// initialize database
|
||||||
let settings = require('../src/node/utils/Settings');
|
const settings = require('../src/node/utils/Settings');
|
||||||
let db = require('../src/node/db/DB');
|
const db = require('../src/node/db/DB');
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
// load extra modules
|
// load extra modules
|
||||||
let dirtyDB = require('../src/node_modules/dirty');
|
const dirtyDB = require('../src/node_modules/dirty');
|
||||||
let padManager = require('../src/node/db/PadManager');
|
const padManager = require('../src/node/db/PadManager');
|
||||||
let util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
// initialize output database
|
// initialize output database
|
||||||
let dirty = dirtyDB(padId + '.db');
|
const dirty = dirtyDB(`${padId}.db`);
|
||||||
|
|
||||||
// Promise wrapped get and set function
|
// Promise wrapped get and set function
|
||||||
let wrapped = db.db.db.wrappedDB;
|
const wrapped = db.db.db.wrappedDB;
|
||||||
let get = util.promisify(wrapped.get.bind(wrapped));
|
const get = util.promisify(wrapped.get.bind(wrapped));
|
||||||
let set = util.promisify(dirty.set.bind(dirty));
|
const set = util.promisify(dirty.set.bind(dirty));
|
||||||
|
|
||||||
// array in which required key values will be accumulated
|
// array in which required key values will be accumulated
|
||||||
let neededDBValues = ['pad:' + padId];
|
const neededDBValues = [`pad:${padId}`];
|
||||||
|
|
||||||
// get the actual pad object
|
// get the actual pad object
|
||||||
let pad = await padManager.getPad(padId);
|
const pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
// add all authors
|
// add all authors
|
||||||
neededDBValues.push(...pad.getAllAuthors().map(author => 'globalAuthor:' + author));
|
neededDBValues.push(...pad.getAllAuthors().map((author) => `globalAuthor:${author}`));
|
||||||
|
|
||||||
// add all revisions
|
// add all revisions
|
||||||
for (let rev = 0; rev <= pad.head; ++rev) {
|
for (let rev = 0; rev <= pad.head; ++rev) {
|
||||||
neededDBValues.push('pad:' + padId + ':revs:' + rev);
|
neededDBValues.push(`pad:${padId}:revs:${rev}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all chat values
|
// add all chat values
|
||||||
for (let chat = 0; chat <= pad.chatHead; ++chat) {
|
for (let chat = 0; chat <= pad.chatHead; ++chat) {
|
||||||
neededDBValues.push('pad:' + padId + ':chat:' + chat);
|
neededDBValues.push(`pad:${padId}:chat:${chat}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let dbkey of neededDBValues) {
|
for (const dbkey of neededDBValues) {
|
||||||
let dbvalue = await get(dbkey);
|
let dbvalue = await get(dbkey);
|
||||||
if (dbvalue && typeof dbvalue !== 'object') {
|
if (dbvalue && typeof dbvalue !== 'object') {
|
||||||
dbvalue = JSON.parse(dbvalue);
|
dbvalue = JSON.parse(dbvalue);
|
||||||
|
|
|
@ -1,69 +1,64 @@
|
||||||
var startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
require("ep_etherpad-lite/node_modules/npm").load({}, function(er,npm) {
|
require('ep_etherpad-lite/node_modules/npm').load({}, (er, npm) => {
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
var fs = require("fs");
|
const ueberDB = require('ep_etherpad-lite/node_modules/ueberdb2');
|
||||||
|
const settings = require('ep_etherpad-lite/node/utils/Settings');
|
||||||
|
const log4js = require('ep_etherpad-lite/node_modules/log4js');
|
||||||
|
|
||||||
var ueberDB = require("ep_etherpad-lite/node_modules/ueberdb2");
|
const dbWrapperSettings = {
|
||||||
var settings = require("ep_etherpad-lite/node/utils/Settings");
|
|
||||||
var log4js = require('ep_etherpad-lite/node_modules/log4js');
|
|
||||||
|
|
||||||
var dbWrapperSettings = {
|
|
||||||
cache: 0,
|
cache: 0,
|
||||||
writeInterval: 100,
|
writeInterval: 100,
|
||||||
json: false // data is already json encoded
|
json: false, // data is already json encoded
|
||||||
};
|
};
|
||||||
var db = new ueberDB.database(settings.dbType, settings.dbSettings, dbWrapperSettings, log4js.getLogger("ueberDB"));
|
const db = new ueberDB.database(settings.dbType, settings.dbSettings, dbWrapperSettings, log4js.getLogger('ueberDB'));
|
||||||
|
|
||||||
var sqlFile = process.argv[2];
|
const sqlFile = process.argv[2];
|
||||||
|
|
||||||
//stop if the settings file is not set
|
// stop if the settings file is not set
|
||||||
if(!sqlFile)
|
if (!sqlFile) {
|
||||||
{
|
console.error('Use: node importSqlFile.js $SQLFILE');
|
||||||
console.error("Use: node importSqlFile.js $SQLFILE");
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
log("initializing db");
|
log('initializing db');
|
||||||
db.init(function(err) {
|
db.init((err) => {
|
||||||
//there was an error while initializing the database, output it and stop
|
// there was an error while initializing the database, output it and stop
|
||||||
if(err)
|
if (err) {
|
||||||
{
|
console.error('ERROR: Problem while initializing the database');
|
||||||
console.error("ERROR: Problem while initializing the database");
|
|
||||||
console.error(err.stack ? err.stack : err);
|
console.error(err.stack ? err.stack : err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
} else {
|
||||||
else
|
log('done');
|
||||||
{
|
|
||||||
log("done");
|
|
||||||
|
|
||||||
log("open output file...");
|
log('open output file...');
|
||||||
var lines = fs.readFileSync(sqlFile, 'utf8').split("\n");
|
const lines = fs.readFileSync(sqlFile, 'utf8').split('\n');
|
||||||
|
|
||||||
var count = lines.length;
|
const count = lines.length;
|
||||||
var keyNo = 0;
|
let keyNo = 0;
|
||||||
|
|
||||||
process.stdout.write("Start importing " + count + " keys...\n");
|
process.stdout.write(`Start importing ${count} keys...\n`);
|
||||||
lines.forEach(function(l) {
|
lines.forEach((l) => {
|
||||||
if (l.substr(0, 27) == "REPLACE INTO store VALUES (") {
|
if (l.substr(0, 27) == 'REPLACE INTO store VALUES (') {
|
||||||
var pos = l.indexOf("', '");
|
const pos = l.indexOf("', '");
|
||||||
var key = l.substr(28, pos - 28);
|
const key = l.substr(28, pos - 28);
|
||||||
var value = l.substr(pos + 3);
|
let value = l.substr(pos + 3);
|
||||||
value = value.substr(0, value.length - 2);
|
value = value.substr(0, value.length - 2);
|
||||||
console.log("key: " + key + " val: " + value);
|
console.log(`key: ${key} val: ${value}`);
|
||||||
console.log("unval: " + unescape(value));
|
console.log(`unval: ${unescape(value)}`);
|
||||||
db.set(key, unescape(value), null);
|
db.set(key, unescape(value), null);
|
||||||
keyNo++;
|
keyNo++;
|
||||||
if (keyNo % 1000 == 0) {
|
if (keyNo % 1000 == 0) {
|
||||||
process.stdout.write(" " + keyNo + "/" + count + "\n");
|
process.stdout.write(` ${keyNo}/${count}\n`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
process.stdout.write("\n");
|
process.stdout.write('\n');
|
||||||
process.stdout.write("done. waiting for db to finish transaction. depended on dbms this may take some time...\n");
|
process.stdout.write('done. waiting for db to finish transaction. depended on dbms this may take some time...\n');
|
||||||
|
|
||||||
db.doShutdown(function() {
|
db.doShutdown(() => {
|
||||||
log("finished, imported " + keyNo + " keys.");
|
log(`finished, imported ${keyNo} keys.`);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -71,22 +66,22 @@ require("ep_etherpad-lite/node_modules/npm").load({}, function(er,npm) {
|
||||||
});
|
});
|
||||||
|
|
||||||
function log(str) {
|
function log(str) {
|
||||||
console.log((Date.now() - startTime)/1000 + "\t" + str);
|
console.log(`${(Date.now() - startTime) / 1000}\t${str}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
unescape = function(val) {
|
unescape = function (val) {
|
||||||
// value is a string
|
// value is a string
|
||||||
if (val.substr(0, 1) == "'") {
|
if (val.substr(0, 1) == "'") {
|
||||||
val = val.substr(0, val.length - 1).substr(1);
|
val = val.substr(0, val.length - 1).substr(1);
|
||||||
|
|
||||||
return val.replace(/\\[0nrbtZ\\'"]/g, function(s) {
|
return val.replace(/\\[0nrbtZ\\'"]/g, (s) => {
|
||||||
switch(s) {
|
switch (s) {
|
||||||
case "\\0": return "\0";
|
case '\\0': return '\0';
|
||||||
case "\\n": return "\n";
|
case '\\n': return '\n';
|
||||||
case "\\r": return "\r";
|
case '\\r': return '\r';
|
||||||
case "\\b": return "\b";
|
case '\\b': return '\b';
|
||||||
case "\\t": return "\t";
|
case '\\t': return '\t';
|
||||||
case "\\Z": return "\x1a";
|
case '\\Z': return '\x1a';
|
||||||
default: return s.substr(1);
|
default: return s.substr(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
require("ep_etherpad-lite/node_modules/npm").load({}, function(er,npm) {
|
require('ep_etherpad-lite/node_modules/npm').load({}, (er, npm) => {
|
||||||
|
process.chdir(`${npm.root}/..`);
|
||||||
process.chdir(npm.root+'/..')
|
|
||||||
|
|
||||||
// This script requires that you have modified your settings.json file
|
// This script requires that you have modified your settings.json file
|
||||||
// to work with a real database. Please make a backup of your dirty.db
|
// to work with a real database. Please make a backup of your dirty.db
|
||||||
|
@ -10,40 +9,40 @@ require("ep_etherpad-lite/node_modules/npm").load({}, function(er,npm) {
|
||||||
// `node --max-old-space-size=4096 bin/migrateDirtyDBtoRealDB.js`
|
// `node --max-old-space-size=4096 bin/migrateDirtyDBtoRealDB.js`
|
||||||
|
|
||||||
|
|
||||||
var settings = require("ep_etherpad-lite/node/utils/Settings");
|
const settings = require('ep_etherpad-lite/node/utils/Settings');
|
||||||
var dirty = require("../src/node_modules/dirty");
|
let dirty = require('../src/node_modules/dirty');
|
||||||
var ueberDB = require("../src/node_modules/ueberdb2");
|
const ueberDB = require('../src/node_modules/ueberdb2');
|
||||||
var log4js = require("../src/node_modules/log4js");
|
const log4js = require('../src/node_modules/log4js');
|
||||||
var dbWrapperSettings = {
|
const dbWrapperSettings = {
|
||||||
"cache": "0", // The cache slows things down when you're mostly writing.
|
cache: '0', // The cache slows things down when you're mostly writing.
|
||||||
"writeInterval": 0 // Write directly to the database, don't buffer
|
writeInterval: 0, // Write directly to the database, don't buffer
|
||||||
};
|
};
|
||||||
var db = new ueberDB.database(settings.dbType, settings.dbSettings, dbWrapperSettings, log4js.getLogger("ueberDB"));
|
const db = new ueberDB.database(settings.dbType, settings.dbSettings, dbWrapperSettings, log4js.getLogger('ueberDB'));
|
||||||
var i = 0;
|
let i = 0;
|
||||||
var length = 0;
|
let length = 0;
|
||||||
|
|
||||||
db.init(function() {
|
db.init(() => {
|
||||||
console.log("Waiting for dirtyDB to parse its file.");
|
console.log('Waiting for dirtyDB to parse its file.');
|
||||||
dirty = dirty('var/dirty.db').on("load", function() {
|
dirty = dirty('var/dirty.db').on('load', () => {
|
||||||
dirty.forEach(function(){
|
dirty.forEach(() => {
|
||||||
length++;
|
length++;
|
||||||
});
|
});
|
||||||
console.log(`Found ${length} records, processing now.`);
|
console.log(`Found ${length} records, processing now.`);
|
||||||
|
|
||||||
dirty.forEach(async function(key, value) {
|
dirty.forEach(async (key, value) => {
|
||||||
let error = await db.set(key, value);
|
const error = await db.set(key, value);
|
||||||
console.log(`Wrote record ${i}`);
|
console.log(`Wrote record ${i}`);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i === length) {
|
if (i === length) {
|
||||||
console.log("finished, just clearing up for a bit...");
|
console.log('finished, just clearing up for a bit...');
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("Please wait for all records to flush to database, then kill this process.");
|
console.log('Please wait for all records to flush to database, then kill this process.');
|
||||||
});
|
});
|
||||||
console.log("done?")
|
console.log('done?');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,96 +9,96 @@ node bin/plugins/checkPlugins.js ep_whatever autofix autocommit
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const fs = require("fs");
|
const fs = require('fs');
|
||||||
const { exec } = require("child_process");
|
const {exec} = require('child_process');
|
||||||
|
|
||||||
// get plugin name & path from user input
|
// get plugin name & path from user input
|
||||||
const pluginName = process.argv[2];
|
const pluginName = process.argv[2];
|
||||||
|
|
||||||
if(!pluginName){
|
if (!pluginName) {
|
||||||
console.error("no plugin name specified");
|
console.error('no plugin name specified');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pluginPath = "node_modules/"+pluginName;
|
const pluginPath = `node_modules/${pluginName}`;
|
||||||
|
|
||||||
console.log("Checking the plugin: "+ pluginName)
|
console.log(`Checking the plugin: ${pluginName}`);
|
||||||
|
|
||||||
// Should we autofix?
|
// Should we autofix?
|
||||||
if (process.argv[3] && process.argv[3] === "autofix") var autoFix = true;
|
if (process.argv[3] && process.argv[3] === 'autofix') var autoFix = true;
|
||||||
|
|
||||||
// Should we update files where possible?
|
// Should we update files where possible?
|
||||||
if (process.argv[5] && process.argv[5] === "autoupdate") var autoUpdate = true;
|
if (process.argv[5] && process.argv[5] === 'autoupdate') var autoUpdate = true;
|
||||||
|
|
||||||
// Should we automcommit and npm publish?!
|
// Should we automcommit and npm publish?!
|
||||||
if (process.argv[4] && process.argv[4] === "autocommit") var autoCommit = true;
|
if (process.argv[4] && process.argv[4] === 'autocommit') var autoCommit = true;
|
||||||
|
|
||||||
|
|
||||||
if(autoCommit){
|
if (autoCommit) {
|
||||||
console.warn("Auto commit is enabled, I hope you know what you are doing...")
|
console.warn('Auto commit is enabled, I hope you know what you are doing...');
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readdir(pluginPath, function (err, rootFiles) {
|
fs.readdir(pluginPath, (err, rootFiles) => {
|
||||||
//handling error
|
// handling error
|
||||||
if (err) {
|
if (err) {
|
||||||
return console.log('Unable to scan directory: ' + err);
|
return console.log(`Unable to scan directory: ${err}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rewriting files to lower case
|
// rewriting files to lower case
|
||||||
var files = [];
|
const files = [];
|
||||||
|
|
||||||
// some files we need to know the actual file name. Not compulsory but might help in the future.
|
// some files we need to know the actual file name. Not compulsory but might help in the future.
|
||||||
var readMeFileName;
|
let readMeFileName;
|
||||||
var repository;
|
let repository;
|
||||||
var hasAutoFixed = false;
|
let hasAutoFixed = false;
|
||||||
|
|
||||||
for (var i = 0; i < rootFiles.length; i++) {
|
for (let i = 0; i < rootFiles.length; i++) {
|
||||||
if(rootFiles[i].toLowerCase().indexOf("readme") !== -1) readMeFileName = rootFiles[i];
|
if (rootFiles[i].toLowerCase().indexOf('readme') !== -1) readMeFileName = rootFiles[i];
|
||||||
files.push(rootFiles[i].toLowerCase());
|
files.push(rootFiles[i].toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf(".git") === -1){
|
if (files.indexOf('.git') === -1) {
|
||||||
console.error("No .git folder, aborting");
|
console.error('No .git folder, aborting');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do a git pull...
|
// do a git pull...
|
||||||
var child_process = require('child_process');
|
var child_process = require('child_process');
|
||||||
try{
|
try {
|
||||||
child_process.execSync('git pull ',{"cwd":pluginPath+"/"});
|
child_process.execSync('git pull ', {cwd: `${pluginPath}/`});
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.error("Error git pull", e);
|
console.error('Error git pull', e);
|
||||||
};
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const path = pluginPath + '/.github/workflows/npmpublish.yml';
|
const path = `${pluginPath}/.github/workflows/npmpublish.yml`;
|
||||||
if (!fs.existsSync(path)) {
|
if (!fs.existsSync(path)) {
|
||||||
console.log('no .github/workflows/npmpublish.yml, create one and set npm secret to auto publish to npm on commit');
|
console.log('no .github/workflows/npmpublish.yml, create one and set npm secret to auto publish to npm on commit');
|
||||||
if (autoFix) {
|
if (autoFix) {
|
||||||
const npmpublish =
|
const npmpublish =
|
||||||
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||||
fs.mkdirSync(pluginPath + '/.github/workflows', {recursive: true});
|
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||||
fs.writeFileSync(path, npmpublish);
|
fs.writeFileSync(path, npmpublish);
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("If you haven't already, setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo");
|
console.log("If you haven't already, setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo");
|
||||||
} else {
|
} else {
|
||||||
console.log('Setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo');
|
console.log('Setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo');
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
// autopublish exists, we should check the version..
|
// autopublish exists, we should check the version..
|
||||||
// checkVersion takes two file paths and checks for a version string in them.
|
// checkVersion takes two file paths and checks for a version string in them.
|
||||||
const currVersionFile = fs.readFileSync(path, {encoding: 'utf8', flag: 'r'});
|
const currVersionFile = fs.readFileSync(path, {encoding: 'utf8', flag: 'r'});
|
||||||
const existingConfigLocation = currVersionFile.indexOf("##ETHERPAD_NPM_V=");
|
const existingConfigLocation = currVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||||
const existingValue = parseInt(currVersionFile.substr(existingConfigLocation+17, existingConfigLocation.length));
|
const existingValue = parseInt(currVersionFile.substr(existingConfigLocation + 17, existingConfigLocation.length));
|
||||||
|
|
||||||
const reqVersionFile = fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
const reqVersionFile = fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||||
const reqConfigLocation = reqVersionFile.indexOf("##ETHERPAD_NPM_V=");
|
const reqConfigLocation = reqVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||||
const reqValue = parseInt(reqVersionFile.substr(reqConfigLocation+17, reqConfigLocation.length));
|
const reqValue = parseInt(reqVersionFile.substr(reqConfigLocation + 17, reqConfigLocation.length));
|
||||||
|
|
||||||
if(!existingValue || (reqValue > existingValue)){
|
if (!existingValue || (reqValue > existingValue)) {
|
||||||
const npmpublish =
|
const npmpublish =
|
||||||
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||||
fs.mkdirSync(pluginPath + '/.github/workflows', {recursive: true});
|
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||||
fs.writeFileSync(path, npmpublish);
|
fs.writeFileSync(path, npmpublish);
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
}
|
}
|
||||||
|
@ -107,152 +107,151 @@ fs.readdir(pluginPath, function (err, rootFiles) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("package.json") === -1){
|
if (files.indexOf('package.json') === -1) {
|
||||||
console.warn("no package.json, please create");
|
console.warn('no package.json, please create');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("package.json") !== -1){
|
if (files.indexOf('package.json') !== -1) {
|
||||||
let packageJSON = fs.readFileSync(pluginPath+"/package.json", {encoding:'utf8', flag:'r'});
|
const packageJSON = fs.readFileSync(`${pluginPath}/package.json`, {encoding: 'utf8', flag: 'r'});
|
||||||
let parsedPackageJSON = JSON.parse(packageJSON);
|
const parsedPackageJSON = JSON.parse(packageJSON);
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
var updatedPackageJSON = false;
|
let updatedPackageJSON = false;
|
||||||
if(!parsedPackageJSON.funding){
|
if (!parsedPackageJSON.funding) {
|
||||||
updatedPackageJSON = true;
|
updatedPackageJSON = true;
|
||||||
parsedPackageJSON.funding = {
|
parsedPackageJSON.funding = {
|
||||||
"type": "individual",
|
type: 'individual',
|
||||||
"url": "http://etherpad.org/"
|
url: 'http://etherpad.org/',
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
if(updatedPackageJSON){
|
if (updatedPackageJSON) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
fs.writeFileSync(pluginPath+"/package.json", JSON.stringify(parsedPackageJSON, null, 2));
|
fs.writeFileSync(`${pluginPath}/package.json`, JSON.stringify(parsedPackageJSON, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(packageJSON.toLowerCase().indexOf("repository") === -1){
|
if (packageJSON.toLowerCase().indexOf('repository') === -1) {
|
||||||
console.warn("No repository in package.json");
|
console.warn('No repository in package.json');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
console.warn("Repository not detected in package.json. Please add repository section manually.")
|
console.warn('Repository not detected in package.json. Please add repository section manually.');
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
// useful for creating README later.
|
// useful for creating README later.
|
||||||
repository = parsedPackageJSON.repository.url;
|
repository = parsedPackageJSON.repository.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// include lint config
|
// include lint config
|
||||||
if(packageJSON.toLowerCase().indexOf("devdependencies") === -1 || !parsedPackageJSON.devDependencies.eslint){
|
if (packageJSON.toLowerCase().indexOf('devdependencies') === -1 || !parsedPackageJSON.devDependencies.eslint) {
|
||||||
console.warn("Missing eslint reference in devDependencies");
|
console.warn('Missing eslint reference in devDependencies');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
let devDependencies = {
|
const devDependencies = {
|
||||||
"eslint": "^7.14.0",
|
'eslint': '^7.14.0',
|
||||||
"eslint-config-etherpad": "^1.0.10",
|
'eslint-config-etherpad': '^1.0.10',
|
||||||
"eslint-plugin-mocha": "^8.0.0",
|
'eslint-plugin-mocha': '^8.0.0',
|
||||||
"eslint-plugin-node": "^11.1.0",
|
'eslint-plugin-node': '^11.1.0',
|
||||||
"eslint-plugin-prefer-arrow": "^1.2.2",
|
'eslint-plugin-prefer-arrow': '^1.2.2',
|
||||||
"eslint-plugin-promise": "^4.2.1"
|
'eslint-plugin-promise': '^4.2.1',
|
||||||
}
|
};
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
parsedPackageJSON.devDependencies = devDependencies;
|
parsedPackageJSON.devDependencies = devDependencies;
|
||||||
fs.writeFileSync(pluginPath+"/package.json", JSON.stringify(parsedPackageJSON, null, 2));
|
fs.writeFileSync(`${pluginPath}/package.json`, JSON.stringify(parsedPackageJSON, null, 2));
|
||||||
|
|
||||||
let child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
try{
|
try {
|
||||||
child_process.execSync('npm install',{"cwd":pluginPath+"/"});
|
child_process.execSync('npm install', {cwd: `${pluginPath}/`});
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.error("Failed to create package-lock.json");
|
console.error('Failed to create package-lock.json');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(packageJSON.toLowerCase().indexOf("eslintconfig") === -1){
|
if (packageJSON.toLowerCase().indexOf('eslintconfig') === -1) {
|
||||||
console.warn("No esLintConfig in package.json");
|
console.warn('No esLintConfig in package.json');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
let eslintConfig = {
|
const eslintConfig = {
|
||||||
"root": true,
|
root: true,
|
||||||
"extends": "etherpad/plugin"
|
extends: 'etherpad/plugin',
|
||||||
}
|
};
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
parsedPackageJSON.eslintConfig = eslintConfig;
|
parsedPackageJSON.eslintConfig = eslintConfig;
|
||||||
fs.writeFileSync(pluginPath+"/package.json", JSON.stringify(parsedPackageJSON, null, 2));
|
fs.writeFileSync(`${pluginPath}/package.json`, JSON.stringify(parsedPackageJSON, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(packageJSON.toLowerCase().indexOf("scripts") === -1){
|
if (packageJSON.toLowerCase().indexOf('scripts') === -1) {
|
||||||
console.warn("No scripts in package.json");
|
console.warn('No scripts in package.json');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
let scripts = {
|
const scripts = {
|
||||||
"lint": "eslint .",
|
'lint': 'eslint .',
|
||||||
"lint:fix": "eslint --fix ."
|
'lint:fix': 'eslint --fix .',
|
||||||
}
|
};
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
parsedPackageJSON.scripts = scripts;
|
parsedPackageJSON.scripts = scripts;
|
||||||
fs.writeFileSync(pluginPath+"/package.json", JSON.stringify(parsedPackageJSON, null, 2));
|
fs.writeFileSync(`${pluginPath}/package.json`, JSON.stringify(parsedPackageJSON, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(packageJSON.toLowerCase().indexOf("engines") === -1){
|
if (packageJSON.toLowerCase().indexOf('engines') === -1) {
|
||||||
console.warn("No engines in package.json");
|
console.warn('No engines in package.json');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
let engines = {
|
const engines = {
|
||||||
"lint": "eslint ."
|
lint: 'eslint .',
|
||||||
}
|
};
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
parsedPackageJSON.engines = engines;
|
parsedPackageJSON.engines = engines;
|
||||||
fs.writeFileSync(pluginPath+"/package.json", JSON.stringify(parsedPackageJSON, null, 2));
|
fs.writeFileSync(`${pluginPath}/package.json`, JSON.stringify(parsedPackageJSON, null, 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("package-lock.json") === -1){
|
if (files.indexOf('package-lock.json') === -1) {
|
||||||
console.warn("package-lock.json file not found. Please run npm install in the plugin folder and commit the package-lock.json file.")
|
console.warn('package-lock.json file not found. Please run npm install in the plugin folder and commit the package-lock.json file.');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
var child_process = require('child_process');
|
var child_process = require('child_process');
|
||||||
try{
|
try {
|
||||||
child_process.execSync('npm install',{"cwd":pluginPath+"/"});
|
child_process.execSync('npm install', {cwd: `${pluginPath}/`});
|
||||||
console.log("Making package-lock.json");
|
console.log('Making package-lock.json');
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.error("Failed to create package-lock.json");
|
console.error('Failed to create package-lock.json');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("readme") === -1 && files.indexOf("readme.md") === -1){
|
if (files.indexOf('readme') === -1 && files.indexOf('readme.md') === -1) {
|
||||||
console.warn("README.md file not found, please create");
|
console.warn('README.md file not found, please create');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
console.log("Autofixing missing README.md file, please edit the README.md file further to include plugin specific details.");
|
console.log('Autofixing missing README.md file, please edit the README.md file further to include plugin specific details.');
|
||||||
let readme = fs.readFileSync("bin/plugins/lib/README.md", {encoding:'utf8', flag:'r'})
|
let readme = fs.readFileSync('bin/plugins/lib/README.md', {encoding: 'utf8', flag: 'r'});
|
||||||
readme = readme.replace(/\[plugin_name\]/g, pluginName);
|
readme = readme.replace(/\[plugin_name\]/g, pluginName);
|
||||||
if(repository){
|
if (repository) {
|
||||||
let org = repository.split("/")[3];
|
const org = repository.split('/')[3];
|
||||||
let name = repository.split("/")[4];
|
const name = repository.split('/')[4];
|
||||||
readme = readme.replace(/\[org_name\]/g, org);
|
readme = readme.replace(/\[org_name\]/g, org);
|
||||||
readme = readme.replace(/\[repo_url\]/g, name);
|
readme = readme.replace(/\[repo_url\]/g, name);
|
||||||
fs.writeFileSync(pluginPath+"/README.md", readme);
|
fs.writeFileSync(`${pluginPath}/README.md`, readme);
|
||||||
}else{
|
} else {
|
||||||
console.warn("Unable to find repository in package.json, aborting.")
|
console.warn('Unable to find repository in package.json, aborting.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("readme") !== -1 && files.indexOf("readme.md") !== -1){
|
if (files.indexOf('readme') !== -1 && files.indexOf('readme.md') !== -1) {
|
||||||
let readme = fs.readFileSync(pluginPath+"/"+readMeFileName, {encoding:'utf8', flag:'r'});
|
const readme = fs.readFileSync(`${pluginPath}/${readMeFileName}`, {encoding: 'utf8', flag: 'r'});
|
||||||
if(readme.toLowerCase().indexOf("license") === -1){
|
if (readme.toLowerCase().indexOf('license') === -1) {
|
||||||
console.warn("No license section in README");
|
console.warn('No license section in README');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
console.warn("Please add License section to README manually.")
|
console.warn('Please add License section to README manually.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("license") === -1 && files.indexOf("license.md") === -1){
|
if (files.indexOf('license') === -1 && files.indexOf('license.md') === -1) {
|
||||||
console.warn("LICENSE.md file not found, please create");
|
console.warn('LICENSE.md file not found, please create');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("Autofixing missing LICENSE.md file, including Apache 2 license.");
|
console.log('Autofixing missing LICENSE.md file, including Apache 2 license.');
|
||||||
exec("git config user.name", (error, name, stderr) => {
|
exec('git config user.name', (error, name, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log(`error: ${error.message}`);
|
console.log(`error: ${error.message}`);
|
||||||
return;
|
return;
|
||||||
|
@ -261,120 +260,118 @@ fs.readdir(pluginPath, function (err, rootFiles) {
|
||||||
console.log(`stderr: ${stderr}`);
|
console.log(`stderr: ${stderr}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let license = fs.readFileSync("bin/plugins/lib/LICENSE.md", {encoding:'utf8', flag:'r'});
|
let license = fs.readFileSync('bin/plugins/lib/LICENSE.md', {encoding: 'utf8', flag: 'r'});
|
||||||
license = license.replace("[yyyy]", new Date().getFullYear());
|
license = license.replace('[yyyy]', new Date().getFullYear());
|
||||||
license = license.replace("[name of copyright owner]", name)
|
license = license.replace('[name of copyright owner]', name);
|
||||||
fs.writeFileSync(pluginPath+"/LICENSE.md", license);
|
fs.writeFileSync(`${pluginPath}/LICENSE.md`, license);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var travisConfig = fs.readFileSync("bin/plugins/lib/travis.yml", {encoding:'utf8', flag:'r'});
|
let travisConfig = fs.readFileSync('bin/plugins/lib/travis.yml', {encoding: 'utf8', flag: 'r'});
|
||||||
travisConfig = travisConfig.replace(/\[plugin_name\]/g, pluginName);
|
travisConfig = travisConfig.replace(/\[plugin_name\]/g, pluginName);
|
||||||
|
|
||||||
if(files.indexOf(".travis.yml") === -1){
|
if (files.indexOf('.travis.yml') === -1) {
|
||||||
console.warn(".travis.yml file not found, please create. .travis.yml is used for automatically CI testing Etherpad. It is useful to know if your plugin breaks another feature for example.")
|
console.warn('.travis.yml file not found, please create. .travis.yml is used for automatically CI testing Etherpad. It is useful to know if your plugin breaks another feature for example.');
|
||||||
// TODO: Make it check version of the .travis file to see if it needs an update.
|
// TODO: Make it check version of the .travis file to see if it needs an update.
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("Autofixing missing .travis.yml file");
|
console.log('Autofixing missing .travis.yml file');
|
||||||
fs.writeFileSync(pluginPath+"/.travis.yml", travisConfig);
|
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||||
console.log("Travis file created, please sign into travis and enable this repository")
|
console.log('Travis file created, please sign into travis and enable this repository');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(autoFix && autoUpdate){
|
if (autoFix && autoUpdate) {
|
||||||
// checks the file versioning of .travis and updates it to the latest.
|
// checks the file versioning of .travis and updates it to the latest.
|
||||||
let existingConfig = fs.readFileSync(pluginPath + "/.travis.yml", {encoding:'utf8', flag:'r'});
|
const existingConfig = fs.readFileSync(`${pluginPath}/.travis.yml`, {encoding: 'utf8', flag: 'r'});
|
||||||
let existingConfigLocation = existingConfig.indexOf("##ETHERPAD_TRAVIS_V=");
|
const existingConfigLocation = existingConfig.indexOf('##ETHERPAD_TRAVIS_V=');
|
||||||
let existingValue = parseInt(existingConfig.substr(existingConfigLocation+20, existingConfig.length));
|
const existingValue = parseInt(existingConfig.substr(existingConfigLocation + 20, existingConfig.length));
|
||||||
|
|
||||||
let newConfigLocation = travisConfig.indexOf("##ETHERPAD_TRAVIS_V=");
|
const newConfigLocation = travisConfig.indexOf('##ETHERPAD_TRAVIS_V=');
|
||||||
let newValue = parseInt(travisConfig.substr(newConfigLocation+20, travisConfig.length));
|
const newValue = parseInt(travisConfig.substr(newConfigLocation + 20, travisConfig.length));
|
||||||
if(existingConfigLocation === -1){
|
if (existingConfigLocation === -1) {
|
||||||
console.warn("no previous .travis.yml version found so writing new.")
|
console.warn('no previous .travis.yml version found so writing new.');
|
||||||
// we will write the newTravisConfig to the location.
|
// we will write the newTravisConfig to the location.
|
||||||
fs.writeFileSync(pluginPath + "/.travis.yml", travisConfig);
|
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||||
}else{
|
} else if (newValue > existingValue) {
|
||||||
if(newValue > existingValue){
|
console.log('updating .travis.yml');
|
||||||
console.log("updating .travis.yml");
|
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||||
fs.writeFileSync(pluginPath + "/.travis.yml", travisConfig);
|
hasAutoFixed = true;
|
||||||
hasAutoFixed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf(".gitignore") === -1){
|
if (files.indexOf('.gitignore') === -1) {
|
||||||
console.warn(".gitignore file not found, please create. .gitignore files are useful to ensure files aren't incorrectly commited to a repository.")
|
console.warn(".gitignore file not found, please create. .gitignore files are useful to ensure files aren't incorrectly commited to a repository.");
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("Autofixing missing .gitignore file");
|
console.log('Autofixing missing .gitignore file');
|
||||||
let gitignore = fs.readFileSync("bin/plugins/lib/gitignore", {encoding:'utf8', flag:'r'});
|
const gitignore = fs.readFileSync('bin/plugins/lib/gitignore', {encoding: 'utf8', flag: 'r'});
|
||||||
fs.writeFileSync(pluginPath+"/.gitignore", gitignore);
|
fs.writeFileSync(`${pluginPath}/.gitignore`, gitignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we include templates but don't have translations...
|
// if we include templates but don't have translations...
|
||||||
if(files.indexOf("templates") !== -1 && files.indexOf("locales") === -1){
|
if (files.indexOf('templates') !== -1 && files.indexOf('locales') === -1) {
|
||||||
console.warn("Translations not found, please create. Translation files help with Etherpad accessibility.");
|
console.warn('Translations not found, please create. Translation files help with Etherpad accessibility.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(files.indexOf(".ep_initialized") !== -1){
|
if (files.indexOf('.ep_initialized') !== -1) {
|
||||||
console.warn(".ep_initialized found, please remove. .ep_initialized should never be commited to git and should only exist once the plugin has been executed one time.")
|
console.warn('.ep_initialized found, please remove. .ep_initialized should never be commited to git and should only exist once the plugin has been executed one time.');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("Autofixing incorrectly existing .ep_initialized file");
|
console.log('Autofixing incorrectly existing .ep_initialized file');
|
||||||
fs.unlinkSync(pluginPath+"/.ep_initialized");
|
fs.unlinkSync(`${pluginPath}/.ep_initialized`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("npm-debug.log") !== -1){
|
if (files.indexOf('npm-debug.log') !== -1) {
|
||||||
console.warn("npm-debug.log found, please remove. npm-debug.log should never be commited to your repository.")
|
console.warn('npm-debug.log found, please remove. npm-debug.log should never be commited to your repository.');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
console.log("Autofixing incorrectly existing npm-debug.log file");
|
console.log('Autofixing incorrectly existing npm-debug.log file');
|
||||||
fs.unlinkSync(pluginPath+"/npm-debug.log");
|
fs.unlinkSync(`${pluginPath}/npm-debug.log`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(files.indexOf("static") !== -1){
|
if (files.indexOf('static') !== -1) {
|
||||||
fs.readdir(pluginPath+"/static", function (errRead, staticFiles) {
|
fs.readdir(`${pluginPath}/static`, (errRead, staticFiles) => {
|
||||||
if(staticFiles.indexOf("tests") === -1){
|
if (staticFiles.indexOf('tests') === -1) {
|
||||||
console.warn("Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin")
|
console.warn('Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin');
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}else{
|
} else {
|
||||||
console.warn("Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin")
|
console.warn('Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin');
|
||||||
}
|
}
|
||||||
|
|
||||||
// linting begins
|
// linting begins
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
var lintCmd = 'npm run lint:fix';
|
var lintCmd = 'npm run lint:fix';
|
||||||
}else{
|
} else {
|
||||||
var lintCmd = 'npm run lint';
|
var lintCmd = 'npm run lint';
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
child_process.execSync(lintCmd,{"cwd":pluginPath+"/"});
|
child_process.execSync(lintCmd, {cwd: `${pluginPath}/`});
|
||||||
console.log("Linting...");
|
console.log('Linting...');
|
||||||
if(autoFix){
|
if (autoFix) {
|
||||||
// todo: if npm run lint doesn't do anything no need for...
|
// todo: if npm run lint doesn't do anything no need for...
|
||||||
hasAutoFixed = true;
|
hasAutoFixed = true;
|
||||||
}
|
}
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
// it is gonna throw an error anyway
|
// it is gonna throw an error anyway
|
||||||
console.log("Manual linting probably required, check with: npm run lint");
|
console.log('Manual linting probably required, check with: npm run lint');
|
||||||
}
|
}
|
||||||
// linting ends.
|
// linting ends.
|
||||||
|
|
||||||
if(hasAutoFixed){
|
if (hasAutoFixed) {
|
||||||
console.log("Fixes applied, please check git diff then run the following command:\n\n")
|
console.log('Fixes applied, please check git diff then run the following command:\n\n');
|
||||||
// bump npm Version
|
// bump npm Version
|
||||||
if(autoCommit){
|
if (autoCommit) {
|
||||||
// holy shit you brave.
|
// holy shit you brave.
|
||||||
console.log("Attempting autocommit and auto publish to npm")
|
console.log('Attempting autocommit and auto publish to npm');
|
||||||
// github should push to npm for us :)
|
// github should push to npm for us :)
|
||||||
exec("cd node_modules/"+ pluginName + " && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && git push && cd ../..", (error, name, stderr) => {
|
exec(`cd node_modules/${pluginName} && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && git push && cd ../..`, (error, name, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log(`error: ${error.message}`);
|
console.log(`error: ${error.message}`);
|
||||||
return;
|
return;
|
||||||
|
@ -383,14 +380,13 @@ fs.readdir(pluginPath, function (err, rootFiles) {
|
||||||
console.log(`stderr: ${stderr}`);
|
console.log(`stderr: ${stderr}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log("I think she's got it! By George she's got it!")
|
console.log("I think she's got it! By George she's got it!");
|
||||||
process.exit(0)
|
process.exit(0);
|
||||||
});
|
});
|
||||||
}else{
|
} else {
|
||||||
console.log("cd node_modules/"+ pluginName + " && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && npm version patch && git add package.json && git commit --allow-empty -m 'bump version' && git push && npm publish && cd ../..")
|
console.log(`cd node_modules/${pluginName} && git add -A && git commit --allow-empty -m 'autofixes from Etherpad checkPlugins.js' && npm version patch && git add package.json && git commit --allow-empty -m 'bump version' && git push && npm publish && cd ../..`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Finished");
|
console.log('Finished');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,120 +3,124 @@
|
||||||
known "good" revision.
|
known "good" revision.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(process.argv.length != 4 && process.argv.length != 5) {
|
if (process.argv.length != 4 && process.argv.length != 5) {
|
||||||
console.error("Use: node bin/repairPad.js $PADID $REV [$NEWPADID]");
|
console.error('Use: node bin/repairPad.js $PADID $REV [$NEWPADID]');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var npm = require("../src/node_modules/npm");
|
const npm = require('../src/node_modules/npm');
|
||||||
var async = require("../src/node_modules/async");
|
const async = require('../src/node_modules/async');
|
||||||
var ueberDB = require("../src/node_modules/ueberdb2");
|
const ueberDB = require('../src/node_modules/ueberdb2');
|
||||||
|
|
||||||
var padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
var newRevHead = process.argv[3];
|
const newRevHead = process.argv[3];
|
||||||
var newPadId = process.argv[4] || padId + "-rebuilt";
|
const newPadId = process.argv[4] || `${padId}-rebuilt`;
|
||||||
|
|
||||||
var db, oldPad, newPad, settings;
|
let db, oldPad, newPad, settings;
|
||||||
var AuthorManager, ChangeSet, Pad, PadManager;
|
let AuthorManager, ChangeSet, Pad, PadManager;
|
||||||
|
|
||||||
async.series([
|
async.series([
|
||||||
function(callback) {
|
function (callback) {
|
||||||
npm.load({}, function(err) {
|
npm.load({}, (err) => {
|
||||||
if(err) {
|
if (err) {
|
||||||
console.error("Could not load NPM: " + err)
|
console.error(`Could not load NPM: ${err}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
function(callback) {
|
function (callback) {
|
||||||
// Get a handle into the database
|
// Get a handle into the database
|
||||||
db = require('../src/node/db/DB');
|
db = require('../src/node/db/DB');
|
||||||
db.init(callback);
|
db.init(callback);
|
||||||
}, function(callback) {
|
},
|
||||||
PadManager = require('../src/node/db/PadManager');
|
function (callback) {
|
||||||
Pad = require('../src/node/db/Pad').Pad;
|
PadManager = require('../src/node/db/PadManager');
|
||||||
// Get references to the original pad and to a newly created pad
|
Pad = require('../src/node/db/Pad').Pad;
|
||||||
// HACK: This is a standalone script, so we want to write everything
|
// Get references to the original pad and to a newly created pad
|
||||||
// out to the database immediately. The only problem with this is
|
// HACK: This is a standalone script, so we want to write everything
|
||||||
// that a driver (like the mysql driver) can hardcode these values.
|
// out to the database immediately. The only problem with this is
|
||||||
db.db.db.settings = {cache: 0, writeInterval: 0, json: true};
|
// that a driver (like the mysql driver) can hardcode these values.
|
||||||
// Validate the newPadId if specified and that a pad with that ID does
|
db.db.db.settings = {cache: 0, writeInterval: 0, json: true};
|
||||||
// not already exist to avoid overwriting it.
|
// Validate the newPadId if specified and that a pad with that ID does
|
||||||
if (!PadManager.isValidPadId(newPadId)) {
|
// not already exist to avoid overwriting it.
|
||||||
console.error("Cannot create a pad with that id as it is invalid");
|
if (!PadManager.isValidPadId(newPadId)) {
|
||||||
process.exit(1);
|
console.error('Cannot create a pad with that id as it is invalid');
|
||||||
}
|
process.exit(1);
|
||||||
PadManager.doesPadExists(newPadId, function(err, exists) {
|
}
|
||||||
if (exists) {
|
PadManager.doesPadExists(newPadId, (err, exists) => {
|
||||||
console.error("Cannot create a pad with that id as it already exists");
|
if (exists) {
|
||||||
process.exit(1);
|
console.error('Cannot create a pad with that id as it already exists');
|
||||||
}
|
process.exit(1);
|
||||||
});
|
}
|
||||||
PadManager.getPad(padId, function(err, pad) {
|
});
|
||||||
oldPad = pad;
|
PadManager.getPad(padId, (err, pad) => {
|
||||||
newPad = new Pad(newPadId);
|
oldPad = pad;
|
||||||
callback();
|
newPad = new Pad(newPadId);
|
||||||
});
|
callback();
|
||||||
}, function(callback) {
|
});
|
||||||
|
},
|
||||||
|
function (callback) {
|
||||||
// Clone all Chat revisions
|
// Clone all Chat revisions
|
||||||
var chatHead = oldPad.chatHead;
|
const chatHead = oldPad.chatHead;
|
||||||
for(var i = 0, curHeadNum = 0; i <= chatHead; i++) {
|
for (var i = 0, curHeadNum = 0; i <= chatHead; i++) {
|
||||||
db.db.get("pad:" + padId + ":chat:" + i, function (err, chat) {
|
db.db.get(`pad:${padId}:chat:${i}`, (err, chat) => {
|
||||||
db.db.set("pad:" + newPadId + ":chat:" + curHeadNum++, chat);
|
db.db.set(`pad:${newPadId}:chat:${curHeadNum++}`, chat);
|
||||||
console.log("Created: Chat Revision: pad:" + newPadId + ":chat:" + curHeadNum);
|
console.log(`Created: Chat Revision: pad:${newPadId}:chat:${curHeadNum}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
}, function(callback) {
|
},
|
||||||
|
function (callback) {
|
||||||
// Rebuild Pad from revisions up to and including the new revision head
|
// Rebuild Pad from revisions up to and including the new revision head
|
||||||
AuthorManager = require("../src/node/db/AuthorManager");
|
AuthorManager = require('../src/node/db/AuthorManager');
|
||||||
Changeset = require("ep_etherpad-lite/static/js/Changeset");
|
Changeset = require('ep_etherpad-lite/static/js/Changeset');
|
||||||
// Author attributes are derived from changesets, but there can also be
|
// Author attributes are derived from changesets, but there can also be
|
||||||
// non-author attributes with specific mappings that changesets depend on
|
// non-author attributes with specific mappings that changesets depend on
|
||||||
// and, AFAICT, cannot be recreated any other way
|
// and, AFAICT, cannot be recreated any other way
|
||||||
newPad.pool.numToAttrib = oldPad.pool.numToAttrib;
|
newPad.pool.numToAttrib = oldPad.pool.numToAttrib;
|
||||||
for(var curRevNum = 0; curRevNum <= newRevHead; curRevNum++) {
|
for (let curRevNum = 0; curRevNum <= newRevHead; curRevNum++) {
|
||||||
db.db.get("pad:" + padId + ":revs:" + curRevNum, function(err, rev) {
|
db.db.get(`pad:${padId}:revs:${curRevNum}`, (err, rev) => {
|
||||||
if (rev.meta) {
|
if (rev.meta) {
|
||||||
throw "The specified revision number could not be found.";
|
throw 'The specified revision number could not be found.';
|
||||||
}
|
}
|
||||||
var newRevNum = ++newPad.head;
|
const newRevNum = ++newPad.head;
|
||||||
var newRevId = "pad:" + newPad.id + ":revs:" + newRevNum;
|
const newRevId = `pad:${newPad.id}:revs:${newRevNum}`;
|
||||||
db.db.set(newRevId, rev);
|
db.db.set(newRevId, rev);
|
||||||
AuthorManager.addPad(rev.meta.author, newPad.id);
|
AuthorManager.addPad(rev.meta.author, newPad.id);
|
||||||
newPad.atext = Changeset.applyToAText(rev.changeset, newPad.atext, newPad.pool);
|
newPad.atext = Changeset.applyToAText(rev.changeset, newPad.atext, newPad.pool);
|
||||||
console.log("Created: Revision: pad:" + newPad.id + ":revs:" + newRevNum);
|
console.log(`Created: Revision: pad:${newPad.id}:revs:${newRevNum}`);
|
||||||
if (newRevNum == newRevHead) {
|
if (newRevNum == newRevHead) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, function(callback) {
|
},
|
||||||
|
function (callback) {
|
||||||
// Add saved revisions up to the new revision head
|
// Add saved revisions up to the new revision head
|
||||||
console.log(newPad.head);
|
console.log(newPad.head);
|
||||||
var newSavedRevisions = [];
|
const newSavedRevisions = [];
|
||||||
for(var i in oldPad.savedRevisions) {
|
for (const i in oldPad.savedRevisions) {
|
||||||
savedRev = oldPad.savedRevisions[i]
|
savedRev = oldPad.savedRevisions[i];
|
||||||
if (savedRev.revNum <= newRevHead) {
|
if (savedRev.revNum <= newRevHead) {
|
||||||
newSavedRevisions.push(savedRev);
|
newSavedRevisions.push(savedRev);
|
||||||
console.log("Added: Saved Revision: " + savedRev.revNum);
|
console.log(`Added: Saved Revision: ${savedRev.revNum}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newPad.savedRevisions = newSavedRevisions;
|
newPad.savedRevisions = newSavedRevisions;
|
||||||
callback();
|
callback();
|
||||||
}, function(callback) {
|
},
|
||||||
|
function (callback) {
|
||||||
// Save the source pad
|
// Save the source pad
|
||||||
db.db.set("pad:"+newPadId, newPad, function(err) {
|
db.db.set(`pad:${newPadId}`, newPad, (err) => {
|
||||||
console.log("Created: Source Pad: pad:" + newPadId);
|
console.log(`Created: Source Pad: pad:${newPadId}`);
|
||||||
newPad.saveToDatabase().then(() => callback(), callback);
|
newPad.saveToDatabase().then(() => callback(), callback);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
], function (err) {
|
], (err) => {
|
||||||
if(err) throw err;
|
if (err) { throw err; } else {
|
||||||
else {
|
console.info('finished');
|
||||||
console.info("finished");
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,47 +2,47 @@
|
||||||
* This is a repair tool. It extracts all datas of a pad, removes and inserts them again.
|
* This is a repair tool. It extracts all datas of a pad, removes and inserts them again.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
console.warn("WARNING: This script must not be used while etherpad is running!");
|
console.warn('WARNING: This script must not be used while etherpad is running!');
|
||||||
|
|
||||||
if (process.argv.length != 3) {
|
if (process.argv.length != 3) {
|
||||||
console.error("Use: node bin/repairPad.js $PADID");
|
console.error('Use: node bin/repairPad.js $PADID');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the padID
|
// get the padID
|
||||||
var padId = process.argv[2];
|
const padId = process.argv[2];
|
||||||
|
|
||||||
let npm = require("../src/node_modules/npm");
|
const npm = require('../src/node_modules/npm');
|
||||||
npm.load({}, async function(er) {
|
npm.load({}, async (er) => {
|
||||||
if (er) {
|
if (er) {
|
||||||
console.error("Could not load NPM: " + er)
|
console.error(`Could not load NPM: ${er}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// intialize database
|
// intialize database
|
||||||
let settings = require('../src/node/utils/Settings');
|
const settings = require('../src/node/utils/Settings');
|
||||||
let db = require('../src/node/db/DB');
|
const db = require('../src/node/db/DB');
|
||||||
await db.init();
|
await db.init();
|
||||||
|
|
||||||
// get the pad
|
// get the pad
|
||||||
let padManager = require('../src/node/db/PadManager');
|
const padManager = require('../src/node/db/PadManager');
|
||||||
let pad = await padManager.getPad(padId);
|
const pad = await padManager.getPad(padId);
|
||||||
|
|
||||||
// accumulate the required keys
|
// accumulate the required keys
|
||||||
let neededDBValues = ["pad:" + padId];
|
const neededDBValues = [`pad:${padId}`];
|
||||||
|
|
||||||
// add all authors
|
// add all authors
|
||||||
neededDBValues.push(...pad.getAllAuthors().map(author => "globalAuthor:"));
|
neededDBValues.push(...pad.getAllAuthors().map((author) => 'globalAuthor:'));
|
||||||
|
|
||||||
// add all revisions
|
// add all revisions
|
||||||
for (let rev = 0; rev <= pad.head; ++rev) {
|
for (let rev = 0; rev <= pad.head; ++rev) {
|
||||||
neededDBValues.push("pad:" + padId + ":revs:" + rev);
|
neededDBValues.push(`pad:${padId}:revs:${rev}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all chat values
|
// add all chat values
|
||||||
for (let chat = 0; chat <= pad.chatHead; ++chat) {
|
for (let chat = 0; chat <= pad.chatHead; ++chat) {
|
||||||
neededDBValues.push("pad:" + padId + ":chat:" + chat);
|
neededDBValues.push(`pad:${padId}:chat:${chat}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -55,21 +55,20 @@ npm.load({}, async function(er) {
|
||||||
//
|
//
|
||||||
// See gitlab issue #3545
|
// See gitlab issue #3545
|
||||||
//
|
//
|
||||||
console.info("aborting [gitlab #3545]");
|
console.info('aborting [gitlab #3545]');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|
||||||
// now fetch and reinsert every key
|
// now fetch and reinsert every key
|
||||||
neededDBValues.forEach(function(key, value) {
|
neededDBValues.forEach((key, value) => {
|
||||||
console.log("Key: " + key+ ", value: " + value);
|
console.log(`Key: ${key}, value: ${value}`);
|
||||||
db.remove(key);
|
db.remove(key);
|
||||||
db.set(key, value);
|
db.set(key, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.info("finished");
|
console.info('finished');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|
||||||
} catch (er) {
|
} catch (er) {
|
||||||
if (er.name === "apierror") {
|
if (er.name === 'apierror') {
|
||||||
console.error(er);
|
console.error(er);
|
||||||
} else {
|
} else {
|
||||||
console.trace(er);
|
console.trace(er);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global __dirname, exports, require */
|
/* global __dirname, exports, require */
|
||||||
|
|
||||||
function m(mod) { return __dirname + '/../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../src/${mod}`; }
|
||||||
|
|
||||||
const apiHandler = require(m('node/handler/APIHandler'));
|
const apiHandler = require(m('node/handler/APIHandler'));
|
||||||
const log4js = require(m('node_modules/log4js'));
|
const log4js = require(m('node_modules/log4js'));
|
||||||
|
@ -25,7 +25,7 @@ const logLevel = exports.logger.level;
|
||||||
// https://github.com/mochajs/mocha/issues/2640
|
// https://github.com/mochajs/mocha/issues/2640
|
||||||
process.on('unhandledRejection', (reason, promise) => { throw reason; });
|
process.on('unhandledRejection', (reason, promise) => { throw reason; });
|
||||||
|
|
||||||
exports.init = async function() {
|
exports.init = async function () {
|
||||||
if (inited) return exports.agent;
|
if (inited) return exports.agent;
|
||||||
inited = true;
|
inited = true;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ exports.init = async function() {
|
||||||
backups.authnFailureDelayMs = webaccess.authnFailureDelayMs;
|
backups.authnFailureDelayMs = webaccess.authnFailureDelayMs;
|
||||||
webaccess.authnFailureDelayMs = 0;
|
webaccess.authnFailureDelayMs = 0;
|
||||||
|
|
||||||
after(async function() {
|
after(async function () {
|
||||||
webaccess.authnFailureDelayMs = backups.authnFailureDelayMs;
|
webaccess.authnFailureDelayMs = backups.authnFailureDelayMs;
|
||||||
await server.stop();
|
await server.stop();
|
||||||
// Note: This does not unset settings that were added.
|
// Note: This does not unset settings that were added.
|
||||||
|
|
|
@ -3,44 +3,44 @@
|
||||||
* Usage: node fuzzImportTest.js
|
* Usage: node fuzzImportTest.js
|
||||||
*/
|
*/
|
||||||
const common = require('./common');
|
const common = require('./common');
|
||||||
const settings = require(__dirname+'/loadSettings').loadSettings();
|
const settings = require(`${__dirname}/loadSettings`).loadSettings();
|
||||||
const host = "http://" + settings.ip + ":" + settings.port;
|
const host = `http://${settings.ip}:${settings.port}`;
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
const froth = require('mocha-froth');
|
const froth = require('mocha-froth');
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
const apiVersion = 1;
|
||||||
var testPadId = "TEST_fuzz" + makeid();
|
const testPadId = `TEST_fuzz${makeid()}`;
|
||||||
|
|
||||||
var endPoint = function(point, version){
|
const endPoint = function (point, version) {
|
||||||
version = version || apiVersion;
|
version = version || apiVersion;
|
||||||
return '/api/'+version+'/'+point+'?apikey='+apiKey;
|
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
console.log("Testing against padID", testPadId);
|
console.log('Testing against padID', testPadId);
|
||||||
console.log("To watch the test live visit " + host + "/p/" + testPadId);
|
console.log(`To watch the test live visit ${host}/p/${testPadId}`);
|
||||||
console.log("Tests will start in 5 seconds, click the URL now!");
|
console.log('Tests will start in 5 seconds, click the URL now!');
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(() => {
|
||||||
for (let i=1; i<1000000; i++) { // 1M runs
|
for (let i = 1; i < 1000000; i++) { // 1M runs
|
||||||
setTimeout( function timer(){
|
setTimeout(() => {
|
||||||
runTest(i);
|
runTest(i);
|
||||||
}, i*100 ); // 100 ms
|
}, i * 100); // 100 ms
|
||||||
}
|
}
|
||||||
},5000); // wait 5 seconds
|
}, 5000); // wait 5 seconds
|
||||||
|
|
||||||
function runTest(number){
|
function runTest(number) {
|
||||||
request(host + endPoint('createPad') + '&padID=' + testPadId, function(err, res, body){
|
request(`${host + endPoint('createPad')}&padID=${testPadId}`, (err, res, body) => {
|
||||||
var req = request.post(host + '/p/'+testPadId+'/import', function (err, res, body) {
|
const req = request.post(`${host}/p/${testPadId}/import`, (err, res, body) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw new Error("FAILURE", err);
|
throw new Error('FAILURE', err);
|
||||||
}else{
|
} else {
|
||||||
console.log("Success");
|
console.log('Success');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var fN = '/test.txt';
|
let fN = '/test.txt';
|
||||||
var cT = 'text/plain';
|
let cT = 'text/plain';
|
||||||
|
|
||||||
// To be more agressive every other test we mess with Etherpad
|
// To be more agressive every other test we mess with Etherpad
|
||||||
// We provide a weird file name and also set a weird contentType
|
// We provide a weird file name and also set a weird contentType
|
||||||
|
@ -49,23 +49,20 @@ function runTest(number){
|
||||||
cT = froth().toString();
|
cT = froth().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
let form = req.form();
|
const form = req.form();
|
||||||
form.append('file', froth().toString(), {
|
form.append('file', froth().toString(), {
|
||||||
filename: fN,
|
filename: fN,
|
||||||
contentType: cT
|
contentType: cT,
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 5; i++ ){
|
for (let i = 0; i < 5; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,23 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const supertest = require(__dirname + '/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const settings = require(__dirname + '/../../../../src/node/utils/Settings');
|
const settings = require(`${__dirname}/../../../../src/node/utils/Settings`);
|
||||||
const api = supertest('http://' + settings.ip + ':' + settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
var validateOpenAPI = require(__dirname + '/../../../../src/node_modules/openapi-schema-validation').validate;
|
const validateOpenAPI = require(`${__dirname}/../../../../src/node_modules/openapi-schema-validation`).validate;
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
let apiVersion = 1;
|
||||||
|
|
||||||
var testPadId = makeid();
|
const testPadId = makeid();
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('API Versioning', function() {
|
describe('API Versioning', function () {
|
||||||
it('errors if can not connect', function(done) {
|
it('errors if can not connect', function (done) {
|
||||||
api
|
api
|
||||||
.get('/api/')
|
.get('/api/')
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
apiVersion = res.body.currentVersion;
|
apiVersion = res.body.currentVersion;
|
||||||
if (!res.body.currentVersion) throw new Error('No version set in API');
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
|
@ -32,12 +32,12 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('OpenAPI definition', function() {
|
describe('OpenAPI definition', function () {
|
||||||
it('generates valid openapi definition document', function(done) {
|
it('generates valid openapi definition document', function (done) {
|
||||||
api
|
api
|
||||||
.get('/api/openapi.json')
|
.get('/api/openapi.json')
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
const { valid, errors } = validateOpenAPI(res.body, 3);
|
const {valid, errors} = validateOpenAPI(res.body, 3);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
const prettyErrors = JSON.stringify(errors, null, 2);
|
const prettyErrors = JSON.stringify(errors, null, 2);
|
||||||
throw new Error(`Document is not valid OpenAPI. ${errors.length} validation errors:\n${prettyErrors}`);
|
throw new Error(`Document is not valid OpenAPI. ${errors.length} validation errors:\n${prettyErrors}`);
|
||||||
|
@ -48,11 +48,11 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('jsonp support', function() {
|
describe('jsonp support', function () {
|
||||||
it('supports jsonp calls', function(done) {
|
it('supports jsonp calls', function (done) {
|
||||||
api
|
api
|
||||||
.get(endPoint('createPad') + '&jsonp=jsonp_1&padID=' + testPadId)
|
.get(`${endPoint('createPad')}&jsonp=jsonp_1&padID=${testPadId}`)
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
if (!res.text.match('jsonp_1')) throw new Error('no jsonp call seen');
|
if (!res.text.match('jsonp_1')) throw new Error('no jsonp call seen');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /javascript/)
|
.expect('Content-Type', /javascript/)
|
||||||
|
@ -61,15 +61,15 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var endPoint = function(point) {
|
var endPoint = function (point) {
|
||||||
return '/api/' + apiVersion + '/' + point + '?apikey=' + apiKey;
|
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = '';
|
let text = '';
|
||||||
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for (var i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|
|
@ -5,86 +5,86 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const supertest = require(__dirname+'/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const settings = require(__dirname + '/../../../../src/node/utils/Settings');
|
const settings = require(`${__dirname}/../../../../src/node/utils/Settings`);
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
let apiVersion = 1;
|
||||||
var testPadId = makeid();
|
const testPadId = makeid();
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('Connectivity For Character Encoding', function() {
|
describe('Connectivity For Character Encoding', function () {
|
||||||
it('can connect', function(done) {
|
it('can connect', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('API Versioning', function() {
|
describe('API Versioning', function () {
|
||||||
it('finds the version tag', function(done) {
|
it('finds the version tag', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
apiVersion = res.body.currentVersion;
|
apiVersion = res.body.currentVersion;
|
||||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('Permission', function() {
|
describe('Permission', function () {
|
||||||
it('errors with invalid APIKey', function(done) {
|
it('errors with invalid APIKey', function (done) {
|
||||||
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343
|
// This is broken because Etherpad doesn't handle HTTP codes properly see #2343
|
||||||
// If your APIKey is password you deserve to fail all tests anyway
|
// If your APIKey is password you deserve to fail all tests anyway
|
||||||
var permErrorURL = '/api/'+apiVersion+'/createPad?apikey=password&padID=test';
|
const permErrorURL = `/api/${apiVersion}/createPad?apikey=password&padID=test`;
|
||||||
api.get(permErrorURL)
|
api.get(permErrorURL)
|
||||||
.expect(401, done)
|
.expect(401, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('createPad', function() {
|
describe('createPad', function () {
|
||||||
it('creates a new Pad', function(done) {
|
it('creates a new Pad', function (done) {
|
||||||
api.get(endPoint('createPad')+"&padID="+testPadId)
|
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Unable to create new Pad");
|
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('setHTML', function() {
|
describe('setHTML', function () {
|
||||||
it('Sets the HTML of a Pad attempting to weird utf8 encoded content', function(done) {
|
it('Sets the HTML of a Pad attempting to weird utf8 encoded content', function (done) {
|
||||||
fs.readFile('../tests/backend/specs/api/emojis.html', 'utf8', function(err, html) {
|
fs.readFile('../tests/backend/specs/api/emojis.html', 'utf8', (err, html) => {
|
||||||
api.post(endPoint('setHTML'))
|
api.post(endPoint('setHTML'))
|
||||||
.send({
|
.send({
|
||||||
"padID": testPadId,
|
padID: testPadId,
|
||||||
"html": html,
|
html,
|
||||||
})
|
})
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Can't set HTML properly");
|
if (res.body.code !== 0) throw new Error("Can't set HTML properly");
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done);
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('getHTML', function() {
|
describe('getHTML', function () {
|
||||||
it('get the HTML of Pad with emojis', function(done) {
|
it('get the HTML of Pad with emojis', function (done) {
|
||||||
api.get(endPoint('getHTML')+"&padID="+testPadId)
|
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if (res.body.data.html.indexOf("🇼") === -1) {
|
if (res.body.data.html.indexOf('🇼') === -1) {
|
||||||
throw new Error("Unable to get the HTML");
|
throw new Error('Unable to get the HTML');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -93,16 +93,16 @@ describe(__filename, function() {
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var endPoint = function(point, version){
|
var endPoint = function (point, version) {
|
||||||
version = version || apiVersion;
|
version = version || apiVersion;
|
||||||
return '/api/'+version+'/'+point+'?apikey='+apiKey;
|
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 10; i++ ){
|
for (let i = 0; i < 10; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
function m(mod) { return __dirname + '/../../../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../../../src/${mod}`; }
|
||||||
|
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const settings = require(m('node/utils/Settings'));
|
const settings = require(m('node/utils/Settings'));
|
||||||
|
@ -6,27 +6,27 @@ const supertest = require(m('node_modules/supertest'));
|
||||||
|
|
||||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
let apiVersion = 1;
|
||||||
var authorID = "";
|
let authorID = '';
|
||||||
var padID = makeid();
|
const padID = makeid();
|
||||||
var timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('API Versioning', function(){
|
describe('API Versioning', function () {
|
||||||
it('errors if can not connect', function(done) {
|
it('errors if can not connect', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
apiVersion = res.body.currentVersion;
|
apiVersion = res.body.currentVersion;
|
||||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
// BEGIN GROUP AND AUTHOR TESTS
|
// BEGIN GROUP AND AUTHOR TESTS
|
||||||
/////////////////////////////////////
|
// ///////////////////////////////////
|
||||||
/////////////////////////////////////
|
// ///////////////////////////////////
|
||||||
|
|
||||||
/* Tests performed
|
/* Tests performed
|
||||||
-> createPad(padID)
|
-> createPad(padID)
|
||||||
|
@ -36,76 +36,76 @@ describe(__filename, function() {
|
||||||
-> getChatHistory(padID)
|
-> getChatHistory(padID)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
describe('createPad', function(){
|
describe('createPad', function () {
|
||||||
it('creates a new Pad', function(done) {
|
it('creates a new Pad', function (done) {
|
||||||
api.get(endPoint('createPad')+"&padID="+padID)
|
api.get(`${endPoint('createPad')}&padID=${padID}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Unable to create new Pad");
|
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('createAuthor', function(){
|
describe('createAuthor', function () {
|
||||||
it('Creates an author with a name set', function(done) {
|
it('Creates an author with a name set', function (done) {
|
||||||
api.get(endPoint('createAuthor'))
|
api.get(endPoint('createAuthor'))
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.code !== 0 || !res.body.data.authorID) throw new Error("Unable to create author");
|
if (res.body.code !== 0 || !res.body.data.authorID) throw new Error('Unable to create author');
|
||||||
authorID = res.body.data.authorID; // we will be this author for the rest of the tests
|
authorID = res.body.data.authorID; // we will be this author for the rest of the tests
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('appendChatMessage', function(){
|
describe('appendChatMessage', function () {
|
||||||
it('Adds a chat message to the pad', function(done) {
|
it('Adds a chat message to the pad', function (done) {
|
||||||
api.get(endPoint('appendChatMessage')+"&padID="+padID+"&text=blalblalbha&authorID="+authorID+"&time="+timestamp)
|
api.get(`${endPoint('appendChatMessage')}&padID=${padID}&text=blalblalbha&authorID=${authorID}&time=${timestamp}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Unable to create chat message");
|
if (res.body.code !== 0) throw new Error('Unable to create chat message');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('getChatHead', function(){
|
describe('getChatHead', function () {
|
||||||
it('Gets the head of chat', function(done) {
|
it('Gets the head of chat', function (done) {
|
||||||
api.get(endPoint('getChatHead')+"&padID="+padID)
|
api.get(`${endPoint('getChatHead')}&padID=${padID}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.data.chatHead !== 0) throw new Error("Chat Head Length is wrong");
|
if (res.body.data.chatHead !== 0) throw new Error('Chat Head Length is wrong');
|
||||||
|
|
||||||
if(res.body.code !== 0) throw new Error("Unable to get chat head");
|
if (res.body.code !== 0) throw new Error('Unable to get chat head');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('getChatHistory', function(){
|
describe('getChatHistory', function () {
|
||||||
it('Gets Chat History of a Pad', function(done) {
|
it('Gets Chat History of a Pad', function (done) {
|
||||||
api.get(endPoint('getChatHistory')+"&padID="+padID)
|
api.get(`${endPoint('getChatHistory')}&padID=${padID}`)
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if(res.body.data.messages.length !== 1) throw new Error("Chat History Length is wrong");
|
if (res.body.data.messages.length !== 1) throw new Error('Chat History Length is wrong');
|
||||||
if(res.body.code !== 0) throw new Error("Unable to get chat history");
|
if (res.body.code !== 0) throw new Error('Unable to get chat history');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var endPoint = function(point){
|
var endPoint = function (point) {
|
||||||
return '/api/'+apiVersion+'/'+point+'?apikey='+apiKey;
|
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 5; i++ ){
|
for (let i = 0; i < 5; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|
|
@ -6,39 +6,39 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const supertest = require(__dirname+'/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const settings = require(__dirname+'/../../../../tests/container/loadSettings.js').loadSettings();
|
const settings = require(`${__dirname}/../../../../tests/container/loadSettings.js`).loadSettings();
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
const apiVersion = 1;
|
||||||
var lastEdited = "";
|
const lastEdited = '';
|
||||||
|
|
||||||
var testImports = {
|
const testImports = {
|
||||||
"malformed": {
|
'malformed': {
|
||||||
input: '<html><body><li>wtf</ul></body></html>',
|
input: '<html><body><li>wtf</ul></body></html>',
|
||||||
expectedHTML: '<!DOCTYPE HTML><html><body>wtf<br><br></body></html>',
|
expectedHTML: '<!DOCTYPE HTML><html><body>wtf<br><br></body></html>',
|
||||||
expectedText: 'wtf\n\n'
|
expectedText: 'wtf\n\n',
|
||||||
},
|
},
|
||||||
"nonelistiteminlist #3620":{
|
'nonelistiteminlist #3620': {
|
||||||
input: '<html><body><ul>test<li>FOO</li></ul></body></html>',
|
input: '<html><body><ul>test<li>FOO</li></ul></body></html>',
|
||||||
expectedHTML: '<!DOCTYPE HTML><html><body><ul class="bullet">test<li>FOO</ul><br></body></html>',
|
expectedHTML: '<!DOCTYPE HTML><html><body><ul class="bullet">test<li>FOO</ul><br></body></html>',
|
||||||
expectedText: '\ttest\n\t* FOO\n\n'
|
expectedText: '\ttest\n\t* FOO\n\n',
|
||||||
},
|
},
|
||||||
"whitespaceinlist #3620":{
|
'whitespaceinlist #3620': {
|
||||||
input: '<html><body><ul> <li>FOO</li></ul></body></html>',
|
input: '<html><body><ul> <li>FOO</li></ul></body></html>',
|
||||||
expectedHTML: '<!DOCTYPE HTML><html><body><ul class="bullet"><li>FOO</ul><br></body></html>',
|
expectedHTML: '<!DOCTYPE HTML><html><body><ul class="bullet"><li>FOO</ul><br></body></html>',
|
||||||
expectedText: '\t* FOO\n\n'
|
expectedText: '\t* FOO\n\n',
|
||||||
},
|
},
|
||||||
"prefixcorrectlinenumber":{
|
'prefixcorrectlinenumber': {
|
||||||
input: '<html><body><ol><li>should be 1</li><li>should be 2</li></ol></body></html>',
|
input: '<html><body><ol><li>should be 1</li><li>should be 2</li></ol></body></html>',
|
||||||
expectedHTML: '<!DOCTYPE HTML><html><body><ol start="1" class="number"><li>should be 1</li><li>should be 2</ol><br></body></html>',
|
expectedHTML: '<!DOCTYPE HTML><html><body><ol start="1" class="number"><li>should be 1</li><li>should be 2</ol><br></body></html>',
|
||||||
expectedText: '\t1. should be 1\n\t2. should be 2\n\n'
|
expectedText: '\t1. should be 1\n\t2. should be 2\n\n',
|
||||||
},
|
},
|
||||||
"prefixcorrectlinenumbernested":{
|
'prefixcorrectlinenumbernested': {
|
||||||
input: '<html><body><ol><li>should be 1</li><ol><li>foo</li></ol><li>should be 2</li></ol></body></html>',
|
input: '<html><body><ol><li>should be 1</li><ol><li>foo</li></ol><li>should be 2</li></ol></body></html>',
|
||||||
expectedHTML: '<!DOCTYPE HTML><html><body><ol start="1" class="number"><li>should be 1<ol start="2" class="number"><li>foo</ol><li>should be 2</ol><br></body></html>',
|
expectedHTML: '<!DOCTYPE HTML><html><body><ol start="1" class="number"><li>should be 1<ol start="2" class="number"><li>foo</ol><li>should be 2</ol><br></body></html>',
|
||||||
expectedText: '\t1. should be 1\n\t\t1.1. foo\n\t2. should be 2\n\n'
|
expectedText: '\t1. should be 1\n\t\t1.1. foo\n\t2. should be 2\n\n',
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -54,39 +54,39 @@ var testImports = {
|
||||||
expectedText: '\t1. should be 1\n\ttest\n\t2. should be 2\n\n'
|
expectedText: '\t1. should be 1\n\ttest\n\t2. should be 2\n\n'
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
};
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
Object.keys(testImports).forEach(function(testName) {
|
Object.keys(testImports).forEach((testName) => {
|
||||||
var testPadId = makeid();
|
const testPadId = makeid();
|
||||||
test = testImports[testName];
|
test = testImports[testName];
|
||||||
describe('createPad', function() {
|
describe('createPad', function () {
|
||||||
it('creates a new Pad', function(done) {
|
it('creates a new Pad', function (done) {
|
||||||
api.get(endPoint('createPad') + "&padID=" + testPadId)
|
api.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Unable to create new Pad");
|
if (res.body.code !== 0) throw new Error('Unable to create new Pad');
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('setHTML', function() {
|
describe('setHTML', function () {
|
||||||
it('Sets the HTML', function(done) {
|
it('Sets the HTML', function (done) {
|
||||||
api.get(endPoint('setHTML') + "&padID=" + testPadId + "&html=" + test.input)
|
api.get(`${endPoint('setHTML')}&padID=${testPadId}&html=${test.input}`)
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
if(res.body.code !== 0) throw new Error("Error:" + testName)
|
if (res.body.code !== 0) throw new Error(`Error:${testName}`);
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('getHTML', function() {
|
describe('getHTML', function () {
|
||||||
it('Gets back the HTML of a Pad', function(done) {
|
it('Gets back the HTML of a Pad', function (done) {
|
||||||
api.get(endPoint('getHTML') + "&padID=" + testPadId)
|
api.get(`${endPoint('getHTML')}&padID=${testPadId}`)
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
var receivedHtml = res.body.data.html;
|
const receivedHtml = res.body.data.html;
|
||||||
if (receivedHtml !== test.expectedHTML) {
|
if (receivedHtml !== test.expectedHTML) {
|
||||||
throw new Error(`HTML received from export is not the one we were expecting.
|
throw new Error(`HTML received from export is not the one we were expecting.
|
||||||
Test Name:
|
Test Name:
|
||||||
|
@ -103,15 +103,15 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('getText', function() {
|
describe('getText', function () {
|
||||||
it('Gets back the Text of a Pad', function(done) {
|
it('Gets back the Text of a Pad', function (done) {
|
||||||
api.get(endPoint('getText') + "&padID=" + testPadId)
|
api.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
var receivedText = res.body.data.text;
|
const receivedText = res.body.data.text;
|
||||||
if (receivedText !== test.expectedText) {
|
if (receivedText !== test.expectedText) {
|
||||||
throw new Error(`Text received from export is not the one we were expecting.
|
throw new Error(`Text received from export is not the one we were expecting.
|
||||||
Test Name:
|
Test Name:
|
||||||
|
@ -128,33 +128,33 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var endPoint = function(point, version){
|
var endPoint = function (point, version) {
|
||||||
version = version || apiVersion;
|
version = version || apiVersion;
|
||||||
return '/api/'+version+'/'+point+'?apikey='+apiKey;
|
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 5; i++ ){
|
for (let i = 0; i < 5; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLongText(){
|
function generateLongText() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 80000; i++ ){
|
for (let i = 0; i < 80000; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
@ -162,22 +162,19 @@ function generateLongText(){
|
||||||
|
|
||||||
// Need this to compare arrays (listSavedRevisions test)
|
// Need this to compare arrays (listSavedRevisions test)
|
||||||
Array.prototype.equals = function (array) {
|
Array.prototype.equals = function (array) {
|
||||||
// if the other array is a falsy value, return
|
// if the other array is a falsy value, return
|
||||||
if (!array)
|
if (!array) return false;
|
||||||
return false;
|
// compare lengths - can save a lot of time
|
||||||
// compare lengths - can save a lot of time
|
if (this.length != array.length) return false;
|
||||||
if (this.length != array.length)
|
for (let i = 0, l = this.length; i < l; i++) {
|
||||||
return false;
|
// Check if we have nested arrays
|
||||||
for (var i = 0, l=this.length; i < l; i++) {
|
if (this[i] instanceof Array && array[i] instanceof Array) {
|
||||||
// Check if we have nested arrays
|
// recurse into the nested arrays
|
||||||
if (this[i] instanceof Array && array[i] instanceof Array) {
|
if (!this[i].equals(array[i])) return false;
|
||||||
// recurse into the nested arrays
|
} else if (this[i] != array[i]) {
|
||||||
if (!this[i].equals(array[i]))
|
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
||||||
return false;
|
return false;
|
||||||
} else if (this[i] != array[i]) {
|
|
||||||
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
}
|
return true;
|
||||||
|
};
|
||||||
|
|
|
@ -6,38 +6,38 @@
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const superagent = require(__dirname+'/../../../../src/node_modules/superagent');
|
const superagent = require(`${__dirname}/../../../../src/node_modules/superagent`);
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const settings = require(__dirname+'/../../../../src/node/utils/Settings');
|
const settings = require(`${__dirname}/../../../../src/node/utils/Settings`);
|
||||||
const padManager = require(__dirname+'/../../../../src/node/db/PadManager');
|
const padManager = require(`${__dirname}/../../../../src/node/db/PadManager`);
|
||||||
const plugins = require(__dirname+'/../../../../src/static/js/pluginfw/plugin_defs');
|
const plugins = require(`${__dirname}/../../../../src/static/js/pluginfw/plugin_defs`);
|
||||||
|
|
||||||
const padText = fs.readFileSync("../tests/backend/specs/api/test.txt");
|
const padText = fs.readFileSync('../tests/backend/specs/api/test.txt');
|
||||||
const etherpadDoc = fs.readFileSync("../tests/backend/specs/api/test.etherpad");
|
const etherpadDoc = fs.readFileSync('../tests/backend/specs/api/test.etherpad');
|
||||||
const wordDoc = fs.readFileSync("../tests/backend/specs/api/test.doc");
|
const wordDoc = fs.readFileSync('../tests/backend/specs/api/test.doc');
|
||||||
const wordXDoc = fs.readFileSync("../tests/backend/specs/api/test.docx");
|
const wordXDoc = fs.readFileSync('../tests/backend/specs/api/test.docx');
|
||||||
const odtDoc = fs.readFileSync("../tests/backend/specs/api/test.odt");
|
const odtDoc = fs.readFileSync('../tests/backend/specs/api/test.odt');
|
||||||
const pdfDoc = fs.readFileSync("../tests/backend/specs/api/test.pdf");
|
const pdfDoc = fs.readFileSync('../tests/backend/specs/api/test.pdf');
|
||||||
|
|
||||||
let agent;
|
let agent;
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = 1;
|
const apiVersion = 1;
|
||||||
const testPadId = makeid();
|
const testPadId = makeid();
|
||||||
const testPadIdEnc = encodeURIComponent(testPadId);
|
const testPadIdEnc = encodeURIComponent(testPadId);
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
before(async function() { agent = await common.init(); });
|
before(async function () { agent = await common.init(); });
|
||||||
|
|
||||||
describe('Connectivity', function(){
|
describe('Connectivity', function () {
|
||||||
it('can connect', async function() {
|
it('can connect', async function () {
|
||||||
await agent.get('/api/')
|
await agent.get('/api/')
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/);
|
.expect('Content-Type', /json/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('API Versioning', function(){
|
describe('API Versioning', function () {
|
||||||
it('finds the version tag', async function() {
|
it('finds the version tag', async function () {
|
||||||
await agent.get('/api/')
|
await agent.get('/api/')
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.body.currentVersion));
|
.expect((res) => assert(res.body.currentVersion));
|
||||||
|
@ -70,10 +70,10 @@ describe(__filename, function() {
|
||||||
curl -s -v --form file=@/home/jose/test.txt http://127.0.0.1:9001/p/foo/import
|
curl -s -v --form file=@/home/jose/test.txt http://127.0.0.1:9001/p/foo/import
|
||||||
*/
|
*/
|
||||||
|
|
||||||
describe('Imports and Exports', function(){
|
describe('Imports and Exports', function () {
|
||||||
const backups = {};
|
const backups = {};
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
backups.hooks = {};
|
backups.hooks = {};
|
||||||
for (const hookName of ['preAuthorize', 'authenticate', 'authorize']) {
|
for (const hookName of ['preAuthorize', 'authenticate', 'authorize']) {
|
||||||
backups.hooks[hookName] = plugins.hooks[hookName];
|
backups.hooks[hookName] = plugins.hooks[hookName];
|
||||||
|
@ -86,43 +86,43 @@ describe(__filename, function() {
|
||||||
settings.users = {user: {password: 'user-password'}};
|
settings.users = {user: {password: 'user-password'}};
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
Object.assign(plugins.hooks, backups.hooks);
|
Object.assign(plugins.hooks, backups.hooks);
|
||||||
// Note: This does not unset settings that were added.
|
// Note: This does not unset settings that were added.
|
||||||
Object.assign(settings, backups.settings);
|
Object.assign(settings, backups.settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a new Pad, imports content to it, checks that content', async function() {
|
it('creates a new Pad, imports content to it, checks that content', async function () {
|
||||||
await agent.get(endPoint('createPad') + `&padID=${testPadId}`)
|
await agent.get(`${endPoint('createPad')}&padID=${testPadId}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => assert.equal(res.body.code, 0));
|
.expect((res) => assert.equal(res.body.code, 0));
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
await agent.get(endPoint('getText') + `&padID=${testPadId}`)
|
await agent.get(`${endPoint('getText')}&padID=${testPadId}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert.equal(res.body.data.text, padText.toString()));
|
.expect((res) => assert.equal(res.body.data.text, padText.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gets read only pad Id and exports the html and text for this pad', async function(){
|
it('gets read only pad Id and exports the html and text for this pad', async function () {
|
||||||
let ro = await agent.get(endPoint('getReadOnlyID')+"&padID="+testPadId)
|
const ro = await agent.get(`${endPoint('getReadOnlyID')}&padID=${testPadId}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert.ok(JSON.parse(res.text).data.readOnlyID));
|
.expect((res) => assert.ok(JSON.parse(res.text).data.readOnlyID));
|
||||||
let readOnlyId = JSON.parse(ro.text).data.readOnlyID;
|
const readOnlyId = JSON.parse(ro.text).data.readOnlyID;
|
||||||
|
|
||||||
await agent.get(`/p/${readOnlyId}/export/html`)
|
await agent.get(`/p/${readOnlyId}/export/html`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.text.indexOf("This is the") !== -1));
|
.expect((res) => assert(res.text.indexOf('This is the') !== -1));
|
||||||
|
|
||||||
await agent.get(`/p/${readOnlyId}/export/txt`)
|
await agent.get(`/p/${readOnlyId}/export/txt`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.text.indexOf("This is the") !== -1));
|
.expect((res) => assert(res.text.indexOf('This is the') !== -1));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('Import/Export tests requiring AbiWord/LibreOffice', function() {
|
describe('Import/Export tests requiring AbiWord/LibreOffice', function () {
|
||||||
before(function() {
|
before(function () {
|
||||||
if ((!settings.abiword || settings.abiword.indexOf('/') === -1) &&
|
if ((!settings.abiword || settings.abiword.indexOf('/') === -1) &&
|
||||||
(!settings.soffice || settings.soffice.indexOf('/') === -1)) {
|
(!settings.soffice || settings.soffice.indexOf('/') === -1)) {
|
||||||
this.skip();
|
this.skip();
|
||||||
|
@ -131,21 +131,21 @@ describe(__filename, function() {
|
||||||
|
|
||||||
// For some reason word import does not work in testing..
|
// For some reason word import does not work in testing..
|
||||||
// TODO: fix support for .doc files..
|
// TODO: fix support for .doc files..
|
||||||
it('Tries to import .doc that uses soffice or abiword', async function() {
|
it('Tries to import .doc that uses soffice or abiword', async function () {
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', wordDoc, {filename: '/test.doc', contentType: 'application/msword'})
|
.attach('file', wordDoc, {filename: '/test.doc', contentType: 'application/msword'})
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(/FrameCall\('undefined', 'ok'\);/);
|
.expect(/FrameCall\('undefined', 'ok'\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports DOC', async function() {
|
it('exports DOC', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/doc`)
|
await agent.get(`/p/${testPadId}/export/doc`)
|
||||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.body.length >= 9000));
|
.expect((res) => assert(res.body.length >= 9000));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Tries to import .docx that uses soffice or abiword', async function() {
|
it('Tries to import .docx that uses soffice or abiword', async function () {
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', wordXDoc, {
|
.attach('file', wordXDoc, {
|
||||||
filename: '/test.docx',
|
filename: '/test.docx',
|
||||||
|
@ -155,44 +155,43 @@ describe(__filename, function() {
|
||||||
.expect(/FrameCall\('undefined', 'ok'\);/);
|
.expect(/FrameCall\('undefined', 'ok'\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports DOC from imported DOCX', async function() {
|
it('exports DOC from imported DOCX', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/doc`)
|
await agent.get(`/p/${testPadId}/export/doc`)
|
||||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.body.length >= 9100));
|
.expect((res) => assert(res.body.length >= 9100));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Tries to import .pdf that uses soffice or abiword', async function() {
|
it('Tries to import .pdf that uses soffice or abiword', async function () {
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', pdfDoc, {filename: '/test.pdf', contentType: 'application/pdf'})
|
.attach('file', pdfDoc, {filename: '/test.pdf', contentType: 'application/pdf'})
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(/FrameCall\('undefined', 'ok'\);/);
|
.expect(/FrameCall\('undefined', 'ok'\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports PDF', async function() {
|
it('exports PDF', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/pdf`)
|
await agent.get(`/p/${testPadId}/export/pdf`)
|
||||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.body.length >= 1000));
|
.expect((res) => assert(res.body.length >= 1000));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Tries to import .odt that uses soffice or abiword', async function() {
|
it('Tries to import .odt that uses soffice or abiword', async function () {
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', odtDoc, {filename: '/test.odt', contentType: 'application/odt'})
|
.attach('file', odtDoc, {filename: '/test.odt', contentType: 'application/odt'})
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(/FrameCall\('undefined', 'ok'\);/);
|
.expect(/FrameCall\('undefined', 'ok'\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports ODT', async function() {
|
it('exports ODT', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/odt`)
|
await agent.get(`/p/${testPadId}/export/odt`)
|
||||||
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
.buffer(true).parse(superagent.parse['application/octet-stream'])
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => assert(res.body.length >= 7000));
|
.expect((res) => assert(res.body.length >= 7000));
|
||||||
});
|
});
|
||||||
|
|
||||||
}); // End of AbiWord/LibreOffice tests.
|
}); // End of AbiWord/LibreOffice tests.
|
||||||
|
|
||||||
it('Tries to import .etherpad', async function() {
|
it('Tries to import .etherpad', async function () {
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', etherpadDoc, {
|
.attach('file', etherpadDoc, {
|
||||||
filename: '/test.etherpad',
|
filename: '/test.etherpad',
|
||||||
|
@ -202,21 +201,21 @@ describe(__filename, function() {
|
||||||
.expect(/FrameCall\('true', 'ok'\);/);
|
.expect(/FrameCall\('true', 'ok'\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports Etherpad', async function() {
|
it('exports Etherpad', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/etherpad`)
|
await agent.get(`/p/${testPadId}/export/etherpad`)
|
||||||
.buffer(true).parse(superagent.parse.text)
|
.buffer(true).parse(superagent.parse.text)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect(/hello/);
|
.expect(/hello/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports HTML for this Etherpad file', async function() {
|
it('exports HTML for this Etherpad file', async function () {
|
||||||
await agent.get(`/p/${testPadId}/export/html`)
|
await agent.get(`/p/${testPadId}/export/html`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('content-type', 'text/html; charset=utf-8')
|
.expect('content-type', 'text/html; charset=utf-8')
|
||||||
.expect(/<ul class="bullet"><li><ul class="bullet"><li>hello<\/ul><\/li><\/ul>/);
|
.expect(/<ul class="bullet"><li><ul class="bullet"><li>hello<\/ul><\/li><\/ul>/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Tries to import unsupported file type', async function() {
|
it('Tries to import unsupported file type', async function () {
|
||||||
settings.allowUnknownFileEnds = false;
|
settings.allowUnknownFileEnds = false;
|
||||||
await agent.post(`/p/${testPadId}/import`)
|
await agent.post(`/p/${testPadId}/import`)
|
||||||
.attach('file', padText, {filename: '/test.xasdasdxx', contentType: 'weirdness/jobby'})
|
.attach('file', padText, {filename: '/test.xasdasdxx', contentType: 'weirdness/jobby'})
|
||||||
|
@ -224,7 +223,7 @@ describe(__filename, function() {
|
||||||
.expect((res) => assert.doesNotMatch(res.text, /FrameCall\('undefined', 'ok'\);/));
|
.expect((res) => assert.doesNotMatch(res.text, /FrameCall\('undefined', 'ok'\);/));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Import authorization checks', function() {
|
describe('Import authorization checks', function () {
|
||||||
let authorize;
|
let authorize;
|
||||||
|
|
||||||
const deleteTestPad = async () => {
|
const deleteTestPad = async () => {
|
||||||
|
@ -240,18 +239,18 @@ describe(__filename, function() {
|
||||||
return pad;
|
return pad;
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
await deleteTestPad();
|
await deleteTestPad();
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
authorize = () => true;
|
authorize = () => true;
|
||||||
plugins.hooks.authorize = [{hook_fn: (hookName, {req}, cb) => cb([authorize(req)])}];
|
plugins.hooks.authorize = [{hook_fn: (hookName, {req}, cb) => cb([authorize(req)])}];
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
await deleteTestPad();
|
await deleteTestPad();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('!authn !exist -> create', async function() {
|
it('!authn !exist -> create', async function () {
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
@ -260,7 +259,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), padText.toString());
|
assert.equal(pad.text(), padText.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('!authn exist -> replace', async function() {
|
it('!authn exist -> replace', async function () {
|
||||||
const pad = await createTestPad('before import');
|
const pad = await createTestPad('before import');
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
||||||
|
@ -269,7 +268,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), padText.toString());
|
assert.equal(pad.text(), padText.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn anonymous !exist -> fail', async function() {
|
it('authn anonymous !exist -> fail', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
.attach('file', padText, {filename: '/test.txt', contentType: 'text/plain'})
|
||||||
|
@ -277,7 +276,7 @@ describe(__filename, function() {
|
||||||
assert(!(await padManager.doesPadExist(testPadId)));
|
assert(!(await padManager.doesPadExist(testPadId)));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn anonymous exist -> fail', async function() {
|
it('authn anonymous exist -> fail', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const pad = await createTestPad('before import\n');
|
const pad = await createTestPad('before import\n');
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
|
@ -286,7 +285,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), 'before import\n');
|
assert.equal(pad.text(), 'before import\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user create !exist -> create', async function() {
|
it('authn user create !exist -> create', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
.auth('user', 'user-password')
|
.auth('user', 'user-password')
|
||||||
|
@ -297,7 +296,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), padText.toString());
|
assert.equal(pad.text(), padText.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user modify !exist -> fail', async function() {
|
it('authn user modify !exist -> fail', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
|
@ -307,7 +306,7 @@ describe(__filename, function() {
|
||||||
assert(!(await padManager.doesPadExist(testPadId)));
|
assert(!(await padManager.doesPadExist(testPadId)));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user readonly !exist -> fail', async function() {
|
it('authn user readonly !exist -> fail', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
|
@ -317,7 +316,7 @@ describe(__filename, function() {
|
||||||
assert(!(await padManager.doesPadExist(testPadId)));
|
assert(!(await padManager.doesPadExist(testPadId)));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user create exist -> replace', async function() {
|
it('authn user create exist -> replace', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const pad = await createTestPad('before import\n');
|
const pad = await createTestPad('before import\n');
|
||||||
await agent.post(`/p/${testPadIdEnc}/import`)
|
await agent.post(`/p/${testPadIdEnc}/import`)
|
||||||
|
@ -327,7 +326,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), padText.toString());
|
assert.equal(pad.text(), padText.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user modify exist -> replace', async function() {
|
it('authn user modify exist -> replace', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
const pad = await createTestPad('before import\n');
|
const pad = await createTestPad('before import\n');
|
||||||
|
@ -338,7 +337,7 @@ describe(__filename, function() {
|
||||||
assert.equal(pad.text(), padText.toString());
|
assert.equal(pad.text(), padText.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authn user readonly exist -> fail', async function() {
|
it('authn user readonly exist -> fail', async function () {
|
||||||
const pad = await createTestPad('before import\n');
|
const pad = await createTestPad('before import\n');
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
|
@ -353,19 +352,16 @@ describe(__filename, function() {
|
||||||
}); // End of tests.
|
}); // End of tests.
|
||||||
|
|
||||||
|
|
||||||
|
var endPoint = function (point, version) {
|
||||||
|
|
||||||
|
|
||||||
var endPoint = function(point, version){
|
|
||||||
version = version || apiVersion;
|
version = version || apiVersion;
|
||||||
return `/api/${version}/${point}?apikey=${apiKey}`;
|
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeid() {
|
function makeid() {
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 5; i++ ){
|
for (let i = 0; i < 5; i++) {
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|
|
@ -4,27 +4,27 @@
|
||||||
* Section "GLOBAL FUNCTIONS" in src/node/db/API.js
|
* Section "GLOBAL FUNCTIONS" in src/node/db/API.js
|
||||||
*/
|
*/
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const supertest = require(__dirname+'/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const settings = require(__dirname+'/../../../../src/node/utils/Settings');
|
const settings = require(`${__dirname}/../../../../src/node/utils/Settings`);
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
var apiVersion = '1.2.14';
|
const apiVersion = '1.2.14';
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('Connectivity for instance-level API tests', function() {
|
describe('Connectivity for instance-level API tests', function () {
|
||||||
it('can connect', function(done) {
|
it('can connect', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getStats', function() {
|
describe('getStats', function () {
|
||||||
it('Gets the stats of a running instance', function(done) {
|
it('Gets the stats of a running instance', function (done) {
|
||||||
api.get(endPoint('getStats'))
|
api.get(endPoint('getStats'))
|
||||||
.expect(function(res) {
|
.expect((res) => {
|
||||||
if (res.body.code !== 0) throw new Error("getStats() failed");
|
if (res.body.code !== 0) throw new Error('getStats() failed');
|
||||||
|
|
||||||
if (!(('totalPads' in res.body.data) && (typeof res.body.data.totalPads === 'number'))) {
|
if (!(('totalPads' in res.body.data) && (typeof res.body.data.totalPads === 'number'))) {
|
||||||
throw new Error(`Response to getStats() does not contain field totalPads, or it's not a number: ${JSON.stringify(res.body.data)}`);
|
throw new Error(`Response to getStats() does not contain field totalPads, or it's not a number: ${JSON.stringify(res.body.data)}`);
|
||||||
|
@ -44,7 +44,7 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var endPoint = function(point, version){
|
var endPoint = function (point, version) {
|
||||||
version = version || apiVersion;
|
version = version || apiVersion;
|
||||||
return '/api/'+version+'/'+point+'?apikey='+apiKey;
|
return `/api/${version}/${point}?apikey=${apiKey}`;
|
||||||
}
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../../common');
|
const common = require('../../common');
|
||||||
const supertest = require(__dirname + '/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const settings = require(__dirname + '/../../../../src/node/utils/Settings');
|
const settings = require(`${__dirname}/../../../../src/node/utils/Settings`);
|
||||||
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
const apiKey = common.apiKey;
|
const apiKey = common.apiKey;
|
||||||
|
@ -11,9 +11,9 @@ let authorID = '';
|
||||||
let sessionID = '';
|
let sessionID = '';
|
||||||
let padID = makeid();
|
let padID = makeid();
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('API Versioning', function() {
|
describe('API Versioning', function () {
|
||||||
it('errors if can not connect', async function() {
|
it('errors if can not connect', async function () {
|
||||||
await api.get('/api/')
|
await api.get('/api/')
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -24,8 +24,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// BEGIN GROUP AND AUTHOR TESTS
|
// BEGIN GROUP AND AUTHOR TESTS
|
||||||
/////////////////////////////////////
|
// ///////////////////////////////////
|
||||||
/////////////////////////////////////
|
// ///////////////////////////////////
|
||||||
|
|
||||||
/* Tests performed
|
/* Tests performed
|
||||||
-> createGroup() -- should return a groupID
|
-> createGroup() -- should return a groupID
|
||||||
|
@ -53,8 +53,8 @@ describe(__filename, function() {
|
||||||
-> listPadsOfAuthor(authorID)
|
-> listPadsOfAuthor(authorID)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
describe('API: Group creation and deletion', function() {
|
describe('API: Group creation and deletion', function () {
|
||||||
it('createGroup', async function() {
|
it('createGroup', async function () {
|
||||||
await api.get(endPoint('createGroup'))
|
await api.get(endPoint('createGroup'))
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
|
@ -65,8 +65,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('listSessionsOfGroup for empty group', async function() {
|
it('listSessionsOfGroup for empty group', async function () {
|
||||||
await api.get(endPoint('listSessionsOfGroup') + `&groupID=${groupID}`)
|
await api.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -75,8 +75,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deleteGroup', async function() {
|
it('deleteGroup', async function () {
|
||||||
await api.get(endPoint('deleteGroup') + `&groupID=${groupID}`)
|
await api.get(`${endPoint('deleteGroup')}&groupID=${groupID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -84,8 +84,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createGroupIfNotExistsFor', async function() {
|
it('createGroupIfNotExistsFor', async function () {
|
||||||
await api.get(endPoint('createGroupIfNotExistsFor') + '&groupMapper=management')
|
await api.get(`${endPoint('createGroupIfNotExistsFor')}&groupMapper=management`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -95,8 +95,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('API: Author creation', function() {
|
describe('API: Author creation', function () {
|
||||||
it('createGroup', async function() {
|
it('createGroup', async function () {
|
||||||
await api.get(endPoint('createGroup'))
|
await api.get(endPoint('createGroup'))
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
|
@ -107,7 +107,7 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createAuthor', async function() {
|
it('createAuthor', async function () {
|
||||||
await api.get(endPoint('createAuthor'))
|
await api.get(endPoint('createAuthor'))
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
|
@ -117,8 +117,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createAuthor with name', async function() {
|
it('createAuthor with name', async function () {
|
||||||
await api.get(endPoint('createAuthor') + '&name=john')
|
await api.get(`${endPoint('createAuthor')}&name=john`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -128,8 +128,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createAuthorIfNotExistsFor', async function() {
|
it('createAuthorIfNotExistsFor', async function () {
|
||||||
await api.get(endPoint('createAuthorIfNotExistsFor') + '&authorMapper=chris')
|
await api.get(`${endPoint('createAuthorIfNotExistsFor')}&authorMapper=chris`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -138,8 +138,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getAuthorName', async function() {
|
it('getAuthorName', async function () {
|
||||||
await api.get(endPoint('getAuthorName') + `&authorID=${authorID}`)
|
await api.get(`${endPoint('getAuthorName')}&authorID=${authorID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -149,10 +149,10 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('API: Sessions', function() {
|
describe('API: Sessions', function () {
|
||||||
it('createSession', async function() {
|
it('createSession', async function () {
|
||||||
await api.get(endPoint('createSession') +
|
await api.get(`${endPoint('createSession')
|
||||||
`&authorID=${authorID}&groupID=${groupID}&validUntil=999999999999`)
|
}&authorID=${authorID}&groupID=${groupID}&validUntil=999999999999`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -162,8 +162,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getSessionInfo', async function() {
|
it('getSessionInfo', async function () {
|
||||||
await api.get(endPoint('getSessionInfo') + `&sessionID=${sessionID}`)
|
await api.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -174,8 +174,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('listSessionsOfGroup', async function() {
|
it('listSessionsOfGroup', async function () {
|
||||||
await api.get(endPoint('listSessionsOfGroup') + `&groupID=${groupID}`)
|
await api.get(`${endPoint('listSessionsOfGroup')}&groupID=${groupID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -184,8 +184,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deleteSession', async function() {
|
it('deleteSession', async function () {
|
||||||
await api.get(endPoint('deleteSession') + `&sessionID=${sessionID}`)
|
await api.get(`${endPoint('deleteSession')}&sessionID=${sessionID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -193,8 +193,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getSessionInfo of deleted session', async function() {
|
it('getSessionInfo of deleted session', async function () {
|
||||||
await api.get(endPoint('getSessionInfo') + `&sessionID=${sessionID}`)
|
await api.get(`${endPoint('getSessionInfo')}&sessionID=${sessionID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -203,9 +203,9 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('API: Group pad management', function() {
|
describe('API: Group pad management', function () {
|
||||||
it('listPads', async function() {
|
it('listPads', async function () {
|
||||||
await api.get(endPoint('listPads') + `&groupID=${groupID}`)
|
await api.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -214,8 +214,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('createGroupPad', async function() {
|
it('createGroupPad', async function () {
|
||||||
await api.get(endPoint('createGroupPad') + `&groupID=${groupID}&padName=${padID}`)
|
await api.get(`${endPoint('createGroupPad')}&groupID=${groupID}&padName=${padID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -224,8 +224,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('listPads after creating a group pad', async function() {
|
it('listPads after creating a group pad', async function () {
|
||||||
await api.get(endPoint('listPads') + `&groupID=${groupID}`)
|
await api.get(`${endPoint('listPads')}&groupID=${groupID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -235,9 +235,9 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('API: Pad security', function() {
|
describe('API: Pad security', function () {
|
||||||
it('getPublicStatus', async function() {
|
it('getPublicStatus', async function () {
|
||||||
await api.get(endPoint('getPublicStatus') + `&padID=${padID}`)
|
await api.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -246,8 +246,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('setPublicStatus', async function() {
|
it('setPublicStatus', async function () {
|
||||||
await api.get(endPoint('setPublicStatus') + `&padID=${padID}&publicStatus=true`)
|
await api.get(`${endPoint('setPublicStatus')}&padID=${padID}&publicStatus=true`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -255,8 +255,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getPublicStatus after changing public status', async function() {
|
it('getPublicStatus after changing public status', async function () {
|
||||||
await api.get(endPoint('getPublicStatus') + `&padID=${padID}`)
|
await api.get(`${endPoint('getPublicStatus')}&padID=${padID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -267,12 +267,12 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// NOT SURE HOW TO POPULAT THIS /-_-\
|
// NOT SURE HOW TO POPULAT THIS /-_-\
|
||||||
///////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
///////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
describe('API: Misc', function() {
|
describe('API: Misc', function () {
|
||||||
it('listPadsOfAuthor', async function() {
|
it('listPadsOfAuthor', async function () {
|
||||||
await api.get(endPoint('listPadsOfAuthor') + `&authorID=${authorID}`)
|
await api.get(`${endPoint('listPadsOfAuthor')}&authorID=${authorID}`)
|
||||||
.expect(200)
|
.expect(200)
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect((res) => {
|
.expect((res) => {
|
||||||
|
@ -284,8 +284,7 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const endPoint = function (point) {
|
||||||
const endPoint = function(point) {
|
|
||||||
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
return `/api/${apiVersion}/${point}?apikey=${apiKey}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
var assert = require('assert')
|
const assert = require('assert');
|
||||||
os = require('os'),
|
os = require('os'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
TidyHtml = null,
|
TidyHtml = null,
|
||||||
Settings = null;
|
Settings = null;
|
||||||
|
|
||||||
var npm = require("../../../../src/node_modules/npm/lib/npm.js");
|
const npm = require('../../../../src/node_modules/npm/lib/npm.js');
|
||||||
var nodeify = require('../../../../src/node_modules/nodeify');
|
const nodeify = require('../../../../src/node_modules/nodeify');
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('tidyHtml', function() {
|
describe('tidyHtml', function () {
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
npm.load({}, function(err) {
|
npm.load({}, (err) => {
|
||||||
assert.ok(!err);
|
assert.ok(!err);
|
||||||
TidyHtml = require('../../../../src/node/utils/TidyHtml');
|
TidyHtml = require('../../../../src/node/utils/TidyHtml');
|
||||||
Settings = require('../../../../src/node/utils/Settings');
|
Settings = require('../../../../src/node/utils/Settings');
|
||||||
return done()
|
return done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ describe(__filename, function() {
|
||||||
return nodeify(TidyHtml.tidy(file), callback);
|
return nodeify(TidyHtml.tidy(file), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
it('Tidies HTML', function(done) {
|
it('Tidies HTML', function (done) {
|
||||||
// If the user hasn't configured Tidy, we skip this tests as it's required for this test
|
// If the user hasn't configured Tidy, we skip this tests as it's required for this test
|
||||||
if (!Settings.tidyHtml) {
|
if (!Settings.tidyHtml) {
|
||||||
this.skip();
|
this.skip();
|
||||||
|
@ -32,15 +32,15 @@ describe(__filename, function() {
|
||||||
// Try to tidy up a bad HTML file
|
// Try to tidy up a bad HTML file
|
||||||
const tmpDir = os.tmpdir();
|
const tmpDir = os.tmpdir();
|
||||||
|
|
||||||
var tmpFile = path.join(tmpDir, 'tmp_' + (Math.floor(Math.random() * 1000000)) + '.html')
|
const tmpFile = path.join(tmpDir, `tmp_${Math.floor(Math.random() * 1000000)}.html`);
|
||||||
fs.writeFileSync(tmpFile, '<html><body><p>a paragraph</p><li>List without outer UL</li>trailing closing p</p></body></html>');
|
fs.writeFileSync(tmpFile, '<html><body><p>a paragraph</p><li>List without outer UL</li>trailing closing p</p></body></html>');
|
||||||
tidy(tmpFile, function(err){
|
tidy(tmpFile, (err) => {
|
||||||
assert.ok(!err);
|
assert.ok(!err);
|
||||||
|
|
||||||
// Read the file again
|
// Read the file again
|
||||||
var cleanedHtml = fs.readFileSync(tmpFile).toString();
|
const cleanedHtml = fs.readFileSync(tmpFile).toString();
|
||||||
|
|
||||||
var expectedHtml = [
|
const expectedHtml = [
|
||||||
'<title></title>',
|
'<title></title>',
|
||||||
'</head>',
|
'</head>',
|
||||||
'<body>',
|
'<body>',
|
||||||
|
@ -57,13 +57,13 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can deal with errors', function(done) {
|
it('can deal with errors', function (done) {
|
||||||
// If the user hasn't configured Tidy, we skip this tests as it's required for this test
|
// If the user hasn't configured Tidy, we skip this tests as it's required for this test
|
||||||
if (!Settings.tidyHtml) {
|
if (!Settings.tidyHtml) {
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
tidy('/some/none/existing/file.html', function(err) {
|
tidy('/some/none/existing/file.html', (err) => {
|
||||||
assert.ok(err);
|
assert.ok(err);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,13 +19,13 @@ let agent;
|
||||||
*
|
*
|
||||||
* @param {string} fileContent the response body
|
* @param {string} fileContent the response body
|
||||||
* @param {URI} resource resource URI
|
* @param {URI} resource resource URI
|
||||||
* @returns {boolean} if it is plaintext
|
* @returns {boolean} if it is plaintext
|
||||||
*/
|
*/
|
||||||
function isPlaintextResponse(fileContent, resource){
|
function isPlaintextResponse(fileContent, resource) {
|
||||||
// callback=require.define&v=1234
|
// callback=require.define&v=1234
|
||||||
const query = url.parse(resource)['query'];
|
const query = url.parse(resource).query;
|
||||||
// require.define
|
// require.define
|
||||||
const jsonp = queryString.parse(query)['callback'];
|
const jsonp = queryString.parse(query).callback;
|
||||||
|
|
||||||
// returns true if the first letters in fileContent equal the content of `jsonp`
|
// returns true if the first letters in fileContent equal the content of `jsonp`
|
||||||
return fileContent.substring(0, jsonp.length) === jsonp;
|
return fileContent.substring(0, jsonp.length) === jsonp;
|
||||||
|
@ -36,40 +36,39 @@ function isPlaintextResponse(fileContent, resource){
|
||||||
*
|
*
|
||||||
* @param {Request} request
|
* @param {Request} request
|
||||||
*/
|
*/
|
||||||
function disableAutoDeflate(request){
|
function disableAutoDeflate(request) {
|
||||||
request._shouldUnzip = function(){
|
request._shouldUnzip = function () {
|
||||||
return false
|
return false;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
const backups = {};
|
const backups = {};
|
||||||
const fantasyEncoding = 'brainwaves'; // non-working encoding until https://github.com/visionmedia/superagent/pull/1560 is resolved
|
const fantasyEncoding = 'brainwaves'; // non-working encoding until https://github.com/visionmedia/superagent/pull/1560 is resolved
|
||||||
const packages = [
|
const packages = [
|
||||||
"/javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define"
|
'/javascripts/lib/ep_etherpad-lite/static/js/ace2_common.js?callback=require.define',
|
||||||
, "/javascripts/lib/ep_etherpad-lite/static/js/ace2_inner.js?callback=require.define"
|
'/javascripts/lib/ep_etherpad-lite/static/js/ace2_inner.js?callback=require.define',
|
||||||
, "/javascripts/lib/ep_etherpad-lite/static/js/pad.js?callback=require.define"
|
'/javascripts/lib/ep_etherpad-lite/static/js/pad.js?callback=require.define',
|
||||||
, "/javascripts/lib/ep_etherpad-lite/static/js/timeslider.js?callback=require.define"
|
'/javascripts/lib/ep_etherpad-lite/static/js/timeslider.js?callback=require.define',
|
||||||
];
|
];
|
||||||
|
|
||||||
before(async function() {
|
before(async function () {
|
||||||
agent = await common.init();
|
agent = await common.init();
|
||||||
});
|
});
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
backups.settings = {};
|
backups.settings = {};
|
||||||
backups.settings['minify'] = settings.minify;
|
backups.settings.minify = settings.minify;
|
||||||
});
|
});
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
Object.assign(settings, backups.settings);
|
Object.assign(settings, backups.settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when minify is false', function(){
|
context('when minify is false', function () {
|
||||||
before(async function() {
|
before(async function () {
|
||||||
settings.minify = false;
|
settings.minify = false;
|
||||||
});
|
});
|
||||||
it('gets packages uncompressed without Accept-Encoding gzip', async function() {
|
it('gets packages uncompressed without Accept-Encoding gzip', async function () {
|
||||||
await Promise.all(packages.map(async (resource) => {
|
await Promise.all(packages.map(async (resource) => agent.get(resource)
|
||||||
return agent.get(resource)
|
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.use(disableAutoDeflate)
|
.use(disableAutoDeflate)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -77,13 +76,11 @@ describe(__filename, function() {
|
||||||
assert.equal(res.header['content-encoding'], undefined);
|
assert.equal(res.header['content-encoding'], undefined);
|
||||||
assert.equal(isPlaintextResponse(res.text, resource), true);
|
assert.equal(isPlaintextResponse(res.text, resource), true);
|
||||||
return;
|
return;
|
||||||
})
|
})));
|
||||||
}))
|
});
|
||||||
})
|
|
||||||
|
|
||||||
it('gets packages compressed with Accept-Encoding gzip', async function() {
|
it('gets packages compressed with Accept-Encoding gzip', async function () {
|
||||||
await Promise.all(packages.map(async (resource) => {
|
await Promise.all(packages.map(async (resource) => agent.get(resource)
|
||||||
return agent.get(resource)
|
|
||||||
.set('Accept-Encoding', 'gzip')
|
.set('Accept-Encoding', 'gzip')
|
||||||
.use(disableAutoDeflate)
|
.use(disableAutoDeflate)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -91,36 +88,28 @@ describe(__filename, function() {
|
||||||
assert.equal(res.header['content-encoding'], 'gzip');
|
assert.equal(res.header['content-encoding'], 'gzip');
|
||||||
assert.equal(isPlaintextResponse(res.text, resource), false);
|
assert.equal(isPlaintextResponse(res.text, resource), false);
|
||||||
return;
|
return;
|
||||||
})
|
})));
|
||||||
}))
|
});
|
||||||
})
|
|
||||||
|
|
||||||
it('does not cache content-encoding headers', async function(){
|
it('does not cache content-encoding headers', async function () {
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], undefined));
|
||||||
return assert.equal(res.header['content-encoding'], undefined);
|
|
||||||
});
|
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', 'gzip')
|
.set('Accept-Encoding', 'gzip')
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], 'gzip'));
|
||||||
return assert.equal(res.header['content-encoding'], 'gzip');
|
|
||||||
});
|
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], undefined));
|
||||||
return assert.equal(res.header['content-encoding'], undefined);
|
});
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when minify is true', function(){
|
context('when minify is true', function () {
|
||||||
before(async function() {
|
before(async function () {
|
||||||
settings.minify = true;
|
settings.minify = true;
|
||||||
});
|
});
|
||||||
it('gets packages uncompressed without Accept-Encoding gzip', async function() {
|
it('gets packages uncompressed without Accept-Encoding gzip', async function () {
|
||||||
await Promise.all(packages.map(async (resource) => {
|
await Promise.all(packages.map(async (resource) => agent.get(resource)
|
||||||
return agent.get(resource)
|
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.use(disableAutoDeflate)
|
.use(disableAutoDeflate)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -128,13 +117,11 @@ describe(__filename, function() {
|
||||||
assert.equal(res.header['content-encoding'], undefined);
|
assert.equal(res.header['content-encoding'], undefined);
|
||||||
assert.equal(isPlaintextResponse(res.text, resource), true);
|
assert.equal(isPlaintextResponse(res.text, resource), true);
|
||||||
return;
|
return;
|
||||||
})
|
})));
|
||||||
}))
|
});
|
||||||
})
|
|
||||||
|
|
||||||
it('gets packages compressed with Accept-Encoding gzip', async function() {
|
it('gets packages compressed with Accept-Encoding gzip', async function () {
|
||||||
await Promise.all(packages.map(async (resource) => {
|
await Promise.all(packages.map(async (resource) => agent.get(resource)
|
||||||
return agent.get(resource)
|
|
||||||
.set('Accept-Encoding', 'gzip')
|
.set('Accept-Encoding', 'gzip')
|
||||||
.use(disableAutoDeflate)
|
.use(disableAutoDeflate)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -142,27 +129,19 @@ describe(__filename, function() {
|
||||||
assert.equal(res.header['content-encoding'], 'gzip');
|
assert.equal(res.header['content-encoding'], 'gzip');
|
||||||
assert.equal(isPlaintextResponse(res.text, resource), false);
|
assert.equal(isPlaintextResponse(res.text, resource), false);
|
||||||
return;
|
return;
|
||||||
})
|
})));
|
||||||
}))
|
});
|
||||||
})
|
|
||||||
|
|
||||||
it('does not cache content-encoding headers', async function(){
|
it('does not cache content-encoding headers', async function () {
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], undefined));
|
||||||
return assert.equal(res.header['content-encoding'], undefined);
|
|
||||||
});
|
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', 'gzip')
|
.set('Accept-Encoding', 'gzip')
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], 'gzip'));
|
||||||
return assert.equal(res.header['content-encoding'], 'gzip');
|
|
||||||
});
|
|
||||||
await agent.get(packages[0])
|
await agent.get(packages[0])
|
||||||
.set('Accept-Encoding', fantasyEncoding)
|
.set('Accept-Encoding', fantasyEncoding)
|
||||||
.then((res) => {
|
.then((res) => assert.equal(res.header['content-encoding'], undefined));
|
||||||
return assert.equal(res.header['content-encoding'], undefined);
|
});
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
const Changeset = require("../../../src/static/js/Changeset");
|
const Changeset = require('../../../src/static/js/Changeset');
|
||||||
const contentcollector = require("../../../src/static/js/contentcollector");
|
const contentcollector = require('../../../src/static/js/contentcollector');
|
||||||
const AttributePool = require("../../../src/static/js/AttributePool");
|
const AttributePool = require('../../../src/static/js/AttributePool');
|
||||||
const cheerio = require("../../../src/node_modules/cheerio");
|
const cheerio = require('../../../src/node_modules/cheerio');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
const tests = {
|
const tests = {
|
||||||
nestedLi:{
|
nestedLi: {
|
||||||
description: "Complex nested Li",
|
description: 'Complex nested Li',
|
||||||
html: '<!doctype html><html><body><ol><li>one</li><li><ol><li>1.1</li></ol></li><li>two</li></ol></body></html>',
|
html: '<!doctype html><html><body><ol><li>one</li><li><ol><li>1.1</li></ol></li><li>two</li></ol></body></html>',
|
||||||
expectedLineAttribs : [
|
expectedLineAttribs: [
|
||||||
'*0*1*2*3+1+3', '*0*4*2*5+1+3', '*0*1*2*5+1+3'
|
'*0*1*2*3+1+3', '*0*4*2*5+1+3', '*0*1*2*5+1+3',
|
||||||
],
|
],
|
||||||
expectedText: [
|
expectedText: [
|
||||||
'*one', '*1.1', '*two'
|
'*one', '*1.1', '*two',
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
complexNest:{
|
complexNest: {
|
||||||
description: "Complex list of different types",
|
description: 'Complex list of different types',
|
||||||
html: '<!doctype html><html><body><ul class="bullet"><li>one</li><li>two</li><li>0</li><li>1</li><li>2<ul class="bullet"><li>3</li><li>4</li></ul></li></ul><ol class="number"><li>item<ol class="number"><li>item1</li><li>item2</li></ol></li></ol></body></html>',
|
html: '<!doctype html><html><body><ul class="bullet"><li>one</li><li>two</li><li>0</li><li>1</li><li>2<ul class="bullet"><li>3</li><li>4</li></ul></li></ul><ol class="number"><li>item<ol class="number"><li>item1</li><li>item2</li></ol></li></ol></body></html>',
|
||||||
expectedLineAttribs : [
|
expectedLineAttribs: [
|
||||||
'*0*1*2+1+3',
|
'*0*1*2+1+3',
|
||||||
'*0*1*2+1+3',
|
'*0*1*2+1+3',
|
||||||
'*0*1*2+1+1',
|
'*0*1*2+1+1',
|
||||||
|
@ -28,113 +28,116 @@ const tests = {
|
||||||
'*0*3*2+1+1',
|
'*0*3*2+1+1',
|
||||||
'*0*4*2*5+1+4',
|
'*0*4*2*5+1+4',
|
||||||
'*0*6*2*7+1+5',
|
'*0*6*2*7+1+5',
|
||||||
'*0*6*2*7+1+5'
|
'*0*6*2*7+1+5',
|
||||||
],
|
],
|
||||||
expectedText: [
|
expectedText: [
|
||||||
'*one', '*two',
|
'*one',
|
||||||
'*0', '*1',
|
'*two',
|
||||||
'*2', '*3',
|
'*0',
|
||||||
'*4', '*item',
|
'*1',
|
||||||
'*item1', '*item2'
|
'*2',
|
||||||
]
|
'*3',
|
||||||
|
'*4',
|
||||||
|
'*item',
|
||||||
|
'*item1',
|
||||||
|
'*item2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
ul: {
|
ul: {
|
||||||
description : "Tests if uls properly get attributes",
|
description: 'Tests if uls properly get attributes',
|
||||||
html : "<html><body><ul><li>a</li><li>b</li></ul><div>div</div><p>foo</p></body></html>",
|
html: '<html><body><ul><li>a</li><li>b</li></ul><div>div</div><p>foo</p></body></html>',
|
||||||
expectedLineAttribs : [ '*0*1*2+1+1', '*0*1*2+1+1', '+3' , '+3'],
|
expectedLineAttribs: ['*0*1*2+1+1', '*0*1*2+1+1', '+3', '+3'],
|
||||||
expectedText: ["*a","*b", "div", "foo"]
|
expectedText: ['*a', '*b', 'div', 'foo'],
|
||||||
}
|
},
|
||||||
,
|
|
||||||
ulIndented: {
|
ulIndented: {
|
||||||
description : "Tests if indented uls properly get attributes",
|
description: 'Tests if indented uls properly get attributes',
|
||||||
html : "<html><body><ul><li>a</li><ul><li>b</li></ul><li>a</li></ul><p>foo</p></body></html>",
|
html: '<html><body><ul><li>a</li><ul><li>b</li></ul><li>a</li></ul><p>foo</p></body></html>',
|
||||||
expectedLineAttribs : [ '*0*1*2+1+1', '*0*3*2+1+1', '*0*1*2+1+1', '+3' ],
|
expectedLineAttribs: ['*0*1*2+1+1', '*0*3*2+1+1', '*0*1*2+1+1', '+3'],
|
||||||
expectedText: ["*a","*b", "*a", "foo"]
|
expectedText: ['*a', '*b', '*a', 'foo'],
|
||||||
},
|
},
|
||||||
ol: {
|
ol: {
|
||||||
description : "Tests if ols properly get line numbers when in a normal OL",
|
description: 'Tests if ols properly get line numbers when in a normal OL',
|
||||||
html : "<html><body><ol><li>a</li><li>b</li><li>c</li></ol><p>test</p></body></html>",
|
html: '<html><body><ol><li>a</li><li>b</li><li>c</li></ol><p>test</p></body></html>',
|
||||||
expectedLineAttribs : ['*0*1*2*3+1+1', '*0*1*2*3+1+1', '*0*1*2*3+1+1', '+4'],
|
expectedLineAttribs: ['*0*1*2*3+1+1', '*0*1*2*3+1+1', '*0*1*2*3+1+1', '+4'],
|
||||||
expectedText: ["*a","*b","*c", "test"],
|
expectedText: ['*a', '*b', '*c', 'test'],
|
||||||
noteToSelf: "Ensure empty P does not induce line attribute marker, wont this break the editor?"
|
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||||
}
|
|
||||||
,
|
|
||||||
lineDoBreakInOl:{
|
|
||||||
description : "A single completely empty line break within an ol should reset count if OL is closed off..",
|
|
||||||
html : "<html><body><ol><li>should be 1</li></ol><p>hello</p><ol><li>should be 1</li><li>should be 2</li></ol><p></p></body></html>",
|
|
||||||
expectedLineAttribs : [ '*0*1*2*3+1+b', '+5', '*0*1*2*4+1+b', '*0*1*2*4+1+b', '' ],
|
|
||||||
expectedText: ["*should be 1","hello", "*should be 1","*should be 2", ""],
|
|
||||||
noteToSelf: "Shouldn't include attribute marker in the <p> line"
|
|
||||||
},
|
},
|
||||||
bulletListInOL:{
|
lineDoBreakInOl: {
|
||||||
description : "A bullet within an OL should not change numbering..",
|
description: 'A single completely empty line break within an ol should reset count if OL is closed off..',
|
||||||
html : "<html><body><ol><li>should be 1</li><ul><li>should be a bullet</li></ul><li>should be 2</li></ol><p></p></body></html>",
|
html: '<html><body><ol><li>should be 1</li></ol><p>hello</p><ol><li>should be 1</li><li>should be 2</li></ol><p></p></body></html>',
|
||||||
expectedLineAttribs : [ '*0*1*2*3+1+b', '*0*4*2*3+1+i', '*0*1*2*5+1+b', '' ],
|
expectedLineAttribs: ['*0*1*2*3+1+b', '+5', '*0*1*2*4+1+b', '*0*1*2*4+1+b', ''],
|
||||||
expectedText: ["*should be 1","*should be a bullet","*should be 2", ""]
|
expectedText: ['*should be 1', 'hello', '*should be 1', '*should be 2', ''],
|
||||||
|
noteToSelf: "Shouldn't include attribute marker in the <p> line",
|
||||||
},
|
},
|
||||||
testP:{
|
bulletListInOL: {
|
||||||
description : "A single <p></p> should create a new line",
|
description: 'A bullet within an OL should not change numbering..',
|
||||||
html : "<html><body><p></p><p></p></body></html>",
|
html: '<html><body><ol><li>should be 1</li><ul><li>should be a bullet</li></ul><li>should be 2</li></ol><p></p></body></html>',
|
||||||
expectedLineAttribs : [ '', ''],
|
expectedLineAttribs: ['*0*1*2*3+1+b', '*0*4*2*3+1+i', '*0*1*2*5+1+b', ''],
|
||||||
expectedText: ["", ""],
|
expectedText: ['*should be 1', '*should be a bullet', '*should be 2', ''],
|
||||||
noteToSelf: "<p></p>should create a line break but not break numbering"
|
},
|
||||||
|
testP: {
|
||||||
|
description: 'A single <p></p> should create a new line',
|
||||||
|
html: '<html><body><p></p><p></p></body></html>',
|
||||||
|
expectedLineAttribs: ['', ''],
|
||||||
|
expectedText: ['', ''],
|
||||||
|
noteToSelf: '<p></p>should create a line break but not break numbering',
|
||||||
},
|
},
|
||||||
nestedOl: {
|
nestedOl: {
|
||||||
description : "Tests if ols properly get line numbers when in a normal OL",
|
description: 'Tests if ols properly get line numbers when in a normal OL',
|
||||||
html : "<html><body>a<ol><li>b<ol><li>c</li></ol></ol>notlist<p>foo</p></body></html>",
|
html: '<html><body>a<ol><li>b<ol><li>c</li></ol></ol>notlist<p>foo</p></body></html>',
|
||||||
expectedLineAttribs : [ '+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1', '+7', '+3' ],
|
expectedLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1', '+7', '+3'],
|
||||||
expectedText: ["a","*b","*c", "notlist", "foo"],
|
expectedText: ['a', '*b', '*c', 'notlist', 'foo'],
|
||||||
noteToSelf: "Ensure empty P does not induce line attribute marker, wont this break the editor?"
|
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||||
},
|
},
|
||||||
nestedOl: {
|
nestedOl: {
|
||||||
description : "First item being an UL then subsequent being OL will fail",
|
description: 'First item being an UL then subsequent being OL will fail',
|
||||||
html : "<html><body><ul><li>a<ol><li>b</li><li>c</li></ol></li></ul></body></html>",
|
html: '<html><body><ul><li>a<ol><li>b</li><li>c</li></ol></li></ul></body></html>',
|
||||||
expectedLineAttribs : [ '+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1' ],
|
expectedLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1'],
|
||||||
expectedText: ["a","*b","*c"],
|
expectedText: ['a', '*b', '*c'],
|
||||||
noteToSelf: "Ensure empty P does not induce line attribute marker, wont this break the editor?",
|
noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?',
|
||||||
disabled: true
|
disabled: true,
|
||||||
},
|
},
|
||||||
lineDontBreakOL:{
|
lineDontBreakOL: {
|
||||||
description : "A single completely empty line break within an ol should NOT reset count",
|
description: 'A single completely empty line break within an ol should NOT reset count',
|
||||||
html : "<html><body><ol><li>should be 1</li><p></p><li>should be 2</li><li>should be 3</li></ol><p></p></body></html>",
|
html: '<html><body><ol><li>should be 1</li><p></p><li>should be 2</li><li>should be 3</li></ol><p></p></body></html>',
|
||||||
expectedLineAttribs : [ ],
|
expectedLineAttribs: [],
|
||||||
expectedText: ["*should be 1","*should be 2","*should be 3"],
|
expectedText: ['*should be 1', '*should be 2', '*should be 3'],
|
||||||
noteToSelf: "<p></p>should create a line break but not break numbering -- This is what I can't get working!",
|
noteToSelf: "<p></p>should create a line break but not break numbering -- This is what I can't get working!",
|
||||||
disabled: true
|
disabled: true,
|
||||||
}
|
},
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
for (let test in tests) {
|
for (const test in tests) {
|
||||||
let testObj = tests[test];
|
const testObj = tests[test];
|
||||||
describe(test, function() {
|
describe(test, function () {
|
||||||
if (testObj.disabled) {
|
if (testObj.disabled) {
|
||||||
return xit("DISABLED:", test, function(done){
|
return xit('DISABLED:', test, function (done) {
|
||||||
done();
|
done();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
it(testObj.description, function(done) {
|
it(testObj.description, function (done) {
|
||||||
var $ = cheerio.load(testObj.html); // Load HTML into Cheerio
|
const $ = cheerio.load(testObj.html); // Load HTML into Cheerio
|
||||||
var doc = $('html')[0]; // Creates a dom-like representation of HTML
|
const doc = $('html')[0]; // Creates a dom-like representation of HTML
|
||||||
// Create an empty attribute pool
|
// Create an empty attribute pool
|
||||||
var apool = new AttributePool();
|
const apool = new AttributePool();
|
||||||
// Convert a dom tree into a list of lines and attribute liens
|
// Convert a dom tree into a list of lines and attribute liens
|
||||||
// using the content collector object
|
// using the content collector object
|
||||||
var cc = contentcollector.makeContentCollector(true, null, apool);
|
const cc = contentcollector.makeContentCollector(true, null, apool);
|
||||||
cc.collectContent(doc);
|
cc.collectContent(doc);
|
||||||
var result = cc.finish();
|
const result = cc.finish();
|
||||||
var recievedAttributes = result.lineAttribs;
|
const recievedAttributes = result.lineAttribs;
|
||||||
var expectedAttributes = testObj.expectedLineAttribs;
|
const expectedAttributes = testObj.expectedLineAttribs;
|
||||||
var recievedText = new Array(result.lines)
|
const recievedText = new Array(result.lines);
|
||||||
var expectedText = testObj.expectedText;
|
const expectedText = testObj.expectedText;
|
||||||
|
|
||||||
// Check recieved text matches the expected text
|
// Check recieved text matches the expected text
|
||||||
if (arraysEqual(recievedText[0], expectedText)) {
|
if (arraysEqual(recievedText[0], expectedText)) {
|
||||||
// console.log("PASS: Recieved Text did match Expected Text\nRecieved:", recievedText[0], "\nExpected:", testObj.expectedText)
|
// console.log("PASS: Recieved Text did match Expected Text\nRecieved:", recievedText[0], "\nExpected:", testObj.expectedText)
|
||||||
} else {
|
} else {
|
||||||
console.error("FAIL: Recieved Text did not match Expected Text\nRecieved:", recievedText[0], "\nExpected:", testObj.expectedText)
|
console.error('FAIL: Recieved Text did not match Expected Text\nRecieved:', recievedText[0], '\nExpected:', testObj.expectedText);
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,9 +146,9 @@ describe(__filename, function() {
|
||||||
// console.log("PASS: Recieved Attributes matched Expected Attributes");
|
// console.log("PASS: Recieved Attributes matched Expected Attributes");
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
console.error("FAIL", test, testObj.description);
|
console.error('FAIL', test, testObj.description);
|
||||||
console.error("FAIL: Recieved Attributes did not match Expected Attributes\nRecieved: ", recievedAttributes, "\nExpected: ", expectedAttributes)
|
console.error('FAIL: Recieved Attributes did not match Expected Attributes\nRecieved: ', recievedAttributes, '\nExpected: ', expectedAttributes);
|
||||||
console.error("FAILING HTML", testObj.html);
|
console.error('FAILING HTML', testObj.html);
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -154,8 +157,6 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function arraysEqual(a, b) {
|
function arraysEqual(a, b) {
|
||||||
if (a === b) return true;
|
if (a === b) return true;
|
||||||
if (a == null || b == null) return false;
|
if (a == null || b == null) return false;
|
||||||
|
@ -166,7 +167,7 @@ function arraysEqual(a, b) {
|
||||||
// Please note that calling sort on an array will modify that array.
|
// Please note that calling sort on an array will modify that array.
|
||||||
// you might want to clone your array first.
|
// you might want to clone your array first.
|
||||||
|
|
||||||
for (var i = 0; i < a.length; ++i) {
|
for (let i = 0; i < a.length; ++i) {
|
||||||
if (a[i] !== b[i]) return false;
|
if (a[i] !== b[i]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global __dirname, __filename, afterEach, beforeEach, describe, it, process, require */
|
/* global __dirname, __filename, afterEach, beforeEach, describe, it, process, require */
|
||||||
|
|
||||||
function m(mod) { return __dirname + '/../../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../../src/${mod}`; }
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
@ -10,13 +10,13 @@ const sinon = require(m('node_modules/sinon'));
|
||||||
|
|
||||||
const logger = common.logger;
|
const logger = common.logger;
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
const hookName = 'testHook';
|
const hookName = 'testHook';
|
||||||
const hookFnName = 'testPluginFileName:testHookFunctionName';
|
const hookFnName = 'testPluginFileName:testHookFunctionName';
|
||||||
let testHooks; // Convenience shorthand for plugins.hooks[hookName].
|
let testHooks; // Convenience shorthand for plugins.hooks[hookName].
|
||||||
let hook; // Convenience shorthand for plugins.hooks[hookName][0].
|
let hook; // Convenience shorthand for plugins.hooks[hookName][0].
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
// Make sure these are not already set so that we don't accidentally step on someone else's
|
// Make sure these are not already set so that we don't accidentally step on someone else's
|
||||||
// toes:
|
// toes:
|
||||||
assert(plugins.hooks[hookName] == null);
|
assert(plugins.hooks[hookName] == null);
|
||||||
|
@ -30,24 +30,22 @@ describe(__filename, function() {
|
||||||
testHooks = plugins.hooks[hookName];
|
testHooks = plugins.hooks[hookName];
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
sinon.restore();
|
sinon.restore();
|
||||||
delete plugins.hooks[hookName];
|
delete plugins.hooks[hookName];
|
||||||
delete hooks.deprecationNotices[hookName];
|
delete hooks.deprecationNotices[hookName];
|
||||||
delete hooks.exportedForTestingOnly.deprecationWarned[hookFnName];
|
delete hooks.exportedForTestingOnly.deprecationWarned[hookFnName];
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeHook = (ret) => {
|
const makeHook = (ret) => ({
|
||||||
return {
|
hook_name: hookName,
|
||||||
hook_name: hookName,
|
// Many tests will likely want to change this. Unfortunately, we can't use a convenience
|
||||||
// Many tests will likely want to change this. Unfortunately, we can't use a convenience
|
// wrapper like `(...args) => hookFn(..args)` because the hooks look at Function.length and
|
||||||
// wrapper like `(...args) => hookFn(..args)` because the hooks look at Function.length and
|
// change behavior depending on the number of parameters.
|
||||||
// change behavior depending on the number of parameters.
|
hook_fn: (hn, ctx, cb) => cb(ret),
|
||||||
hook_fn: (hn, ctx, cb) => cb(ret),
|
hook_fn_name: hookFnName,
|
||||||
hook_fn_name: hookFnName,
|
part: {plugin: 'testPluginName'},
|
||||||
part: {plugin: 'testPluginName'},
|
});
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hook functions that should work for both synchronous and asynchronous hooks.
|
// Hook functions that should work for both synchronous and asynchronous hooks.
|
||||||
const supportedSyncHookFunctions = [
|
const supportedSyncHookFunctions = [
|
||||||
|
@ -95,30 +93,30 @@ describe(__filename, function() {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('callHookFnSync', function() {
|
describe('callHookFnSync', function () {
|
||||||
const callHookFnSync = hooks.exportedForTestingOnly.callHookFnSync; // Convenience shorthand.
|
const callHookFnSync = hooks.exportedForTestingOnly.callHookFnSync; // Convenience shorthand.
|
||||||
|
|
||||||
describe('basic behavior', function() {
|
describe('basic behavior', function () {
|
||||||
it('passes hook name', async function() {
|
it('passes hook name', async function () {
|
||||||
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
||||||
callHookFnSync(hook);
|
callHookFnSync(hook);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes context', async function() {
|
it('passes context', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
|
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
|
||||||
callHookFnSync(hook, val);
|
callHookFnSync(hook, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the value provided to the callback', async function() {
|
it('returns the value provided to the callback', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
|
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
|
||||||
assert.equal(callHookFnSync(hook, val), val);
|
assert.equal(callHookFnSync(hook, val), val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the value returned by the hook function', async function() {
|
it('returns the value returned by the hook function', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
// Must not have the cb parameter otherwise returning undefined will error.
|
// Must not have the cb parameter otherwise returning undefined will error.
|
||||||
hook.hook_fn = (hn, ctx) => ctx;
|
hook.hook_fn = (hn, ctx) => ctx;
|
||||||
|
@ -126,17 +124,17 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not catch exceptions', async function() {
|
it('does not catch exceptions', async function () {
|
||||||
hook.hook_fn = () => { throw new Error('test exception'); };
|
hook.hook_fn = () => { throw new Error('test exception'); };
|
||||||
assert.throws(() => callHookFnSync(hook), {message: 'test exception'});
|
assert.throws(() => callHookFnSync(hook), {message: 'test exception'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('callback returns undefined', async function() {
|
it('callback returns undefined', async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
|
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
|
||||||
callHookFnSync(hook);
|
callHookFnSync(hook);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('checks for deprecation', async function() {
|
it('checks for deprecation', async function () {
|
||||||
sinon.stub(console, 'warn');
|
sinon.stub(console, 'warn');
|
||||||
hooks.deprecationNotices[hookName] = 'test deprecation';
|
hooks.deprecationNotices[hookName] = 'test deprecation';
|
||||||
callHookFnSync(hook);
|
callHookFnSync(hook);
|
||||||
|
@ -146,9 +144,9 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('supported hook function styles', function() {
|
describe('supported hook function styles', function () {
|
||||||
for (const tc of supportedSyncHookFunctions) {
|
for (const tc of supportedSyncHookFunctions) {
|
||||||
it(tc.name, async function() {
|
it(tc.name, async function () {
|
||||||
sinon.stub(console, 'warn');
|
sinon.stub(console, 'warn');
|
||||||
sinon.stub(console, 'error');
|
sinon.stub(console, 'error');
|
||||||
hook.hook_fn = tc.fn;
|
hook.hook_fn = tc.fn;
|
||||||
|
@ -164,7 +162,7 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('bad hook function behavior (other than double settle)', function() {
|
describe('bad hook function behavior (other than double settle)', function () {
|
||||||
const promise1 = Promise.resolve('val1');
|
const promise1 = Promise.resolve('val1');
|
||||||
const promise2 = Promise.resolve('val2');
|
const promise2 = Promise.resolve('val2');
|
||||||
|
|
||||||
|
@ -192,7 +190,7 @@ describe(__filename, function() {
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const tc of testCases) {
|
for (const tc of testCases) {
|
||||||
it(tc.name, async function() {
|
it(tc.name, async function () {
|
||||||
sinon.stub(console, 'error');
|
sinon.stub(console, 'error');
|
||||||
hook.hook_fn = tc.fn;
|
hook.hook_fn = tc.fn;
|
||||||
assert.equal(callHookFnSync(hook), tc.wantVal);
|
assert.equal(callHookFnSync(hook), tc.wantVal);
|
||||||
|
@ -204,8 +202,8 @@ describe(__filename, function() {
|
||||||
|
|
||||||
// Test various ways a hook might attempt to settle twice. (Examples: call the callback a second
|
// Test various ways a hook might attempt to settle twice. (Examples: call the callback a second
|
||||||
// time, or call the callback and then return a value.)
|
// time, or call the callback and then return a value.)
|
||||||
describe('bad hook function behavior (double settle)', function() {
|
describe('bad hook function behavior (double settle)', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
sinon.stub(console, 'error');
|
sinon.stub(console, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -243,7 +241,7 @@ describe(__filename, function() {
|
||||||
// settle would complicate the tests, and it is sufficient to test only double settles.
|
// settle would complicate the tests, and it is sufficient to test only double settles.
|
||||||
if (step1.async && step2.async) continue;
|
if (step1.async && step2.async) continue;
|
||||||
|
|
||||||
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function() {
|
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => {
|
hook.hook_fn = (hn, ctx, cb) => {
|
||||||
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
|
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
|
||||||
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
|
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
|
||||||
|
@ -306,7 +304,7 @@ describe(__filename, function() {
|
||||||
// doesn't, so skip those cases.
|
// doesn't, so skip those cases.
|
||||||
if (step1.rejects !== step2.rejects) continue;
|
if (step1.rejects !== step2.rejects) continue;
|
||||||
|
|
||||||
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function() {
|
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function () {
|
||||||
const err = new Error('val');
|
const err = new Error('val');
|
||||||
hook.hook_fn = (hn, ctx, cb) => {
|
hook.hook_fn = (hn, ctx, cb) => {
|
||||||
step1.fn(cb, err, 'val');
|
step1.fn(cb, err, 'val');
|
||||||
|
@ -329,66 +327,66 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hooks.callAll', function() {
|
describe('hooks.callAll', function () {
|
||||||
describe('basic behavior', function() {
|
describe('basic behavior', function () {
|
||||||
it('calls all in order', async function() {
|
it('calls all in order', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(1), makeHook(2), makeHook(3));
|
testHooks.push(makeHook(1), makeHook(2), makeHook(3));
|
||||||
assert.deepEqual(hooks.callAll(hookName), [1, 2, 3]);
|
assert.deepEqual(hooks.callAll(hookName), [1, 2, 3]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes hook name', async function() {
|
it('passes hook name', async function () {
|
||||||
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
||||||
hooks.callAll(hookName);
|
hooks.callAll(hookName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('undefined context -> {}', async function() {
|
it('undefined context -> {}', async function () {
|
||||||
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
||||||
hooks.callAll(hookName);
|
hooks.callAll(hookName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('null context -> {}', async function() {
|
it('null context -> {}', async function () {
|
||||||
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
||||||
hooks.callAll(hookName, null);
|
hooks.callAll(hookName, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('context unmodified', async function() {
|
it('context unmodified', async function () {
|
||||||
const wantContext = {};
|
const wantContext = {};
|
||||||
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, wantContext); };
|
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, wantContext); };
|
||||||
hooks.callAll(hookName, wantContext);
|
hooks.callAll(hookName, wantContext);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('result processing', function() {
|
describe('result processing', function () {
|
||||||
it('no registered hooks (undefined) -> []', async function() {
|
it('no registered hooks (undefined) -> []', async function () {
|
||||||
delete plugins.hooks.testHook;
|
delete plugins.hooks.testHook;
|
||||||
assert.deepEqual(hooks.callAll(hookName), []);
|
assert.deepEqual(hooks.callAll(hookName), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no registered hooks (empty list) -> []', async function() {
|
it('no registered hooks (empty list) -> []', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
assert.deepEqual(hooks.callAll(hookName), []);
|
assert.deepEqual(hooks.callAll(hookName), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('flattens one level', async function() {
|
it('flattens one level', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
|
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
|
||||||
assert.deepEqual(hooks.callAll(hookName), [1, 2, [3]]);
|
assert.deepEqual(hooks.callAll(hookName), [1, 2, [3]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters out undefined', async function() {
|
it('filters out undefined', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]));
|
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]));
|
||||||
assert.deepEqual(hooks.callAll(hookName), [2, [3]]);
|
assert.deepEqual(hooks.callAll(hookName), [2, [3]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preserves null', async function() {
|
it('preserves null', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(null), makeHook([2]), makeHook([[3]]));
|
testHooks.push(makeHook(null), makeHook([2]), makeHook([[3]]));
|
||||||
assert.deepEqual(hooks.callAll(hookName), [null, 2, [3]]);
|
assert.deepEqual(hooks.callAll(hookName), [null, 2, [3]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('all undefined -> []', async function() {
|
it('all undefined -> []', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(), makeHook());
|
testHooks.push(makeHook(), makeHook());
|
||||||
assert.deepEqual(hooks.callAll(hookName), []);
|
assert.deepEqual(hooks.callAll(hookName), []);
|
||||||
|
@ -396,23 +394,23 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('callHookFnAsync', function() {
|
describe('callHookFnAsync', function () {
|
||||||
const callHookFnAsync = hooks.exportedForTestingOnly.callHookFnAsync; // Convenience shorthand.
|
const callHookFnAsync = hooks.exportedForTestingOnly.callHookFnAsync; // Convenience shorthand.
|
||||||
|
|
||||||
describe('basic behavior', function() {
|
describe('basic behavior', function () {
|
||||||
it('passes hook name', async function() {
|
it('passes hook name', async function () {
|
||||||
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
hook.hook_fn = (hn) => { assert.equal(hn, hookName); };
|
||||||
await callHookFnAsync(hook);
|
await callHookFnAsync(hook);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes context', async function() {
|
it('passes context', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
|
hook.hook_fn = (hn, ctx) => { assert.equal(ctx, val); };
|
||||||
await callHookFnAsync(hook, val);
|
await callHookFnAsync(hook, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the value provided to the callback', async function() {
|
it('returns the value provided to the callback', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
|
hook.hook_fn = (hn, ctx, cb) => { cb(ctx); };
|
||||||
assert.equal(await callHookFnAsync(hook, val), val);
|
assert.equal(await callHookFnAsync(hook, val), val);
|
||||||
|
@ -420,7 +418,7 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the value returned by the hook function', async function() {
|
it('returns the value returned by the hook function', async function () {
|
||||||
for (const val of ['value', null, undefined]) {
|
for (const val of ['value', null, undefined]) {
|
||||||
// Must not have the cb parameter otherwise returning undefined will never resolve.
|
// Must not have the cb parameter otherwise returning undefined will never resolve.
|
||||||
hook.hook_fn = (hn, ctx) => ctx;
|
hook.hook_fn = (hn, ctx) => ctx;
|
||||||
|
@ -429,27 +427,27 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects if it throws an exception', async function() {
|
it('rejects if it throws an exception', async function () {
|
||||||
hook.hook_fn = () => { throw new Error('test exception'); };
|
hook.hook_fn = () => { throw new Error('test exception'); };
|
||||||
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects if rejected Promise passed to callback', async function() {
|
it('rejects if rejected Promise passed to callback', async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => cb(Promise.reject(new Error('test exception')));
|
hook.hook_fn = (hn, ctx, cb) => cb(Promise.reject(new Error('test exception')));
|
||||||
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects if rejected Promise returned', async function() {
|
it('rejects if rejected Promise returned', async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => Promise.reject(new Error('test exception'));
|
hook.hook_fn = (hn, ctx, cb) => Promise.reject(new Error('test exception'));
|
||||||
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
await assert.rejects(callHookFnAsync(hook), {message: 'test exception'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('callback returns undefined', async function() {
|
it('callback returns undefined', async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
|
hook.hook_fn = (hn, ctx, cb) => { assert.equal(cb('foo'), undefined); };
|
||||||
await callHookFnAsync(hook);
|
await callHookFnAsync(hook);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('checks for deprecation', async function() {
|
it('checks for deprecation', async function () {
|
||||||
sinon.stub(console, 'warn');
|
sinon.stub(console, 'warn');
|
||||||
hooks.deprecationNotices[hookName] = 'test deprecation';
|
hooks.deprecationNotices[hookName] = 'test deprecation';
|
||||||
await callHookFnAsync(hook);
|
await callHookFnAsync(hook);
|
||||||
|
@ -459,7 +457,7 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('supported hook function styles', function() {
|
describe('supported hook function styles', function () {
|
||||||
const supportedHookFunctions = supportedSyncHookFunctions.concat([
|
const supportedHookFunctions = supportedSyncHookFunctions.concat([
|
||||||
{
|
{
|
||||||
name: 'legacy async cb',
|
name: 'legacy async cb',
|
||||||
|
@ -541,7 +539,7 @@ describe(__filename, function() {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (const tc of supportedSyncHookFunctions.concat(supportedHookFunctions)) {
|
for (const tc of supportedSyncHookFunctions.concat(supportedHookFunctions)) {
|
||||||
it(tc.name, async function() {
|
it(tc.name, async function () {
|
||||||
sinon.stub(console, 'warn');
|
sinon.stub(console, 'warn');
|
||||||
sinon.stub(console, 'error');
|
sinon.stub(console, 'error');
|
||||||
hook.hook_fn = tc.fn;
|
hook.hook_fn = tc.fn;
|
||||||
|
@ -559,8 +557,8 @@ describe(__filename, function() {
|
||||||
|
|
||||||
// Test various ways a hook might attempt to settle twice. (Examples: call the callback a second
|
// Test various ways a hook might attempt to settle twice. (Examples: call the callback a second
|
||||||
// time, or call the callback and then return a value.)
|
// time, or call the callback and then return a value.)
|
||||||
describe('bad hook function behavior (double settle)', function() {
|
describe('bad hook function behavior (double settle)', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
sinon.stub(console, 'error');
|
sinon.stub(console, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -688,7 +686,7 @@ describe(__filename, function() {
|
||||||
// There can't be a second step if the first step is to return or throw.
|
// There can't be a second step if the first step is to return or throw.
|
||||||
if (step1.name.startsWith('return ') || step1.name === 'throw') continue;
|
if (step1.name.startsWith('return ') || step1.name === 'throw') continue;
|
||||||
for (const step2 of behaviors) {
|
for (const step2 of behaviors) {
|
||||||
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function() {
|
it(`${step1.name} then ${step2.name} (diff. outcomes) -> log+throw`, async function () {
|
||||||
hook.hook_fn = (hn, ctx, cb) => {
|
hook.hook_fn = (hn, ctx, cb) => {
|
||||||
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
|
step1.fn(cb, new Error(ctx.ret1), ctx.ret1);
|
||||||
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
|
return step2.fn(cb, new Error(ctx.ret2), ctx.ret2);
|
||||||
|
@ -729,8 +727,8 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.equal(console.error.callCount, 1,
|
assert.equal(console.error.callCount, 1,
|
||||||
'Got errors:\n' +
|
`Got errors:\n${
|
||||||
console.error.getCalls().map((call) => call.args[0]).join('\n'));
|
console.error.getCalls().map((call) => call.args[0]).join('\n')}`);
|
||||||
assert.match(console.error.getCall(0).args[0], /DOUBLE SETTLE BUG/);
|
assert.match(console.error.getCall(0).args[0], /DOUBLE SETTLE BUG/);
|
||||||
assert(asyncErr instanceof Error);
|
assert(asyncErr instanceof Error);
|
||||||
assert.match(asyncErr.message, /DOUBLE SETTLE BUG/);
|
assert.match(asyncErr.message, /DOUBLE SETTLE BUG/);
|
||||||
|
@ -741,7 +739,7 @@ describe(__filename, function() {
|
||||||
// doesn't, so skip those cases.
|
// doesn't, so skip those cases.
|
||||||
if (step1.rejects !== step2.rejects) continue;
|
if (step1.rejects !== step2.rejects) continue;
|
||||||
|
|
||||||
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function() {
|
it(`${step1.name} then ${step2.name} (same outcome) -> only log`, async function () {
|
||||||
const err = new Error('val');
|
const err = new Error('val');
|
||||||
hook.hook_fn = (hn, ctx, cb) => {
|
hook.hook_fn = (hn, ctx, cb) => {
|
||||||
step1.fn(cb, err, 'val');
|
step1.fn(cb, err, 'val');
|
||||||
|
@ -764,9 +762,9 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hooks.aCallAll', function() {
|
describe('hooks.aCallAll', function () {
|
||||||
describe('basic behavior', function() {
|
describe('basic behavior', function () {
|
||||||
it('calls all asynchronously, returns values in order', async function() {
|
it('calls all asynchronously, returns values in order', async function () {
|
||||||
testHooks.length = 0; // Delete the boilerplate hook -- this test doesn't use it.
|
testHooks.length = 0; // Delete the boilerplate hook -- this test doesn't use it.
|
||||||
let nextIndex = 0;
|
let nextIndex = 0;
|
||||||
const hookPromises = [];
|
const hookPromises = [];
|
||||||
|
@ -800,35 +798,35 @@ describe(__filename, function() {
|
||||||
assert.deepEqual(await p, [0, 1]);
|
assert.deepEqual(await p, [0, 1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('passes hook name', async function() {
|
it('passes hook name', async function () {
|
||||||
hook.hook_fn = async (hn) => { assert.equal(hn, hookName); };
|
hook.hook_fn = async (hn) => { assert.equal(hn, hookName); };
|
||||||
await hooks.aCallAll(hookName);
|
await hooks.aCallAll(hookName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('undefined context -> {}', async function() {
|
it('undefined context -> {}', async function () {
|
||||||
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
||||||
await hooks.aCallAll(hookName);
|
await hooks.aCallAll(hookName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('null context -> {}', async function() {
|
it('null context -> {}', async function () {
|
||||||
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); };
|
||||||
await hooks.aCallAll(hookName, null);
|
await hooks.aCallAll(hookName, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('context unmodified', async function() {
|
it('context unmodified', async function () {
|
||||||
const wantContext = {};
|
const wantContext = {};
|
||||||
hook.hook_fn = async (hn, ctx) => { assert.equal(ctx, wantContext); };
|
hook.hook_fn = async (hn, ctx) => { assert.equal(ctx, wantContext); };
|
||||||
await hooks.aCallAll(hookName, wantContext);
|
await hooks.aCallAll(hookName, wantContext);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('aCallAll callback', function() {
|
describe('aCallAll callback', function () {
|
||||||
it('exception in callback rejects', async function() {
|
it('exception in callback rejects', async function () {
|
||||||
const p = hooks.aCallAll(hookName, {}, () => { throw new Error('test exception'); });
|
const p = hooks.aCallAll(hookName, {}, () => { throw new Error('test exception'); });
|
||||||
await assert.rejects(p, {message: 'test exception'});
|
await assert.rejects(p, {message: 'test exception'});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('propagates error on exception', async function() {
|
it('propagates error on exception', async function () {
|
||||||
hook.hook_fn = () => { throw new Error('test exception'); };
|
hook.hook_fn = () => { throw new Error('test exception'); };
|
||||||
await hooks.aCallAll(hookName, {}, (err) => {
|
await hooks.aCallAll(hookName, {}, (err) => {
|
||||||
assert(err instanceof Error);
|
assert(err instanceof Error);
|
||||||
|
@ -836,54 +834,54 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('propagages null error on success', async function() {
|
it('propagages null error on success', async function () {
|
||||||
await hooks.aCallAll(hookName, {}, (err) => {
|
await hooks.aCallAll(hookName, {}, (err) => {
|
||||||
assert(err == null, `got non-null error: ${err}`);
|
assert(err == null, `got non-null error: ${err}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('propagages results on success', async function() {
|
it('propagages results on success', async function () {
|
||||||
hook.hook_fn = () => 'val';
|
hook.hook_fn = () => 'val';
|
||||||
await hooks.aCallAll(hookName, {}, (err, results) => {
|
await hooks.aCallAll(hookName, {}, (err, results) => {
|
||||||
assert.deepEqual(results, ['val']);
|
assert.deepEqual(results, ['val']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns callback return value', async function() {
|
it('returns callback return value', async function () {
|
||||||
assert.equal(await hooks.aCallAll(hookName, {}, () => 'val'), 'val');
|
assert.equal(await hooks.aCallAll(hookName, {}, () => 'val'), 'val');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('result processing', function() {
|
describe('result processing', function () {
|
||||||
it('no registered hooks (undefined) -> []', async function() {
|
it('no registered hooks (undefined) -> []', async function () {
|
||||||
delete plugins.hooks[hookName];
|
delete plugins.hooks[hookName];
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no registered hooks (empty list) -> []', async function() {
|
it('no registered hooks (empty list) -> []', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('flattens one level', async function() {
|
it('flattens one level', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
|
testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]]));
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), [1, 2, [3]]);
|
assert.deepEqual(await hooks.aCallAll(hookName), [1, 2, [3]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters out undefined', async function() {
|
it('filters out undefined', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]), makeHook(Promise.resolve()));
|
testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]), makeHook(Promise.resolve()));
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), [2, [3]]);
|
assert.deepEqual(await hooks.aCallAll(hookName), [2, [3]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('preserves null', async function() {
|
it('preserves null', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(null), makeHook([2]), makeHook(Promise.resolve(null)));
|
testHooks.push(makeHook(null), makeHook([2]), makeHook(Promise.resolve(null)));
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), [null, 2, null]);
|
assert.deepEqual(await hooks.aCallAll(hookName), [null, 2, null]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('all undefined -> []', async function() {
|
it('all undefined -> []', async function () {
|
||||||
testHooks.length = 0;
|
testHooks.length = 0;
|
||||||
testHooks.push(makeHook(), makeHook(Promise.resolve()));
|
testHooks.push(makeHook(), makeHook(Promise.resolve()));
|
||||||
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
assert.deepEqual(await hooks.aCallAll(hookName), []);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
function m(mod) { return __dirname + '/../../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../../src/${mod}`; }
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const promises = require(m('node/utils/promises'));
|
const promises = require(m('node/utils/promises'));
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
describe('promises.timesLimit', function() {
|
describe('promises.timesLimit', function () {
|
||||||
let wantIndex = 0;
|
let wantIndex = 0;
|
||||||
const testPromises = [];
|
const testPromises = [];
|
||||||
const makePromise = (index) => {
|
const makePromise = (index) => {
|
||||||
|
@ -25,18 +25,18 @@ describe(__filename, function() {
|
||||||
const concurrency = 7;
|
const concurrency = 7;
|
||||||
const timesLimitPromise = promises.timesLimit(total, concurrency, makePromise);
|
const timesLimitPromise = promises.timesLimit(total, concurrency, makePromise);
|
||||||
|
|
||||||
it('honors concurrency', async function() {
|
it('honors concurrency', async function () {
|
||||||
assert.equal(wantIndex, concurrency);
|
assert.equal(wantIndex, concurrency);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates another when one completes', async function() {
|
it('creates another when one completes', async function () {
|
||||||
const {promise, resolve} = testPromises.shift();
|
const {promise, resolve} = testPromises.shift();
|
||||||
resolve();
|
resolve();
|
||||||
await promise;
|
await promise;
|
||||||
assert.equal(wantIndex, concurrency + 1);
|
assert.equal(wantIndex, concurrency + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates the expected total number of promises', async function() {
|
it('creates the expected total number of promises', async function () {
|
||||||
while (testPromises.length > 0) {
|
while (testPromises.length > 0) {
|
||||||
// Resolve them in random order to ensure that the resolution order doesn't matter.
|
// Resolve them in random order to ensure that the resolution order doesn't matter.
|
||||||
const i = Math.floor(Math.random() * Math.floor(testPromises.length));
|
const i = Math.floor(Math.random() * Math.floor(testPromises.length));
|
||||||
|
@ -47,11 +47,11 @@ describe(__filename, function() {
|
||||||
assert.equal(wantIndex, total);
|
assert.equal(wantIndex, total);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resolves', async function() {
|
it('resolves', async function () {
|
||||||
await timesLimitPromise;
|
await timesLimitPromise;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not create too many promises if total < concurrency', async function() {
|
it('does not create too many promises if total < concurrency', async function () {
|
||||||
wantIndex = 0;
|
wantIndex = 0;
|
||||||
assert.equal(testPromises.length, 0);
|
assert.equal(testPromises.length, 0);
|
||||||
const total = 7;
|
const total = 7;
|
||||||
|
@ -66,21 +66,21 @@ describe(__filename, function() {
|
||||||
assert.equal(wantIndex, total);
|
assert.equal(wantIndex, total);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts total === 0, concurrency > 0', async function() {
|
it('accepts total === 0, concurrency > 0', async function () {
|
||||||
wantIndex = 0;
|
wantIndex = 0;
|
||||||
assert.equal(testPromises.length, 0);
|
assert.equal(testPromises.length, 0);
|
||||||
await promises.timesLimit(0, concurrency, makePromise);
|
await promises.timesLimit(0, concurrency, makePromise);
|
||||||
assert.equal(wantIndex, 0);
|
assert.equal(wantIndex, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accepts total === 0, concurrency === 0', async function() {
|
it('accepts total === 0, concurrency === 0', async function () {
|
||||||
wantIndex = 0;
|
wantIndex = 0;
|
||||||
assert.equal(testPromises.length, 0);
|
assert.equal(testPromises.length, 0);
|
||||||
await promises.timesLimit(0, 0, makePromise);
|
await promises.timesLimit(0, 0, makePromise);
|
||||||
assert.equal(wantIndex, 0);
|
assert.equal(wantIndex, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects total > 0, concurrency === 0', async function() {
|
it('rejects total > 0, concurrency === 0', async function () {
|
||||||
await assert.rejects(promises.timesLimit(total, 0, makePromise), RangeError);
|
await assert.rejects(promises.timesLimit(total, 0, makePromise), RangeError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global __dirname, __filename, afterEach, before, beforeEach, clearTimeout, describe, it, require, setTimeout */
|
/* global __dirname, __filename, afterEach, before, beforeEach, clearTimeout, describe, it, require, setTimeout */
|
||||||
|
|
||||||
function m(mod) { return __dirname + '/../../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../../src/${mod}`; }
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
|
@ -50,9 +50,7 @@ const getSocketEvent = async (socket, event) => {
|
||||||
const connect = async (res) => {
|
const connect = async (res) => {
|
||||||
// Convert the `set-cookie` header(s) into a `cookie` header.
|
// Convert the `set-cookie` header(s) into a `cookie` header.
|
||||||
const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true});
|
const resCookies = (res == null) ? {} : setCookieParser.parse(res, {map: true});
|
||||||
const reqCookieHdr = Object.entries(resCookies).map(([name, cookie]) => {
|
const reqCookieHdr = Object.entries(resCookies).map(([name, cookie]) => `${name}=${encodeURIComponent(cookie.value)}`).join('; ');
|
||||||
return `${name}=${encodeURIComponent(cookie.value)}`;
|
|
||||||
}).join('; ');
|
|
||||||
|
|
||||||
logger.debug('socket.io connecting...');
|
logger.debug('socket.io connecting...');
|
||||||
const socket = io(`${common.baseUrl}/`, {
|
const socket = io(`${common.baseUrl}/`, {
|
||||||
|
@ -91,7 +89,7 @@ const handshake = async (socket, padID) => {
|
||||||
return msg;
|
return msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
let agent;
|
let agent;
|
||||||
let authorize;
|
let authorize;
|
||||||
const backups = {};
|
const backups = {};
|
||||||
|
@ -106,8 +104,8 @@ describe(__filename, function() {
|
||||||
};
|
};
|
||||||
let socket;
|
let socket;
|
||||||
|
|
||||||
before(async function() { agent = await common.init(); });
|
before(async function () { agent = await common.init(); });
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
backups.hooks = {};
|
backups.hooks = {};
|
||||||
for (const hookName of ['preAuthorize', 'authenticate', 'authorize']) {
|
for (const hookName of ['preAuthorize', 'authenticate', 'authorize']) {
|
||||||
backups.hooks[hookName] = plugins.hooks[hookName];
|
backups.hooks[hookName] = plugins.hooks[hookName];
|
||||||
|
@ -126,12 +124,10 @@ describe(__filename, function() {
|
||||||
};
|
};
|
||||||
assert(socket == null);
|
assert(socket == null);
|
||||||
authorize = () => true;
|
authorize = () => true;
|
||||||
plugins.hooks.authorize = [{hook_fn: (hookName, {req}, cb) => {
|
plugins.hooks.authorize = [{hook_fn: (hookName, {req}, cb) => cb([authorize(req)])}];
|
||||||
return cb([authorize(req)]);
|
|
||||||
}}];
|
|
||||||
await cleanUpPads();
|
await cleanUpPads();
|
||||||
});
|
});
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
if (socket) socket.close();
|
if (socket) socket.close();
|
||||||
socket = null;
|
socket = null;
|
||||||
await cleanUpPads();
|
await cleanUpPads();
|
||||||
|
@ -139,32 +135,32 @@ describe(__filename, function() {
|
||||||
Object.assign(settings, backups.settings);
|
Object.assign(settings, backups.settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Normal accesses', function() {
|
describe('Normal accesses', function () {
|
||||||
it('!authn anonymous cookie /p/pad -> 200, ok', async function() {
|
it('!authn anonymous cookie /p/pad -> 200, ok', async function () {
|
||||||
const res = await agent.get('/p/pad').expect(200);
|
const res = await agent.get('/p/pad').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('!authn !cookie -> ok', async function() {
|
it('!authn !cookie -> ok', async function () {
|
||||||
socket = await connect(null);
|
socket = await connect(null);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('!authn user /p/pad -> 200, ok', async function() {
|
it('!authn user /p/pad -> 200, ok', async function () {
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('authn user /p/pad -> 200, ok', async function() {
|
it('authn user /p/pad -> 200, ok', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('authz user /p/pad -> 200, ok', async function() {
|
it('authz user /p/pad -> 200, ok', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -172,7 +168,7 @@ describe(__filename, function() {
|
||||||
const clientVars = await handshake(socket, 'pad');
|
const clientVars = await handshake(socket, 'pad');
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
});
|
});
|
||||||
it('supports pad names with characters that must be percent-encoded', async function() {
|
it('supports pad names with characters that must be percent-encoded', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
// requireAuthorization is set to true here to guarantee that the user's padAuthorizations
|
// requireAuthorization is set to true here to guarantee that the user's padAuthorizations
|
||||||
// object is populated. Technically this isn't necessary because the user's padAuthorizations
|
// object is populated. Technically this isn't necessary because the user's padAuthorizations
|
||||||
|
@ -187,8 +183,8 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Abnormal access attempts', function() {
|
describe('Abnormal access attempts', function () {
|
||||||
it('authn anonymous /p/pad -> 401, error', async function() {
|
it('authn anonymous /p/pad -> 401, error', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
const res = await agent.get('/p/pad').expect(401);
|
const res = await agent.get('/p/pad').expect(401);
|
||||||
// Despite the 401, try to create the pad via a socket.io connection anyway.
|
// Despite the 401, try to create the pad via a socket.io connection anyway.
|
||||||
|
@ -196,13 +192,13 @@ describe(__filename, function() {
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('authn !cookie -> error', async function() {
|
it('authn !cookie -> error', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
socket = await connect(null);
|
socket = await connect(null);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('authorization bypass attempt -> error', async function() {
|
it('authorization bypass attempt -> error', async function () {
|
||||||
// Only allowed to access /p/pad.
|
// Only allowed to access /p/pad.
|
||||||
authorize = (req) => req.path === '/p/pad';
|
authorize = (req) => req.path === '/p/pad';
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
|
@ -216,13 +212,13 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Authorization levels via authorize hook', function() {
|
describe('Authorization levels via authorize hook', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("level='create' -> can create", async function() {
|
it("level='create' -> can create", async function () {
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
|
@ -230,7 +226,7 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it('level=true -> can create', async function() {
|
it('level=true -> can create', async function () {
|
||||||
authorize = () => true;
|
authorize = () => true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
|
@ -238,7 +234,7 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it("level='modify' -> can modify", async function() {
|
it("level='modify' -> can modify", async function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -247,7 +243,7 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it("level='create' settings.editOnly=true -> unable to create", async function() {
|
it("level='create' settings.editOnly=true -> unable to create", async function () {
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
settings.editOnly = true;
|
settings.editOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -255,7 +251,7 @@ describe(__filename, function() {
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='modify' settings.editOnly=false -> unable to create", async function() {
|
it("level='modify' settings.editOnly=false -> unable to create", async function () {
|
||||||
authorize = () => 'modify';
|
authorize = () => 'modify';
|
||||||
settings.editOnly = false;
|
settings.editOnly = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -263,14 +259,14 @@ describe(__filename, function() {
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='readOnly' -> unable to create", async function() {
|
it("level='readOnly' -> unable to create", async function () {
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it("level='readOnly' -> unable to modify", async function() {
|
it("level='readOnly' -> unable to modify", async function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -281,12 +277,12 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Authorization levels via user settings', function() {
|
describe('Authorization levels via user settings', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('user.canCreate = true -> can create and modify', async function() {
|
it('user.canCreate = true -> can create and modify', async function () {
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
|
@ -294,21 +290,21 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it('user.canCreate = false -> unable to create', async function() {
|
it('user.canCreate = false -> unable to create', async function () {
|
||||||
settings.users.user.canCreate = false;
|
settings.users.user.canCreate = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user.readOnly = true -> unable to create', async function() {
|
it('user.readOnly = true -> unable to create', async function () {
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user.readOnly = true -> unable to modify', async function() {
|
it('user.readOnly = true -> unable to modify', async function () {
|
||||||
await padManager.getPad('pad'); // Create the pad.
|
await padManager.getPad('pad'); // Create the pad.
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -317,7 +313,7 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, true);
|
assert.equal(clientVars.data.readonly, true);
|
||||||
});
|
});
|
||||||
it('user.readOnly = false -> can create and modify', async function() {
|
it('user.readOnly = false -> can create and modify', async function () {
|
||||||
settings.users.user.readOnly = false;
|
settings.users.user.readOnly = false;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
socket = await connect(res);
|
socket = await connect(res);
|
||||||
|
@ -325,7 +321,7 @@ describe(__filename, function() {
|
||||||
assert.equal(clientVars.type, 'CLIENT_VARS');
|
assert.equal(clientVars.type, 'CLIENT_VARS');
|
||||||
assert.equal(clientVars.data.readonly, false);
|
assert.equal(clientVars.data.readonly, false);
|
||||||
});
|
});
|
||||||
it('user.readOnly = true, user.canCreate = true -> unable to create', async function() {
|
it('user.readOnly = true, user.canCreate = true -> unable to create', async function () {
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -335,13 +331,13 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Authorization level interaction between authorize hook and user settings', function() {
|
describe('Authorization level interaction between authorize hook and user settings', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('authorize hook does not elevate level from user settings', async function() {
|
it('authorize hook does not elevate level from user settings', async function () {
|
||||||
settings.users.user.readOnly = true;
|
settings.users.user.readOnly = true;
|
||||||
authorize = () => 'create';
|
authorize = () => 'create';
|
||||||
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
const res = await agent.get('/p/pad').auth('user', 'user-password').expect(200);
|
||||||
|
@ -349,7 +345,7 @@ describe(__filename, function() {
|
||||||
const message = await handshake(socket, 'pad');
|
const message = await handshake(socket, 'pad');
|
||||||
assert.equal(message.accessStatus, 'deny');
|
assert.equal(message.accessStatus, 'deny');
|
||||||
});
|
});
|
||||||
it('user settings does not elevate level from authorize hook', async function() {
|
it('user settings does not elevate level from authorize hook', async function () {
|
||||||
settings.users.user.readOnly = false;
|
settings.users.user.readOnly = false;
|
||||||
settings.users.user.canCreate = true;
|
settings.users.user.canCreate = true;
|
||||||
authorize = () => 'readOnly';
|
authorize = () => 'readOnly';
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const settings = require('ep_etherpad-lite/node/utils/Settings');
|
const settings = require('ep_etherpad-lite/node/utils/Settings');
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
let agent;
|
let agent;
|
||||||
const backups = {};
|
const backups = {};
|
||||||
before(async function() { agent = await common.init(); });
|
before(async function () { agent = await common.init(); });
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
backups.settings = {};
|
backups.settings = {};
|
||||||
for (const setting of ['requireAuthentication', 'requireAuthorization']) {
|
for (const setting of ['requireAuthentication', 'requireAuthorization']) {
|
||||||
backups.settings[setting] = settings[setting];
|
backups.settings[setting] = settings[setting];
|
||||||
|
@ -13,12 +13,12 @@ describe(__filename, function() {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
});
|
});
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
Object.assign(settings, backups.settings);
|
Object.assign(settings, backups.settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('/javascript', function() {
|
describe('/javascript', function () {
|
||||||
it('/javascript -> 200', async function() {
|
it('/javascript -> 200', async function () {
|
||||||
await agent.get('/javascript').expect(200);
|
await agent.get('/javascript').expect(200);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
/* global __dirname, __filename, Buffer, afterEach, before, beforeEach, describe, it, require */
|
/* global __dirname, __filename, Buffer, afterEach, before, beforeEach, describe, it, require */
|
||||||
|
|
||||||
function m(mod) { return __dirname + '/../../../src/' + mod; }
|
function m(mod) { return `${__dirname}/../../../src/${mod}`; }
|
||||||
|
|
||||||
const assert = require('assert').strict;
|
const assert = require('assert').strict;
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const plugins = require(m('static/js/pluginfw/plugin_defs'));
|
const plugins = require(m('static/js/pluginfw/plugin_defs'));
|
||||||
const settings = require(m('node/utils/Settings'));
|
const settings = require(m('node/utils/Settings'));
|
||||||
|
|
||||||
describe(__filename, function() {
|
describe(__filename, function () {
|
||||||
let agent;
|
let agent;
|
||||||
const backups = {};
|
const backups = {};
|
||||||
const authHookNames = ['preAuthorize', 'authenticate', 'authorize'];
|
const authHookNames = ['preAuthorize', 'authenticate', 'authorize'];
|
||||||
const failHookNames = ['preAuthzFailure', 'authnFailure', 'authzFailure', 'authFailure'];
|
const failHookNames = ['preAuthzFailure', 'authnFailure', 'authzFailure', 'authFailure'];
|
||||||
before(async function() { agent = await common.init(); });
|
before(async function () { agent = await common.init(); });
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
backups.hooks = {};
|
backups.hooks = {};
|
||||||
for (const hookName of authHookNames.concat(failHookNames)) {
|
for (const hookName of authHookNames.concat(failHookNames)) {
|
||||||
backups.hooks[hookName] = plugins.hooks[hookName];
|
backups.hooks[hookName] = plugins.hooks[hookName];
|
||||||
|
@ -30,76 +30,76 @@ describe(__filename, function() {
|
||||||
user: {password: 'user-password'},
|
user: {password: 'user-password'},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
afterEach(async function() {
|
afterEach(async function () {
|
||||||
Object.assign(plugins.hooks, backups.hooks);
|
Object.assign(plugins.hooks, backups.hooks);
|
||||||
Object.assign(settings, backups.settings);
|
Object.assign(settings, backups.settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('webaccess: without plugins', function() {
|
describe('webaccess: without plugins', function () {
|
||||||
it('!authn !authz anonymous / -> 200', async function() {
|
it('!authn !authz anonymous / -> 200', async function () {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/').expect(200);
|
await agent.get('/').expect(200);
|
||||||
});
|
});
|
||||||
it('!authn !authz anonymous /admin/ -> 401', async function() {
|
it('!authn !authz anonymous /admin/ -> 401', async function () {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/admin/').expect(401);
|
await agent.get('/admin/').expect(401);
|
||||||
});
|
});
|
||||||
it('authn !authz anonymous / -> 401', async function() {
|
it('authn !authz anonymous / -> 401', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
});
|
});
|
||||||
it('authn !authz user / -> 200', async function() {
|
it('authn !authz user / -> 200', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200);
|
await agent.get('/').auth('user', 'user-password').expect(200);
|
||||||
});
|
});
|
||||||
it('authn !authz user /admin/ -> 403', async function() {
|
it('authn !authz user /admin/ -> 403', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/admin/').auth('user', 'user-password').expect(403);
|
await agent.get('/admin/').auth('user', 'user-password').expect(403);
|
||||||
});
|
});
|
||||||
it('authn !authz admin / -> 200', async function() {
|
it('authn !authz admin / -> 200', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/').auth('admin', 'admin-password').expect(200);
|
await agent.get('/').auth('admin', 'admin-password').expect(200);
|
||||||
});
|
});
|
||||||
it('authn !authz admin /admin/ -> 200', async function() {
|
it('authn !authz admin /admin/ -> 200', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
||||||
});
|
});
|
||||||
it('authn authz user / -> 403', async function() {
|
it('authn authz user / -> 403', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(403);
|
await agent.get('/').auth('user', 'user-password').expect(403);
|
||||||
});
|
});
|
||||||
it('authn authz user /admin/ -> 403', async function() {
|
it('authn authz user /admin/ -> 403', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
await agent.get('/admin/').auth('user', 'user-password').expect(403);
|
await agent.get('/admin/').auth('user', 'user-password').expect(403);
|
||||||
});
|
});
|
||||||
it('authn authz admin / -> 200', async function() {
|
it('authn authz admin / -> 200', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
await agent.get('/').auth('admin', 'admin-password').expect(200);
|
await agent.get('/').auth('admin', 'admin-password').expect(200);
|
||||||
});
|
});
|
||||||
it('authn authz admin /admin/ -> 200', async function() {
|
it('authn authz admin /admin/ -> 200', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('login fails if password is nullish', function() {
|
describe('login fails if password is nullish', function () {
|
||||||
for (const adminPassword of [undefined, null]) {
|
for (const adminPassword of [undefined, null]) {
|
||||||
// https://tools.ietf.org/html/rfc7617 says that the username and password are sent as
|
// https://tools.ietf.org/html/rfc7617 says that the username and password are sent as
|
||||||
// base64(username + ':' + password), but there's nothing stopping a malicious user from
|
// base64(username + ':' + password), but there's nothing stopping a malicious user from
|
||||||
// sending just base64(username) (no colon). The lack of colon could throw off credential
|
// sending just base64(username) (no colon). The lack of colon could throw off credential
|
||||||
// parsing, resulting in successful comparisons against a null or undefined password.
|
// parsing, resulting in successful comparisons against a null or undefined password.
|
||||||
for (const creds of ['admin', 'admin:']) {
|
for (const creds of ['admin', 'admin:']) {
|
||||||
it(`admin password: ${adminPassword} credentials: ${creds}`, async function() {
|
it(`admin password: ${adminPassword} credentials: ${creds}`, async function () {
|
||||||
settings.users.admin.password = adminPassword;
|
settings.users.admin.password = adminPassword;
|
||||||
const encCreds = Buffer.from(creds).toString('base64');
|
const encCreds = Buffer.from(creds).toString('base64');
|
||||||
await agent.get('/admin/').set('Authorization', `Basic ${encCreds}`).expect(401);
|
await agent.get('/admin/').set('Authorization', `Basic ${encCreds}`).expect(401);
|
||||||
|
@ -109,7 +109,7 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('webaccess: preAuthorize, authenticate, and authorize hooks', function() {
|
describe('webaccess: preAuthorize, authenticate, and authorize hooks', function () {
|
||||||
let callOrder;
|
let callOrder;
|
||||||
const Handler = class {
|
const Handler = class {
|
||||||
constructor(hookName, suffix) {
|
constructor(hookName, suffix) {
|
||||||
|
@ -134,7 +134,7 @@ describe(__filename, function() {
|
||||||
};
|
};
|
||||||
const handlers = {};
|
const handlers = {};
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
callOrder = [];
|
callOrder = [];
|
||||||
for (const hookName of authHookNames) {
|
for (const hookName of authHookNames) {
|
||||||
// Create two handlers for each hook to test deferral to the next function.
|
// Create two handlers for each hook to test deferral to the next function.
|
||||||
|
@ -145,38 +145,38 @@ describe(__filename, function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('preAuthorize', function() {
|
describe('preAuthorize', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('defers if it returns []', async function() {
|
it('defers if it returns []', async function () {
|
||||||
await agent.get('/').expect(200);
|
await agent.get('/').expect(200);
|
||||||
// Note: The preAuthorize hook always runs even if requireAuthorization is false.
|
// Note: The preAuthorize hook always runs even if requireAuthorization is false.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
||||||
});
|
});
|
||||||
it('bypasses authenticate and authorize hooks when true is returned', async function() {
|
it('bypasses authenticate and authorize hooks when true is returned', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
handlers.preAuthorize[0].innerHandle = () => [true];
|
handlers.preAuthorize[0].innerHandle = () => [true];
|
||||||
await agent.get('/').expect(200);
|
await agent.get('/').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
||||||
});
|
});
|
||||||
it('bypasses authenticate and authorize hooks when false is returned', async function() {
|
it('bypasses authenticate and authorize hooks when false is returned', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
handlers.preAuthorize[0].innerHandle = () => [false];
|
handlers.preAuthorize[0].innerHandle = () => [false];
|
||||||
await agent.get('/').expect(403);
|
await agent.get('/').expect(403);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
||||||
});
|
});
|
||||||
it('bypasses authenticate and authorize hooks for static content, defers', async function() {
|
it('bypasses authenticate and authorize hooks for static content, defers', async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
await agent.get('/static/robots.txt').expect(200);
|
await agent.get('/static/robots.txt').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
||||||
});
|
});
|
||||||
it('cannot grant access to /admin', async function() {
|
it('cannot grant access to /admin', async function () {
|
||||||
handlers.preAuthorize[0].innerHandle = () => [true];
|
handlers.preAuthorize[0].innerHandle = () => [true];
|
||||||
await agent.get('/admin/').expect(401);
|
await agent.get('/admin/').expect(401);
|
||||||
// Notes:
|
// Notes:
|
||||||
|
@ -184,15 +184,17 @@ describe(__filename, function() {
|
||||||
// 'true' entries are ignored for /admin/* requests.
|
// 'true' entries are ignored for /admin/* requests.
|
||||||
// * The authenticate hook always runs for /admin/* requests even if
|
// * The authenticate hook always runs for /admin/* requests even if
|
||||||
// settings.requireAuthentication is false.
|
// settings.requireAuthentication is false.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('can deny access to /admin', async function() {
|
it('can deny access to /admin', async function () {
|
||||||
handlers.preAuthorize[0].innerHandle = () => [false];
|
handlers.preAuthorize[0].innerHandle = () => [false];
|
||||||
await agent.get('/admin/').auth('admin', 'admin-password').expect(403);
|
await agent.get('/admin/').auth('admin', 'admin-password').expect(403);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0']);
|
||||||
});
|
});
|
||||||
it('runs preAuthzFailure hook when access is denied', async function() {
|
it('runs preAuthzFailure hook when access is denied', async function () {
|
||||||
handlers.preAuthorize[0].innerHandle = () => [false];
|
handlers.preAuthorize[0].innerHandle = () => [false];
|
||||||
let called = false;
|
let called = false;
|
||||||
plugins.hooks.preAuthzFailure = [{hook_fn: (hookName, {req, res}, cb) => {
|
plugins.hooks.preAuthzFailure = [{hook_fn: (hookName, {req, res}, cb) => {
|
||||||
|
@ -207,149 +209,177 @@ describe(__filename, function() {
|
||||||
await agent.get('/admin/').auth('admin', 'admin-password').expect(200, 'injected');
|
await agent.get('/admin/').auth('admin', 'admin-password').expect(200, 'injected');
|
||||||
assert(called);
|
assert(called);
|
||||||
});
|
});
|
||||||
it('returns 500 if an exception is thrown', async function() {
|
it('returns 500 if an exception is thrown', async function () {
|
||||||
handlers.preAuthorize[0].innerHandle = () => { throw new Error('exception test'); };
|
handlers.preAuthorize[0].innerHandle = () => { throw new Error('exception test'); };
|
||||||
await agent.get('/').expect(500);
|
await agent.get('/').expect(500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('authenticate', function() {
|
describe('authenticate', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is not called if !requireAuthentication and not /admin/*', async function() {
|
it('is not called if !requireAuthentication and not /admin/*', async function () {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
await agent.get('/').expect(200);
|
await agent.get('/').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1']);
|
||||||
});
|
});
|
||||||
it('is called if !requireAuthentication and /admin/*', async function() {
|
it('is called if !requireAuthentication and /admin/*', async function () {
|
||||||
settings.requireAuthentication = false;
|
settings.requireAuthentication = false;
|
||||||
await agent.get('/admin/').expect(401);
|
await agent.get('/admin/').expect(401);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('defers if empty list returned', async function() {
|
it('defers if empty list returned', async function () {
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('does not defer if return [true], 200', async function() {
|
it('does not defer if return [true], 200', async function () {
|
||||||
handlers.authenticate[0].innerHandle = (req) => { req.session.user = {}; return [true]; };
|
handlers.authenticate[0].innerHandle = (req) => { req.session.user = {}; return [true]; };
|
||||||
await agent.get('/').expect(200);
|
await agent.get('/').expect(200);
|
||||||
// Note: authenticate_1 was not called because authenticate_0 handled it.
|
// Note: authenticate_1 was not called because authenticate_0 handled it.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
||||||
});
|
});
|
||||||
it('does not defer if return [false], 401', async function() {
|
it('does not defer if return [false], 401', async function () {
|
||||||
handlers.authenticate[0].innerHandle = (req) => [false];
|
handlers.authenticate[0].innerHandle = (req) => [false];
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
// Note: authenticate_1 was not called because authenticate_0 handled it.
|
// Note: authenticate_1 was not called because authenticate_0 handled it.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
||||||
});
|
});
|
||||||
it('falls back to HTTP basic auth', async function() {
|
it('falls back to HTTP basic auth', async function () {
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200);
|
await agent.get('/').auth('user', 'user-password').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('passes settings.users in context', async function() {
|
it('passes settings.users in context', async function () {
|
||||||
handlers.authenticate[0].checkContext = ({users}) => {
|
handlers.authenticate[0].checkContext = ({users}) => {
|
||||||
assert.equal(users, settings.users);
|
assert.equal(users, settings.users);
|
||||||
};
|
};
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('passes user, password in context if provided', async function() {
|
it('passes user, password in context if provided', async function () {
|
||||||
handlers.authenticate[0].checkContext = ({username, password}) => {
|
handlers.authenticate[0].checkContext = ({username, password}) => {
|
||||||
assert.equal(username, 'user');
|
assert.equal(username, 'user');
|
||||||
assert.equal(password, 'user-password');
|
assert.equal(password, 'user-password');
|
||||||
};
|
};
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200);
|
await agent.get('/').auth('user', 'user-password').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('does not pass user, password in context if not provided', async function() {
|
it('does not pass user, password in context if not provided', async function () {
|
||||||
handlers.authenticate[0].checkContext = ({username, password}) => {
|
handlers.authenticate[0].checkContext = ({username, password}) => {
|
||||||
assert(username == null);
|
assert(username == null);
|
||||||
assert(password == null);
|
assert(password == null);
|
||||||
};
|
};
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('errors if req.session.user is not created', async function() {
|
it('errors if req.session.user is not created', async function () {
|
||||||
handlers.authenticate[0].innerHandle = () => [true];
|
handlers.authenticate[0].innerHandle = () => [true];
|
||||||
await agent.get('/').expect(500);
|
await agent.get('/').expect(500);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
||||||
});
|
});
|
||||||
it('returns 500 if an exception is thrown', async function() {
|
it('returns 500 if an exception is thrown', async function () {
|
||||||
handlers.authenticate[0].innerHandle = () => { throw new Error('exception test'); };
|
handlers.authenticate[0].innerHandle = () => { throw new Error('exception test'); };
|
||||||
await agent.get('/').expect(500);
|
await agent.get('/').expect(500);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1', 'authenticate_0']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('authorize', function() {
|
describe('authorize', function () {
|
||||||
beforeEach(async function() {
|
beforeEach(async function () {
|
||||||
settings.requireAuthentication = true;
|
settings.requireAuthentication = true;
|
||||||
settings.requireAuthorization = true;
|
settings.requireAuthorization = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is not called if !requireAuthorization (non-/admin)', async function() {
|
it('is not called if !requireAuthorization (non-/admin)', async function () {
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200);
|
await agent.get('/').auth('user', 'user-password').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('is not called if !requireAuthorization (/admin)', async function() {
|
it('is not called if !requireAuthorization (/admin)', async function () {
|
||||||
settings.requireAuthorization = false;
|
settings.requireAuthorization = false;
|
||||||
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
await agent.get('/admin/').auth('admin', 'admin-password').expect(200);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1']);
|
'preAuthorize_1',
|
||||||
|
'authenticate_0',
|
||||||
|
'authenticate_1']);
|
||||||
});
|
});
|
||||||
it('defers if empty list returned', async function() {
|
it('defers if empty list returned', async function () {
|
||||||
await agent.get('/').auth('user', 'user-password').expect(403);
|
await agent.get('/').auth('user', 'user-password').expect(403);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1',
|
'preAuthorize_1',
|
||||||
'authorize_0', 'authorize_1']);
|
'authenticate_0',
|
||||||
|
'authenticate_1',
|
||||||
|
'authorize_0',
|
||||||
|
'authorize_1']);
|
||||||
});
|
});
|
||||||
it('does not defer if return [true], 200', async function() {
|
it('does not defer if return [true], 200', async function () {
|
||||||
handlers.authorize[0].innerHandle = () => [true];
|
handlers.authorize[0].innerHandle = () => [true];
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200);
|
await agent.get('/').auth('user', 'user-password').expect(200);
|
||||||
// Note: authorize_1 was not called because authorize_0 handled it.
|
// Note: authorize_1 was not called because authorize_0 handled it.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1',
|
'preAuthorize_1',
|
||||||
'authorize_0']);
|
'authenticate_0',
|
||||||
|
'authenticate_1',
|
||||||
|
'authorize_0']);
|
||||||
});
|
});
|
||||||
it('does not defer if return [false], 403', async function() {
|
it('does not defer if return [false], 403', async function () {
|
||||||
handlers.authorize[0].innerHandle = (req) => [false];
|
handlers.authorize[0].innerHandle = (req) => [false];
|
||||||
await agent.get('/').auth('user', 'user-password').expect(403);
|
await agent.get('/').auth('user', 'user-password').expect(403);
|
||||||
// Note: authorize_1 was not called because authorize_0 handled it.
|
// Note: authorize_1 was not called because authorize_0 handled it.
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1',
|
'preAuthorize_1',
|
||||||
'authorize_0']);
|
'authenticate_0',
|
||||||
|
'authenticate_1',
|
||||||
|
'authorize_0']);
|
||||||
});
|
});
|
||||||
it('passes req.path in context', async function() {
|
it('passes req.path in context', async function () {
|
||||||
handlers.authorize[0].checkContext = ({resource}) => {
|
handlers.authorize[0].checkContext = ({resource}) => {
|
||||||
assert.equal(resource, '/');
|
assert.equal(resource, '/');
|
||||||
};
|
};
|
||||||
await agent.get('/').auth('user', 'user-password').expect(403);
|
await agent.get('/').auth('user', 'user-password').expect(403);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1',
|
'preAuthorize_1',
|
||||||
'authorize_0', 'authorize_1']);
|
'authenticate_0',
|
||||||
|
'authenticate_1',
|
||||||
|
'authorize_0',
|
||||||
|
'authorize_1']);
|
||||||
});
|
});
|
||||||
it('returns 500 if an exception is thrown', async function() {
|
it('returns 500 if an exception is thrown', async function () {
|
||||||
handlers.authorize[0].innerHandle = () => { throw new Error('exception test'); };
|
handlers.authorize[0].innerHandle = () => { throw new Error('exception test'); };
|
||||||
await agent.get('/').auth('user', 'user-password').expect(500);
|
await agent.get('/').auth('user', 'user-password').expect(500);
|
||||||
assert.deepEqual(callOrder, ['preAuthorize_0', 'preAuthorize_1',
|
assert.deepEqual(callOrder, ['preAuthorize_0',
|
||||||
'authenticate_0', 'authenticate_1',
|
'preAuthorize_1',
|
||||||
'authorize_0']);
|
'authenticate_0',
|
||||||
|
'authenticate_1',
|
||||||
|
'authorize_0']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('webaccess: authnFailure, authzFailure, authFailure hooks', function() {
|
describe('webaccess: authnFailure, authzFailure, authFailure hooks', function () {
|
||||||
const Handler = class {
|
const Handler = class {
|
||||||
constructor(hookName) {
|
constructor(hookName) {
|
||||||
this.hookName = hookName;
|
this.hookName = hookName;
|
||||||
|
@ -372,7 +402,7 @@ describe(__filename, function() {
|
||||||
};
|
};
|
||||||
const handlers = {};
|
const handlers = {};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
failHookNames.forEach((hookName) => {
|
failHookNames.forEach((hookName) => {
|
||||||
const handler = new Handler(hookName);
|
const handler = new Handler(hookName);
|
||||||
handlers[hookName] = handler;
|
handlers[hookName] = handler;
|
||||||
|
@ -383,61 +413,61 @@ describe(__filename, function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// authn failure tests
|
// authn failure tests
|
||||||
it('authn fail, no hooks handle -> 401', async function() {
|
it('authn fail, no hooks handle -> 401', async function () {
|
||||||
await agent.get('/').expect(401);
|
await agent.get('/').expect(401);
|
||||||
assert(handlers['authnFailure'].called);
|
assert(handlers.authnFailure.called);
|
||||||
assert(!handlers['authzFailure'].called);
|
assert(!handlers.authzFailure.called);
|
||||||
assert(handlers['authFailure'].called);
|
assert(handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authn fail, authnFailure handles', async function() {
|
it('authn fail, authnFailure handles', async function () {
|
||||||
handlers['authnFailure'].shouldHandle = true;
|
handlers.authnFailure.shouldHandle = true;
|
||||||
await agent.get('/').expect(200, 'authnFailure');
|
await agent.get('/').expect(200, 'authnFailure');
|
||||||
assert(handlers['authnFailure'].called);
|
assert(handlers.authnFailure.called);
|
||||||
assert(!handlers['authzFailure'].called);
|
assert(!handlers.authzFailure.called);
|
||||||
assert(!handlers['authFailure'].called);
|
assert(!handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authn fail, authFailure handles', async function() {
|
it('authn fail, authFailure handles', async function () {
|
||||||
handlers['authFailure'].shouldHandle = true;
|
handlers.authFailure.shouldHandle = true;
|
||||||
await agent.get('/').expect(200, 'authFailure');
|
await agent.get('/').expect(200, 'authFailure');
|
||||||
assert(handlers['authnFailure'].called);
|
assert(handlers.authnFailure.called);
|
||||||
assert(!handlers['authzFailure'].called);
|
assert(!handlers.authzFailure.called);
|
||||||
assert(handlers['authFailure'].called);
|
assert(handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authnFailure trumps authFailure', async function() {
|
it('authnFailure trumps authFailure', async function () {
|
||||||
handlers['authnFailure'].shouldHandle = true;
|
handlers.authnFailure.shouldHandle = true;
|
||||||
handlers['authFailure'].shouldHandle = true;
|
handlers.authFailure.shouldHandle = true;
|
||||||
await agent.get('/').expect(200, 'authnFailure');
|
await agent.get('/').expect(200, 'authnFailure');
|
||||||
assert(handlers['authnFailure'].called);
|
assert(handlers.authnFailure.called);
|
||||||
assert(!handlers['authFailure'].called);
|
assert(!handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
// authz failure tests
|
// authz failure tests
|
||||||
it('authz fail, no hooks handle -> 403', async function() {
|
it('authz fail, no hooks handle -> 403', async function () {
|
||||||
await agent.get('/').auth('user', 'user-password').expect(403);
|
await agent.get('/').auth('user', 'user-password').expect(403);
|
||||||
assert(!handlers['authnFailure'].called);
|
assert(!handlers.authnFailure.called);
|
||||||
assert(handlers['authzFailure'].called);
|
assert(handlers.authzFailure.called);
|
||||||
assert(handlers['authFailure'].called);
|
assert(handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authz fail, authzFailure handles', async function() {
|
it('authz fail, authzFailure handles', async function () {
|
||||||
handlers['authzFailure'].shouldHandle = true;
|
handlers.authzFailure.shouldHandle = true;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200, 'authzFailure');
|
await agent.get('/').auth('user', 'user-password').expect(200, 'authzFailure');
|
||||||
assert(!handlers['authnFailure'].called);
|
assert(!handlers.authnFailure.called);
|
||||||
assert(handlers['authzFailure'].called);
|
assert(handlers.authzFailure.called);
|
||||||
assert(!handlers['authFailure'].called);
|
assert(!handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authz fail, authFailure handles', async function() {
|
it('authz fail, authFailure handles', async function () {
|
||||||
handlers['authFailure'].shouldHandle = true;
|
handlers.authFailure.shouldHandle = true;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200, 'authFailure');
|
await agent.get('/').auth('user', 'user-password').expect(200, 'authFailure');
|
||||||
assert(!handlers['authnFailure'].called);
|
assert(!handlers.authnFailure.called);
|
||||||
assert(handlers['authzFailure'].called);
|
assert(handlers.authzFailure.called);
|
||||||
assert(handlers['authFailure'].called);
|
assert(handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
it('authzFailure trumps authFailure', async function() {
|
it('authzFailure trumps authFailure', async function () {
|
||||||
handlers['authzFailure'].shouldHandle = true;
|
handlers.authzFailure.shouldHandle = true;
|
||||||
handlers['authFailure'].shouldHandle = true;
|
handlers.authFailure.shouldHandle = true;
|
||||||
await agent.get('/').auth('user', 'user-password').expect(200, 'authzFailure');
|
await agent.get('/').auth('user', 'user-password').expect(200, 'authzFailure');
|
||||||
assert(handlers['authzFailure'].called);
|
assert(handlers.authzFailure.called);
|
||||||
assert(!handlers['authFailure'].called);
|
assert(!handlers.authFailure.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,16 +12,16 @@
|
||||||
* back to a default)
|
* back to a default)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var jsonminify = require(__dirname+"/../../src/node_modules/jsonminify");
|
const jsonminify = require(`${__dirname}/../../src/node_modules/jsonminify`);
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
function loadSettings(){
|
function loadSettings() {
|
||||||
var settingsStr = fs.readFileSync(__dirname+"/../../settings.json.docker").toString();
|
let settingsStr = fs.readFileSync(`${__dirname}/../../settings.json.docker`).toString();
|
||||||
// try to parse the settings
|
// try to parse the settings
|
||||||
try {
|
try {
|
||||||
if(settingsStr) {
|
if (settingsStr) {
|
||||||
settingsStr = jsonminify(settingsStr).replace(",]","]").replace(",}","}");
|
settingsStr = jsonminify(settingsStr).replace(',]', ']').replace(',}', '}');
|
||||||
var settings = JSON.parse(settingsStr);
|
const settings = JSON.parse(settingsStr);
|
||||||
|
|
||||||
// custom settings for running in a container
|
// custom settings for running in a container
|
||||||
settings.ip = 'localhost';
|
settings.ip = 'localhost';
|
||||||
|
@ -29,8 +29,8 @@ function loadSettings(){
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.error("whoops something is bad with settings");
|
console.error('whoops something is bad with settings');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,34 +5,34 @@
|
||||||
* TODO: unify those two files, and merge in a single one.
|
* TODO: unify those two files, and merge in a single one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const supertest = require(__dirname+'/../../../../src/node_modules/supertest');
|
const supertest = require(`${__dirname}/../../../../src/node_modules/supertest`);
|
||||||
const settings = require(__dirname+'/../../loadSettings').loadSettings();
|
const settings = require(`${__dirname}/../../loadSettings`).loadSettings();
|
||||||
const api = supertest('http://'+settings.ip+":"+settings.port);
|
const api = supertest(`http://${settings.ip}:${settings.port}`);
|
||||||
|
|
||||||
var apiVersion = 1;
|
const apiVersion = 1;
|
||||||
|
|
||||||
describe('Connectivity', function(){
|
describe('Connectivity', function () {
|
||||||
it('can connect', function(done) {
|
it('can connect', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect('Content-Type', /json/)
|
.expect('Content-Type', /json/)
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('API Versioning', function(){
|
describe('API Versioning', function () {
|
||||||
it('finds the version tag', function(done) {
|
it('finds the version tag', function (done) {
|
||||||
api.get('/api/')
|
api.get('/api/')
|
||||||
.expect(function(res){
|
.expect((res) => {
|
||||||
if (!res.body.currentVersion) throw new Error("No version set in API");
|
if (!res.body.currentVersion) throw new Error('No version set in API');
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.expect(200, done)
|
.expect(200, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
describe('Permission', function(){
|
describe('Permission', function () {
|
||||||
it('errors with invalid APIKey', function(done) {
|
it('errors with invalid APIKey', function (done) {
|
||||||
api.get('/api/'+apiVersion+'/createPad?apikey=wrong_password&padID=test')
|
api.get(`/api/${apiVersion}/createPad?apikey=wrong_password&padID=test`)
|
||||||
.expect(401, done)
|
.expect(401, done);
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
|
@ -1,65 +1,65 @@
|
||||||
var helper = {};
|
var helper = {};
|
||||||
|
|
||||||
(function(){
|
(function () {
|
||||||
var $iframe, jsLibraries = {};
|
let $iframe; const
|
||||||
|
jsLibraries = {};
|
||||||
|
|
||||||
helper.init = function(cb){
|
helper.init = function (cb) {
|
||||||
$.get('/static/js/jquery.js').done(function(code){
|
$.get('/static/js/jquery.js').done((code) => {
|
||||||
// make sure we don't override existing jquery
|
// make sure we don't override existing jquery
|
||||||
jsLibraries["jquery"] = "if(typeof $ === 'undefined') {\n" + code + "\n}";
|
jsLibraries.jquery = `if(typeof $ === 'undefined') {\n${code}\n}`;
|
||||||
|
|
||||||
$.get('/tests/frontend/lib/sendkeys.js').done(function(code){
|
$.get('/tests/frontend/lib/sendkeys.js').done((code) => {
|
||||||
jsLibraries["sendkeys"] = code;
|
jsLibraries.sendkeys = code;
|
||||||
|
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
helper.randomString = function randomString(len) {
|
helper.randomString = function randomString(len) {
|
||||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||||
var randomstring = '';
|
let randomstring = '';
|
||||||
for (var i = 0; i < len; i++)
|
for (let i = 0; i < len; i++) {
|
||||||
{
|
const rnum = Math.floor(Math.random() * chars.length);
|
||||||
var rnum = Math.floor(Math.random() * chars.length);
|
|
||||||
randomstring += chars.substring(rnum, rnum + 1);
|
randomstring += chars.substring(rnum, rnum + 1);
|
||||||
}
|
}
|
||||||
return randomstring;
|
return randomstring;
|
||||||
}
|
};
|
||||||
|
|
||||||
var getFrameJQuery = function($iframe){
|
const getFrameJQuery = function ($iframe) {
|
||||||
/*
|
/*
|
||||||
I tried over 9000 ways to inject javascript into iframes.
|
I tried over 9000 ways to inject javascript into iframes.
|
||||||
This is the only way I found that worked in IE 7+8+9, FF and Chrome
|
This is the only way I found that worked in IE 7+8+9, FF and Chrome
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var win = $iframe[0].contentWindow;
|
const win = $iframe[0].contentWindow;
|
||||||
var doc = win.document;
|
const doc = win.document;
|
||||||
|
|
||||||
//IE 8+9 Hack to make eval appear
|
// IE 8+9 Hack to make eval appear
|
||||||
//http://stackoverflow.com/questions/2720444/why-does-this-window-object-not-have-the-eval-function
|
// http://stackoverflow.com/questions/2720444/why-does-this-window-object-not-have-the-eval-function
|
||||||
win.execScript && win.execScript("null");
|
win.execScript && win.execScript('null');
|
||||||
|
|
||||||
win.eval(jsLibraries["jquery"]);
|
win.eval(jsLibraries.jquery);
|
||||||
win.eval(jsLibraries["sendkeys"]);
|
win.eval(jsLibraries.sendkeys);
|
||||||
|
|
||||||
win.$.window = win;
|
win.$.window = win;
|
||||||
win.$.document = doc;
|
win.$.document = doc;
|
||||||
|
|
||||||
return win.$;
|
return win.$;
|
||||||
}
|
};
|
||||||
|
|
||||||
helper.clearSessionCookies = function(){
|
helper.clearSessionCookies = function () {
|
||||||
// Expire cookies, so author and language are changed after reloading the pad.
|
// 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
|
// 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 = '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=/';
|
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
|
// Can only happen when the iframe exists, so we're doing it separately from other cookies
|
||||||
helper.clearPadPrefCookie = function(){
|
helper.clearPadPrefCookie = function () {
|
||||||
helper.padChrome$.document.cookie = 'prefsHttp=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
helper.padChrome$.document.cookie = 'prefsHttp=;expires=Thu, 01 Jan 1970 00:00:00 GMT';
|
||||||
}
|
};
|
||||||
|
|
||||||
// Overwrite all prefs in pad cookie. Assumes http, not https.
|
// Overwrite all prefs in pad cookie. Assumes http, not https.
|
||||||
//
|
//
|
||||||
|
@ -67,65 +67,64 @@ var helper = {};
|
||||||
// seem to have independent cookies, UNLESS we put path=/ here (which we don't).
|
// 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
|
// I don't fully understand it, but this function seems to properly simulate
|
||||||
// padCookie.setPref in the client code
|
// padCookie.setPref in the client code
|
||||||
helper.setPadPrefCookie = function(prefs){
|
helper.setPadPrefCookie = function (prefs) {
|
||||||
helper.padChrome$.document.cookie = ("prefsHttp=" + escape(JSON.stringify(prefs)) + ";expires=Thu, 01 Jan 3000 00:00:00 GMT");
|
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
|
// Functionality for knowing what key event type is required for tests
|
||||||
var evtType = "keydown";
|
let evtType = 'keydown';
|
||||||
// if it's IE require keypress
|
// if it's IE require keypress
|
||||||
if(window.navigator.userAgent.indexOf("MSIE") > -1){
|
if (window.navigator.userAgent.indexOf('MSIE') > -1) {
|
||||||
evtType = "keypress";
|
evtType = 'keypress';
|
||||||
}
|
}
|
||||||
// Edge also requires keypress.
|
// Edge also requires keypress.
|
||||||
if(window.navigator.userAgent.indexOf("Edge") > -1){
|
if (window.navigator.userAgent.indexOf('Edge') > -1) {
|
||||||
evtType = "keypress";
|
evtType = 'keypress';
|
||||||
}
|
}
|
||||||
// Opera also requires keypress.
|
// Opera also requires keypress.
|
||||||
if(window.navigator.userAgent.indexOf("OPR") > -1){
|
if (window.navigator.userAgent.indexOf('OPR') > -1) {
|
||||||
evtType = "keypress";
|
evtType = 'keypress';
|
||||||
}
|
}
|
||||||
helper.evtType = evtType;
|
helper.evtType = evtType;
|
||||||
|
|
||||||
// @todo needs fixing asap
|
// @todo needs fixing asap
|
||||||
// newPad occasionally timeouts, might be a problem with ready/onload code during page setup
|
// newPad occasionally timeouts, might be a problem with ready/onload code during page setup
|
||||||
// This ensures that tests run regardless of this problem
|
// This ensures that tests run regardless of this problem
|
||||||
helper.retry = 0
|
helper.retry = 0;
|
||||||
|
|
||||||
helper.newPad = function(cb, padName){
|
helper.newPad = function (cb, padName) {
|
||||||
//build opts object
|
// build opts object
|
||||||
var opts = {clearCookies: true}
|
let opts = {clearCookies: true};
|
||||||
if(typeof cb === 'function'){
|
if (typeof cb === 'function') {
|
||||||
opts.cb = cb
|
opts.cb = cb;
|
||||||
} else {
|
} else {
|
||||||
opts = _.defaults(cb, opts);
|
opts = _.defaults(cb, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if opts.params is set we manipulate the URL to include URL parameters IE ?foo=Bah.
|
// if opts.params is set we manipulate the URL to include URL parameters IE ?foo=Bah.
|
||||||
if(opts.params){
|
if (opts.params) {
|
||||||
var encodedParams = "?" + $.param(opts.params);
|
var encodedParams = `?${$.param(opts.params)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear cookies
|
// clear cookies
|
||||||
if(opts.clearCookies){
|
if (opts.clearCookies) {
|
||||||
helper.clearSessionCookies();
|
helper.clearSessionCookies();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!padName)
|
if (!padName) padName = `FRONTEND_TEST_${helper.randomString(20)}`;
|
||||||
padName = "FRONTEND_TEST_" + helper.randomString(20);
|
$iframe = $(`<iframe src='/p/${padName}${encodedParams || ''}'></iframe>`);
|
||||||
$iframe = $("<iframe src='/p/" + padName + (encodedParams || '') + "'></iframe>");
|
|
||||||
|
|
||||||
// needed for retry
|
// needed for retry
|
||||||
let origPadName = padName;
|
const origPadName = padName;
|
||||||
|
|
||||||
//clean up inner iframe references
|
// clean up inner iframe references
|
||||||
helper.padChrome$ = helper.padOuter$ = helper.padInner$ = null;
|
helper.padChrome$ = helper.padOuter$ = helper.padInner$ = null;
|
||||||
|
|
||||||
//remove old iframe
|
// remove old iframe
|
||||||
$("#iframe-container iframe").remove();
|
$('#iframe-container iframe').remove();
|
||||||
//set new iframe
|
// set new iframe
|
||||||
$("#iframe-container").append($iframe);
|
$('#iframe-container').append($iframe);
|
||||||
$iframe.one('load', function(){
|
$iframe.one('load', () => {
|
||||||
helper.padChrome$ = getFrameJQuery($('#iframe-container iframe'));
|
helper.padChrome$ = getFrameJQuery($('#iframe-container iframe'));
|
||||||
if (opts.clearCookies) {
|
if (opts.clearCookies) {
|
||||||
helper.clearPadPrefCookie();
|
helper.clearPadPrefCookie();
|
||||||
|
@ -133,13 +132,11 @@ var helper = {};
|
||||||
if (opts.padPrefs) {
|
if (opts.padPrefs) {
|
||||||
helper.setPadPrefCookie(opts.padPrefs);
|
helper.setPadPrefCookie(opts.padPrefs);
|
||||||
}
|
}
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => !$iframe.contents().find('#editorloadingbox').is(':visible'), 10000).done(() => {
|
||||||
return !$iframe.contents().find("#editorloadingbox").is(":visible");
|
helper.padOuter$ = getFrameJQuery(helper.padChrome$('iframe[name="ace_outer"]'));
|
||||||
}, 10000).done(function(){
|
helper.padInner$ = getFrameJQuery(helper.padOuter$('iframe[name="ace_inner"]'));
|
||||||
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
|
// disable all animations, this makes tests faster and easier
|
||||||
helper.padChrome$.fx.off = true;
|
helper.padChrome$.fx.off = true;
|
||||||
helper.padOuter$.fx.off = true;
|
helper.padOuter$.fx.off = true;
|
||||||
helper.padInner$.fx.off = true;
|
helper.padInner$.fx.off = true;
|
||||||
|
@ -149,13 +146,13 @@ var helper = {};
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
helper.chatMessages = [];
|
helper.chatMessages = [];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* changeset commits from the server
|
* changeset commits from the server
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
helper.commits = [];
|
helper.commits = [];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* userInfo messages from the server
|
* userInfo messages from the server
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
|
@ -165,23 +162,23 @@ var helper = {};
|
||||||
// listen for server messages
|
// listen for server messages
|
||||||
helper.spyOnSocketIO();
|
helper.spyOnSocketIO();
|
||||||
opts.cb();
|
opts.cb();
|
||||||
}).fail(function(){
|
}).fail(() => {
|
||||||
if (helper.retry > 3) {
|
if (helper.retry > 3) {
|
||||||
throw new Error("Pad never loaded");
|
throw new Error('Pad never loaded');
|
||||||
}
|
}
|
||||||
helper.retry++;
|
helper.retry++;
|
||||||
helper.newPad(cb,origPadName);
|
helper.newPad(cb, origPadName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return padName;
|
return padName;
|
||||||
}
|
};
|
||||||
|
|
||||||
helper.waitFor = function(conditionFunc, timeoutTime = 1900, intervalTime = 10) {
|
helper.waitFor = function (conditionFunc, timeoutTime = 1900, intervalTime = 10) {
|
||||||
var deferred = $.Deferred();
|
const deferred = $.Deferred();
|
||||||
|
|
||||||
const _fail = deferred.fail.bind(deferred);
|
const _fail = deferred.fail.bind(deferred);
|
||||||
var listenForFail = false;
|
let listenForFail = false;
|
||||||
deferred.fail = (...args) => {
|
deferred.fail = (...args) => {
|
||||||
listenForFail = true;
|
listenForFail = true;
|
||||||
return _fail(...args);
|
return _fail(...args);
|
||||||
|
@ -202,10 +199,10 @@ var helper = {};
|
||||||
|
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
clearInterval(intervalCheck);
|
clearInterval(intervalCheck);
|
||||||
var error = new Error("wait for condition never became true " + conditionFunc.toString());
|
const error = new Error(`wait for condition never became true ${conditionFunc.toString()}`);
|
||||||
deferred.reject(error);
|
deferred.reject(error);
|
||||||
|
|
||||||
if(!listenForFail){
|
if (!listenForFail) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}, timeoutTime);
|
}, timeoutTime);
|
||||||
|
@ -222,56 +219,56 @@ var helper = {};
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
helper.waitForPromise = async function(...args) {
|
helper.waitForPromise = async function (...args) {
|
||||||
// Note: waitFor() has a strange API: On timeout it rejects, but it also throws an uncatchable
|
// Note: waitFor() has a strange API: On timeout it rejects, but it also throws an uncatchable
|
||||||
// exception unless .fail() has been called. That uncatchable exception is disabled here by
|
// exception unless .fail() has been called. That uncatchable exception is disabled here by
|
||||||
// passing a no-op function to .fail().
|
// passing a no-op function to .fail().
|
||||||
return await this.waitFor(...args).fail(() => {});
|
return await this.waitFor(...args).fail(() => {});
|
||||||
};
|
};
|
||||||
|
|
||||||
helper.selectLines = function($startLine, $endLine, startOffset, endOffset){
|
helper.selectLines = function ($startLine, $endLine, startOffset, endOffset) {
|
||||||
// if no offset is provided, use beginning of start line and end of end line
|
// if no offset is provided, use beginning of start line and end of end line
|
||||||
startOffset = startOffset || 0;
|
startOffset = startOffset || 0;
|
||||||
endOffset = endOffset === undefined ? $endLine.text().length : endOffset;
|
endOffset = endOffset === undefined ? $endLine.text().length : endOffset;
|
||||||
|
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
var range = selection.getRangeAt(0);
|
const range = selection.getRangeAt(0);
|
||||||
|
|
||||||
var start = getTextNodeAndOffsetOf($startLine, startOffset);
|
const start = getTextNodeAndOffsetOf($startLine, startOffset);
|
||||||
var end = getTextNodeAndOffsetOf($endLine, endOffset);
|
const end = getTextNodeAndOffsetOf($endLine, endOffset);
|
||||||
|
|
||||||
range.setStart(start.node, start.offset);
|
range.setStart(start.node, start.offset);
|
||||||
range.setEnd(end.node, end.offset);
|
range.setEnd(end.node, end.offset);
|
||||||
|
|
||||||
selection.removeAllRanges();
|
selection.removeAllRanges();
|
||||||
selection.addRange(range);
|
selection.addRange(range);
|
||||||
}
|
};
|
||||||
|
|
||||||
var getTextNodeAndOffsetOf = function($targetLine, targetOffsetAtLine){
|
var getTextNodeAndOffsetOf = function ($targetLine, targetOffsetAtLine) {
|
||||||
var $textNodes = $targetLine.find('*').contents().filter(function(){
|
const $textNodes = $targetLine.find('*').contents().filter(function () {
|
||||||
return this.nodeType === Node.TEXT_NODE;
|
return this.nodeType === Node.TEXT_NODE;
|
||||||
});
|
});
|
||||||
|
|
||||||
// search node where targetOffsetAtLine is reached, and its 'inner offset'
|
// search node where targetOffsetAtLine is reached, and its 'inner offset'
|
||||||
var textNodeWhereOffsetIs = null;
|
let textNodeWhereOffsetIs = null;
|
||||||
var offsetBeforeTextNode = 0;
|
let offsetBeforeTextNode = 0;
|
||||||
var offsetInsideTextNode = 0;
|
let offsetInsideTextNode = 0;
|
||||||
$textNodes.each(function(index, element){
|
$textNodes.each((index, element) => {
|
||||||
var elementTotalOffset = element.textContent.length;
|
const elementTotalOffset = element.textContent.length;
|
||||||
textNodeWhereOffsetIs = element;
|
textNodeWhereOffsetIs = element;
|
||||||
offsetInsideTextNode = targetOffsetAtLine - offsetBeforeTextNode;
|
offsetInsideTextNode = targetOffsetAtLine - offsetBeforeTextNode;
|
||||||
|
|
||||||
var foundTextNode = offsetBeforeTextNode + elementTotalOffset >= targetOffsetAtLine;
|
const foundTextNode = offsetBeforeTextNode + elementTotalOffset >= targetOffsetAtLine;
|
||||||
if (foundTextNode){
|
if (foundTextNode) {
|
||||||
return false; //stop .each by returning false
|
return false; // stop .each by returning false
|
||||||
}
|
}
|
||||||
|
|
||||||
offsetBeforeTextNode += elementTotalOffset;
|
offsetBeforeTextNode += elementTotalOffset;
|
||||||
});
|
});
|
||||||
|
|
||||||
// edge cases
|
// edge cases
|
||||||
if (textNodeWhereOffsetIs === null){
|
if (textNodeWhereOffsetIs === null) {
|
||||||
// there was no text node inside $targetLine, so it is an empty line (<br>).
|
// there was no text node inside $targetLine, so it is an empty line (<br>).
|
||||||
// Use beginning of line
|
// Use beginning of line
|
||||||
textNodeWhereOffsetIs = $targetLine.get(0);
|
textNodeWhereOffsetIs = $targetLine.get(0);
|
||||||
|
@ -279,16 +276,16 @@ var helper = {};
|
||||||
}
|
}
|
||||||
// avoid errors if provided targetOffsetAtLine is higher than line offset (maxOffset).
|
// avoid errors if provided targetOffsetAtLine is higher than line offset (maxOffset).
|
||||||
// Use max allowed instead
|
// Use max allowed instead
|
||||||
var maxOffset = textNodeWhereOffsetIs.textContent.length;
|
const maxOffset = textNodeWhereOffsetIs.textContent.length;
|
||||||
offsetInsideTextNode = Math.min(offsetInsideTextNode, maxOffset);
|
offsetInsideTextNode = Math.min(offsetInsideTextNode, maxOffset);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
node: textNodeWhereOffsetIs,
|
node: textNodeWhereOffsetIs,
|
||||||
offset: offsetInsideTextNode,
|
offset: offsetInsideTextNode,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
/* Ensure console.log doesn't blow up in IE, ugly but ok for a test framework imho*/
|
/* Ensure console.log doesn't blow up in IE, ugly but ok for a test framework imho*/
|
||||||
window.console = window.console || {};
|
window.console = window.console || {};
|
||||||
window.console.log = window.console.log || function(){}
|
window.console.log = window.console.log || function () {};
|
||||||
})()
|
})();
|
||||||
|
|
|
@ -2,22 +2,19 @@
|
||||||
* Spys on socket.io messages and saves them into several arrays
|
* Spys on socket.io messages and saves them into several arrays
|
||||||
* that are visible in tests
|
* that are visible in tests
|
||||||
*/
|
*/
|
||||||
helper.spyOnSocketIO = function (){
|
helper.spyOnSocketIO = function () {
|
||||||
helper.contentWindow().pad.socket.on('message', function(msg){
|
helper.contentWindow().pad.socket.on('message', (msg) => {
|
||||||
if (msg.type == "COLLABROOM") {
|
if (msg.type == 'COLLABROOM') {
|
||||||
|
|
||||||
if (msg.data.type == 'ACCEPT_COMMIT') {
|
if (msg.data.type == 'ACCEPT_COMMIT') {
|
||||||
helper.commits.push(msg);
|
helper.commits.push(msg);
|
||||||
}
|
} else if (msg.data.type == 'USER_NEWINFO') {
|
||||||
else if (msg.data.type == 'USER_NEWINFO') {
|
helper.userInfos.push(msg);
|
||||||
helper.userInfos.push(msg)
|
} else if (msg.data.type == 'CHAT_MESSAGE') {
|
||||||
}
|
helper.chatMessages.push(msg);
|
||||||
else if (msg.data.type == 'CHAT_MESSAGE') {
|
|
||||||
helper.chatMessages.push(msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes an edit via `sendkeys` to the position of the caret and ensures ACCEPT_COMMIT
|
* Makes an edit via `sendkeys` to the position of the caret and ensures ACCEPT_COMMIT
|
||||||
|
@ -31,14 +28,12 @@ helper.spyOnSocketIO = function (){
|
||||||
* @todo needs to support writing to a specified caret position
|
* @todo needs to support writing to a specified caret position
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
helper.edit = async function(message, line){
|
helper.edit = async function (message, line) {
|
||||||
let editsNum = helper.commits.length;
|
const editsNum = helper.commits.length;
|
||||||
line = line ? line - 1 : 0;
|
line = line ? line - 1 : 0;
|
||||||
helper.linesDiv()[line].sendkeys(message);
|
helper.linesDiv()[line].sendkeys(message);
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => editsNum + 1 === helper.commits.length);
|
||||||
return editsNum + 1 === helper.commits.length;
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pad text as an array of divs
|
* The pad text as an array of divs
|
||||||
|
@ -48,11 +43,11 @@ helper.edit = async function(message, line){
|
||||||
*
|
*
|
||||||
* @returns {Array.<HTMLElement>} array of divs
|
* @returns {Array.<HTMLElement>} array of divs
|
||||||
*/
|
*/
|
||||||
helper.linesDiv = function(){
|
helper.linesDiv = function () {
|
||||||
return helper.padInner$('.ace-line').map(function(){
|
return helper.padInner$('.ace-line').map(function () {
|
||||||
return $(this)
|
return $(this);
|
||||||
}).get()
|
}).get();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The pad text as an array of lines
|
* The pad text as an array of lines
|
||||||
|
@ -60,18 +55,18 @@ helper.linesDiv = function(){
|
||||||
*
|
*
|
||||||
* @returns {Array.<string>} lines of text
|
* @returns {Array.<string>} lines of text
|
||||||
*/
|
*/
|
||||||
helper.textLines = function(){
|
helper.textLines = function () {
|
||||||
return helper.linesDiv().map((div) => div.text());
|
return helper.linesDiv().map((div) => div.text());
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default pad text transmitted via `clientVars`
|
* The default pad text transmitted via `clientVars`
|
||||||
*
|
*
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
helper.defaultText = function(){
|
helper.defaultText = function () {
|
||||||
return helper.padChrome$.window.clientVars.collab_client_vars.initialAttributedText.text;
|
return helper.padChrome$.window.clientVars.collab_client_vars.initialAttributedText.text;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a chat `message` via `sendKeys`
|
* Sends a chat `message` via `sendKeys`
|
||||||
|
@ -87,25 +82,23 @@ helper.defaultText = function(){
|
||||||
* @param {string} message the chat message to be sent
|
* @param {string} message the chat message to be sent
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.sendChatMessage = function(message){
|
helper.sendChatMessage = function (message) {
|
||||||
let noOfChatMessages = helper.chatMessages.length;
|
const noOfChatMessages = helper.chatMessages.length;
|
||||||
helper.padChrome$("#chatinput").sendkeys(message)
|
helper.padChrome$('#chatinput').sendkeys(message);
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => noOfChatMessages + 1 === helper.chatMessages.length);
|
||||||
return noOfChatMessages + 1 === helper.chatMessages.length;
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the settings menu if its hidden via button
|
* Opens the settings menu if its hidden via button
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.showSettings = function() {
|
helper.showSettings = function () {
|
||||||
if(!helper.isSettingsShown()){
|
if (!helper.isSettingsShown()) {
|
||||||
helper.settingsButton().click()
|
helper.settingsButton().click();
|
||||||
return helper.waitForPromise(function(){return helper.isSettingsShown(); },2000);
|
return helper.waitForPromise(() => helper.isSettingsShown(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide the settings menu if its open via button
|
* Hide the settings menu if its open via button
|
||||||
|
@ -113,12 +106,12 @@ helper.showSettings = function() {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
* @todo untested
|
* @todo untested
|
||||||
*/
|
*/
|
||||||
helper.hideSettings = function() {
|
helper.hideSettings = function () {
|
||||||
if(helper.isSettingsShown()){
|
if (helper.isSettingsShown()) {
|
||||||
helper.settingsButton().click()
|
helper.settingsButton().click();
|
||||||
return helper.waitForPromise(function(){return !helper.isSettingsShown(); },2000);
|
return helper.waitForPromise(() => !helper.isSettingsShown(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the chat window sticky via settings menu if the settings menu is
|
* Makes the chat window sticky via settings menu if the settings menu is
|
||||||
|
@ -126,15 +119,13 @@ helper.hideSettings = function() {
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.enableStickyChatviaSettings = function() {
|
helper.enableStickyChatviaSettings = function () {
|
||||||
var stickyChat = helper.padChrome$('#options-stickychat');
|
const stickyChat = helper.padChrome$('#options-stickychat');
|
||||||
if(helper.isSettingsShown() && !stickyChat.is(':checked')) {
|
if (helper.isSettingsShown() && !stickyChat.is(':checked')) {
|
||||||
stickyChat.click();
|
stickyChat.click();
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => helper.isChatboxSticky(), 2000);
|
||||||
return helper.isChatboxSticky();
|
|
||||||
},2000);
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsticks the chat window via settings menu if the settings menu is open
|
* Unsticks the chat window via settings menu if the settings menu is open
|
||||||
|
@ -142,13 +133,13 @@ helper.enableStickyChatviaSettings = function() {
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.disableStickyChatviaSettings = function() {
|
helper.disableStickyChatviaSettings = function () {
|
||||||
var stickyChat = helper.padChrome$('#options-stickychat');
|
const stickyChat = helper.padChrome$('#options-stickychat');
|
||||||
if(helper.isSettingsShown() && stickyChat.is(':checked')) {
|
if (helper.isSettingsShown() && stickyChat.is(':checked')) {
|
||||||
stickyChat.click();
|
stickyChat.click();
|
||||||
return helper.waitForPromise(function(){return !helper.isChatboxSticky()},2000);
|
return helper.waitForPromise(() => !helper.isChatboxSticky(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the chat window sticky via an icon on the top right of the chat
|
* Makes the chat window sticky via an icon on the top right of the chat
|
||||||
|
@ -156,13 +147,13 @@ helper.disableStickyChatviaSettings = function() {
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.enableStickyChatviaIcon = function() {
|
helper.enableStickyChatviaIcon = function () {
|
||||||
var stickyChat = helper.padChrome$('#titlesticky');
|
const stickyChat = helper.padChrome$('#titlesticky');
|
||||||
if(helper.isChatboxShown() && !helper.isChatboxSticky()) {
|
if (helper.isChatboxShown() && !helper.isChatboxSticky()) {
|
||||||
stickyChat.click();
|
stickyChat.click();
|
||||||
return helper.waitForPromise(function(){return helper.isChatboxSticky()},2000);
|
return helper.waitForPromise(() => helper.isChatboxSticky(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disables the stickyness of the chat window via an icon on the
|
* Disables the stickyness of the chat window via an icon on the
|
||||||
|
@ -170,12 +161,12 @@ helper.enableStickyChatviaIcon = function() {
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.disableStickyChatviaIcon = function() {
|
helper.disableStickyChatviaIcon = function () {
|
||||||
if(helper.isChatboxShown() && helper.isChatboxSticky()) {
|
if (helper.isChatboxShown() && helper.isChatboxSticky()) {
|
||||||
helper.titlecross().click()
|
helper.titlecross().click();
|
||||||
return helper.waitForPromise(function(){return !helper.isChatboxSticky()},2000);
|
return helper.waitForPromise(() => !helper.isChatboxSticky(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the src-attribute of the main iframe to the timeslider
|
* Sets the src-attribute of the main iframe to the timeslider
|
||||||
|
@ -189,15 +180,14 @@ helper.disableStickyChatviaIcon = function() {
|
||||||
* @todo for some reason this does only work the first time, you cannot
|
* @todo for some reason this does only work the first time, you cannot
|
||||||
* goto rev 0 and then via the same method to rev 5. Use buttons instead
|
* goto rev 0 and then via the same method to rev 5. Use buttons instead
|
||||||
*/
|
*/
|
||||||
helper.gotoTimeslider = function(revision){
|
helper.gotoTimeslider = function (revision) {
|
||||||
revision = Number.isInteger(revision) ? '#'+revision : '';
|
revision = Number.isInteger(revision) ? `#${revision}` : '';
|
||||||
var iframe = $('#iframe-container iframe');
|
const iframe = $('#iframe-container iframe');
|
||||||
iframe.attr('src', iframe.attr('src')+'/timeslider' + revision);
|
iframe.attr('src', `${iframe.attr('src')}/timeslider${revision}`);
|
||||||
|
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => helper.timesliderTimerTime() &&
|
||||||
return helper.timesliderTimerTime()
|
!Number.isNaN(new Date(helper.timesliderTimerTime()).getTime()), 10000);
|
||||||
&& !Number.isNaN(new Date(helper.timesliderTimerTime()).getTime()) },10000);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clicks in the timeslider at a specific offset
|
* Clicks in the timeslider at a specific offset
|
||||||
|
@ -206,24 +196,24 @@ helper.gotoTimeslider = function(revision){
|
||||||
* @todo no mousemove test
|
* @todo no mousemove test
|
||||||
* @param {number} X coordinate
|
* @param {number} X coordinate
|
||||||
*/
|
*/
|
||||||
helper.sliderClick = function(X){
|
helper.sliderClick = function (X) {
|
||||||
let sliderBar = helper.sliderBar()
|
const sliderBar = helper.sliderBar();
|
||||||
let edown = new jQuery.Event('mousedown');
|
const edown = new jQuery.Event('mousedown');
|
||||||
let eup = new jQuery.Event('mouseup');
|
const eup = new jQuery.Event('mouseup');
|
||||||
edown.clientX = eup.clientX = X;
|
edown.clientX = eup.clientX = X;
|
||||||
edown.clientY = eup.clientY = sliderBar.offset().top;
|
edown.clientY = eup.clientY = sliderBar.offset().top;
|
||||||
|
|
||||||
sliderBar.trigger(edown);
|
sliderBar.trigger(edown);
|
||||||
sliderBar.trigger(eup);
|
sliderBar.trigger(eup);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timeslider text as an array of lines
|
* The timeslider text as an array of lines
|
||||||
*
|
*
|
||||||
* @returns {Array.<string>} lines of text
|
* @returns {Array.<string>} lines of text
|
||||||
*/
|
*/
|
||||||
helper.timesliderTextLines = function(){
|
helper.timesliderTextLines = function () {
|
||||||
return helper.contentWindow().$('.ace-line').map(function(){
|
return helper.contentWindow().$('.ace-line').map(function () {
|
||||||
return $(this).text()
|
return $(this).text();
|
||||||
}).get()
|
}).get();
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} contentWindow
|
* @returns {HTMLElement} contentWindow
|
||||||
*/
|
*/
|
||||||
helper.contentWindow = function(){
|
helper.contentWindow = function () {
|
||||||
return $('#iframe-container iframe')[0].contentWindow;
|
return $('#iframe-container iframe')[0].contentWindow;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the chat unless it is already open via an
|
* Opens the chat unless it is already open via an
|
||||||
|
@ -13,117 +13,118 @@ helper.contentWindow = function(){
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.showChat = function(){
|
helper.showChat = function () {
|
||||||
var chaticon = helper.chatIcon();
|
const chaticon = helper.chatIcon();
|
||||||
if(chaticon.hasClass('visible')) {
|
if (chaticon.hasClass('visible')) {
|
||||||
chaticon.click()
|
chaticon.click();
|
||||||
return helper.waitForPromise(function(){return !chaticon.hasClass('visible'); },2000)
|
return helper.waitForPromise(() => !chaticon.hasClass('visible'), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the chat window if it is shown and not sticky
|
* Closes the chat window if it is shown and not sticky
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
helper.hideChat = function(){
|
helper.hideChat = function () {
|
||||||
if(helper.isChatboxShown() && !helper.isChatboxSticky()) {
|
if (helper.isChatboxShown() && !helper.isChatboxSticky()) {
|
||||||
helper.titlecross().click()
|
helper.titlecross().click();
|
||||||
return helper.waitForPromise(function(){return !helper.isChatboxShown(); },2000);
|
return helper.waitForPromise(() => !helper.isChatboxShown(), 2000);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the chat icon from the bottom right of the page
|
* Gets the chat icon from the bottom right of the page
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} the chat icon
|
* @returns {HTMLElement} the chat icon
|
||||||
*/
|
*/
|
||||||
helper.chatIcon = function(){return helper.padChrome$('#chaticon')}
|
helper.chatIcon = function () { return helper.padChrome$('#chaticon'); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The chat messages from the UI
|
* The chat messages from the UI
|
||||||
*
|
*
|
||||||
* @returns {Array.<HTMLElement>}
|
* @returns {Array.<HTMLElement>}
|
||||||
*/
|
*/
|
||||||
helper.chatTextParagraphs = function(){return helper.padChrome$('#chattext').children("p")}
|
helper.chatTextParagraphs = function () { return helper.padChrome$('#chattext').children('p'); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the chat box is sticky
|
* Returns true if the chat box is sticky
|
||||||
*
|
*
|
||||||
* @returns {boolean} stickyness of the chat box
|
* @returns {boolean} stickyness of the chat box
|
||||||
*/
|
*/
|
||||||
helper.isChatboxSticky = function() {
|
helper.isChatboxSticky = function () {
|
||||||
return helper.padChrome$('#chatbox').hasClass('stickyChat');
|
return helper.padChrome$('#chatbox').hasClass('stickyChat');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the chat box is shown
|
* Returns true if the chat box is shown
|
||||||
*
|
*
|
||||||
* @returns {boolean} visibility of the chat box
|
* @returns {boolean} visibility of the chat box
|
||||||
*/
|
*/
|
||||||
helper.isChatboxShown = function() {
|
helper.isChatboxShown = function () {
|
||||||
return helper.padChrome$('#chatbox').hasClass('visible');
|
return helper.padChrome$('#chatbox').hasClass('visible');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the settings menu
|
* Gets the settings menu
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} the settings menu
|
* @returns {HTMLElement} the settings menu
|
||||||
*/
|
*/
|
||||||
helper.settingsMenu = function(){return helper.padChrome$('#settings') };
|
helper.settingsMenu = function () { return helper.padChrome$('#settings'); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the settings button
|
* Gets the settings button
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} the settings button
|
* @returns {HTMLElement} the settings button
|
||||||
*/
|
*/
|
||||||
helper.settingsButton = function(){return helper.padChrome$("button[data-l10n-id='pad.toolbar.settings.title']") }
|
helper.settingsButton = function () { return helper.padChrome$("button[data-l10n-id='pad.toolbar.settings.title']"); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the titlecross icon
|
* Gets the titlecross icon
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} the titlecross icon
|
* @returns {HTMLElement} the titlecross icon
|
||||||
*/
|
*/
|
||||||
helper.titlecross = function(){return helper.padChrome$('#titlecross')}
|
helper.titlecross = function () { return helper.padChrome$('#titlecross'); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the settings menu is visible
|
* Returns true if the settings menu is visible
|
||||||
*
|
*
|
||||||
* @returns {boolean} is the settings menu shown?
|
* @returns {boolean} is the settings menu shown?
|
||||||
*/
|
*/
|
||||||
helper.isSettingsShown = function() {
|
helper.isSettingsShown = function () {
|
||||||
return helper.padChrome$('#settings').hasClass('popup-show');
|
return helper.padChrome$('#settings').hasClass('popup-show');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the timer div of a timeslider that has the datetime of the revision
|
* Gets the timer div of a timeslider that has the datetime of the revision
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} timer
|
* @returns {HTMLElement} timer
|
||||||
*/
|
*/
|
||||||
helper.timesliderTimer = function(){
|
helper.timesliderTimer = function () {
|
||||||
if(typeof helper.contentWindow().$ == 'function'){
|
if (typeof helper.contentWindow().$ === 'function') {
|
||||||
return helper.contentWindow().$('#timer') }
|
return helper.contentWindow().$('#timer');
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the time of the revision on a timeslider
|
* Gets the time of the revision on a timeslider
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} timer
|
* @returns {HTMLElement} timer
|
||||||
*/
|
*/
|
||||||
helper.timesliderTimerTime = function(){
|
helper.timesliderTimerTime = function () {
|
||||||
if(helper.timesliderTimer()){
|
if (helper.timesliderTimer()) {
|
||||||
return helper.timesliderTimer().text()
|
return helper.timesliderTimer().text();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ui-slidar-bar element in the timeslider
|
* The ui-slidar-bar element in the timeslider
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
helper.sliderBar = function(){
|
helper.sliderBar = function () {
|
||||||
return helper.contentWindow().$('#ui-slider-bar')
|
return helper.contentWindow().$('#ui-slider-bar');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* revision_date element
|
* revision_date element
|
||||||
|
@ -131,9 +132,9 @@ helper.sliderBar = function(){
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
helper.revisionDateElem = function(){
|
helper.revisionDateElem = function () {
|
||||||
return helper.contentWindow().$('#revision_date').text();
|
return helper.contentWindow().$('#revision_date').text();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* revision_label element
|
* revision_label element
|
||||||
|
@ -141,6 +142,6 @@ helper.revisionDateElem = function(){
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
helper.revisionLabelElem = function(){
|
helper.revisionLabelElem = function () {
|
||||||
return helper.contentWindow().$('#revision_label')
|
return helper.contentWindow().$('#revision_label');
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
$(function(){
|
$(() => {
|
||||||
|
function stringifyException(exception) {
|
||||||
function stringifyException(exception){
|
let err = exception.stack || exception.toString();
|
||||||
var err = exception.stack || exception.toString();
|
|
||||||
|
|
||||||
// FF / Opera do not add the message
|
// FF / Opera do not add the message
|
||||||
if (!~err.indexOf(exception.message)) {
|
if (!~err.indexOf(exception.message)) {
|
||||||
err = exception.message + '\n' + err;
|
err = `${exception.message}\n${err}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
|
||||||
|
@ -14,57 +13,57 @@ $(function(){
|
||||||
|
|
||||||
// Safari doesn't give you a stack. Let's at least provide a source line.
|
// Safari doesn't give you a stack. Let's at least provide a source line.
|
||||||
if (!exception.stack && exception.sourceURL && exception.line !== undefined) {
|
if (!exception.stack && exception.sourceURL && exception.line !== undefined) {
|
||||||
err += "\n(" + exception.sourceURL + ":" + exception.line + ")";
|
err += `\n(${exception.sourceURL}:${exception.line})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CustomRunner(runner) {
|
function CustomRunner(runner) {
|
||||||
var stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 };
|
const stats = {suites: 0, tests: 0, passes: 0, pending: 0, failures: 0};
|
||||||
|
|
||||||
if (!runner) return;
|
if (!runner) return;
|
||||||
|
|
||||||
runner.on('start', function(){
|
runner.on('start', () => {
|
||||||
stats.start = new Date;
|
stats.start = new Date();
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('suite', function(suite){
|
runner.on('suite', (suite) => {
|
||||||
suite.root || stats.suites++;
|
suite.root || stats.suites++;
|
||||||
if (suite.root) return;
|
if (suite.root) return;
|
||||||
append(suite.title);
|
append(suite.title);
|
||||||
level++;
|
level++;
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('suite end', function(suite){
|
runner.on('suite end', (suite) => {
|
||||||
if (suite.root) return;
|
if (suite.root) return;
|
||||||
level--;
|
level--;
|
||||||
|
|
||||||
if(level == 0) {
|
if (level == 0) {
|
||||||
append("");
|
append('');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scroll down test display after each test
|
// Scroll down test display after each test
|
||||||
let mochaEl = $('#mocha')[0];
|
const mochaEl = $('#mocha')[0];
|
||||||
runner.on('test', function(){
|
runner.on('test', () => {
|
||||||
mochaEl.scrollTop = mochaEl.scrollHeight;
|
mochaEl.scrollTop = mochaEl.scrollHeight;
|
||||||
});
|
});
|
||||||
|
|
||||||
// max time a test is allowed to run
|
// max time a test is allowed to run
|
||||||
// TODO this should be lowered once timeslider_revision.js is faster
|
// TODO this should be lowered once timeslider_revision.js is faster
|
||||||
var killTimeout;
|
let killTimeout;
|
||||||
runner.on('test end', function(){
|
runner.on('test end', () => {
|
||||||
stats.tests++;
|
stats.tests++;
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('pass', function(test){
|
runner.on('pass', (test) => {
|
||||||
if(killTimeout) clearTimeout(killTimeout);
|
if (killTimeout) clearTimeout(killTimeout);
|
||||||
killTimeout = setTimeout(function(){
|
killTimeout = setTimeout(() => {
|
||||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
append('FINISHED - [red]no test started since 3 minutes, tests stopped[clear]');
|
||||||
}, 60000 * 3);
|
}, 60000 * 3);
|
||||||
|
|
||||||
var medium = test.slow() / 2;
|
const medium = test.slow() / 2;
|
||||||
test.speed = test.duration > test.slow()
|
test.speed = test.duration > test.slow()
|
||||||
? 'slow'
|
? 'slow'
|
||||||
: test.duration > medium
|
: test.duration > medium
|
||||||
|
@ -72,107 +71,104 @@ $(function(){
|
||||||
: 'fast';
|
: 'fast';
|
||||||
|
|
||||||
stats.passes++;
|
stats.passes++;
|
||||||
append("->","[green]PASSED[clear] :", test.title," ",test.duration,"ms");
|
append('->', '[green]PASSED[clear] :', test.title, ' ', test.duration, 'ms');
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('fail', function(test, err){
|
runner.on('fail', (test, err) => {
|
||||||
if(killTimeout) clearTimeout(killTimeout);
|
if (killTimeout) clearTimeout(killTimeout);
|
||||||
killTimeout = setTimeout(function(){
|
killTimeout = setTimeout(() => {
|
||||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
append('FINISHED - [red]no test started since 3 minutes, tests stopped[clear]');
|
||||||
}, 60000 * 3);
|
}, 60000 * 3);
|
||||||
|
|
||||||
stats.failures++;
|
stats.failures++;
|
||||||
test.err = err;
|
test.err = err;
|
||||||
append("->","[red]FAILED[clear] :", test.title, stringifyException(test.err));
|
append('->', '[red]FAILED[clear] :', test.title, stringifyException(test.err));
|
||||||
});
|
});
|
||||||
|
|
||||||
runner.on('pending', function(test){
|
runner.on('pending', (test) => {
|
||||||
if(killTimeout) clearTimeout(killTimeout);
|
if (killTimeout) clearTimeout(killTimeout);
|
||||||
killTimeout = setTimeout(function(){
|
killTimeout = setTimeout(() => {
|
||||||
append("FINISHED - [red]no test started since 3 minutes, tests stopped[clear]");
|
append('FINISHED - [red]no test started since 3 minutes, tests stopped[clear]');
|
||||||
}, 60000 * 3);
|
}, 60000 * 3);
|
||||||
|
|
||||||
stats.pending++;
|
stats.pending++;
|
||||||
append("->","[yellow]PENDING[clear]:", test.title);
|
append('->', '[yellow]PENDING[clear]:', test.title);
|
||||||
});
|
});
|
||||||
|
|
||||||
var $console = $("#console");
|
const $console = $('#console');
|
||||||
var level = 0;
|
var level = 0;
|
||||||
var append = function(){
|
var append = function () {
|
||||||
var text = Array.prototype.join.apply(arguments, [" "]);
|
const text = Array.prototype.join.apply(arguments, [' ']);
|
||||||
var oldText = $console.text();
|
const oldText = $console.text();
|
||||||
|
|
||||||
var space = "";
|
let space = '';
|
||||||
for(var i=0;i<level*2;i++){
|
for (let i = 0; i < level * 2; i++) {
|
||||||
space+=" ";
|
space += ' ';
|
||||||
}
|
|
||||||
|
|
||||||
var splitedText = "";
|
|
||||||
_(text.split("\n")).each(function(line){
|
|
||||||
while(line.length > 0){
|
|
||||||
var split = line.substr(0,100);
|
|
||||||
line = line.substr(100);
|
|
||||||
if(splitedText.length > 0) splitedText+="\n";
|
|
||||||
splitedText += split;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//indent all lines with the given amount of space
|
|
||||||
var newText = _(splitedText.split("\n")).map(function(line){
|
|
||||||
return space + line;
|
|
||||||
}).join("\\n");
|
|
||||||
|
|
||||||
$console.text(oldText + newText + "\\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var total = runner.total;
|
let splitedText = '';
|
||||||
runner.on('end', function(){
|
_(text.split('\n')).each((line) => {
|
||||||
stats.end = new Date;
|
while (line.length > 0) {
|
||||||
stats.duration = stats.end - stats.start;
|
const split = line.substr(0, 100);
|
||||||
var minutes = Math.floor(stats.duration / 1000 / 60);
|
line = line.substr(100);
|
||||||
var seconds = Math.round((stats.duration / 1000) % 60) // chrome < 57 does not like this .toString().padStart("2","0");
|
if (splitedText.length > 0) splitedText += '\n';
|
||||||
if(stats.tests === total){
|
splitedText += split;
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// indent all lines with the given amount of space
|
||||||
|
const newText = _(splitedText.split('\n')).map((line) => space + line).join('\\n');
|
||||||
|
|
||||||
|
$console.text(`${oldText + newText}\\n`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const total = runner.total;
|
||||||
|
runner.on('end', () => {
|
||||||
|
stats.end = new Date();
|
||||||
|
stats.duration = stats.end - stats.start;
|
||||||
|
const minutes = Math.floor(stats.duration / 1000 / 60);
|
||||||
|
const 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
|
// http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
|
||||||
var getURLParameter = function (name) {
|
const getURLParameter = function (name) {
|
||||||
return decodeURI(
|
return decodeURI(
|
||||||
(RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
|
(RegExp(`${name}=` + '(.+?)(&|$)').exec(location.search) || [, null])[1],
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
//get the list of specs and filter it if requested
|
// get the list of specs and filter it if requested
|
||||||
var specs = specs_list.slice();
|
const specs = specs_list.slice();
|
||||||
|
|
||||||
//inject spec scripts into the dom
|
// inject spec scripts into the dom
|
||||||
var $body = $('body');
|
const $body = $('body');
|
||||||
$.each(specs, function(i, spec){
|
$.each(specs, (i, spec) => {
|
||||||
if(spec[0] != "/"){ // if the spec isn't a plugin spec which means the spec file might be in a different subfolder
|
if (spec[0] != '/') { // if the spec isn't a plugin spec which means the spec file might be in a different subfolder
|
||||||
$body.append('<script src="specs/' + spec + '"></script>')
|
$body.append(`<script src="specs/${spec}"></script>`);
|
||||||
}else{
|
} else {
|
||||||
$body.append('<script src="' + spec + '"></script>')
|
$body.append(`<script src="${spec}"></script>`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//initalize the test helper
|
// initalize the test helper
|
||||||
helper.init(function(){
|
helper.init(() => {
|
||||||
//configure and start the test framework
|
// configure and start the test framework
|
||||||
var grep = getURLParameter("grep");
|
const grep = getURLParameter('grep');
|
||||||
if(grep != "null"){
|
if (grep != 'null') {
|
||||||
mocha.grep(grep);
|
mocha.grep(grep);
|
||||||
}
|
}
|
||||||
|
|
||||||
var runner = mocha.run();
|
const runner = mocha.run();
|
||||||
CustomRunner(runner)
|
CustomRunner(runner);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
describe("All the alphabet works n stuff", function(){
|
describe('All the alphabet works n stuff', function () {
|
||||||
var expectedString = "abcdefghijklmnopqrstuvwxyz";
|
const expectedString = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when you enter any char it appears right", function(done) {
|
it('when you enter any char it appears right', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var firstTextElement = inner$("div").first();
|
const firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// simulate key presses to delete content
|
// simulate key presses to delete content
|
||||||
firstTextElement.sendkeys('{selectall}'); // select all
|
firstTextElement.sendkeys('{selectall}'); // select all
|
||||||
firstTextElement.sendkeys('{del}'); // clear the first line
|
firstTextElement.sendkeys('{del}'); // clear the first line
|
||||||
firstTextElement.sendkeys(expectedString); // insert the string
|
firstTextElement.sendkeys(expectedString); // insert the string
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().text() === expectedString, 2000).done(done);
|
||||||
return inner$("div").first().text() === expectedString;
|
|
||||||
}, 2000).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
describe('author of pad edition', function() {
|
describe('author of pad edition', function () {
|
||||||
var REGULAR_LINE = 0;
|
const REGULAR_LINE = 0;
|
||||||
var LINE_WITH_ORDERED_LIST = 1;
|
const LINE_WITH_ORDERED_LIST = 1;
|
||||||
var LINE_WITH_UNORDERED_LIST = 2;
|
const LINE_WITH_UNORDERED_LIST = 2;
|
||||||
|
|
||||||
// author 1 creates a new pad with some content (regular lines and lists)
|
// author 1 creates a new pad with some content (regular lines and lists)
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
var padId = helper.newPad(function() {
|
var padId = helper.newPad(() => {
|
||||||
// make sure pad has at least 3 lines
|
// make sure pad has at least 3 lines
|
||||||
var $firstLine = helper.padInner$('div').first();
|
const $firstLine = helper.padInner$('div').first();
|
||||||
var threeLines = ['regular line', 'line with ordered list', 'line with unordered list'].join('<br>');
|
const threeLines = ['regular line', 'line with ordered list', 'line with unordered list'].join('<br>');
|
||||||
$firstLine.html(threeLines);
|
$firstLine.html(threeLines);
|
||||||
|
|
||||||
// wait for lines to be processed by Etherpad
|
// wait for lines to be processed by Etherpad
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
||||||
return $lineWithUnorderedList.text() === 'line with unordered list';
|
return $lineWithUnorderedList.text() === 'line with unordered list';
|
||||||
}).done(function() {
|
}).done(() => {
|
||||||
// create the unordered list
|
// create the unordered list
|
||||||
var $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
||||||
$lineWithUnorderedList.sendkeys('{selectall}');
|
$lineWithUnorderedList.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertUnorderedListButton = helper.padChrome$('.buttonicon-insertunorderedlist');
|
const $insertUnorderedListButton = helper.padChrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertUnorderedListButton.click();
|
$insertUnorderedListButton.click();
|
||||||
|
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
const $lineWithUnorderedList = getLine(LINE_WITH_UNORDERED_LIST);
|
||||||
return $lineWithUnorderedList.find('ul li').length === 1;
|
return $lineWithUnorderedList.find('ul li').length === 1;
|
||||||
}).done(function() {
|
}).done(() => {
|
||||||
// create the ordered list
|
// create the ordered list
|
||||||
var $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
|
const $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
|
||||||
$lineWithOrderedList.sendkeys('{selectall}');
|
$lineWithOrderedList.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertOrderedListButton = helper.padChrome$('.buttonicon-insertorderedlist');
|
const $insertOrderedListButton = helper.padChrome$('.buttonicon-insertorderedlist');
|
||||||
$insertOrderedListButton.click();
|
$insertOrderedListButton.click();
|
||||||
|
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
|
const $lineWithOrderedList = getLine(LINE_WITH_ORDERED_LIST);
|
||||||
return $lineWithOrderedList.find('ol li').length === 1;
|
return $lineWithOrderedList.find('ol li').length === 1;
|
||||||
}).done(function() {
|
}).done(() => {
|
||||||
// Reload pad, to make changes as a second user. Need a timeout here to make sure
|
// Reload pad, to make changes as a second user. Need a timeout here to make sure
|
||||||
// all changes were saved before reloading
|
// all changes were saved before reloading
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// Expire cookie, so author is changed after reloading the pad.
|
// 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
|
// 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.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
||||||
|
@ -55,55 +55,51 @@ describe('author of pad edition', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// author 2 makes some changes on the pad
|
// author 2 makes some changes on the pad
|
||||||
it('marks only the new content as changes of the second user on a regular line', function(done) {
|
it('marks only the new content as changes of the second user on a regular line', function (done) {
|
||||||
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(REGULAR_LINE, 'x', done);
|
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(REGULAR_LINE, 'x', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('marks only the new content as changes of the second user on a line with ordered list', function(done) {
|
it('marks only the new content as changes of the second user on a line with ordered list', function (done) {
|
||||||
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_ORDERED_LIST, 'y', done);
|
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_ORDERED_LIST, 'y', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('marks only the new content as changes of the second user on a line with unordered list', function(done) {
|
it('marks only the new content as changes of the second user on a line with unordered list', function (done) {
|
||||||
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_UNORDERED_LIST, 'z', done);
|
changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_UNORDERED_LIST, 'z', done);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* ********************** Helper functions ************************ */
|
/* ********************** Helper functions ************************ */
|
||||||
var getLine = function(lineNumber) {
|
var getLine = function (lineNumber) {
|
||||||
return helper.padInner$('div').eq(lineNumber);
|
return helper.padInner$('div').eq(lineNumber);
|
||||||
}
|
};
|
||||||
|
|
||||||
var getAuthorFromClassList = function(classes) {
|
const getAuthorFromClassList = function (classes) {
|
||||||
return classes.find(function(cls) {
|
return classes.find((cls) => cls.startsWith('author'));
|
||||||
return cls.startsWith('author');
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var changeLineAndCheckOnlyThatChangeIsFromThisAuthor = function(lineNumber, textChange, done) {
|
var changeLineAndCheckOnlyThatChangeIsFromThisAuthor = function (lineNumber, textChange, done) {
|
||||||
// get original author class
|
// get original author class
|
||||||
var classes = getLine(lineNumber).find('span').first().attr('class').split(' ');
|
const classes = getLine(lineNumber).find('span').first().attr('class').split(' ');
|
||||||
var originalAuthor = getAuthorFromClassList(classes);
|
const originalAuthor = getAuthorFromClassList(classes);
|
||||||
|
|
||||||
// make change on target line
|
// make change on target line
|
||||||
var $regularLine = getLine(lineNumber);
|
const $regularLine = getLine(lineNumber);
|
||||||
helper.selectLines($regularLine, $regularLine, 2, 2); // place caret after 2nd char of line
|
helper.selectLines($regularLine, $regularLine, 2, 2); // place caret after 2nd char of line
|
||||||
$regularLine.sendkeys(textChange);
|
$regularLine.sendkeys(textChange);
|
||||||
|
|
||||||
// wait for change to be processed by Etherpad
|
// wait for change to be processed by Etherpad
|
||||||
var otherAuthorsOfLine;
|
let otherAuthorsOfLine;
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var authorsOfLine = getLine(lineNumber).find('span').map(function() {
|
const authorsOfLine = getLine(lineNumber).find('span').map(function () {
|
||||||
return getAuthorFromClassList($(this).attr('class').split(' '));
|
return getAuthorFromClassList($(this).attr('class').split(' '));
|
||||||
}).get();
|
}).get();
|
||||||
otherAuthorsOfLine = authorsOfLine.filter(function(author) {
|
otherAuthorsOfLine = authorsOfLine.filter((author) => author !== originalAuthor);
|
||||||
return author !== originalAuthor;
|
const lineHasChangeOfThisAuthor = otherAuthorsOfLine.length > 0;
|
||||||
});
|
|
||||||
var lineHasChangeOfThisAuthor = otherAuthorsOfLine.length > 0;
|
|
||||||
return lineHasChangeOfThisAuthor;
|
return lineHasChangeOfThisAuthor;
|
||||||
}).done(function() {
|
}).done(() => {
|
||||||
var thisAuthor = otherAuthorsOfLine[0];
|
const thisAuthor = otherAuthorsOfLine[0];
|
||||||
var $changeOfThisAuthor = getLine(lineNumber).find('span.' + thisAuthor);
|
const $changeOfThisAuthor = getLine(lineNumber).find(`span.${thisAuthor}`);
|
||||||
expect($changeOfThisAuthor.text()).to.be(textChange);
|
expect($changeOfThisAuthor.text()).to.be(textChange);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,64 +1,64 @@
|
||||||
describe("bold button", function(){
|
describe('bold button', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text bold on click", function(done) {
|
it('makes text bold on click', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
//get the bold button and click it
|
// get the bold button and click it
|
||||||
var $boldButton = chrome$(".buttonicon-bold");
|
const $boldButton = chrome$('.buttonicon-bold');
|
||||||
$boldButton.click();
|
$boldButton.click();
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
// ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// is there a <b> element now?
|
// is there a <b> element now?
|
||||||
var isBold = $newFirstTextElement.find("b").length === 1;
|
const isBold = $newFirstTextElement.find('b').length === 1;
|
||||||
|
|
||||||
//expect it to be bold
|
// expect it to be bold
|
||||||
expect(isBold).to.be(true);
|
expect(isBold).to.be(true);
|
||||||
|
|
||||||
//make sure the text hasn't changed
|
// make sure the text hasn't changed
|
||||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text bold on keypress", function(done) {
|
it('makes text bold on keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 66; // b
|
e.which = 66; // b
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
// ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// is there a <b> element now?
|
// is there a <b> element now?
|
||||||
var isBold = $newFirstTextElement.find("b").length === 1;
|
const isBold = $newFirstTextElement.find('b').length === 1;
|
||||||
|
|
||||||
//expect it to be bold
|
// expect it to be bold
|
||||||
expect(isBold).to.be(true);
|
expect(isBold).to.be(true);
|
||||||
|
|
||||||
//make sure the text hasn't changed
|
// make sure the text hasn't changed
|
||||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
describe("As the caret is moved is the UI properly updated?", function(){
|
describe('As the caret is moved is the UI properly updated?', function () {
|
||||||
var padName;
|
let padName;
|
||||||
var numberOfRows = 50;
|
const numberOfRows = 50;
|
||||||
/*
|
/*
|
||||||
|
|
||||||
//create a new pad before each test run
|
//create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function(cb){
|
||||||
|
@ -28,7 +28,7 @@ describe("As the caret is moved is the UI properly updated?", function(){
|
||||||
* How do we keep the authors focus on a line if the lines above the author are modified? We should only redraw the user to a location if they are typing and make sure shift and arrow keys aren't redrawing the UI else highlight - copy/paste would get broken
|
* How do we keep the authors focus on a line if the lines above the author are modified? We should only redraw the user to a location if they are typing and make sure shift and arrow keys aren't redrawing the UI else highlight - copy/paste would get broken
|
||||||
* How can we simulate an edit event in the test framework?
|
* How can we simulate an edit event in the test framework?
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
// THIS DOESNT WORK IN CHROME AS IT DOESNT MOVE THE CURSOR!
|
// THIS DOESNT WORK IN CHROME AS IT DOESNT MOVE THE CURSOR!
|
||||||
it("down arrow", function(done){
|
it("down arrow", function(done){
|
||||||
var inner$ = helper.padInner$;
|
var inner$ = helper.padInner$;
|
||||||
|
@ -194,7 +194,6 @@ console.log(inner$);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
it("Creates N rows, changes height of rows, updates UI by caret key events", function(done){
|
it("Creates N rows, changes height of rows, updates UI by caret key events", function(done){
|
||||||
var inner$ = helper.padInner$;
|
var inner$ = helper.padInner$;
|
||||||
|
@ -264,7 +263,6 @@ console.log(inner$);
|
||||||
}).done(function(){ // Once the DOM has registered the items
|
}).done(function(){ // Once the DOM has registered the items
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -284,54 +282,51 @@ console.log(inner$);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function prepareDocument(n, target){ // generates a random document with random content on n lines
|
function prepareDocument(n, target) { // generates a random document with random content on n lines
|
||||||
var i = 0;
|
let i = 0;
|
||||||
while(i < n){ // for each line
|
while (i < n) { // for each line
|
||||||
target.sendkeys(makeStr()); // generate a random string and send that to the editor
|
target.sendkeys(makeStr()); // generate a random string and send that to the editor
|
||||||
target.sendkeys('{enter}'); // generator an enter keypress
|
target.sendkeys('{enter}'); // generator an enter keypress
|
||||||
i++; // rinse n times
|
i++; // rinse n times
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyEvent(target, charCode, ctrl, shift){ // sends a charCode to the window
|
function keyEvent(target, charCode, ctrl, shift) { // sends a charCode to the window
|
||||||
|
const e = target.Event(helper.evtType);
|
||||||
var e = target.Event(helper.evtType);
|
if (ctrl) {
|
||||||
if(ctrl){
|
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
}
|
}
|
||||||
if(shift){
|
if (shift) {
|
||||||
e.shiftKey = true; // Shift Key
|
e.shiftKey = true; // Shift Key
|
||||||
}
|
}
|
||||||
e.which = charCode;
|
e.which = charCode;
|
||||||
e.keyCode = charCode;
|
e.keyCode = charCode;
|
||||||
target("#innerdocbody").trigger(e);
|
target('#innerdocbody').trigger(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function makeStr(){ // from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
|
function makeStr() { // from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript
|
||||||
var text = "";
|
let text = '';
|
||||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
|
||||||
for( var i=0; i < 5; i++ )
|
for (let i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isScrolledIntoView(elem, $){ // from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
|
function isScrolledIntoView(elem, $) { // from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
|
||||||
var docViewTop = $(window).scrollTop();
|
const docViewTop = $(window).scrollTop();
|
||||||
var docViewBottom = docViewTop + $(window).height();
|
const docViewBottom = docViewTop + $(window).height();
|
||||||
var elemTop = $(elem).offset().top; // how far the element is from the top of it's container
|
const elemTop = $(elem).offset().top; // how far the element is from the top of it's container
|
||||||
var elemBottom = elemTop + $(elem).height(); // how far plus the height of the elem.. IE is it all in?
|
let elemBottom = elemTop + $(elem).height(); // how far plus the height of the elem.. IE is it all in?
|
||||||
elemBottom = elemBottom - 16; // don't ask, sorry but this is needed..
|
elemBottom -= 16; // don't ask, sorry but this is needed..
|
||||||
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
|
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
|
||||||
}
|
}
|
||||||
|
|
||||||
function caretPosition($){
|
function caretPosition($) {
|
||||||
var doc = $.window.document;
|
const doc = $.window.document;
|
||||||
var pos = doc.getSelection();
|
const pos = doc.getSelection();
|
||||||
pos.y = pos.anchorNode.parentElement.offsetTop;
|
pos.y = pos.anchorNode.parentElement.offsetTop;
|
||||||
pos.x = pos.anchorNode.parentElement.offsetLeft;
|
pos.x = pos.anchorNode.parentElement.offsetLeft;
|
||||||
return pos;
|
return pos;
|
||||||
|
|
|
@ -1,102 +1,101 @@
|
||||||
describe("change user color", function(){
|
describe('change user color', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Color picker matches original color and remembers the user color after a refresh", function(done) {
|
it('Color picker matches original color and remembers the user color after a refresh', function (done) {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $userSwatch = chrome$("#myswatch");
|
const $userSwatch = chrome$('#myswatch');
|
||||||
$userSwatch.click();
|
$userSwatch.click();
|
||||||
|
|
||||||
var fb = chrome$.farbtastic('#colorpicker')
|
const fb = chrome$.farbtastic('#colorpicker');
|
||||||
var $colorPickerSave = chrome$("#mycolorpickersave");
|
const $colorPickerSave = chrome$('#mycolorpickersave');
|
||||||
var $colorPickerPreview = chrome$("#mycolorpickerpreview");
|
const $colorPickerPreview = chrome$('#mycolorpickerpreview');
|
||||||
|
|
||||||
// Same color represented in two different ways
|
// Same color represented in two different ways
|
||||||
const testColorHash = '#abcdef'
|
const testColorHash = '#abcdef';
|
||||||
const testColorRGB = 'rgb(171, 205, 239)'
|
const testColorRGB = 'rgb(171, 205, 239)';
|
||||||
|
|
||||||
// Check that the color picker matches the automatically assigned random color on the swatch.
|
// 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
|
// 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.
|
// off-chance the randomly assigned color is the same as the test color.
|
||||||
expect($colorPickerPreview.css('background-color')).to.be($userSwatch.css('background-color'))
|
expect($colorPickerPreview.css('background-color')).to.be($userSwatch.css('background-color'));
|
||||||
|
|
||||||
// The swatch updates as the test color is picked.
|
// The swatch updates as the test color is picked.
|
||||||
fb.setColor(testColorHash)
|
fb.setColor(testColorHash);
|
||||||
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB)
|
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB);
|
||||||
$colorPickerSave.click();
|
$colorPickerSave.click();
|
||||||
expect($userSwatch.css('background-color')).to.be(testColorRGB)
|
expect($userSwatch.css('background-color')).to.be(testColorRGB);
|
||||||
|
|
||||||
setTimeout(function(){ //give it a second to save the color on the server side
|
setTimeout(() => { // give it a second to save the color on the server side
|
||||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||||
clearCookies: false
|
clearCookies: false,
|
||||||
, cb: function(){
|
cb() {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $userSwatch = chrome$("#myswatch");
|
const $userSwatch = chrome$('#myswatch');
|
||||||
$userSwatch.click();
|
$userSwatch.click();
|
||||||
|
|
||||||
var $colorPickerPreview = chrome$("#mycolorpickerpreview");
|
const $colorPickerPreview = chrome$('#mycolorpickerpreview');
|
||||||
|
|
||||||
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB)
|
expect($colorPickerPreview.css('background-color')).to.be(testColorRGB);
|
||||||
expect($userSwatch.css('background-color')).to.be(testColorRGB)
|
expect($userSwatch.css('background-color')).to.be(testColorRGB);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Own user color is shown when you enter a chat", function(done) {
|
it('Own user color is shown when you enter a chat', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $colorOption = helper.padChrome$('#options-colorscheck');
|
const $colorOption = helper.padChrome$('#options-colorscheck');
|
||||||
if (!$colorOption.is(':checked')) {
|
if (!$colorOption.is(':checked')) {
|
||||||
$colorOption.click();
|
$colorOption.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $userSwatch = chrome$("#myswatch");
|
const $userSwatch = chrome$('#myswatch');
|
||||||
$userSwatch.click();
|
$userSwatch.click();
|
||||||
|
|
||||||
var fb = chrome$.farbtastic('#colorpicker')
|
const fb = chrome$.farbtastic('#colorpicker');
|
||||||
var $colorPickerSave = chrome$("#mycolorpickersave");
|
const $colorPickerSave = chrome$('#mycolorpickersave');
|
||||||
|
|
||||||
// Same color represented in two different ways
|
// Same color represented in two different ways
|
||||||
const testColorHash = '#abcdef'
|
const testColorHash = '#abcdef';
|
||||||
const testColorRGB = 'rgb(171, 205, 239)'
|
const testColorRGB = 'rgb(171, 205, 239)';
|
||||||
|
|
||||||
fb.setColor(testColorHash)
|
fb.setColor(testColorHash);
|
||||||
$colorPickerSave.click();
|
$colorPickerSave.click();
|
||||||
|
|
||||||
//click on the chat button to make chat visible
|
// click on the chat button to make chat visible
|
||||||
var $chatButton = chrome$("#chaticon");
|
const $chatButton = chrome$('#chaticon');
|
||||||
$chatButton.click();
|
$chatButton.click();
|
||||||
var $chatInput = chrome$("#chatinput");
|
const $chatInput = chrome$('#chatinput');
|
||||||
$chatInput.sendkeys('O hi'); // simulate a keypress of typing user
|
$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
|
$chatInput.sendkeys('{enter}'); // simulate a keypress of enter actually does evt.which = 10 not 13
|
||||||
|
|
||||||
//check if chat shows up
|
// check if chat shows up
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => chrome$('#chattext').children('p').length !== 0, // wait until the chat message shows up
|
||||||
return chrome$("#chattext").children("p").length !== 0; // wait until the chat message shows up
|
).done(() => {
|
||||||
}).done(function(){
|
const $firstChatMessage = chrome$('#chattext').children('p');
|
||||||
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
|
expect($firstChatMessage.css('background-color')).to.be(testColorRGB); // expect the first chat message to be of the user's color
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,70 +1,69 @@
|
||||||
describe("change username value", function(){
|
describe('change username value', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Remembers the user name after a refresh", function(done) {
|
it('Remembers the user name after a refresh', function (done) {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $usernameInput = chrome$("#myusernameedit");
|
const $usernameInput = chrome$('#myusernameedit');
|
||||||
$usernameInput.click();
|
$usernameInput.click();
|
||||||
|
|
||||||
$usernameInput.val('John McLear');
|
$usernameInput.val('John McLear');
|
||||||
$usernameInput.blur();
|
$usernameInput.blur();
|
||||||
|
|
||||||
setTimeout(function(){ //give it a second to save the username on the server side
|
setTimeout(() => { // give it a second to save the username on the server side
|
||||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||||
clearCookies: false
|
clearCookies: false,
|
||||||
, cb: function(){
|
cb() {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $usernameInput = chrome$("#myusernameedit");
|
const $usernameInput = chrome$('#myusernameedit');
|
||||||
expect($usernameInput.val()).to.be('John McLear')
|
expect($usernameInput.val()).to.be('John McLear');
|
||||||
done();
|
done();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("Own user name is shown when you enter a chat", function(done) {
|
it('Own user name is shown when you enter a chat', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $usernameInput = chrome$("#myusernameedit");
|
const $usernameInput = chrome$('#myusernameedit');
|
||||||
$usernameInput.click();
|
$usernameInput.click();
|
||||||
|
|
||||||
$usernameInput.val('John McLear');
|
$usernameInput.val('John McLear');
|
||||||
$usernameInput.blur();
|
$usernameInput.blur();
|
||||||
|
|
||||||
//click on the chat button to make chat visible
|
// click on the chat button to make chat visible
|
||||||
var $chatButton = chrome$("#chaticon");
|
const $chatButton = chrome$('#chaticon');
|
||||||
$chatButton.click();
|
$chatButton.click();
|
||||||
var $chatInput = chrome$("#chatinput");
|
const $chatInput = chrome$('#chatinput');
|
||||||
$chatInput.sendkeys('O hi'); // simulate a keypress of typing JohnMcLear
|
$chatInput.sendkeys('O hi'); // simulate a keypress of typing JohnMcLear
|
||||||
$chatInput.sendkeys('{enter}'); // simulate a keypress of enter actually does evt.which = 10 not 13
|
$chatInput.sendkeys('{enter}'); // simulate a keypress of enter actually does evt.which = 10 not 13
|
||||||
|
|
||||||
//check if chat shows up
|
// check if chat shows up
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => chrome$('#chattext').children('p').length !== 0, // wait until the chat message shows up
|
||||||
return chrome$("#chattext").children("p").length !== 0; // wait until the chat message shows up
|
).done(() => {
|
||||||
}).done(function(){
|
const $firstChatMessage = chrome$('#chattext').children('p');
|
||||||
var $firstChatMessage = chrome$("#chattext").children("p");
|
const containsJohnMcLear = $firstChatMessage.text().indexOf('John McLear') !== -1; // does the string contain John McLear
|
||||||
var containsJohnMcLear = $firstChatMessage.text().indexOf("John McLear") !== -1; // does the string contain John McLear
|
|
||||||
expect(containsJohnMcLear).to.be(true); // expect the first chat message to contain JohnMcLear
|
expect(containsJohnMcLear).to.be(true); // expect the first chat message to contain JohnMcLear
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
describe("Chat messages and UI", function(){
|
describe('Chat messages and UI', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("opens chat, sends a message, makes sure it exists on the page and hides chat", async function() {
|
it('opens chat, sends a message, makes sure it exists on the page and hides chat', async function () {
|
||||||
var chatValue = "JohnMcLear";
|
const chatValue = 'JohnMcLear';
|
||||||
|
|
||||||
await helper.showChat();
|
await helper.showChat();
|
||||||
await helper.sendChatMessage(`${chatValue}{enter}`);
|
await helper.sendChatMessage(`${chatValue}{enter}`);
|
||||||
|
@ -18,33 +18,33 @@ describe("Chat messages and UI", function(){
|
||||||
// <span class="time author-a-qjkwz78zs4z122z0pz80zz82zz79zphz83z">12:38
|
// <span class="time author-a-qjkwz78zs4z122z0pz80zz82zz79zphz83z">12:38
|
||||||
// </span> JohnMcLear
|
// </span> JohnMcLear
|
||||||
// </p>
|
// </p>
|
||||||
let username = helper.chatTextParagraphs().children("b").text();
|
const username = helper.chatTextParagraphs().children('b').text();
|
||||||
let time = helper.chatTextParagraphs().children(".time").text();
|
const time = helper.chatTextParagraphs().children('.time').text();
|
||||||
|
|
||||||
expect(helper.chatTextParagraphs().text()).to.be(`${username}${time} ${chatValue}`);
|
expect(helper.chatTextParagraphs().text()).to.be(`${username}${time} ${chatValue}`);
|
||||||
|
|
||||||
await helper.hideChat();
|
await helper.hideChat();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes sure that an empty message can't be sent", async function() {
|
it("makes sure that an empty message can't be sent", async function () {
|
||||||
var chatValue = "mluto";
|
const chatValue = 'mluto';
|
||||||
|
|
||||||
await helper.showChat();
|
await helper.showChat();
|
||||||
|
|
||||||
await helper.sendChatMessage(`{enter}${chatValue}{enter}`); // simulate a keypress of typing enter, mluto and enter (to send 'mluto')
|
await helper.sendChatMessage(`{enter}${chatValue}{enter}`); // simulate a keypress of typing enter, mluto and enter (to send 'mluto')
|
||||||
|
|
||||||
let chat = helper.chatTextParagraphs();
|
const chat = helper.chatTextParagraphs();
|
||||||
|
|
||||||
expect(chat.length).to.be(1);
|
expect(chat.length).to.be(1);
|
||||||
|
|
||||||
// check that the received message is not the empty one
|
// check that the received message is not the empty one
|
||||||
let username = chat.children("b").text();
|
const username = chat.children('b').text();
|
||||||
let time = chat.children(".time").text();
|
const time = chat.children('.time').text();
|
||||||
|
|
||||||
expect(chat.text()).to.be(`${username}${time} ${chatValue}`);
|
expect(chat.text()).to.be(`${username}${time} ${chatValue}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes chat stick to right side of the screen via settings, remove sticky via settings, close it", async function() {
|
it('makes chat stick to right side of the screen via settings, remove sticky via settings, close it', async function () {
|
||||||
await helper.showSettings();
|
await helper.showSettings();
|
||||||
|
|
||||||
await helper.enableStickyChatviaSettings();
|
await helper.enableStickyChatviaSettings();
|
||||||
|
@ -60,7 +60,7 @@ describe("Chat messages and UI", function(){
|
||||||
expect(helper.isChatboxShown()).to.be(false);
|
expect(helper.isChatboxShown()).to.be(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes chat stick to right side of the screen via icon on the top right, remove sticky via icon, close it", async function() {
|
it('makes chat stick to right side of the screen via icon on the top right, remove sticky via icon, close it', async function () {
|
||||||
await helper.showChat();
|
await helper.showChat();
|
||||||
|
|
||||||
await helper.enableStickyChatviaIcon();
|
await helper.enableStickyChatviaIcon();
|
||||||
|
@ -76,39 +76,36 @@ describe("Chat messages and UI", function(){
|
||||||
expect(helper.isChatboxShown()).to.be(false);
|
expect(helper.isChatboxShown()).to.be(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
xit("Checks showChat=false URL Parameter hides chat then when removed it shows chat", function(done) {
|
xit('Checks showChat=false URL Parameter hides chat then when removed it shows chat', function (done) {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
setTimeout(function(){ //give it a second to save the username on the server side
|
setTimeout(() => { // give it a second to save the username on the server side
|
||||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||||
clearCookies: false,
|
clearCookies: false,
|
||||||
params:{
|
params: {
|
||||||
showChat: "false"
|
showChat: 'false',
|
||||||
}, cb: function(){
|
}, cb() {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chaticon = chrome$("#chaticon");
|
const chaticon = chrome$('#chaticon');
|
||||||
// chat should be hidden.
|
// chat should be hidden.
|
||||||
expect(chaticon.is(":visible")).to.be(false);
|
expect(chaticon.is(':visible')).to.be(false);
|
||||||
|
|
||||||
setTimeout(function(){ //give it a second to save the username on the server side
|
setTimeout(() => { // give it a second to save the username on the server side
|
||||||
helper.newPad({ // get a new pad, but don't clear the cookies
|
helper.newPad({ // get a new pad, but don't clear the cookies
|
||||||
clearCookies: false
|
clearCookies: false,
|
||||||
, cb: function(){
|
cb() {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chaticon = chrome$("#chaticon");
|
const chaticon = chrome$('#chaticon');
|
||||||
// chat should be visible.
|
// chat should be visible.
|
||||||
expect(chaticon.is(":visible")).to.be(true);
|
expect(chaticon.is(':visible')).to.be(true);
|
||||||
done();
|
done();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,85 +1,77 @@
|
||||||
describe("chat-load-messages", function(){
|
describe('chat-load-messages', function () {
|
||||||
var padName;
|
let padName;
|
||||||
|
|
||||||
it("creates a pad", function(done) {
|
it('creates a pad', function (done) {
|
||||||
padName = helper.newPad(done);
|
padName = helper.newPad(done);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("adds a lot of messages", function(done) {
|
it('adds a lot of messages', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chatButton = chrome$("#chaticon");
|
const chatButton = chrome$('#chaticon');
|
||||||
chatButton.click();
|
chatButton.click();
|
||||||
var chatInput = chrome$("#chatinput");
|
const chatInput = chrome$('#chatinput');
|
||||||
var chatText = chrome$("#chattext");
|
const chatText = chrome$('#chattext');
|
||||||
|
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
|
|
||||||
var messages = 140;
|
const messages = 140;
|
||||||
for(var i=1; i <= messages; i++) {
|
for (let i = 1; i <= messages; i++) {
|
||||||
var num = ''+i;
|
let num = `${i}`;
|
||||||
if(num.length == 1)
|
if (num.length == 1) num = `00${num}`;
|
||||||
num = '00'+num;
|
if (num.length == 2) num = `0${num}`;
|
||||||
if(num.length == 2)
|
chatInput.sendkeys(`msg${num}`);
|
||||||
num = '0'+num;
|
|
||||||
chatInput.sendkeys('msg' + num);
|
|
||||||
chatInput.sendkeys('{enter}');
|
chatInput.sendkeys('{enter}');
|
||||||
}
|
}
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => chatText.children('p').length == messages, 60000).always(() => {
|
||||||
return chatText.children("p").length == messages;
|
expect(chatText.children('p').length).to.be(messages);
|
||||||
}, 60000).always(function(){
|
|
||||||
expect(chatText.children("p").length).to.be(messages);
|
|
||||||
helper.newPad(done, padName);
|
helper.newPad(done, padName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks initial message count", function(done) {
|
it('checks initial message count', function (done) {
|
||||||
var chatText;
|
let chatText;
|
||||||
var expectedCount = 101;
|
const expectedCount = 101;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var chatButton = chrome$("#chaticon");
|
const chatButton = chrome$('#chaticon');
|
||||||
chatButton.click();
|
chatButton.click();
|
||||||
chatText = chrome$("#chattext");
|
chatText = chrome$('#chattext');
|
||||||
return chatText.children("p").length == expectedCount;
|
return chatText.children('p').length == expectedCount;
|
||||||
}).always(function(){
|
}).always(() => {
|
||||||
expect(chatText.children("p").length).to.be(expectedCount);
|
expect(chatText.children('p').length).to.be(expectedCount);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("loads more messages", function(done) {
|
it('loads more messages', function (done) {
|
||||||
var expectedCount = 122;
|
const expectedCount = 122;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chatButton = chrome$("#chaticon");
|
const chatButton = chrome$('#chaticon');
|
||||||
chatButton.click();
|
chatButton.click();
|
||||||
var chatText = chrome$("#chattext");
|
const chatText = chrome$('#chattext');
|
||||||
var loadMsgBtn = chrome$("#chatloadmessagesbutton");
|
const loadMsgBtn = chrome$('#chatloadmessagesbutton');
|
||||||
|
|
||||||
loadMsgBtn.click();
|
loadMsgBtn.click();
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => chatText.children('p').length == expectedCount).always(() => {
|
||||||
return chatText.children("p").length == expectedCount;
|
expect(chatText.children('p').length).to.be(expectedCount);
|
||||||
}).always(function(){
|
|
||||||
expect(chatText.children("p").length).to.be(expectedCount);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks for button vanishing", function(done) {
|
it('checks for button vanishing', function (done) {
|
||||||
var expectedDisplay = 'none';
|
const expectedDisplay = 'none';
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chatButton = chrome$("#chaticon");
|
const chatButton = chrome$('#chaticon');
|
||||||
chatButton.click();
|
chatButton.click();
|
||||||
var chatText = chrome$("#chattext");
|
const chatText = chrome$('#chattext');
|
||||||
var loadMsgBtn = chrome$("#chatloadmessagesbutton");
|
const loadMsgBtn = chrome$('#chatloadmessagesbutton');
|
||||||
var loadMsgBall = chrome$("#chatloadmessagesball");
|
const loadMsgBall = chrome$('#chatloadmessagesball');
|
||||||
|
|
||||||
loadMsgBtn.click();
|
loadMsgBtn.click();
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => loadMsgBtn.css('display') == expectedDisplay &&
|
||||||
return loadMsgBtn.css('display') == expectedDisplay &&
|
loadMsgBall.css('display') == expectedDisplay).always(() => {
|
||||||
loadMsgBall.css('display') == expectedDisplay;
|
|
||||||
}).always(function(){
|
|
||||||
expect(loadMsgBtn.css('display')).to.be(expectedDisplay);
|
expect(loadMsgBtn.css('display')).to.be(expectedDisplay);
|
||||||
expect(loadMsgBall.css('display')).to.be(expectedDisplay);
|
expect(loadMsgBall.css('display')).to.be(expectedDisplay);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -1,133 +1,128 @@
|
||||||
describe("clear authorship colors button", function(){
|
describe('clear authorship colors button', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text clear authorship colors", function(done) {
|
it('makes text clear authorship colors', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// override the confirm dialogue functioon
|
// override the confirm dialogue functioon
|
||||||
helper.padChrome$.window.confirm = function(){
|
helper.padChrome$.window.confirm = function () {
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// Get the original text
|
// Get the original text
|
||||||
var originalText = inner$("div").first().text();
|
const originalText = inner$('div').first().text();
|
||||||
|
|
||||||
// Set some new text
|
// Set some new text
|
||||||
var sentText = "Hello";
|
const sentText = 'Hello';
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
$firstTextElement.sendkeys(sentText);
|
$firstTextElement.sendkeys(sentText);
|
||||||
$firstTextElement.sendkeys('{rightarrow}');
|
$firstTextElement.sendkeys('{rightarrow}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1, // wait until we have the full value available
|
||||||
return inner$("div span").first().attr("class").indexOf("author") !== -1; // wait until we have the full value available
|
).done(() => {
|
||||||
}).done(function(){
|
// IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
|
||||||
//IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
|
inner$('div').first().focus();
|
||||||
inner$("div").first().focus();
|
|
||||||
|
|
||||||
//get the clear authorship colors button and click it
|
// get the clear authorship colors button and click it
|
||||||
var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship");
|
const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
|
||||||
$clearauthorshipcolorsButton.click();
|
$clearauthorshipcolorsButton.click();
|
||||||
|
|
||||||
// does the first divs span include an author class?
|
// does the first divs span include an author class?
|
||||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
var hasAuthorClass = inner$('div span').first().attr('class').indexOf('author') !== -1;
|
||||||
//expect(hasAuthorClass).to.be(false);
|
// expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
// does the first div include an author class?
|
// does the first div include an author class?
|
||||||
var hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
var hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
|
||||||
expect(hasAuthorClass).to.be(false);
|
expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
|
||||||
return (disconnectVisible === true)
|
return (disconnectVisible === true);
|
||||||
});
|
});
|
||||||
|
|
||||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
|
||||||
expect(disconnectVisible).to.be(true);
|
expect(disconnectVisible).to.be(true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text clear authorship colors and checks it can't be undone", function(done) {
|
it("makes text clear authorship colors and checks it can't be undone", function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// override the confirm dialogue functioon
|
// override the confirm dialogue functioon
|
||||||
helper.padChrome$.window.confirm = function(){
|
helper.padChrome$.window.confirm = function () {
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// Get the original text
|
// Get the original text
|
||||||
var originalText = inner$("div").first().text();
|
const originalText = inner$('div').first().text();
|
||||||
|
|
||||||
// Set some new text
|
// Set some new text
|
||||||
var sentText = "Hello";
|
const sentText = 'Hello';
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
$firstTextElement.sendkeys(sentText);
|
$firstTextElement.sendkeys(sentText);
|
||||||
$firstTextElement.sendkeys('{rightarrow}');
|
$firstTextElement.sendkeys('{rightarrow}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1, // wait until we have the full value available
|
||||||
return inner$("div span").first().attr("class").indexOf("author") !== -1; // wait until we have the full value available
|
).done(() => {
|
||||||
}).done(function(){
|
// IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
|
||||||
//IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship
|
inner$('div').first().focus();
|
||||||
inner$("div").first().focus();
|
|
||||||
|
|
||||||
//get the clear authorship colors button and click it
|
// get the clear authorship colors button and click it
|
||||||
var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship");
|
const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
|
||||||
$clearauthorshipcolorsButton.click();
|
$clearauthorshipcolorsButton.click();
|
||||||
|
|
||||||
// does the first divs span include an author class?
|
// does the first divs span include an author class?
|
||||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
var hasAuthorClass = inner$('div span').first().attr('class').indexOf('author') !== -1;
|
||||||
//expect(hasAuthorClass).to.be(false);
|
// expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
// does the first div include an author class?
|
// does the first div include an author class?
|
||||||
var hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
var hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
|
||||||
expect(hasAuthorClass).to.be(false);
|
expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 90; // z
|
e.which = 90; // z
|
||||||
inner$("#innerdocbody").trigger(e); // shouldn't od anything
|
inner$('#innerdocbody').trigger(e); // shouldn't od anything
|
||||||
|
|
||||||
// does the first div include an author class?
|
// does the first div include an author class?
|
||||||
hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
|
||||||
expect(hasAuthorClass).to.be(false);
|
expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
// get undo and redo buttons
|
// get undo and redo buttons
|
||||||
var $undoButton = chrome$(".buttonicon-undo");
|
const $undoButton = chrome$('.buttonicon-undo');
|
||||||
|
|
||||||
// click the button
|
// click the button
|
||||||
$undoButton.click(); // shouldn't do anything
|
$undoButton.click(); // shouldn't do anything
|
||||||
hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1;
|
hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1;
|
||||||
expect(hasAuthorClass).to.be(false);
|
expect(hasAuthorClass).to.be(false);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
|
||||||
return (disconnectVisible === true)
|
return (disconnectVisible === true);
|
||||||
});
|
});
|
||||||
|
|
||||||
var disconnectVisible = chrome$("div.disconnected").attr("class").indexOf("visible") === -1
|
const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1;
|
||||||
expect(disconnectVisible).to.be(true);
|
expect(disconnectVisible).to.be(true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
describe("delete keystroke", function(){
|
describe('delete keystroke', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text delete", function(done) {
|
it('makes text delete', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// get the original length of this element
|
// get the original length of this element
|
||||||
var elementLength = $firstTextElement.text().length;
|
const elementLength = $firstTextElement.text().length;
|
||||||
|
|
||||||
// get the original string value minus the last char
|
// get the original string value minus the last char
|
||||||
var originalTextValue = $firstTextElement.text();
|
const originalTextValue = $firstTextElement.text();
|
||||||
var originalTextValueMinusFirstChar = originalTextValue.substring(1, originalTextValue.length );
|
const originalTextValueMinusFirstChar = originalTextValue.substring(1, originalTextValue.length);
|
||||||
|
|
||||||
// simulate key presses to delete content
|
// simulate key presses to delete content
|
||||||
$firstTextElement.sendkeys('{leftarrow}'); // simulate a keypress of the left arrow key
|
$firstTextElement.sendkeys('{leftarrow}'); // simulate a keypress of the left arrow key
|
||||||
$firstTextElement.sendkeys('{del}'); // simulate a keypress of delete
|
$firstTextElement.sendkeys('{del}'); // simulate a keypress of delete
|
||||||
|
|
||||||
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
// ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// get the new length of this element
|
// get the new length of this element
|
||||||
var newElementLength = $newFirstTextElement.text().length;
|
const newElementLength = $newFirstTextElement.text().length;
|
||||||
|
|
||||||
//expect it to be one char less in length
|
// expect it to be one char less in length
|
||||||
expect(newElementLength).to.be((elementLength-1));
|
expect(newElementLength).to.be((elementLength - 1));
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
// WARNING: drag and drop is only simulated on these tests, so manual testing might also be necessary
|
// WARNING: drag and drop is only simulated on these tests, so manual testing might also be necessary
|
||||||
describe('drag and drop', function() {
|
describe('drag and drop', function () {
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
helper.newPad(function() {
|
helper.newPad(() => {
|
||||||
createScriptWithSeveralLines(done);
|
createScriptWithSeveralLines(done);
|
||||||
});
|
});
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when user drags part of one line and drops it far form its original place', function() {
|
context('when user drags part of one line and drops it far form its original place', function () {
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
selectPartOfSourceLine();
|
selectPartOfSourceLine();
|
||||||
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
|
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
|
||||||
|
|
||||||
// make sure DnD was correctly simulated
|
// make sure DnD was correctly simulated
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var $targetLine = getLine(TARGET_LINE);
|
const $targetLine = getLine(TARGET_LINE);
|
||||||
var sourceWasMovedToTarget = $targetLine.text() === 'Target line [line 1]';
|
const sourceWasMovedToTarget = $targetLine.text() === 'Target line [line 1]';
|
||||||
return sourceWasMovedToTarget;
|
return sourceWasMovedToTarget;
|
||||||
}).done(done);
|
}).done(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user triggers UNDO', function() {
|
context('and user triggers UNDO', function () {
|
||||||
before(function() {
|
before(function () {
|
||||||
var $undoButton = helper.padChrome$(".buttonicon-undo");
|
const $undoButton = helper.padChrome$('.buttonicon-undo');
|
||||||
$undoButton.click();
|
$undoButton.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('moves text back to its original place', function(done) {
|
it('moves text back to its original place', function (done) {
|
||||||
// test text was removed from drop target
|
// test text was removed from drop target
|
||||||
var $targetLine = getLine(TARGET_LINE);
|
const $targetLine = getLine(TARGET_LINE);
|
||||||
expect($targetLine.text()).to.be('Target line []');
|
expect($targetLine.text()).to.be('Target line []');
|
||||||
|
|
||||||
// test text was added back to original place
|
// test text was added back to original place
|
||||||
var $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
const $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
||||||
var $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
||||||
expect($firstSourceLine.text()).to.be('Source line 1.');
|
expect($firstSourceLine.text()).to.be('Source line 1.');
|
||||||
expect($lastSourceLine.text()).to.be('Source line 2.');
|
expect($lastSourceLine.text()).to.be('Source line 2.');
|
||||||
|
|
||||||
|
@ -42,33 +42,33 @@ describe('drag and drop', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when user drags some lines far form its original place', function() {
|
context('when user drags some lines far form its original place', function () {
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
selectMultipleSourceLines();
|
selectMultipleSourceLines();
|
||||||
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
|
dragSelectedTextAndDropItIntoMiddleOfLine(TARGET_LINE);
|
||||||
|
|
||||||
// make sure DnD was correctly simulated
|
// make sure DnD was correctly simulated
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => {
|
||||||
var $lineAfterTarget = getLine(TARGET_LINE + 1);
|
const $lineAfterTarget = getLine(TARGET_LINE + 1);
|
||||||
var sourceWasMovedToTarget = $lineAfterTarget.text() !== '...';
|
const sourceWasMovedToTarget = $lineAfterTarget.text() !== '...';
|
||||||
return sourceWasMovedToTarget;
|
return sourceWasMovedToTarget;
|
||||||
}).done(done);
|
}).done(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user triggers UNDO', function() {
|
context('and user triggers UNDO', function () {
|
||||||
before(function() {
|
before(function () {
|
||||||
var $undoButton = helper.padChrome$(".buttonicon-undo");
|
const $undoButton = helper.padChrome$('.buttonicon-undo');
|
||||||
$undoButton.click();
|
$undoButton.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('moves text back to its original place', function(done) {
|
it('moves text back to its original place', function (done) {
|
||||||
// test text was removed from drop target
|
// test text was removed from drop target
|
||||||
var $targetLine = getLine(TARGET_LINE);
|
const $targetLine = getLine(TARGET_LINE);
|
||||||
expect($targetLine.text()).to.be('Target line []');
|
expect($targetLine.text()).to.be('Target line []');
|
||||||
|
|
||||||
// test text was added back to original place
|
// test text was added back to original place
|
||||||
var $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
const $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
||||||
var $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
||||||
expect($firstSourceLine.text()).to.be('Source line 1.');
|
expect($firstSourceLine.text()).to.be('Source line 1.');
|
||||||
expect($lastSourceLine.text()).to.be('Source line 2.');
|
expect($lastSourceLine.text()).to.be('Source line 2.');
|
||||||
|
|
||||||
|
@ -81,88 +81,88 @@ describe('drag and drop', function() {
|
||||||
var TARGET_LINE = 2;
|
var TARGET_LINE = 2;
|
||||||
var FIRST_SOURCE_LINE = 5;
|
var FIRST_SOURCE_LINE = 5;
|
||||||
|
|
||||||
var getLine = function(lineNumber) {
|
var getLine = function (lineNumber) {
|
||||||
var $lines = helper.padInner$('div');
|
const $lines = helper.padInner$('div');
|
||||||
return $lines.slice(lineNumber, lineNumber + 1);
|
return $lines.slice(lineNumber, lineNumber + 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
var createScriptWithSeveralLines = function(done) {
|
var createScriptWithSeveralLines = function (done) {
|
||||||
// create some lines to be used on the tests
|
// create some lines to be used on the tests
|
||||||
var $firstLine = helper.padInner$('div').first();
|
const $firstLine = helper.padInner$('div').first();
|
||||||
$firstLine.html('...<br>...<br>Target line []<br>...<br>...<br>Source line 1.<br>Source line 2.<br>');
|
$firstLine.html('...<br>...<br>Target line []<br>...<br>...<br>Source line 1.<br>Source line 2.<br>');
|
||||||
|
|
||||||
// wait for lines to be split
|
// wait for lines to be split
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
||||||
return $lastSourceLine.text() === 'Source line 2.';
|
return $lastSourceLine.text() === 'Source line 2.';
|
||||||
}).done(done);
|
}).done(done);
|
||||||
}
|
};
|
||||||
|
|
||||||
var selectPartOfSourceLine = function() {
|
var selectPartOfSourceLine = function () {
|
||||||
var $sourceLine = getLine(FIRST_SOURCE_LINE);
|
const $sourceLine = getLine(FIRST_SOURCE_LINE);
|
||||||
|
|
||||||
// select 'line 1' from 'Source line 1.'
|
// select 'line 1' from 'Source line 1.'
|
||||||
var start = 'Source '.length;
|
const start = 'Source '.length;
|
||||||
var end = start + 'line 1'.length;
|
const end = start + 'line 1'.length;
|
||||||
helper.selectLines($sourceLine, $sourceLine, start, end);
|
helper.selectLines($sourceLine, $sourceLine, start, end);
|
||||||
}
|
};
|
||||||
var selectMultipleSourceLines = function() {
|
var selectMultipleSourceLines = function () {
|
||||||
var $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
const $firstSourceLine = getLine(FIRST_SOURCE_LINE);
|
||||||
var $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1);
|
||||||
|
|
||||||
helper.selectLines($firstSourceLine, $lastSourceLine);
|
helper.selectLines($firstSourceLine, $lastSourceLine);
|
||||||
}
|
};
|
||||||
|
|
||||||
var dragSelectedTextAndDropItIntoMiddleOfLine = function(targetLineNumber) {
|
var dragSelectedTextAndDropItIntoMiddleOfLine = function (targetLineNumber) {
|
||||||
// dragstart: start dragging content
|
// dragstart: start dragging content
|
||||||
triggerEvent('dragstart');
|
triggerEvent('dragstart');
|
||||||
|
|
||||||
// drop: get HTML data from selected text
|
// drop: get HTML data from selected text
|
||||||
var draggedHtml = getHtmlFromSelectedText();
|
const draggedHtml = getHtmlFromSelectedText();
|
||||||
triggerEvent('drop');
|
triggerEvent('drop');
|
||||||
|
|
||||||
// dragend: remove original content + insert HTML data into target
|
// dragend: remove original content + insert HTML data into target
|
||||||
moveSelectionIntoTarget(draggedHtml, targetLineNumber);
|
moveSelectionIntoTarget(draggedHtml, targetLineNumber);
|
||||||
triggerEvent('dragend');
|
triggerEvent('dragend');
|
||||||
}
|
};
|
||||||
|
|
||||||
var getHtmlFromSelectedText = function() {
|
var getHtmlFromSelectedText = function () {
|
||||||
var innerDocument = helper.padInner$.document;
|
const innerDocument = helper.padInner$.document;
|
||||||
|
|
||||||
var range = innerDocument.getSelection().getRangeAt(0);
|
const range = innerDocument.getSelection().getRangeAt(0);
|
||||||
var clonedSelection = range.cloneContents();
|
const clonedSelection = range.cloneContents();
|
||||||
var span = innerDocument.createElement('span');
|
const span = innerDocument.createElement('span');
|
||||||
span.id = 'buffer';
|
span.id = 'buffer';
|
||||||
span.appendChild(clonedSelection);
|
span.appendChild(clonedSelection);
|
||||||
var draggedHtml = span.outerHTML;
|
const draggedHtml = span.outerHTML;
|
||||||
|
|
||||||
return draggedHtml;
|
return draggedHtml;
|
||||||
}
|
};
|
||||||
|
|
||||||
var triggerEvent = function(eventName) {
|
var triggerEvent = function (eventName) {
|
||||||
var event = helper.padInner$.Event(eventName);
|
const event = helper.padInner$.Event(eventName);
|
||||||
helper.padInner$('#innerdocbody').trigger(event);
|
helper.padInner$('#innerdocbody').trigger(event);
|
||||||
}
|
};
|
||||||
|
|
||||||
var moveSelectionIntoTarget = function(draggedHtml, targetLineNumber) {
|
var moveSelectionIntoTarget = function (draggedHtml, targetLineNumber) {
|
||||||
var innerDocument = helper.padInner$.document;
|
const innerDocument = helper.padInner$.document;
|
||||||
|
|
||||||
// delete original content
|
// delete original content
|
||||||
innerDocument.execCommand('delete');
|
innerDocument.execCommand('delete');
|
||||||
|
|
||||||
// set position to insert content on target line
|
// set position to insert content on target line
|
||||||
var $target = getLine(targetLineNumber);
|
const $target = getLine(targetLineNumber);
|
||||||
$target.sendkeys('{selectall}{rightarrow}{leftarrow}');
|
$target.sendkeys('{selectall}{rightarrow}{leftarrow}');
|
||||||
|
|
||||||
// Insert content.
|
// Insert content.
|
||||||
// Based on http://stackoverflow.com/a/6691294, to be IE-compatible
|
// Based on http://stackoverflow.com/a/6691294, to be IE-compatible
|
||||||
var range = innerDocument.getSelection().getRangeAt(0);
|
const range = innerDocument.getSelection().getRangeAt(0);
|
||||||
var frag = innerDocument.createDocumentFragment();
|
const frag = innerDocument.createDocumentFragment();
|
||||||
var el = innerDocument.createElement('div');
|
const el = innerDocument.createElement('div');
|
||||||
el.innerHTML = draggedHtml;
|
el.innerHTML = draggedHtml;
|
||||||
while (el.firstChild) {
|
while (el.firstChild) {
|
||||||
frag.appendChild(el.firstChild);
|
frag.appendChild(el.firstChild);
|
||||||
}
|
}
|
||||||
range.insertNode(frag);
|
range.insertNode(frag);
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,135 +1,133 @@
|
||||||
describe("embed links", function(){
|
describe('embed links', function () {
|
||||||
var objectify = function (str) {
|
const objectify = function (str) {
|
||||||
var hash = {};
|
const hash = {};
|
||||||
var parts = str.split('&');
|
const parts = str.split('&');
|
||||||
for(var i = 0; i < parts.length; i++)
|
for (let i = 0; i < parts.length; i++) {
|
||||||
{
|
const keyValue = parts[i].split('=');
|
||||||
var keyValue = parts[i].split('=');
|
|
||||||
hash[keyValue[0]] = keyValue[1];
|
hash[keyValue[0]] = keyValue[1];
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
};
|
||||||
|
|
||||||
var checkiFrameCode = function(embedCode, readonly){
|
const checkiFrameCode = function (embedCode, readonly) {
|
||||||
//turn the code into an html element
|
// turn the code into an html element
|
||||||
var $embediFrame = $(embedCode);
|
const $embediFrame = $(embedCode);
|
||||||
|
|
||||||
//read and check the frame attributes
|
// read and check the frame attributes
|
||||||
var width = $embediFrame.attr("width");
|
const width = $embediFrame.attr('width');
|
||||||
var height = $embediFrame.attr("height");
|
const height = $embediFrame.attr('height');
|
||||||
var name = $embediFrame.attr("name");
|
const name = $embediFrame.attr('name');
|
||||||
expect(width).to.be('100%');
|
expect(width).to.be('100%');
|
||||||
expect(height).to.be('600');
|
expect(height).to.be('600');
|
||||||
expect(name).to.be(readonly ? "embed_readonly" : "embed_readwrite");
|
expect(name).to.be(readonly ? 'embed_readonly' : 'embed_readwrite');
|
||||||
|
|
||||||
//parse the url
|
// parse the url
|
||||||
var src = $embediFrame.attr("src");
|
const src = $embediFrame.attr('src');
|
||||||
var questionMark = src.indexOf("?");
|
const questionMark = src.indexOf('?');
|
||||||
var url = src.substr(0,questionMark);
|
const url = src.substr(0, questionMark);
|
||||||
var paramsStr = src.substr(questionMark+1);
|
const paramsStr = src.substr(questionMark + 1);
|
||||||
var params = objectify(paramsStr);
|
const params = objectify(paramsStr);
|
||||||
|
|
||||||
var expectedParams = {
|
const expectedParams = {
|
||||||
showControls: 'true'
|
showControls: 'true',
|
||||||
, showChat: 'true'
|
showChat: 'true',
|
||||||
, showLineNumbers: 'true'
|
showLineNumbers: 'true',
|
||||||
, useMonospaceFont: 'false'
|
useMonospaceFont: 'false',
|
||||||
}
|
};
|
||||||
|
|
||||||
//check the url
|
// check the url
|
||||||
if(readonly){
|
if (readonly) {
|
||||||
expect(url.indexOf("r.") > 0).to.be(true);
|
expect(url.indexOf('r.') > 0).to.be(true);
|
||||||
} else {
|
} else {
|
||||||
expect(url).to.be(helper.padChrome$.window.location.href);
|
expect(url).to.be(helper.padChrome$.window.location.href);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if all parts of the url are like expected
|
// check if all parts of the url are like expected
|
||||||
expect(params).to.eql(expectedParams);
|
expect(params).to.eql(expectedParams);
|
||||||
}
|
};
|
||||||
|
|
||||||
describe("read and write", function(){
|
describe('read and write', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the share link", function(){
|
describe('the share link', function () {
|
||||||
it("is the actual pad url", function(done){
|
it('is the actual pad url', function (done) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//open share dropdown
|
// open share dropdown
|
||||||
chrome$(".buttonicon-embed").click();
|
chrome$('.buttonicon-embed').click();
|
||||||
|
|
||||||
//get the link of the share field + the actual pad url and compare them
|
// get the link of the share field + the actual pad url and compare them
|
||||||
var shareLink = chrome$("#linkinput").val();
|
const shareLink = chrome$('#linkinput').val();
|
||||||
var padURL = chrome$.window.location.href;
|
const padURL = chrome$.window.location.href;
|
||||||
expect(shareLink).to.be(padURL);
|
expect(shareLink).to.be(padURL);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the embed as iframe code", function(){
|
describe('the embed as iframe code', function () {
|
||||||
it("is an iframe with the the correct url parameters and correct size", function(done){
|
it('is an iframe with the the correct url parameters and correct size', function (done) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//open share dropdown
|
// open share dropdown
|
||||||
chrome$(".buttonicon-embed").click();
|
chrome$('.buttonicon-embed').click();
|
||||||
|
|
||||||
//get the link of the share field + the actual pad url and compare them
|
// get the link of the share field + the actual pad url and compare them
|
||||||
var embedCode = chrome$("#embedinput").val();
|
const embedCode = chrome$('#embedinput').val();
|
||||||
|
|
||||||
checkiFrameCode(embedCode, false)
|
checkiFrameCode(embedCode, false);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when read only option is set", function(){
|
describe('when read only option is set', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the share link", function(){
|
describe('the share link', function () {
|
||||||
it("shows a read only url", function(done){
|
it('shows a read only url', function (done) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//open share dropdown
|
// open share dropdown
|
||||||
chrome$(".buttonicon-embed").click();
|
chrome$('.buttonicon-embed').click();
|
||||||
chrome$('#readonlyinput').click();
|
chrome$('#readonlyinput').click();
|
||||||
chrome$('#readonlyinput:checkbox:not(:checked)').attr('checked', 'checked');
|
chrome$('#readonlyinput:checkbox:not(:checked)').attr('checked', 'checked');
|
||||||
|
|
||||||
//get the link of the share field + the actual pad url and compare them
|
// get the link of the share field + the actual pad url and compare them
|
||||||
var shareLink = chrome$("#linkinput").val();
|
const shareLink = chrome$('#linkinput').val();
|
||||||
var containsReadOnlyLink = shareLink.indexOf("r.") > 0
|
const containsReadOnlyLink = shareLink.indexOf('r.') > 0;
|
||||||
expect(containsReadOnlyLink).to.be(true);
|
expect(containsReadOnlyLink).to.be(true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the embed as iframe code", function(){
|
describe('the embed as iframe code', function () {
|
||||||
it("is an iframe with the the correct url parameters and correct size", function(done){
|
it('is an iframe with the the correct url parameters and correct size', function (done) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//open share dropdown
|
// open share dropdown
|
||||||
chrome$(".buttonicon-embed").click();
|
chrome$('.buttonicon-embed').click();
|
||||||
//check read only checkbox, a bit hacky
|
// check read only checkbox, a bit hacky
|
||||||
chrome$('#readonlyinput').click();
|
chrome$('#readonlyinput').click();
|
||||||
chrome$('#readonlyinput:checkbox:not(:checked)').attr('checked', 'checked');
|
chrome$('#readonlyinput:checkbox:not(:checked)').attr('checked', 'checked');
|
||||||
|
|
||||||
|
|
||||||
//get the link of the share field + the actual pad url and compare them
|
// get the link of the share field + the actual pad url and compare them
|
||||||
var embedCode = chrome$("#embedinput").val();
|
const embedCode = chrome$('#embedinput').val();
|
||||||
|
|
||||||
checkiFrameCode(embedCode, true);
|
checkiFrameCode(embedCode, true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
describe("enter keystroke", function(){
|
describe('enter keystroke', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("creates a new line & puts cursor onto a new line", function(done) {
|
it('creates a new line & puts cursor onto a new line', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// get the original string value minus the last char
|
// get the original string value minus the last char
|
||||||
var originalTextValue = $firstTextElement.text();
|
const originalTextValue = $firstTextElement.text();
|
||||||
|
|
||||||
// simulate key presses to enter content
|
// simulate key presses to enter content
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
|
|
||||||
//ace creates a new dom element when you press a keystroke, so just get the first text element again
|
// ace creates a new dom element when you press a keystroke, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().text() === '').done(() => {
|
||||||
return inner$("div").first().text() === "";
|
const $newSecondLine = inner$('div').first().next();
|
||||||
}).done(function(){
|
const newFirstTextElementValue = inner$('div').first().text();
|
||||||
var $newSecondLine = inner$("div").first().next();
|
expect(newFirstTextElementValue).to.be(''); // expect the first line to be blank
|
||||||
var newFirstTextElementValue = inner$("div").first().text();
|
|
||||||
expect(newFirstTextElementValue).to.be(""); // expect the first line to be blank
|
|
||||||
expect($newSecondLine.text()).to.be(originalTextValue); // expect the second line to be the same as the original first line.
|
expect($newSecondLine.text()).to.be(originalTextValue); // expect the second line to be the same as the original first line.
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,31 +1,31 @@
|
||||||
describe("font select", function(){
|
describe('font select', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text RobotoMono", function(done) {
|
it('makes text RobotoMono', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $settingsButton = chrome$(".buttonicon-settings");
|
const $settingsButton = chrome$('.buttonicon-settings');
|
||||||
$settingsButton.click();
|
$settingsButton.click();
|
||||||
|
|
||||||
//get the font menu and RobotoMono option
|
// get the font menu and RobotoMono option
|
||||||
var $viewfontmenu = chrome$("#viewfontmenu");
|
const $viewfontmenu = chrome$('#viewfontmenu');
|
||||||
var $RobotoMonooption = $viewfontmenu.find("[value=RobotoMono]");
|
const $RobotoMonooption = $viewfontmenu.find('[value=RobotoMono]');
|
||||||
|
|
||||||
//select RobotoMono and fire change event
|
// select RobotoMono and fire change event
|
||||||
// $RobotoMonooption.attr('selected','selected');
|
// $RobotoMonooption.attr('selected','selected');
|
||||||
// commenting out above will break safari test
|
// commenting out above will break safari test
|
||||||
$viewfontmenu.val("RobotoMono");
|
$viewfontmenu.val('RobotoMono');
|
||||||
$viewfontmenu.change();
|
$viewfontmenu.change();
|
||||||
|
|
||||||
//check if font changed to RobotoMono
|
// check if font changed to RobotoMono
|
||||||
var fontFamily = inner$("body").css("font-family").toLowerCase();
|
const fontFamily = inner$('body').css('font-family').toLowerCase();
|
||||||
var containsStr = fontFamily.indexOf("robotomono");
|
const containsStr = fontFamily.indexOf('robotomono');
|
||||||
expect(containsStr).to.not.be(-1);
|
expect(containsStr).to.not.be(-1);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
describe("the test helper", function(){
|
describe('the test helper', function () {
|
||||||
describe("the newPad method", function(){
|
describe('the newPad method', function () {
|
||||||
xit("doesn't leak memory if you creates iframes over and over again", function(done){
|
xit("doesn't leak memory if you creates iframes over and over again", function (done) {
|
||||||
this.timeout(100000);
|
this.timeout(100000);
|
||||||
|
|
||||||
var times = 10;
|
let times = 10;
|
||||||
|
|
||||||
var loadPad = function(){
|
var loadPad = function () {
|
||||||
helper.newPad(function(){
|
helper.newPad(() => {
|
||||||
times--;
|
times--;
|
||||||
if(times > 0){
|
if (times > 0) {
|
||||||
loadPad();
|
loadPad();
|
||||||
} else {
|
} else {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
loadPad();
|
loadPad();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("gives me 3 jquery instances of chrome, outer and inner", function(done){
|
it('gives me 3 jquery instances of chrome, outer and inner', function (done) {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
helper.newPad(function(){
|
helper.newPad(() => {
|
||||||
//check if the jquery selectors have the desired elements
|
// check if the jquery selectors have the desired elements
|
||||||
expect(helper.padChrome$("#editbar").length).to.be(1);
|
expect(helper.padChrome$('#editbar').length).to.be(1);
|
||||||
expect(helper.padOuter$("#outerdocbody").length).to.be(1);
|
expect(helper.padOuter$('#outerdocbody').length).to.be(1);
|
||||||
expect(helper.padInner$("#innerdocbody").length).to.be(1);
|
expect(helper.padInner$('#innerdocbody').length).to.be(1);
|
||||||
|
|
||||||
//check if the document object was set correctly
|
// check if the document object was set correctly
|
||||||
expect(helper.padChrome$.window.document).to.be(helper.padChrome$.document);
|
expect(helper.padChrome$.window.document).to.be(helper.padChrome$.document);
|
||||||
expect(helper.padOuter$.window.document).to.be(helper.padOuter$.document);
|
expect(helper.padOuter$.window.document).to.be(helper.padOuter$.document);
|
||||||
expect(helper.padInner$.window.document).to.be(helper.padInner$.document);
|
expect(helper.padInner$.window.document).to.be(helper.padInner$.document);
|
||||||
|
@ -43,7 +43,7 @@ describe("the test helper", function(){
|
||||||
// However this doesn't seem to always be easily replicated, so this
|
// 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
|
// timeout may or may end up in the code. None the less, we test here
|
||||||
// to catch it if the bug comes up again.
|
// to catch it if the bug comes up again.
|
||||||
it("clears cookies", function(done) {
|
it('clears cookies', function (done) {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
|
|
||||||
// set cookies far into the future to make sure they're not expired yet
|
// set cookies far into the future to make sure they're not expired yet
|
||||||
|
@ -53,20 +53,20 @@ describe("the test helper", function(){
|
||||||
expect(window.document.cookie).to.contain('token=foo');
|
expect(window.document.cookie).to.contain('token=foo');
|
||||||
expect(window.document.cookie).to.contain('language=bar');
|
expect(window.document.cookie).to.contain('language=bar');
|
||||||
|
|
||||||
helper.newPad(function(){
|
helper.newPad(() => {
|
||||||
// helper function seems to have cleared cookies
|
// 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
|
// NOTE: this doesn't yet mean it's proven to have taken effect by this point in execution
|
||||||
var firstCookie = window.document.cookie
|
const firstCookie = window.document.cookie;
|
||||||
expect(firstCookie).to.not.contain('token=foo');
|
expect(firstCookie).to.not.contain('token=foo');
|
||||||
expect(firstCookie).to.not.contain('language=bar');
|
expect(firstCookie).to.not.contain('language=bar');
|
||||||
|
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
var $usernameInput = chrome$("#myusernameedit");
|
const $usernameInput = chrome$('#myusernameedit');
|
||||||
$usernameInput.click();
|
$usernameInput.click();
|
||||||
|
|
||||||
$usernameInput.val('John McLear');
|
$usernameInput.val('John McLear');
|
||||||
|
@ -84,9 +84,9 @@ describe("the test helper", function(){
|
||||||
// be sure.
|
// be sure.
|
||||||
expect(window.document.cookie).to.not.contain('prefsHtml=baz');
|
expect(window.document.cookie).to.not.contain('prefsHtml=baz');
|
||||||
|
|
||||||
setTimeout(function(){ //give it a second to save the username on the server side
|
setTimeout(() => { // give it a second to save the username on the server side
|
||||||
helper.newPad(function(){ // get a new pad, let it clear the cookies
|
helper.newPad(() => { // get a new pad, let it clear the cookies
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// helper function seems to have cleared cookies
|
// helper function seems to have cleared cookies
|
||||||
// NOTE: this doesn't yet mean cookies were cleared effectively.
|
// NOTE: this doesn't yet mean cookies were cleared effectively.
|
||||||
|
@ -99,11 +99,11 @@ describe("the test helper", function(){
|
||||||
expect(window.document.cookie).to.not.be(firstCookie);
|
expect(window.document.cookie).to.not.be(firstCookie);
|
||||||
|
|
||||||
// click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $userButton = chrome$(".buttonicon-showusers");
|
const $userButton = chrome$('.buttonicon-showusers');
|
||||||
$userButton.click();
|
$userButton.click();
|
||||||
|
|
||||||
// confirm that the session was actually cleared
|
// confirm that the session was actually cleared
|
||||||
var $usernameInput = chrome$("#myusernameedit");
|
const $usernameInput = chrome$('#myusernameedit');
|
||||||
expect($usernameInput.val()).to.be('');
|
expect($usernameInput.val()).to.be('');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
@ -112,43 +112,41 @@ describe("the test helper", function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets pad prefs cookie", function(done) {
|
it('sets pad prefs cookie', function (done) {
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
|
|
||||||
helper.newPad({
|
helper.newPad({
|
||||||
padPrefs: {foo:"bar"},
|
padPrefs: {foo: 'bar'},
|
||||||
cb: function(){
|
cb() {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
expect(chrome$.document.cookie).to.contain('prefsHttp=%7B%22');
|
expect(chrome$.document.cookie).to.contain('prefsHttp=%7B%22');
|
||||||
expect(chrome$.document.cookie).to.contain('foo%22%3A%22bar');
|
expect(chrome$.document.cookie).to.contain('foo%22%3A%22bar');
|
||||||
done();
|
done();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the waitFor method", function(){
|
describe('the waitFor method', function () {
|
||||||
it("takes a timeout and waits long enough", function(done){
|
it('takes a timeout and waits long enough', function (done) {
|
||||||
this.timeout(2000);
|
this.timeout(2000);
|
||||||
var startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => false, 1500).fail(() => {
|
||||||
return false;
|
const duration = Date.now() - startTime;
|
||||||
}, 1500).fail(function(){
|
|
||||||
var duration = Date.now() - startTime;
|
|
||||||
expect(duration).to.be.greaterThan(1490);
|
expect(duration).to.be.greaterThan(1490);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("takes an interval and checks on every interval", function(done){
|
it('takes an interval and checks on every interval', function (done) {
|
||||||
this.timeout(4000);
|
this.timeout(4000);
|
||||||
var checks = 0;
|
let checks = 0;
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
checks++;
|
checks++;
|
||||||
return false;
|
return false;
|
||||||
}, 2000, 100).fail(function(){
|
}, 2000, 100).fail(() => {
|
||||||
// One at the beginning, and 19-20 more depending on whether it's the timeout or the final
|
// One at the beginning, and 19-20 more depending on whether it's the timeout or the final
|
||||||
// poll that wins at 2000ms.
|
// poll that wins at 2000ms.
|
||||||
expect(checks).to.be.greaterThan(15);
|
expect(checks).to.be.greaterThan(15);
|
||||||
|
@ -157,7 +155,7 @@ describe("the test helper", function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects if the predicate throws', async function() {
|
it('rejects if the predicate throws', async function () {
|
||||||
let err;
|
let err;
|
||||||
await helper.waitFor(() => { throw new Error('test exception'); })
|
await helper.waitFor(() => { throw new Error('test exception'); })
|
||||||
.fail(() => {}) // Suppress the redundant uncatchable exception.
|
.fail(() => {}) // Suppress the redundant uncatchable exception.
|
||||||
|
@ -166,44 +164,38 @@ describe("the test helper", function(){
|
||||||
expect(err.message).to.be('test exception');
|
expect(err.message).to.be('test exception');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("returns a deferred object", function(){
|
describe('returns a deferred object', function () {
|
||||||
it("it calls done after success", function(done){
|
it('it calls done after success', function (done) {
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => true).done(() => {
|
||||||
return true;
|
|
||||||
}).done(function(){
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls fail after failure", function(done){
|
it('calls fail after failure', function (done) {
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => false, 0).fail(() => {
|
||||||
return false;
|
|
||||||
},0).fail(function(){
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
xit("throws if you don't listen for fails", function(done){
|
xit("throws if you don't listen for fails", function (done) {
|
||||||
var onerror = window.onerror;
|
const onerror = window.onerror;
|
||||||
window.onerror = function(){
|
window.onerror = function () {
|
||||||
window.onerror = onerror;
|
window.onerror = onerror;
|
||||||
done();
|
done();
|
||||||
}
|
};
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => false, 100);
|
||||||
return false;
|
|
||||||
},100);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('checks first then sleeps', function() {
|
describe('checks first then sleeps', function () {
|
||||||
it('resolves quickly if the predicate is immediately true', async function() {
|
it('resolves quickly if the predicate is immediately true', async function () {
|
||||||
const before = Date.now();
|
const before = Date.now();
|
||||||
await helper.waitFor(() => true, 1000, 900);
|
await helper.waitFor(() => true, 1000, 900);
|
||||||
expect(Date.now() - before).to.be.lessThan(800);
|
expect(Date.now() - before).to.be.lessThan(800);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('polls exactly once if timeout < interval', async function() {
|
it('polls exactly once if timeout < interval', async function () {
|
||||||
let calls = 0;
|
let calls = 0;
|
||||||
await helper.waitFor(() => { calls++; }, 1, 1000)
|
await helper.waitFor(() => { calls++; }, 1, 1000)
|
||||||
.fail(() => {}) // Suppress the redundant uncatchable exception.
|
.fail(() => {}) // Suppress the redundant uncatchable exception.
|
||||||
|
@ -211,18 +203,18 @@ describe("the test helper", function(){
|
||||||
expect(calls).to.be(1);
|
expect(calls).to.be(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resolves if condition is immediately true even if timeout is 0', async function() {
|
it('resolves if condition is immediately true even if timeout is 0', async function () {
|
||||||
await helper.waitFor(() => true, 0);
|
await helper.waitFor(() => true, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('the waitForPromise method', function() {
|
describe('the waitForPromise method', function () {
|
||||||
it('returns a Promise', async function() {
|
it('returns a Promise', async function () {
|
||||||
expect(helper.waitForPromise(() => true)).to.be.a(Promise);
|
expect(helper.waitForPromise(() => true)).to.be.a(Promise);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('takes a timeout and waits long enough', async function() {
|
it('takes a timeout and waits long enough', async function () {
|
||||||
this.timeout(2000);
|
this.timeout(2000);
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
let rejected;
|
let rejected;
|
||||||
|
@ -233,60 +225,60 @@ describe("the test helper", function(){
|
||||||
expect(duration).to.be.greaterThan(1490);
|
expect(duration).to.be.greaterThan(1490);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('takes an interval and checks on every interval', async function() {
|
it('takes an interval and checks on every interval', async function () {
|
||||||
this.timeout(4000);
|
this.timeout(4000);
|
||||||
let checks = 0;
|
let checks = 0;
|
||||||
let rejected;
|
let rejected;
|
||||||
await helper.waitForPromise(() => { checks++; return false; }, 2000, 100)
|
await helper.waitForPromise(() => { checks++; return false; }, 2000, 100)
|
||||||
.catch(() => { rejected = true; });
|
.catch(() => { rejected = true; });
|
||||||
expect(rejected).to.be(true);
|
expect(rejected).to.be(true);
|
||||||
// `checks` is expected to be 20 or 21: one at the beginning, plus 19 or 20 more depending on
|
// `checks` is expected to be 20 or 21: one at the beginning, plus 19 or 20 more depending on
|
||||||
// whether it's the timeout or the final poll that wins at 2000ms. Margin is added to reduce
|
// whether it's the timeout or the final poll that wins at 2000ms. Margin is added to reduce
|
||||||
// flakiness on slow test machines.
|
// flakiness on slow test machines.
|
||||||
expect(checks).to.be.greaterThan(15);
|
expect(checks).to.be.greaterThan(15);
|
||||||
expect(checks).to.be.lessThan(24);
|
expect(checks).to.be.lessThan(24);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("the selectLines method", function(){
|
describe('the selectLines method', function () {
|
||||||
// function to support tests, use a single way to represent whitespaces
|
// function to support tests, use a single way to represent whitespaces
|
||||||
var cleanText = function(text){
|
const cleanText = function (text) {
|
||||||
return text
|
return text
|
||||||
// IE replaces line breaks with a whitespace, so we need to unify its behavior
|
// IE replaces line breaks with a whitespace, so we need to unify its behavior
|
||||||
// for other browsers, to have all tests running for all browsers
|
// for other browsers, to have all tests running for all browsers
|
||||||
.replace(/\n/gi, "")
|
.replace(/\n/gi, '')
|
||||||
.replace(/\s/gi, " ");
|
.replace(/\s/gi, ' ');
|
||||||
}
|
};
|
||||||
|
|
||||||
before(function(done){
|
before(function (done) {
|
||||||
helper.newPad(function() {
|
helper.newPad(() => {
|
||||||
// create some lines to be used on the tests
|
// create some lines to be used on the tests
|
||||||
var $firstLine = helper.padInner$("div").first();
|
const $firstLine = helper.padInner$('div').first();
|
||||||
$firstLine.sendkeys("{selectall}some{enter}short{enter}lines{enter}to test{enter}{enter}");
|
$firstLine.sendkeys('{selectall}some{enter}short{enter}lines{enter}to test{enter}{enter}');
|
||||||
|
|
||||||
// wait for lines to be split
|
// wait for lines to be split
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var $fourthLine = helper.padInner$("div").eq(3);
|
const $fourthLine = helper.padInner$('div').eq(3);
|
||||||
return $fourthLine.text() === "to test";
|
return $fourthLine.text() === 'to test';
|
||||||
}).done(done);
|
}).done(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes editor selection to be between startOffset of $startLine and endOffset of $endLine", function(done){
|
it('changes editor selection to be between startOffset of $startLine and endOffset of $endLine', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
|
|
||||||
var startOffset = 2;
|
const startOffset = 2;
|
||||||
var endOffset = 4;
|
const endOffset = 4;
|
||||||
|
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $startLine = $lines.eq(1);
|
const $startLine = $lines.eq(1);
|
||||||
var $endLine = $lines.eq(3);
|
const $endLine = $lines.eq(3);
|
||||||
|
|
||||||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||||
|
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replace() is required here because Firefox keeps the line breaks.
|
* replace() is required here because Firefox keeps the line breaks.
|
||||||
|
@ -295,24 +287,24 @@ describe("the test helper", function(){
|
||||||
* is not consistent between browsers but that's the situation so that's
|
* is not consistent between browsers but that's the situation so that's
|
||||||
* how I'm covering it in this test.
|
* how I'm covering it in this test.
|
||||||
*/
|
*/
|
||||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to t");
|
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to t');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ends selection at beginning of $endLine when it is an empty line", function(done){
|
it('ends selection at beginning of $endLine when it is an empty line', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
|
|
||||||
var startOffset = 2;
|
const startOffset = 2;
|
||||||
var endOffset = 1;
|
const endOffset = 1;
|
||||||
|
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $startLine = $lines.eq(1);
|
const $startLine = $lines.eq(1);
|
||||||
var $endLine = $lines.eq(4);
|
const $endLine = $lines.eq(4);
|
||||||
|
|
||||||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||||
|
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replace() is required here because Firefox keeps the line breaks.
|
* replace() is required here because Firefox keeps the line breaks.
|
||||||
|
@ -321,24 +313,24 @@ describe("the test helper", function(){
|
||||||
* is not consistent between browsers but that's the situation so that's
|
* is not consistent between browsers but that's the situation so that's
|
||||||
* how I'm covering it in this test.
|
* how I'm covering it in this test.
|
||||||
*/
|
*/
|
||||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to test");
|
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ends selection at beginning of $endLine when its offset is zero", function(done){
|
it('ends selection at beginning of $endLine when its offset is zero', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
|
|
||||||
var startOffset = 2;
|
const startOffset = 2;
|
||||||
var endOffset = 0;
|
const endOffset = 0;
|
||||||
|
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $startLine = $lines.eq(1);
|
const $startLine = $lines.eq(1);
|
||||||
var $endLine = $lines.eq(3);
|
const $endLine = $lines.eq(3);
|
||||||
|
|
||||||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||||
|
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replace() is required here because Firefox keeps the line breaks.
|
* replace() is required here because Firefox keeps the line breaks.
|
||||||
|
@ -347,24 +339,24 @@ describe("the test helper", function(){
|
||||||
* is not consistent between browsers but that's the situation so that's
|
* is not consistent between browsers but that's the situation so that's
|
||||||
* how I'm covering it in this test.
|
* how I'm covering it in this test.
|
||||||
*/
|
*/
|
||||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines ");
|
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines ');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("selects full line when offset is longer than line content", function(done){
|
it('selects full line when offset is longer than line content', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
|
|
||||||
var startOffset = 2;
|
const startOffset = 2;
|
||||||
var endOffset = 50;
|
const endOffset = 50;
|
||||||
|
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $startLine = $lines.eq(1);
|
const $startLine = $lines.eq(1);
|
||||||
var $endLine = $lines.eq(3);
|
const $endLine = $lines.eq(3);
|
||||||
|
|
||||||
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
helper.selectLines($startLine, $endLine, startOffset, endOffset);
|
||||||
|
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replace() is required here because Firefox keeps the line breaks.
|
* replace() is required here because Firefox keeps the line breaks.
|
||||||
|
@ -373,21 +365,21 @@ describe("the test helper", function(){
|
||||||
* is not consistent between browsers but that's the situation so that's
|
* is not consistent between browsers but that's the situation so that's
|
||||||
* how I'm covering it in this test.
|
* how I'm covering it in this test.
|
||||||
*/
|
*/
|
||||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("ort lines to test");
|
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("selects all text between beginning of $startLine and end of $endLine when no offset is provided", function(done){
|
it('selects all text between beginning of $startLine and end of $endLine when no offset is provided', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
|
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $startLine = $lines.eq(1);
|
const $startLine = $lines.eq(1);
|
||||||
var $endLine = $lines.eq(3);
|
const $endLine = $lines.eq(3);
|
||||||
|
|
||||||
helper.selectLines($startLine, $endLine);
|
helper.selectLines($startLine, $endLine);
|
||||||
|
|
||||||
var selection = inner$.document.getSelection();
|
const selection = inner$.document.getSelection();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* replace() is required here because Firefox keeps the line breaks.
|
* replace() is required here because Firefox keeps the line breaks.
|
||||||
|
@ -396,73 +388,73 @@ describe("the test helper", function(){
|
||||||
* is not consistent between browsers but that's the situation so that's
|
* is not consistent between browsers but that's the situation so that's
|
||||||
* how I'm covering it in this test.
|
* how I'm covering it in this test.
|
||||||
*/
|
*/
|
||||||
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm,""))).to.be("short lines to test");
|
expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('short lines to test');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('helper',function(){
|
describe('helper', function () {
|
||||||
before(function(cb){
|
before(function (cb) {
|
||||||
helper.newPad(function(){
|
helper.newPad(() => {
|
||||||
cb();
|
cb();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
it(".textLines() returns the text of the pad as strings", async function(){
|
it('.textLines() returns the text of the pad as strings', async function () {
|
||||||
let lines = helper.textLines();
|
const lines = helper.textLines();
|
||||||
let defaultText = helper.defaultText();
|
const defaultText = helper.defaultText();
|
||||||
expect(Array.isArray(lines)).to.be(true);
|
expect(Array.isArray(lines)).to.be(true);
|
||||||
expect(lines[0]).to.be.an('string');
|
expect(lines[0]).to.be.an('string');
|
||||||
// @todo
|
// @todo
|
||||||
// final "\n" is added automatically, but my understanding is this should happen
|
// final "\n" is added automatically, but my understanding is this should happen
|
||||||
// only when the default text does not end with "\n" already
|
// only when the default text does not end with "\n" already
|
||||||
expect(lines.join("\n")+"\n").to.equal(defaultText);
|
expect(`${lines.join('\n')}\n`).to.equal(defaultText);
|
||||||
})
|
});
|
||||||
|
|
||||||
it(".linesDiv() returns the text of the pad as div elements", async function(){
|
it('.linesDiv() returns the text of the pad as div elements', async function () {
|
||||||
let lines = helper.linesDiv();
|
const lines = helper.linesDiv();
|
||||||
let defaultText = helper.defaultText();
|
const defaultText = helper.defaultText();
|
||||||
expect(Array.isArray(lines)).to.be(true);
|
expect(Array.isArray(lines)).to.be(true);
|
||||||
expect(lines[0]).to.be.an('object');
|
expect(lines[0]).to.be.an('object');
|
||||||
expect(lines[0].text()).to.be.an('string');
|
expect(lines[0].text()).to.be.an('string');
|
||||||
_.each(defaultText.split("\n"), function(line, index){
|
_.each(defaultText.split('\n'), (line, index) => {
|
||||||
//last line of default text
|
// last line of default text
|
||||||
if(index === lines.length){
|
if (index === lines.length) {
|
||||||
expect(line).to.equal('');
|
expect(line).to.equal('');
|
||||||
} else {
|
} else {
|
||||||
expect(lines[index].text()).to.equal(line);
|
expect(lines[index].text()).to.equal(line);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
it(".edit() defaults to send an edit to the first line", async function(){
|
it('.edit() defaults to send an edit to the first line', async function () {
|
||||||
let firstLine = helper.textLines()[0];
|
const firstLine = helper.textLines()[0];
|
||||||
await helper.edit("line")
|
await helper.edit('line');
|
||||||
expect(helper.textLines()[0]).to.be(`line${firstLine}`);
|
expect(helper.textLines()[0]).to.be(`line${firstLine}`);
|
||||||
})
|
});
|
||||||
|
|
||||||
it(".edit() to the line specified with parameter lineNo", async function(){
|
it('.edit() to the line specified with parameter lineNo', async function () {
|
||||||
let firstLine = helper.textLines()[0];
|
const firstLine = helper.textLines()[0];
|
||||||
await helper.edit("second line", 2);
|
await helper.edit('second line', 2);
|
||||||
|
|
||||||
let text = helper.textLines();
|
const text = helper.textLines();
|
||||||
expect(text[0]).to.equal(firstLine);
|
expect(text[0]).to.equal(firstLine);
|
||||||
expect(text[1]).to.equal("second line");
|
expect(text[1]).to.equal('second line');
|
||||||
})
|
});
|
||||||
|
|
||||||
it(".edit() supports sendkeys syntax ({selectall},{del},{enter})", async function(){
|
it('.edit() supports sendkeys syntax ({selectall},{del},{enter})', async function () {
|
||||||
expect(helper.textLines()[0]).to.not.equal('');
|
expect(helper.textLines()[0]).to.not.equal('');
|
||||||
|
|
||||||
// select first line
|
// select first line
|
||||||
helper.linesDiv()[0].sendkeys("{selectall}")
|
helper.linesDiv()[0].sendkeys('{selectall}');
|
||||||
// delete first line
|
// delete first line
|
||||||
await helper.edit("{del}")
|
await helper.edit('{del}');
|
||||||
|
|
||||||
expect(helper.textLines()[0]).to.be('');
|
expect(helper.textLines()[0]).to.be('');
|
||||||
let noOfLines = helper.textLines().length;
|
const noOfLines = helper.textLines().length;
|
||||||
await helper.edit("{enter}")
|
await helper.edit('{enter}');
|
||||||
expect(helper.textLines().length).to.be(noOfLines+1);
|
expect(helper.textLines().length).to.be(noOfLines + 1);
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,176 +1,162 @@
|
||||||
describe("import functionality", function(){
|
describe('import functionality', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb); // creates a new pad
|
helper.newPad(cb); // creates a new pad
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getinnertext(){
|
function getinnertext() {
|
||||||
var inner = helper.padInner$
|
const inner = helper.padInner$;
|
||||||
if(!inner){
|
if (!inner) {
|
||||||
return ""
|
return '';
|
||||||
}
|
}
|
||||||
var newtext = ""
|
let newtext = '';
|
||||||
inner("div").each(function(line,el){
|
inner('div').each((line, el) => {
|
||||||
newtext += el.innerHTML+"\n"
|
newtext += `${el.innerHTML}\n`;
|
||||||
})
|
});
|
||||||
return newtext
|
return newtext;
|
||||||
}
|
}
|
||||||
function importrequest(data,importurl,type){
|
function importrequest(data, importurl, type) {
|
||||||
var success;
|
let success;
|
||||||
var error;
|
let error;
|
||||||
var result = $.ajax({
|
const result = $.ajax({
|
||||||
url: importurl,
|
url: importurl,
|
||||||
type: "post",
|
type: 'post',
|
||||||
processData: false,
|
processData: false,
|
||||||
async: false,
|
async: false,
|
||||||
contentType: 'multipart/form-data; boundary=boundary',
|
contentType: 'multipart/form-data; boundary=boundary',
|
||||||
accepts: {
|
accepts: {
|
||||||
text: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
text: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
},
|
},
|
||||||
data: 'Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.'+type+'"\r\nContent-Type: text/plain\r\n\r\n' + data + '\r\n\r\n--boundary',
|
data: `Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.${type}"\r\nContent-Type: text/plain\r\n\r\n${data}\r\n\r\n--boundary`,
|
||||||
error: function(res){
|
error(res) {
|
||||||
error = res
|
error = res;
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
expect(error).to.be(undefined)
|
expect(error).to.be(undefined);
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
function exportfunc(link){
|
function exportfunc(link) {
|
||||||
var exportresults = []
|
const exportresults = [];
|
||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
async:false
|
async: false,
|
||||||
})
|
});
|
||||||
$.get(link+"/export/html",function(data){
|
$.get(`${link}/export/html`, (data) => {
|
||||||
var start = data.indexOf("<body>")
|
const start = data.indexOf('<body>');
|
||||||
var end = data.indexOf("</body>")
|
const end = data.indexOf('</body>');
|
||||||
var html = data.substr(start+6,end-start-6)
|
const html = data.substr(start + 6, end - start - 6);
|
||||||
exportresults.push(["html",html])
|
exportresults.push(['html', html]);
|
||||||
})
|
});
|
||||||
$.get(link+"/export/txt",function(data){
|
$.get(`${link}/export/txt`, (data) => {
|
||||||
exportresults.push(["txt",data])
|
exportresults.push(['txt', data]);
|
||||||
})
|
});
|
||||||
return exportresults
|
return exportresults;
|
||||||
}
|
}
|
||||||
|
|
||||||
xit("import a pad with newlines from txt", function(done){
|
xit('import a pad with newlines from txt', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var textWithNewLines = 'imported text\nnewline'
|
const textWithNewLines = 'imported text\nnewline';
|
||||||
importrequest(textWithNewLines,importurl,"txt")
|
importrequest(textWithNewLines, importurl, 'txt');
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => expect(getinnertext()).to.be('<span class="">imported text</span>\n<span class="">newline</span>\n<br>\n'));
|
||||||
return expect(getinnertext()).to.be('<span class="">imported text</span>\n<span class="">newline</span>\n<br>\n')
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
})
|
expect(results[0][1]).to.be('imported text<br>newline<br><br>');
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
expect(results[1][1]).to.be('imported text\nnewline\n\n');
|
||||||
expect(results[0][1]).to.be("imported text<br>newline<br><br>")
|
done();
|
||||||
expect(results[1][1]).to.be("imported text\nnewline\n\n")
|
});
|
||||||
done()
|
xit('import a pad with newlines from html', function (done) {
|
||||||
})
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
xit("import a pad with newlines from html", function(done){
|
const htmlWithNewLines = '<html><body>htmltext<br/>newline</body></html>';
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
importrequest(htmlWithNewLines, importurl, 'html');
|
||||||
var htmlWithNewLines = '<html><body>htmltext<br/>newline</body></html>'
|
helper.waitFor(() => expect(getinnertext()).to.be('<span class="">htmltext</span>\n<span class="">newline</span>\n<br>\n'));
|
||||||
importrequest(htmlWithNewLines,importurl,"html")
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
helper.waitFor(function(){
|
expect(results[0][1]).to.be('htmltext<br>newline<br><br>');
|
||||||
return expect(getinnertext()).to.be('<span class="">htmltext</span>\n<span class="">newline</span>\n<br>\n')
|
expect(results[1][1]).to.be('htmltext\nnewline\n\n');
|
||||||
})
|
done();
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
});
|
||||||
expect(results[0][1]).to.be("htmltext<br>newline<br><br>")
|
xit('import a pad with attributes from html', function (done) {
|
||||||
expect(results[1][1]).to.be("htmltext\nnewline\n\n")
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
done()
|
const htmlWithNewLines = '<html><body>htmltext<br/><span class="b s i u"><b><i><s><u>newline</u></s></i></b></body></html>';
|
||||||
})
|
importrequest(htmlWithNewLines, importurl, 'html');
|
||||||
xit("import a pad with attributes from html", function(done){
|
helper.waitFor(() => expect(getinnertext()).to.be('<span class="">htmltext</span>\n<span class="b i s u"><b><i><s><u>newline</u></s></i></b></span>\n<br>\n'));
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
var htmlWithNewLines = '<html><body>htmltext<br/><span class="b s i u"><b><i><s><u>newline</u></s></i></b></body></html>'
|
expect(results[0][1]).to.be('htmltext<br><strong><em><s><u>newline</u></s></em></strong><br><br>');
|
||||||
importrequest(htmlWithNewLines,importurl,"html")
|
expect(results[1][1]).to.be('htmltext\nnewline\n\n');
|
||||||
helper.waitFor(function(){
|
done();
|
||||||
return expect(getinnertext()).to.be('<span class="">htmltext</span>\n<span class="b i s u"><b><i><s><u>newline</u></s></i></b></span>\n<br>\n')
|
});
|
||||||
})
|
xit('import a pad with bullets from html', function (done) {
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
expect(results[0][1]).to.be('htmltext<br><strong><em><s><u>newline</u></s></em></strong><br><br>')
|
const htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li><li>bullet2 line 2</li></ul></ul></body></html>';
|
||||||
expect(results[1][1]).to.be('htmltext\nnewline\n\n')
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
done()
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
})
|
|
||||||
xit("import a pad with bullets from html", function(done){
|
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
|
||||||
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li><li>bullet2 line 2</li></ul></ul></body></html>'
|
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
|
||||||
helper.waitFor(function(){
|
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 2</span></li></ul>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 2</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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><li>bullet2 line 2</li></ul></ul><br>');
|
||||||
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><li>bullet2 line 2</li></ul></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* bullet2 line 2\n\n');
|
||||||
expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t* bullet2 line 2\n\n')
|
done();
|
||||||
done()
|
});
|
||||||
})
|
xit('import a pad with bullets and newlines from html', function (done) {
|
||||||
xit("import a pad with bullets and newlines from html", function(done){
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><li>bullet2 line 2</li></ul></ul></body></html>';
|
||||||
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><li>bullet2 line 2</li></ul></ul></body></html>'
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
helper.waitFor(function(){
|
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 2</span></li></ul>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 2</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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 class="bullet"><li>bullet2 line 2</li></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 class="bullet"><li>bullet2 line 2</li></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* bullet2 line 2\n\n');
|
||||||
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* bullet2 line 2\n\n')
|
done();
|
||||||
done()
|
});
|
||||||
})
|
xit('import a pad with bullets and newlines and attributes from html', function (done) {
|
||||||
xit("import a pad with bullets and newlines and attributes from html", function(done){
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li></ul></ul></ul></ul></body></html>';
|
||||||
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li></ul></ul></ul></ul></body></html>'
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
helper.waitFor(function(){
|
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\<br>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\<br>\n\
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n<br>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n<br>\n\
|
||||||
<ul class="list-bullet4"><li><span class="b i s u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li></ul>\n\
|
<ul class="list-bullet4"><li><span class="b i s u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li></ul>\n\
|
||||||
<ul class="list-bullet4"><li><span class="b s"><b><s>bullet4 line 2 bs</s></b></span></li></ul>\n\
|
<ul class="list-bullet4"><li><span class="b s"><b><s>bullet4 line 2 bs</s></b></span></li></ul>\n\
|
||||||
<ul class="list-bullet4"><li><span class="u"><u>bullet4 line 2 u</u></span><span class="i s u"><i><s><u>uis</u></s></i></span></li></ul>\n\
|
<ul class="list-bullet4"><li><span class="u"><u>bullet4 line 2 u</u></span><span class="i s u"><i><s><u>uis</u></s></i></span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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><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><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\n');
|
||||||
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\n')
|
done();
|
||||||
done()
|
});
|
||||||
})
|
xit('import a pad with nested bullets from html', function (done) {
|
||||||
xit("import a pad with nested bullets from html", function(done){
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><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></body></html>';
|
||||||
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><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></body></html>'
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
const oldtext = getinnertext();
|
||||||
var oldtext=getinnertext()
|
helper.waitFor(() => oldtext != getinnertext(),
|
||||||
helper.waitFor(function(){
|
// return expect(getinnertext()).to.be('\
|
||||||
return oldtext != getinnertext()
|
// <ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
||||||
// return expect(getinnertext()).to.be('\
|
// <ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
||||||
//<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\
|
// <ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
||||||
//<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
// <ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
||||||
//<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n\
|
// <ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
||||||
//<ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
// <ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
||||||
//<ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
// <br>\n')
|
||||||
//<ul class="list-bullet4"><li><span class="">bullet4 line 2</span></li></ul>\n\
|
);
|
||||||
//<br>\n')
|
|
||||||
})
|
|
||||||
|
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
const 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[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')
|
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');
|
||||||
done()
|
done();
|
||||||
})
|
});
|
||||||
xit("import a pad with 8 levels of bullets and newlines and attributes from html", function(done){
|
xit('import a pad with 8 levels of bullets and newlines and attributes from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-bullet5"><ul class="list-bullet6"><ul class="list-bullet7"><ul class="list-bullet8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-bullet5"><li>foobar</li></ul></ul></ul></ul></body></html>'
|
const htmlWithBullets = '<html><body><ul class="list-bullet1"><li>bullet line 1</li></ul><br/><ul class="list-bullet1"><li>bullet line 2</li><ul class="list-bullet2"><li>bullet2 line 1</li></ul></ul><br/><ul class="list-bullet1"><ul class="list-bullet2"><ul class="list-bullet3"><ul class="list-bullet4"><li><span class="b s i u"><b><i><s><u>bullet4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>bullet4 line 2 bs</s></b></span></li><li><span class="u"><u>bullet4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-bullet5"><ul class="list-bullet6"><ul class="list-bullet7"><ul class="list-bullet8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-bullet5"><li>foobar</li></ul></ul></ul></ul></body></html>';
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\<br>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 1</span></li></ul>\n\<br>\n\
|
||||||
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
<ul class="list-bullet1"><li><span class="">bullet line 2</span></li></ul>\n\
|
||||||
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n<br>\n\
|
<ul class="list-bullet2"><li><span class="">bullet2 line 1</span></li></ul>\n<br>\n\
|
||||||
|
@ -180,32 +166,31 @@ describe("import functionality", function(){
|
||||||
<ul class="list-bullet8"><li><span class="">foo</span></li></ul>\n\
|
<ul class="list-bullet8"><li><span class="">foo</span></li></ul>\n\
|
||||||
<ul class="list-bullet8"><li><span class="b s"><b><s>foobar bs</s></b></span></li></ul>\n\
|
<ul class="list-bullet8"><li><span class="b s"><b><s>foobar bs</s></b></span></li></ul>\n\
|
||||||
<ul class="list-bullet5"><li><span class="">foobar</span></li></ul>\n\
|
<ul class="list-bullet5"><li><span class="">foobar</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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');
|
||||||
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();
|
||||||
done()
|
});
|
||||||
})
|
|
||||||
|
|
||||||
xit("import a pad with ordered lists from html", function(done){
|
xit('import a pad with ordered lists from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const 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>'
|
const 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>';
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
importrequest(htmlWithBullets, importurl, 'html') -
|
||||||
-console.error(getinnertext())
|
console.error(getinnertext());
|
||||||
expect(getinnertext()).to.be('\
|
expect(getinnertext()).to.be('\
|
||||||
<ol class="list-number1" start="1"><li><span class="">number 1 line 1</span></li></ol>\n\
|
<ol class="list-number1" start="1"><li><span class="">number 1 line 1</span></li></ol>\n\
|
||||||
<ol class="list-number1" start="2"><li><span class="">number 2 line 2</span></li></ol>\n\
|
<ol class="list-number1" start="2"><li><span class="">number 2 line 2</span></li></ol>\n\
|
||||||
<br>\n')
|
<br>\n');
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
expect(results[0][1]).to.be('<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>')
|
expect(results[0][1]).to.be('<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>');
|
||||||
expect(results[1][1]).to.be('')
|
expect(results[1][1]).to.be('');
|
||||||
done()
|
done();
|
||||||
})
|
});
|
||||||
xit("import a pad with ordered lists and newlines from html", function(done){
|
xit('import a pad with ordered lists and newlines from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var htmlWithBullets = '<html><body><ol class="list-number1" start="1"><li>number 9 line 1</li></ol><br/><ol class="list-number1" start="2"><li>number 10 line 2</li><ol class="list-number2"><li>number 2 times line 1</li></ol></ol><br/><ol class="list-bullet1"><ol class="list-number2"><li>number 2 times line 2</li></ol></ol></body></html>'
|
const htmlWithBullets = '<html><body><ol class="list-number1" start="1"><li>number 9 line 1</li></ol><br/><ol class="list-number1" start="2"><li>number 10 line 2</li><ol class="list-number2"><li>number 2 times line 1</li></ol></ol><br/><ol class="list-bullet1"><ol class="list-number2"><li>number 2 times line 2</li></ol></ol></body></html>';
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
expect(getinnertext()).to.be('\
|
expect(getinnertext()).to.be('\
|
||||||
<ol class="list-number1" start="1"><li><span class="">number 9 line 1</span></li></ol>\n\
|
<ol class="list-number1" start="1"><li><span class="">number 9 line 1</span></li></ol>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
|
@ -213,15 +198,15 @@ describe("import functionality", function(){
|
||||||
<ol class="list-number2"><li><span class="">number 2 times line 1</span></li></ol>\n\
|
<ol class="list-number2"><li><span class="">number 2 times line 1</span></li></ol>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ol class="list-number2"><li><span class="">number 2 times line 2</span></li></ol>\n\
|
<ol class="list-number2"><li><span class="">number 2 times line 2</span></li></ol>\n\
|
||||||
<br>\n')
|
<br>\n');
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
console.error(results)
|
console.error(results);
|
||||||
done()
|
done();
|
||||||
})
|
});
|
||||||
xit("import a pad with nested ordered lists and attributes and newlines from html", function(done){
|
xit('import a pad with nested ordered lists and attributes and newlines from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var htmlWithBullets = '<html><body><ol class="list-number1" start="1"><li><span class="b s i u"><b><i><s><u>bold strikethrough italics underline</u></s><i/></b></span> line <span class="b"><b>1bold</b></span></li></ol><br/><span class="i"><i><ol class="list-number1" start="2"><li>number 10 line 2</li><ol class="list-number2"><li>number 2 times line 1</li></ol></ol></i></span><br/><ol class="list-bullet1"><ol class="list-number2"><li>number 2 times line 2</li></ol></ol></body></html>'
|
const htmlWithBullets = '<html><body><ol class="list-number1" start="1"><li><span class="b s i u"><b><i><s><u>bold strikethrough italics underline</u></s><i/></b></span> line <span class="b"><b>1bold</b></span></li></ol><br/><span class="i"><i><ol class="list-number1" start="2"><li>number 10 line 2</li><ol class="list-number2"><li>number 2 times line 1</li></ol></ol></i></span><br/><ol class="list-bullet1"><ol class="list-number2"><li>number 2 times line 2</li></ol></ol></body></html>';
|
||||||
importrequest(htmlWithBullets,importurl,"html")
|
importrequest(htmlWithBullets, importurl, 'html');
|
||||||
expect(getinnertext()).to.be('\
|
expect(getinnertext()).to.be('\
|
||||||
<ol class="list-number1"><li><span class="b i s u"><b><i><s><u>bold strikethrough italics underline</u></s></i></b></span><span class=""> line </span><span class="b"><b>1bold</b></span></li></ol>\n\
|
<ol class="list-number1"><li><span class="b i s u"><b><i><s><u>bold strikethrough italics underline</u></s></i></b></span><span class=""> line </span><span class="b"><b>1bold</b></span></li></ol>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
|
@ -229,9 +214,9 @@ describe("import functionality", function(){
|
||||||
<ol class="list-number2"><li><span class="i"><i>number 2 times line 1</i></span></li></ol>\n\
|
<ol class="list-number2"><li><span class="i"><i>number 2 times line 1</i></span></li></ol>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ol class="list-number2"><li><span class="">number 2 times line 2</span></li></ol>\n\
|
<ol class="list-number2"><li><span class="">number 2 times line 2</span></li></ol>\n\
|
||||||
<br>\n')
|
<br>\n');
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
console.error(results)
|
console.error(results);
|
||||||
done()
|
done();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
|
@ -1,97 +1,92 @@
|
||||||
describe("import indents functionality", function(){
|
describe('import indents functionality', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb); // creates a new pad
|
helper.newPad(cb); // creates a new pad
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getinnertext(){
|
function getinnertext() {
|
||||||
var inner = helper.padInner$
|
const inner = helper.padInner$;
|
||||||
var newtext = ""
|
let newtext = '';
|
||||||
inner("div").each(function(line,el){
|
inner('div').each((line, el) => {
|
||||||
newtext += el.innerHTML+"\n"
|
newtext += `${el.innerHTML}\n`;
|
||||||
})
|
});
|
||||||
return newtext
|
return newtext;
|
||||||
}
|
}
|
||||||
function importrequest(data,importurl,type){
|
function importrequest(data, importurl, type) {
|
||||||
var success;
|
let success;
|
||||||
var error;
|
let error;
|
||||||
var result = $.ajax({
|
const result = $.ajax({
|
||||||
url: importurl,
|
url: importurl,
|
||||||
type: "post",
|
type: 'post',
|
||||||
processData: false,
|
processData: false,
|
||||||
async: false,
|
async: false,
|
||||||
contentType: 'multipart/form-data; boundary=boundary',
|
contentType: 'multipart/form-data; boundary=boundary',
|
||||||
accepts: {
|
accepts: {
|
||||||
text: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
text: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
},
|
},
|
||||||
data: 'Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.'+type+'"\r\nContent-Type: text/plain\r\n\r\n' + data + '\r\n\r\n--boundary',
|
data: `Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.${type}"\r\nContent-Type: text/plain\r\n\r\n${data}\r\n\r\n--boundary`,
|
||||||
error: function(res){
|
error(res) {
|
||||||
error = res
|
error = res;
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
expect(error).to.be(undefined)
|
expect(error).to.be(undefined);
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
function exportfunc(link){
|
function exportfunc(link) {
|
||||||
var exportresults = []
|
const exportresults = [];
|
||||||
$.ajaxSetup({
|
$.ajaxSetup({
|
||||||
async:false
|
async: false,
|
||||||
})
|
});
|
||||||
$.get(link+"/export/html",function(data){
|
$.get(`${link}/export/html`, (data) => {
|
||||||
var start = data.indexOf("<body>")
|
const start = data.indexOf('<body>');
|
||||||
var end = data.indexOf("</body>")
|
const end = data.indexOf('</body>');
|
||||||
var html = data.substr(start+6,end-start-6)
|
const html = data.substr(start + 6, end - start - 6);
|
||||||
exportresults.push(["html",html])
|
exportresults.push(['html', html]);
|
||||||
})
|
});
|
||||||
$.get(link+"/export/txt",function(data){
|
$.get(`${link}/export/txt`, (data) => {
|
||||||
exportresults.push(["txt",data])
|
exportresults.push(['txt', data]);
|
||||||
})
|
});
|
||||||
return exportresults
|
return exportresults;
|
||||||
}
|
}
|
||||||
|
|
||||||
xit("import a pad with indents from html", function(done){
|
xit('import a pad with indents from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li><li>indent2 line 2</li></ul></ul></body></html>'
|
const htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li><li>indent2 line 2</li></ul></ul></body></html>';
|
||||||
importrequest(htmlWithIndents,importurl,"html")
|
importrequest(htmlWithIndents, importurl, 'html');
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\
|
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\
|
||||||
<ul class="list-indent1"><li><span class="">indent line 2</span></li></ul>\n\
|
<ul class="list-indent1"><li><span class="">indent line 2</span></li></ul>\n\
|
||||||
<ul class="list-indent2"><li><span class="">indent2 line 1</span></li></ul>\n\
|
<ul class="list-indent2"><li><span class="">indent2 line 1</span></li></ul>\n\
|
||||||
<ul class="list-indent2"><li><span class="">indent2 line 2</span></li></ul>\n\
|
<ul class="list-indent2"><li><span class="">indent2 line 2</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
var results = exportfunc(helper.padChrome$.window.location.href)
|
expect(results[0][1]).to.be('<ul class="indent"><li>indent line 1</li><li>indent line 2</li><ul class="indent"><li>indent2 line 1</li><li>indent2 line 2</li></ul></ul><br>');
|
||||||
expect(results[0][1]).to.be('<ul class="indent"><li>indent line 1</li><li>indent line 2</li><ul class="indent"><li>indent2 line 1</li><li>indent2 line 2</li></ul></ul><br>')
|
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');
|
||||||
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();
|
||||||
done()
|
});
|
||||||
})
|
|
||||||
|
|
||||||
xit("import a pad with indented lists and newlines from html", function(done){
|
xit('import a pad with indented lists and newlines from html', function (done) {
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const 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>'
|
const 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>';
|
||||||
importrequest(htmlWithIndents,importurl,"html")
|
importrequest(htmlWithIndents, importurl, 'html');
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\
|
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ul class="list-indent1"><li><span class="">indent 1 line 2</span></li></ul>\n\
|
<ul class="list-indent1"><li><span class="">indent 1 line 2</span></li></ul>\n\
|
||||||
<ul class="list-indent2"><li><span class="">indent 2 times line 1</span></li></ul>\n\
|
<ul class="list-indent2"><li><span class="">indent 2 times line 1</span></li></ul>\n\
|
||||||
<br>\n\
|
<br>\n\
|
||||||
<ul class="list-indent2"><li><span class="">indent 2 times line 2</span></li></ul>\n\
|
<ul class="list-indent2"><li><span class="">indent 2 times line 2</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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 1 line 2</li><ul class="indent"><li>indent 2 times line 1</li></ul></ul><br><ul><ul class="indent"><li>indent 2 times line 2</li></ul></ul><br>');
|
||||||
expect(results[0][1]).to.be('<ul class="indent"><li>indent line 1</li></ul><br><ul class="indent"><li>indent 1 line 2</li><ul class="indent"><li>indent 2 times line 1</li></ul></ul><br><ul><ul class="indent"><li>indent 2 times line 2</li></ul></ul><br>')
|
expect(results[1][1]).to.be('\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n\t\tindent 2 times line 2\n\n');
|
||||||
expect(results[1][1]).to.be('\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n\t\tindent 2 times line 2\n\n')
|
done();
|
||||||
done()
|
});
|
||||||
})
|
xit('import a pad with 8 levels of indents and newlines and attributes from html', function (done) {
|
||||||
xit("import a pad with 8 levels of indents and newlines and attributes from html", function(done){
|
const importurl = `${helper.padChrome$.window.location.href}/import`;
|
||||||
var importurl = helper.padChrome$.window.location.href+'/import'
|
const htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li></ul><br/><ul class="list-indent1"><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li></ul></ul><br/><ul class="list-indent1"><ul class="list-indent2"><ul class="list-indent3"><ul class="list-indent4"><li><span class="b s i u"><b><i><s><u>indent4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>indent4 line 2 bs</s></b></span></li><li><span class="u"><u>indent4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-indent5"><ul class="list-indent6"><ul class="list-indent7"><ul class="list-indent8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-indent5"><li>foobar</li></ul></ul></ul></ul></body></html>';
|
||||||
var htmlWithIndents = '<html><body><ul class="list-indent1"><li>indent line 1</li></ul><br/><ul class="list-indent1"><li>indent line 2</li><ul class="list-indent2"><li>indent2 line 1</li></ul></ul><br/><ul class="list-indent1"><ul class="list-indent2"><ul class="list-indent3"><ul class="list-indent4"><li><span class="b s i u"><b><i><s><u>indent4 line 2 bisu</u></s></i></b></span></li><li><span class="b s "><b><s>indent4 line 2 bs</s></b></span></li><li><span class="u"><u>indent4 line 2 u</u></span><span class="u i s"><i><s><u>uis</u></s></i></span></li><ul class="list-indent5"><ul class="list-indent6"><ul class="list-indent7"><ul class="list-indent8"><li><span class="">foo</span></li><li><span class="b s"><b><s>foobar bs</b></s></span></li></ul></ul></ul></ul><ul class="list-indent5"><li>foobar</li></ul></ul></ul></ul></body></html>'
|
importrequest(htmlWithIndents, importurl, 'html');
|
||||||
importrequest(htmlWithIndents,importurl,"html")
|
helper.waitFor(() => expect(getinnertext()).to.be('\
|
||||||
helper.waitFor(function(){
|
|
||||||
return expect(getinnertext()).to.be('\
|
|
||||||
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\<br>\n\
|
<ul class="list-indent1"><li><span class="">indent line 1</span></li></ul>\n\<br>\n\
|
||||||
<ul class="list-indent1"><li><span class="">indent line 2</span></li></ul>\n\
|
<ul class="list-indent1"><li><span class="">indent line 2</span></li></ul>\n\
|
||||||
<ul class="list-indent2"><li><span class="">indent2 line 1</span></li></ul>\n<br>\n\
|
<ul class="list-indent2"><li><span class="">indent2 line 1</span></li></ul>\n<br>\n\
|
||||||
|
@ -101,11 +96,10 @@ describe("import indents functionality", function(){
|
||||||
<ul class="list-indent8"><li><span class="">foo</span></li></ul>\n\
|
<ul class="list-indent8"><li><span class="">foo</span></li></ul>\n\
|
||||||
<ul class="list-indent8"><li><span class="b s"><b><s>foobar bs</s></b></span></li></ul>\n\
|
<ul class="list-indent8"><li><span class="b s"><b><s>foobar bs</s></b></span></li></ul>\n\
|
||||||
<ul class="list-indent5"><li><span class="">foobar</span></li></ul>\n\
|
<ul class="list-indent5"><li><span class="">foobar</span></li></ul>\n\
|
||||||
<br>\n')
|
<br>\n'));
|
||||||
})
|
const results = exportfunc(helper.padChrome$.window.location.href);
|
||||||
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');
|
||||||
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();
|
||||||
done()
|
});
|
||||||
})
|
});
|
||||||
})
|
|
||||||
|
|
|
@ -1,178 +1,164 @@
|
||||||
describe("indentation button", function(){
|
describe('indentation button', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent text with keypress", function(done){
|
it('indent text with keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.keyCode = 9; // tab :|
|
e.keyCode = 9; // tab :|
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('ul li').length === 1).done(done);
|
||||||
return inner$("div").first().find("ul li").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent text with button", function(done){
|
it('indent text with button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
const $indentButton = chrome$('.buttonicon-indent');
|
||||||
$indentButton.click();
|
$indentButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('ul li').length === 1).done(done);
|
||||||
return inner$("div").first().find("ul li").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps the indent on enter for the new line", function(done){
|
it('keeps the indent on enter for the new line', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
const $indentButton = chrome$('.buttonicon-indent');
|
||||||
$indentButton.click();
|
$indentButton.click();
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
// type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
$firstTextElement.sendkeys('line 1');
|
$firstTextElement.sendkeys('line 1');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
$firstTextElement.sendkeys('line 2');
|
$firstTextElement.sendkeys('line 2');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text().indexOf('line 2') === -1).done(() => {
|
||||||
return inner$("div span").first().text().indexOf("line 2") === -1;
|
const $newSecondLine = inner$('div').first().next();
|
||||||
}).done(function(){
|
const hasULElement = $newSecondLine.find('ul li').length === 1;
|
||||||
var $newSecondLine = inner$("div").first().next();
|
|
||||||
var hasULElement = $newSecondLine.find("ul li").length === 1;
|
|
||||||
|
|
||||||
expect(hasULElement).to.be(true);
|
expect(hasULElement).to.be(true);
|
||||||
expect($newSecondLine.text()).to.be("line 2");
|
expect($newSecondLine.text()).to.be('line 2');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indents text with spaces on enter if previous line ends with ':', '[', '(', or '{'", function(done){
|
it("indents text with spaces on enter if previous line ends with ':', '[', '(', or '{'", function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
// type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
$firstTextElement.sendkeys("line with ':'{enter}");
|
$firstTextElement.sendkeys("line with ':'{enter}");
|
||||||
$firstTextElement.sendkeys("line with '['{enter}");
|
$firstTextElement.sendkeys("line with '['{enter}");
|
||||||
$firstTextElement.sendkeys("line with '('{enter}");
|
$firstTextElement.sendkeys("line with '('{enter}");
|
||||||
$firstTextElement.sendkeys("line with '{{}'{enter}");
|
$firstTextElement.sendkeys("line with '{{}'{enter}");
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
// wait for Etherpad to split four lines into separated divs
|
// wait for Etherpad to split four lines into separated divs
|
||||||
var $fourthLine = inner$("div").first().next().next().next();
|
const $fourthLine = inner$('div').first().next().next().next();
|
||||||
return $fourthLine.text().indexOf("line with '{'") === 0;
|
return $fourthLine.text().indexOf("line with '{'") === 0;
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
// we validate bottom to top for easier implementation
|
// we validate bottom to top for easier implementation
|
||||||
|
|
||||||
// curly braces
|
// curly braces
|
||||||
var $lineWithCurlyBraces = inner$("div").first().next().next().next();
|
const $lineWithCurlyBraces = inner$('div').first().next().next().next();
|
||||||
$lineWithCurlyBraces.sendkeys('{{}');
|
$lineWithCurlyBraces.sendkeys('{{}');
|
||||||
pressEnter(); // cannot use sendkeys('{enter}') here, browser does not read the command properly
|
pressEnter(); // cannot use sendkeys('{enter}') here, browser does not read the command properly
|
||||||
var $lineAfterCurlyBraces = inner$("div").first().next().next().next().next();
|
const $lineAfterCurlyBraces = inner$('div').first().next().next().next().next();
|
||||||
expect($lineAfterCurlyBraces.text()).to.match(/\s{4}/); // tab === 4 spaces
|
expect($lineAfterCurlyBraces.text()).to.match(/\s{4}/); // tab === 4 spaces
|
||||||
|
|
||||||
// parenthesis
|
// parenthesis
|
||||||
var $lineWithParenthesis = inner$("div").first().next().next();
|
const $lineWithParenthesis = inner$('div').first().next().next();
|
||||||
$lineWithParenthesis.sendkeys('(');
|
$lineWithParenthesis.sendkeys('(');
|
||||||
pressEnter();
|
pressEnter();
|
||||||
var $lineAfterParenthesis = inner$("div").first().next().next().next();
|
const $lineAfterParenthesis = inner$('div').first().next().next().next();
|
||||||
expect($lineAfterParenthesis.text()).to.match(/\s{4}/);
|
expect($lineAfterParenthesis.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
// bracket
|
// bracket
|
||||||
var $lineWithBracket = inner$("div").first().next();
|
const $lineWithBracket = inner$('div').first().next();
|
||||||
$lineWithBracket.sendkeys('[');
|
$lineWithBracket.sendkeys('[');
|
||||||
pressEnter();
|
pressEnter();
|
||||||
var $lineAfterBracket = inner$("div").first().next().next();
|
const $lineAfterBracket = inner$('div').first().next().next();
|
||||||
expect($lineAfterBracket.text()).to.match(/\s{4}/);
|
expect($lineAfterBracket.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
// colon
|
// colon
|
||||||
var $lineWithColon = inner$("div").first();
|
const $lineWithColon = inner$('div').first();
|
||||||
$lineWithColon.sendkeys(':');
|
$lineWithColon.sendkeys(':');
|
||||||
pressEnter();
|
pressEnter();
|
||||||
var $lineAfterColon = inner$("div").first().next();
|
const $lineAfterColon = inner$('div').first().next();
|
||||||
expect($lineAfterColon.text()).to.match(/\s{4}/);
|
expect($lineAfterColon.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("appends indentation to the indent of previous line if previous line ends with ':', '[', '(', or '{'", function(done){
|
it("appends indentation to the indent of previous line if previous line ends with ':', '[', '(', or '{'", function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
// type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
$firstTextElement.sendkeys(" line with some indentation and ':'{enter}");
|
$firstTextElement.sendkeys(" line with some indentation and ':'{enter}");
|
||||||
$firstTextElement.sendkeys("line 2{enter}");
|
$firstTextElement.sendkeys('line 2{enter}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
// wait for Etherpad to split two lines into separated divs
|
// wait for Etherpad to split two lines into separated divs
|
||||||
var $secondLine = inner$("div").first().next();
|
const $secondLine = inner$('div').first().next();
|
||||||
return $secondLine.text().indexOf("line 2") === 0;
|
return $secondLine.text().indexOf('line 2') === 0;
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
var $lineWithColon = inner$("div").first();
|
const $lineWithColon = inner$('div').first();
|
||||||
$lineWithColon.sendkeys(':');
|
$lineWithColon.sendkeys(':');
|
||||||
pressEnter();
|
pressEnter();
|
||||||
var $lineAfterColon = inner$("div").first().next();
|
const $lineAfterColon = inner$('div').first().next();
|
||||||
expect($lineAfterColon.text()).to.match(/\s{6}/); // previous line indentation + regular tab (4 spaces)
|
expect($lineAfterColon.text()).to.match(/\s{6}/); // previous line indentation + regular tab (4 spaces)
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", function(done){
|
it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// make sure pad has more than one line
|
// make sure pad has more than one line
|
||||||
inner$("div").first().sendkeys("First{enter}Second{enter}");
|
inner$('div').first().sendkeys('First{enter}Second{enter}');
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().text().trim() === 'First').done(() => {
|
||||||
return inner$("div").first().text().trim() === "First";
|
|
||||||
}).done(function(){
|
|
||||||
// indent first 2 lines
|
// indent first 2 lines
|
||||||
var $lines = inner$("div");
|
const $lines = inner$('div');
|
||||||
var $firstLine = $lines.first();
|
const $firstLine = $lines.first();
|
||||||
var $secondLine = $lines.slice(1,2);
|
const $secondLine = $lines.slice(1, 2);
|
||||||
helper.selectLines($firstLine, $secondLine);
|
helper.selectLines($firstLine, $secondLine);
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
const $indentButton = chrome$('.buttonicon-indent');
|
||||||
$indentButton.click();
|
$indentButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('ul li').length === 1).done(() => {
|
||||||
return inner$("div").first().find("ul li").length === 1;
|
|
||||||
}).done(function(){
|
|
||||||
// apply bold
|
// apply bold
|
||||||
var $boldButton = chrome$(".buttonicon-bold");
|
const $boldButton = chrome$('.buttonicon-bold');
|
||||||
$boldButton.click();
|
$boldButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('b').length === 1).done(() => {
|
||||||
return inner$("div").first().find("b").length === 1;
|
|
||||||
}).done(function(){
|
|
||||||
// outdent first 2 lines
|
// outdent first 2 lines
|
||||||
var $outdentButton = chrome$(".buttonicon-outdent");
|
const $outdentButton = chrome$('.buttonicon-outdent');
|
||||||
$outdentButton.click();
|
$outdentButton.click();
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('ul li').length === 0).done(() => {
|
||||||
return inner$("div").first().find("ul li").length === 0;
|
|
||||||
}).done(function(){
|
|
||||||
// check if '*' is displayed
|
// check if '*' is displayed
|
||||||
var $secondLine = inner$("div").slice(1,2);
|
const $secondLine = inner$('div').slice(1, 2);
|
||||||
expect($secondLine.text().trim()).to.be("Second");
|
expect($secondLine.text().trim()).to.be('Second');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -314,12 +300,11 @@ describe("indentation button", function(){
|
||||||
expect(isLI).to.be(true);
|
expect(isLI).to.be(true);
|
||||||
},1000);
|
},1000);
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function pressEnter(){
|
function pressEnter() {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.keyCode = 13; // enter :|
|
e.keyCode = 13; // enter :|
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +1,66 @@
|
||||||
describe("italic some text", function(){
|
describe('italic some text', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text italic using button", function(done) {
|
it('makes text italic using button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
//get the bold button and click it
|
// get the bold button and click it
|
||||||
var $boldButton = chrome$(".buttonicon-italic");
|
const $boldButton = chrome$('.buttonicon-italic');
|
||||||
$boldButton.click();
|
$boldButton.click();
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
// ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// is there a <i> element now?
|
// is there a <i> element now?
|
||||||
var isItalic = $newFirstTextElement.find("i").length === 1;
|
const isItalic = $newFirstTextElement.find('i').length === 1;
|
||||||
|
|
||||||
//expect it to be bold
|
// expect it to be bold
|
||||||
expect(isItalic).to.be(true);
|
expect(isItalic).to.be(true);
|
||||||
|
|
||||||
//make sure the text hasn't changed
|
// make sure the text hasn't changed
|
||||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text italic using keypress", function(done) {
|
it('makes text italic using keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 105; // i
|
e.which = 105; // i
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
// ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// is there a <i> element now?
|
// is there a <i> element now?
|
||||||
var isItalic = $newFirstTextElement.find("i").length === 1;
|
const isItalic = $newFirstTextElement.find('i').length === 1;
|
||||||
|
|
||||||
//expect it to be bold
|
// expect it to be bold
|
||||||
expect(isItalic).to.be(true);
|
expect(isItalic).to.be(true);
|
||||||
|
|
||||||
//make sure the text hasn't changed
|
// make sure the text hasn't changed
|
||||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,135 +1,127 @@
|
||||||
function deletecookie(name) {
|
function deletecookie(name) {
|
||||||
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Language select and change", function(){
|
describe('Language select and change', function () {
|
||||||
// Destroy language cookies
|
// Destroy language cookies
|
||||||
deletecookie("language", null);
|
deletecookie('language', null);
|
||||||
|
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Destroy language cookies
|
// Destroy language cookies
|
||||||
it("makes text german", function(done) {
|
it('makes text german', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $settingsButton = chrome$(".buttonicon-settings");
|
const $settingsButton = chrome$('.buttonicon-settings');
|
||||||
$settingsButton.click();
|
$settingsButton.click();
|
||||||
|
|
||||||
//click the language button
|
// click the language button
|
||||||
var $language = chrome$("#languagemenu");
|
const $language = chrome$('#languagemenu');
|
||||||
var $languageoption = $language.find("[value=de]");
|
const $languageoption = $language.find('[value=de]');
|
||||||
|
|
||||||
//select german
|
// select german
|
||||||
$languageoption.attr('selected','selected');
|
$languageoption.attr('selected', 'selected');
|
||||||
$language.change();
|
$language.change();
|
||||||
|
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => chrome$('.buttonicon-bold').parent()[0].title == 'Fett (Strg-B)')
|
||||||
return chrome$(".buttonicon-bold").parent()[0]["title"] == "Fett (Strg-B)";
|
.done(() => {
|
||||||
})
|
// get the value of the bold button
|
||||||
.done(function(){
|
const $boldButton = chrome$('.buttonicon-bold').parent();
|
||||||
//get the value of the bold button
|
|
||||||
var $boldButton = chrome$(".buttonicon-bold").parent();
|
|
||||||
|
|
||||||
//get the title of the bold button
|
// get the title of the bold button
|
||||||
var boldButtonTitle = $boldButton[0]["title"];
|
const boldButtonTitle = $boldButton[0].title;
|
||||||
|
|
||||||
//check if the language is now german
|
// check if the language is now german
|
||||||
expect(boldButtonTitle).to.be("Fett (Strg-B)");
|
expect(boldButtonTitle).to.be('Fett (Strg-B)');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text English", function(done) {
|
it('makes text English', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $settingsButton = chrome$(".buttonicon-settings");
|
const $settingsButton = chrome$('.buttonicon-settings');
|
||||||
$settingsButton.click();
|
$settingsButton.click();
|
||||||
|
|
||||||
//click the language button
|
// click the language button
|
||||||
var $language = chrome$("#languagemenu");
|
const $language = chrome$('#languagemenu');
|
||||||
//select english
|
// select english
|
||||||
$language.val("en");
|
$language.val('en');
|
||||||
$language.change();
|
$language.change();
|
||||||
|
|
||||||
//get the value of the bold button
|
// get the value of the bold button
|
||||||
var $boldButton = chrome$(".buttonicon-bold").parent();
|
const $boldButton = chrome$('.buttonicon-bold').parent();
|
||||||
|
|
||||||
helper.waitFor(function() { return $boldButton[0]["title"] != "Fett (Strg+B)";})
|
helper.waitFor(() => $boldButton[0].title != 'Fett (Strg+B)')
|
||||||
.done(function(){
|
.done(() => {
|
||||||
|
// get the value of the bold button
|
||||||
|
const $boldButton = chrome$('.buttonicon-bold').parent();
|
||||||
|
|
||||||
//get the value of the bold button
|
// get the title of the bold button
|
||||||
var $boldButton = chrome$(".buttonicon-bold").parent();
|
const boldButtonTitle = $boldButton[0].title;
|
||||||
|
|
||||||
//get the title of the bold button
|
// check if the language is now English
|
||||||
var boldButtonTitle = $boldButton[0]["title"];
|
expect(boldButtonTitle).to.be('Bold (Ctrl+B)');
|
||||||
|
done();
|
||||||
//check if the language is now English
|
});
|
||||||
expect(boldButtonTitle).to.be("Bold (Ctrl+B)");
|
|
||||||
done();
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes direction when picking an rtl lang", function(done) {
|
it('changes direction when picking an rtl lang', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $settingsButton = chrome$(".buttonicon-settings");
|
const $settingsButton = chrome$('.buttonicon-settings');
|
||||||
$settingsButton.click();
|
$settingsButton.click();
|
||||||
|
|
||||||
//click the language button
|
// click the language button
|
||||||
var $language = chrome$("#languagemenu");
|
const $language = chrome$('#languagemenu');
|
||||||
var $languageoption = $language.find("[value=ar]");
|
const $languageoption = $language.find('[value=ar]');
|
||||||
|
|
||||||
//select arabic
|
// select arabic
|
||||||
// $languageoption.attr('selected','selected'); // Breaks the test..
|
// $languageoption.attr('selected','selected'); // Breaks the test..
|
||||||
$language.val("ar");
|
$language.val('ar');
|
||||||
$languageoption.change();
|
$languageoption.change();
|
||||||
|
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => chrome$('html')[0].dir != 'ltr')
|
||||||
return chrome$("html")[0]["dir"] != 'ltr';
|
.done(() => {
|
||||||
})
|
// check if the document's direction was changed
|
||||||
.done(function(){
|
expect(chrome$('html')[0].dir).to.be('rtl');
|
||||||
// check if the document's direction was changed
|
done();
|
||||||
expect(chrome$("html")[0]["dir"]).to.be("rtl");
|
});
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes direction when picking an ltr lang", function(done) {
|
it('changes direction when picking an ltr lang', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//click on the settings button to make settings visible
|
// click on the settings button to make settings visible
|
||||||
var $settingsButton = chrome$(".buttonicon-settings");
|
const $settingsButton = chrome$('.buttonicon-settings');
|
||||||
$settingsButton.click();
|
$settingsButton.click();
|
||||||
|
|
||||||
//click the language button
|
// click the language button
|
||||||
var $language = chrome$("#languagemenu");
|
const $language = chrome$('#languagemenu');
|
||||||
var $languageoption = $language.find("[value=en]");
|
const $languageoption = $language.find('[value=en]');
|
||||||
|
|
||||||
//select english
|
// select english
|
||||||
//select arabic
|
// select arabic
|
||||||
$languageoption.attr('selected','selected');
|
$languageoption.attr('selected', 'selected');
|
||||||
$language.val("en");
|
$language.val('en');
|
||||||
$languageoption.change();
|
$languageoption.change();
|
||||||
|
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => chrome$('html')[0].dir != 'rtl')
|
||||||
return chrome$("html")[0]["dir"] != 'rtl';
|
.done(() => {
|
||||||
})
|
// check if the document's direction was changed
|
||||||
.done(function(){
|
expect(chrome$('html')[0].dir).to.be('ltr');
|
||||||
// check if the document's direction was changed
|
done();
|
||||||
expect(chrome$("html")[0]["dir"]).to.be("ltr");
|
});
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
describe('author of pad edition', function() {
|
describe('author of pad edition', function () {
|
||||||
// author 1 creates a new pad with some content (regular lines and lists)
|
// author 1 creates a new pad with some content (regular lines and lists)
|
||||||
before(function(done) {
|
before(function (done) {
|
||||||
var padId = helper.newPad(function() {
|
var padId = helper.newPad(() => {
|
||||||
// make sure pad has at least 3 lines
|
// make sure pad has at least 3 lines
|
||||||
var $firstLine = helper.padInner$('div').first();
|
const $firstLine = helper.padInner$('div').first();
|
||||||
$firstLine.html("Hello World");
|
$firstLine.html('Hello World');
|
||||||
|
|
||||||
// wait for lines to be processed by Etherpad
|
// wait for lines to be processed by Etherpad
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => $firstLine.text() === 'Hello World').done(() => {
|
||||||
return $firstLine.text() === 'Hello World';
|
|
||||||
}).done(function() {
|
|
||||||
// Reload pad, to make changes as a second user. Need a timeout here to make sure
|
// Reload pad, to make changes as a second user. Need a timeout here to make sure
|
||||||
// all changes were saved before reloading
|
// all changes were saved before reloading
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// Expire cookie, so author is changed after reloading the pad.
|
// 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
|
// 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.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
|
||||||
|
@ -25,27 +23,27 @@ describe('author of pad edition', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// author 2 makes some changes on the pad
|
// author 2 makes some changes on the pad
|
||||||
it('Clears Authorship by second user', function(done) {
|
it('Clears Authorship by second user', function (done) {
|
||||||
clearAuthorship(done);
|
clearAuthorship(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
var clearAuthorship = function(done){
|
var clearAuthorship = function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// override the confirm dialogue functioon
|
// override the confirm dialogue functioon
|
||||||
helper.padChrome$.window.confirm = function(){
|
helper.padChrome$.window.confirm = function () {
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
//get the clear authorship colors button and click it
|
// get the clear authorship colors button and click it
|
||||||
var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship");
|
const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship');
|
||||||
$clearauthorshipcolorsButton.click();
|
$clearauthorshipcolorsButton.click();
|
||||||
|
|
||||||
// does the first divs span include an author class?
|
// does the first divs span include an author class?
|
||||||
var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1;
|
const hasAuthorClass = inner$('div span').first().attr('class').indexOf('author') !== -1;
|
||||||
|
|
||||||
expect(hasAuthorClass).to.be(false)
|
expect(hasAuthorClass).to.be(false);
|
||||||
done();
|
done();
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,204 +1,180 @@
|
||||||
describe("assign ordered list", function(){
|
describe('assign ordered list', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("inserts ordered list text", function(done){
|
it('inserts ordered list text', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('ol li').length === 1).done(done);
|
||||||
return inner$("div").first().find("ol li").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when user presses Ctrl+Shift+N', function() {
|
context('when user presses Ctrl+Shift+N', function () {
|
||||||
context('and pad shortcut is enabled', function() {
|
context('and pad shortcut is enabled', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
makeSureShortcutIsEnabled('cmdShiftN');
|
makeSureShortcutIsEnabled('cmdShiftN');
|
||||||
triggerCtrlShiftShortcut('N');
|
triggerCtrlShiftShortcut('N');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts unordered list', function(done) {
|
it('inserts unordered list', function (done) {
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(done);
|
||||||
return helper.padInner$('div').first().find('ol li').length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and pad shortcut is disabled', function() {
|
context('and pad shortcut is disabled', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
makeSureShortcutIsDisabled('cmdShiftN');
|
makeSureShortcutIsDisabled('cmdShiftN');
|
||||||
triggerCtrlShiftShortcut('N');
|
triggerCtrlShiftShortcut('N');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not insert unordered list', function(done) {
|
it('does not insert unordered list', function (done) {
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(() => {
|
||||||
return helper.padInner$('div').first().find('ol li').length === 1;
|
expect().fail(() => 'Unordered list inserted, should ignore shortcut');
|
||||||
}).done(function() {
|
}).fail(() => {
|
||||||
expect().fail(function() { return 'Unordered list inserted, should ignore shortcut' });
|
|
||||||
}).fail(function() {
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when user presses Ctrl+Shift+1', function() {
|
context('when user presses Ctrl+Shift+1', function () {
|
||||||
context('and pad shortcut is enabled', function() {
|
context('and pad shortcut is enabled', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
makeSureShortcutIsEnabled('cmdShift1');
|
makeSureShortcutIsEnabled('cmdShift1');
|
||||||
triggerCtrlShiftShortcut('1');
|
triggerCtrlShiftShortcut('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts unordered list', function(done) {
|
it('inserts unordered list', function (done) {
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(done);
|
||||||
return helper.padInner$('div').first().find('ol li').length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and pad shortcut is disabled', function() {
|
context('and pad shortcut is disabled', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
makeSureShortcutIsDisabled('cmdShift1');
|
makeSureShortcutIsDisabled('cmdShift1');
|
||||||
triggerCtrlShiftShortcut('1');
|
triggerCtrlShiftShortcut('1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not insert unordered list', function(done) {
|
it('does not insert unordered list', function (done) {
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(() => {
|
||||||
return helper.padInner$('div').first().find('ol li').length === 1;
|
expect().fail(() => 'Unordered list inserted, should ignore shortcut');
|
||||||
}).done(function() {
|
}).fail(() => {
|
||||||
expect().fail(function() { return 'Unordered list inserted, should ignore shortcut' });
|
|
||||||
}).fail(function() {
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
xit("issue #1125 keeps the numbered list on enter for the new line - EMULATES PASTING INTO A PAD", function(done){
|
xit('issue #1125 keeps the numbered list on enter for the new line - EMULATES PASTING INTO A PAD', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
// type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
$firstTextElement.sendkeys('line 1');
|
$firstTextElement.sendkeys('line 1');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
$firstTextElement.sendkeys('line 2');
|
$firstTextElement.sendkeys('line 2');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text().indexOf('line 2') === -1).done(() => {
|
||||||
return inner$("div span").first().text().indexOf("line 2") === -1;
|
const $newSecondLine = inner$('div').first().next();
|
||||||
}).done(function(){
|
const hasOLElement = $newSecondLine.find('ol li').length === 1;
|
||||||
var $newSecondLine = inner$("div").first().next();
|
|
||||||
var hasOLElement = $newSecondLine.find("ol li").length === 1;
|
|
||||||
expect(hasOLElement).to.be(true);
|
expect(hasOLElement).to.be(true);
|
||||||
expect($newSecondLine.text()).to.be("line 2");
|
expect($newSecondLine.text()).to.be('line 2');
|
||||||
var hasLineNumber = $newSecondLine.find("ol").attr("start") === 2;
|
const hasLineNumber = $newSecondLine.find('ol').attr('start') === 2;
|
||||||
expect(hasLineNumber).to.be(true); // This doesn't work because pasting in content doesn't work
|
expect(hasLineNumber).to.be(true); // This doesn't work because pasting in content doesn't work
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var triggerCtrlShiftShortcut = function(shortcutChar) {
|
var triggerCtrlShiftShortcut = function (shortcutChar) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true;
|
e.ctrlKey = true;
|
||||||
e.shiftKey = true;
|
e.shiftKey = true;
|
||||||
e.which = shortcutChar.toString().charCodeAt(0);
|
e.which = shortcutChar.toString().charCodeAt(0);
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
}
|
};
|
||||||
|
|
||||||
var makeSureShortcutIsDisabled = function(shortcut) {
|
var makeSureShortcutIsDisabled = function (shortcut) {
|
||||||
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = false;
|
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = false;
|
||||||
}
|
};
|
||||||
var makeSureShortcutIsEnabled = function(shortcut) {
|
var makeSureShortcutIsEnabled = function (shortcut) {
|
||||||
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = true;
|
helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Pressing Tab in an OL increases and decreases indentation", function(){
|
describe('Pressing Tab in an OL increases and decreases indentation', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent and de-indent list item with keypress", function(done){
|
it('indent and de-indent list item with keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.keyCode = 9; // tab
|
e.keyCode = 9; // tab
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
expect(inner$("div").first().find(".list-number2").length === 1).to.be(true);
|
expect(inner$('div').first().find('.list-number2').length === 1).to.be(true);
|
||||||
e.shiftKey = true; // shift
|
e.shiftKey = true; // shift
|
||||||
e.keyCode = 9; // tab
|
e.keyCode = 9; // tab
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
|
||||||
return inner$("div").first().find(".list-number1").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
|
|
||||||
|
helper.waitFor(() => 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(){
|
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
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent and de-indent list item with indent button", function(done){
|
it('indent and de-indent list item with indent button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
const $indentButton = chrome$('.buttonicon-indent');
|
||||||
$indentButton.click(); // make it indented twice
|
$indentButton.click(); // make it indented twice
|
||||||
|
|
||||||
expect(inner$("div").first().find(".list-number2").length === 1).to.be(true);
|
expect(inner$('div').first().find('.list-number2').length === 1).to.be(true);
|
||||||
|
|
||||||
var $outdentButton = chrome$(".buttonicon-outdent");
|
const $outdentButton = chrome$('.buttonicon-outdent');
|
||||||
$outdentButton.click(); // make it deindented to 1
|
$outdentButton.click(); // make it deindented to 1
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('.list-number1').length === 1).done(done);
|
||||||
return inner$("div").first().find(".list-number1").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,36 +1,34 @@
|
||||||
describe('Pad modal', function() {
|
describe('Pad modal', function () {
|
||||||
context('when modal is a "force reconnect" message', function() {
|
context('when modal is a "force reconnect" message', function () {
|
||||||
var MODAL_SELECTOR = '#connectivity';
|
const MODAL_SELECTOR = '#connectivity';
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function (done) {
|
||||||
helper.newPad(function() {
|
helper.newPad(() => {
|
||||||
// force a "slowcommit" error
|
// force a "slowcommit" error
|
||||||
helper.padChrome$.window.pad.handleChannelStateChange('DISCONNECTED', 'slowcommit');
|
helper.padChrome$.window.pad.handleChannelStateChange('DISCONNECTED', 'slowcommit');
|
||||||
|
|
||||||
// wait for modal to be displayed
|
// wait for modal to be displayed
|
||||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
const $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => $modal.hasClass('popup-show'), 50000).done(done);
|
||||||
return $modal.hasClass('popup-show');
|
|
||||||
}, 50000).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disables editor', function(done) {
|
it('disables editor', function (done) {
|
||||||
expect(isEditorDisabled()).to.be(true);
|
expect(isEditorDisabled()).to.be(true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user clicks on editor', function() {
|
context('and user clicks on editor', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
clickOnPadInner();
|
clickOnPadInner();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not close the modal', function(done) {
|
it('does not close the modal', function (done) {
|
||||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
const $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||||
var modalIsVisible = $modal.hasClass('popup-show');
|
const modalIsVisible = $modal.hasClass('popup-show');
|
||||||
|
|
||||||
expect(modalIsVisible).to.be(true);
|
expect(modalIsVisible).to.be(true);
|
||||||
|
|
||||||
|
@ -38,14 +36,14 @@ describe('Pad modal', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user clicks on pad outer', function() {
|
context('and user clicks on pad outer', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
clickOnPadOuter();
|
clickOnPadOuter();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not close the modal', function(done) {
|
it('does not close the modal', function (done) {
|
||||||
var $modal = helper.padChrome$(MODAL_SELECTOR);
|
const $modal = helper.padChrome$(MODAL_SELECTOR);
|
||||||
var modalIsVisible = $modal.hasClass('popup-show');
|
const modalIsVisible = $modal.hasClass('popup-show');
|
||||||
|
|
||||||
expect(modalIsVisible).to.be(true);
|
expect(modalIsVisible).to.be(true);
|
||||||
|
|
||||||
|
@ -55,79 +53,77 @@ describe('Pad modal', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// we use "settings" here, but other modals have the same behaviour
|
// we use "settings" here, but other modals have the same behaviour
|
||||||
context('when modal is not an error message', function() {
|
context('when modal is not an error message', function () {
|
||||||
var MODAL_SELECTOR = '#settings';
|
const MODAL_SELECTOR = '#settings';
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function (done) {
|
||||||
helper.newPad(function() {
|
helper.newPad(() => {
|
||||||
openSettingsAndWaitForModalToBeVisible(done);
|
openSettingsAndWaitForModalToBeVisible(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
// This test breaks safari testing
|
// This test breaks safari testing
|
||||||
/*
|
/*
|
||||||
it('does not disable editor', function(done) {
|
it('does not disable editor', function(done) {
|
||||||
expect(isEditorDisabled()).to.be(false);
|
expect(isEditorDisabled()).to.be(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
context('and user clicks on editor', function() {
|
context('and user clicks on editor', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
clickOnPadInner();
|
clickOnPadInner();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('closes the modal', function(done) {
|
it('closes the modal', function (done) {
|
||||||
expect(isModalOpened(MODAL_SELECTOR)).to.be(false);
|
expect(isModalOpened(MODAL_SELECTOR)).to.be(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user clicks on pad outer', function() {
|
context('and user clicks on pad outer', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
clickOnPadOuter();
|
clickOnPadOuter();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('closes the modal', function(done) {
|
it('closes the modal', function (done) {
|
||||||
expect(isModalOpened(MODAL_SELECTOR)).to.be(false);
|
expect(isModalOpened(MODAL_SELECTOR)).to.be(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var clickOnPadInner = function() {
|
var clickOnPadInner = function () {
|
||||||
var $editor = helper.padInner$('#innerdocbody');
|
const $editor = helper.padInner$('#innerdocbody');
|
||||||
$editor.click();
|
$editor.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
var clickOnPadOuter = function() {
|
var clickOnPadOuter = function () {
|
||||||
var $lineNumbersColumn = helper.padOuter$('#sidedivinner');
|
const $lineNumbersColumn = helper.padOuter$('#sidedivinner');
|
||||||
$lineNumbersColumn.click();
|
$lineNumbersColumn.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
var openSettingsAndWaitForModalToBeVisible = function(done) {
|
var openSettingsAndWaitForModalToBeVisible = function (done) {
|
||||||
helper.padChrome$('.buttonicon-settings').click();
|
helper.padChrome$('.buttonicon-settings').click();
|
||||||
|
|
||||||
// wait for modal to be displayed
|
// wait for modal to be displayed
|
||||||
var modalSelector = '#settings';
|
const modalSelector = '#settings';
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => isModalOpened(modalSelector), 10000).done(done);
|
||||||
return isModalOpened(modalSelector);
|
};
|
||||||
}, 10000).done(done);
|
|
||||||
}
|
|
||||||
|
|
||||||
var isEditorDisabled = function() {
|
var isEditorDisabled = function () {
|
||||||
var editorDocument = helper.padOuter$("iframe[name='ace_inner']").get(0).contentDocument;
|
const editorDocument = helper.padOuter$("iframe[name='ace_inner']").get(0).contentDocument;
|
||||||
var editorBody = editorDocument.getElementById('innerdocbody');
|
const editorBody = editorDocument.getElementById('innerdocbody');
|
||||||
|
|
||||||
var editorIsDisabled = editorBody.contentEditable === 'false' // IE/Safari
|
const editorIsDisabled = editorBody.contentEditable === 'false' || // IE/Safari
|
||||||
|| editorDocument.designMode === 'off'; // other browsers
|
editorDocument.designMode === 'off'; // other browsers
|
||||||
|
|
||||||
return editorIsDisabled;
|
return editorIsDisabled;
|
||||||
}
|
};
|
||||||
|
|
||||||
var isModalOpened = function(modalSelector) {
|
var isModalOpened = function (modalSelector) {
|
||||||
var $modal = helper.padChrome$(modalSelector);
|
const $modal = helper.padChrome$(modalSelector);
|
||||||
|
|
||||||
return $modal.hasClass('popup-show');
|
return $modal.hasClass('popup-show');
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,68 +1,63 @@
|
||||||
describe("undo button then redo button", function(){
|
describe('undo button then redo button', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb); // creates a new pad
|
helper.newPad(cb); // creates a new pad
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("redo some typing with button", function(done){
|
it('redo some typing with button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// get the first text element inside the editable space
|
// get the first text element inside the editable space
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
var originalValue = $firstTextElement.text(); // get the original value
|
const originalValue = $firstTextElement.text(); // get the original value
|
||||||
var newString = "Foo";
|
const newString = 'Foo';
|
||||||
|
|
||||||
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
||||||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||||
|
|
||||||
// get undo and redo buttons
|
// get undo and redo buttons
|
||||||
var $undoButton = chrome$(".buttonicon-undo");
|
const $undoButton = chrome$('.buttonicon-undo');
|
||||||
var $redoButton = chrome$(".buttonicon-redo");
|
const $redoButton = chrome$('.buttonicon-redo');
|
||||||
// click the buttons
|
// click the buttons
|
||||||
$undoButton.click(); // removes foo
|
$undoButton.click(); // removes foo
|
||||||
$redoButton.click(); // resends foo
|
$redoButton.click(); // resends foo
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text() === newString).done(() => {
|
||||||
return inner$("div span").first().text() === newString;
|
const finalValue = inner$('div').first().text();
|
||||||
}).done(function(){
|
|
||||||
var finalValue = inner$("div").first().text();
|
|
||||||
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("redo some typing with keypress", function(done){
|
it('redo some typing with keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// get the first text element inside the editable space
|
// get the first text element inside the editable space
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
var originalValue = $firstTextElement.text(); // get the original value
|
const originalValue = $firstTextElement.text(); // get the original value
|
||||||
var newString = "Foo";
|
const newString = 'Foo';
|
||||||
|
|
||||||
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
$firstTextElement.sendkeys(newString); // send line 1 to the pad
|
||||||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
var e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 90; // z
|
e.which = 90; // z
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
var e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 121; // y
|
e.which = 121; // y
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text() === newString).done(() => {
|
||||||
return inner$("div span").first().text() === newString;
|
const finalValue = inner$('div').first().text();
|
||||||
}).done(function(){
|
|
||||||
var finalValue = inner$("div").first().text();
|
|
||||||
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
expect(finalValue).to.be(modifiedValue); // expect the value to change
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
// Adapted from John McLear's original test case.
|
// Adapted from John McLear's original test case.
|
||||||
|
|
||||||
xdescribe('Responsiveness of Editor', function() {
|
xdescribe('Responsiveness of Editor', function () {
|
||||||
// create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb) {
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(6000);
|
this.timeout(6000);
|
||||||
});
|
});
|
||||||
|
@ -23,67 +23,62 @@ xdescribe('Responsiveness of Editor', function() {
|
||||||
// And the test needs to be fixed to work in Firefox 52 on Windows 7. I am not sure why it fails on this specific platform
|
// And the test needs to be fixed to work in Firefox 52 on Windows 7. I am not sure why it fails on this specific platform
|
||||||
// The errors show this.timeout... then crash the browser but I am sure something is actually causing the stack trace and
|
// The errors show this.timeout... then crash the browser but I am sure something is actually causing the stack trace and
|
||||||
// I just need to narrow down what, offers to help accepted.
|
// I just need to narrow down what, offers to help accepted.
|
||||||
it('Fast response to keypress in pad with large amount of contents', function(done) {
|
it('Fast response to keypress in pad with large amount of contents', function (done) {
|
||||||
|
// skip on Windows Firefox 52.0
|
||||||
//skip on Windows Firefox 52.0
|
if (window.bowser && window.bowser.windows && window.bowser.firefox && window.bowser.version == '52.0') {
|
||||||
if(window.bowser && window.bowser.windows && window.bowser.firefox && window.bowser.version == "52.0") {
|
|
||||||
this.skip();
|
this.skip();
|
||||||
}
|
}
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var chars = '0000000000'; // row of placeholder chars
|
const chars = '0000000000'; // row of placeholder chars
|
||||||
var amount = 200000; //number of blocks of chars we will insert
|
const amount = 200000; // number of blocks of chars we will insert
|
||||||
var length = (amount * (chars.length) +1); // include a counter for each space
|
const length = (amount * (chars.length) + 1); // include a counter for each space
|
||||||
var text = ''; // the text we're gonna insert
|
let text = ''; // the text we're gonna insert
|
||||||
this.timeout(amount * 150); // Changed from 100 to 150 to allow Mac OSX Safari to be slow.
|
this.timeout(amount * 150); // Changed from 100 to 150 to allow Mac OSX Safari to be slow.
|
||||||
|
|
||||||
// get keys to send
|
// get keys to send
|
||||||
var keyMultiplier = 10; // multiplier * 10 == total number of key events
|
const keyMultiplier = 10; // multiplier * 10 == total number of key events
|
||||||
var keysToSend = '';
|
let keysToSend = '';
|
||||||
for(var i=0; i <= keyMultiplier; i++) {
|
for (var i = 0; i <= keyMultiplier; i++) {
|
||||||
keysToSend += chars;
|
keysToSend += chars;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textElement = inner$('div');
|
const textElement = inner$('div');
|
||||||
textElement.sendkeys('{selectall}'); // select all
|
textElement.sendkeys('{selectall}'); // select all
|
||||||
textElement.sendkeys('{del}'); // clear the pad text
|
textElement.sendkeys('{del}'); // clear the pad text
|
||||||
|
|
||||||
for(var i=0; i <= amount; i++) {
|
for (var i = 0; i <= amount; i++) {
|
||||||
text = text + chars + ' '; // add the chars and space to the text contents
|
text = `${text + chars} `; // add the chars and space to the text contents
|
||||||
}
|
}
|
||||||
inner$('div').first().text(text); // Put the text contents into the pad
|
inner$('div').first().text(text); // Put the text contents into the pad
|
||||||
|
|
||||||
helper.waitFor(function(){ // Wait for the new contents to be on the pad
|
helper.waitFor(() => // Wait for the new contents to be on the pad
|
||||||
return inner$('div').text().length > length;
|
inner$('div').text().length > length,
|
||||||
}).done(function(){
|
).done(() => {
|
||||||
|
expect(inner$('div').text().length).to.be.greaterThan(length); // has the text changed?
|
||||||
expect( inner$('div').text().length ).to.be.greaterThan( length ); // has the text changed?
|
const start = Date.now(); // 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)
|
// send some new text to the screen (ensure all 3 key events are sent)
|
||||||
var el = inner$('div').first();
|
const el = inner$('div').first();
|
||||||
for(var i = 0; i < keysToSend.length; ++i) {
|
for (let i = 0; i < keysToSend.length; ++i) {
|
||||||
var x = keysToSend.charCodeAt(i);
|
var x = keysToSend.charCodeAt(i);
|
||||||
['keyup', 'keypress', 'keydown'].forEach(function(type) {
|
['keyup', 'keypress', 'keydown'].forEach((type) => {
|
||||||
var e = $.Event(type);
|
const e = $.Event(type);
|
||||||
e.keyCode = x;
|
e.keyCode = x;
|
||||||
el.trigger(e);
|
el.trigger(e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
helper.waitFor(function(){ // Wait for the ability to process
|
helper.waitFor(() => { // Wait for the ability to process
|
||||||
var el = inner$('body');
|
const el = inner$('body');
|
||||||
if(el[0].textContent.length > amount) return true;
|
if (el[0].textContent.length > amount) return true;
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
var end = Date.now(); // get the current time
|
const end = Date.now(); // get the current time
|
||||||
var delay = end - start; // get the delay as the current time minus the start time
|
const delay = end - start; // get the delay as the current time minus the start time
|
||||||
|
|
||||||
expect(delay).to.be.below(600);
|
expect(delay).to.be.below(600);
|
||||||
done();
|
done();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
}, 10000);
|
}, 10000);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,105 +1,101 @@
|
||||||
describe("select formatting buttons when selection has style applied", function(){
|
describe('select formatting buttons when selection has style applied', function () {
|
||||||
var STYLES = ['italic', 'bold', 'underline', 'strikethrough'];
|
const STYLES = ['italic', 'bold', 'underline', 'strikethrough'];
|
||||||
var SHORTCUT_KEYS = ['I', 'B', 'U', '5']; // italic, bold, underline, strikethrough
|
const SHORTCUT_KEYS = ['I', 'B', 'U', '5']; // italic, bold, underline, strikethrough
|
||||||
var FIRST_LINE = 0;
|
const FIRST_LINE = 0;
|
||||||
|
|
||||||
before(function(cb){
|
before(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
var applyStyleOnLine = function(style, line) {
|
const applyStyleOnLine = function (style, line) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
selectLine(line);
|
selectLine(line);
|
||||||
var $formattingButton = chrome$('.buttonicon-' + style);
|
const $formattingButton = chrome$(`.buttonicon-${style}`);
|
||||||
$formattingButton.click();
|
$formattingButton.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
var isButtonSelected = function(style) {
|
const isButtonSelected = function (style) {
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var $formattingButton = chrome$('.buttonicon-' + style);
|
const $formattingButton = chrome$(`.buttonicon-${style}`);
|
||||||
return $formattingButton.parent().hasClass('selected');
|
return $formattingButton.parent().hasClass('selected');
|
||||||
}
|
};
|
||||||
|
|
||||||
var selectLine = function(lineNumber, offsetStart, offsetEnd) {
|
var selectLine = function (lineNumber, offsetStart, offsetEnd) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var $line = inner$("div").eq(lineNumber);
|
const $line = inner$('div').eq(lineNumber);
|
||||||
helper.selectLines($line, $line, offsetStart, offsetEnd);
|
helper.selectLines($line, $line, offsetStart, offsetEnd);
|
||||||
}
|
};
|
||||||
|
|
||||||
var placeCaretOnLine = function(lineNumber) {
|
const placeCaretOnLine = function (lineNumber) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var $line = inner$("div").eq(lineNumber);
|
const $line = inner$('div').eq(lineNumber);
|
||||||
$line.sendkeys('{leftarrow}');
|
$line.sendkeys('{leftarrow}');
|
||||||
}
|
};
|
||||||
|
|
||||||
var undo = function() {
|
const undo = function () {
|
||||||
var $undoButton = helper.padChrome$(".buttonicon-undo");
|
const $undoButton = helper.padChrome$('.buttonicon-undo');
|
||||||
$undoButton.click();
|
$undoButton.click();
|
||||||
}
|
};
|
||||||
|
|
||||||
var testIfFormattingButtonIsDeselected = function(style) {
|
const testIfFormattingButtonIsDeselected = function (style) {
|
||||||
it('deselects the ' + style + ' button', function(done) {
|
it(`deselects the ${style} button`, function (done) {
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => isButtonSelected(style) === false).done(done);
|
||||||
return isButtonSelected(style) === false;
|
|
||||||
}).done(done)
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
var testIfFormattingButtonIsSelected = function(style) {
|
const testIfFormattingButtonIsSelected = function (style) {
|
||||||
it('selects the ' + style + ' button', function(done) {
|
it(`selects the ${style} button`, function (done) {
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => isButtonSelected(style)).done(done);
|
||||||
return isButtonSelected(style);
|
|
||||||
}).done(done)
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
var applyStyleOnLineAndSelectIt = function(line, style, cb) {
|
const applyStyleOnLineAndSelectIt = function (line, style, cb) {
|
||||||
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, selectLine, cb);
|
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, selectLine, cb);
|
||||||
}
|
};
|
||||||
|
|
||||||
var applyStyleOnLineAndPlaceCaretOnit = function(line, style, cb) {
|
const applyStyleOnLineAndPlaceCaretOnit = function (line, style, cb) {
|
||||||
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, placeCaretOnLine, cb);
|
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, placeCaretOnLine, cb);
|
||||||
}
|
};
|
||||||
|
|
||||||
var applyStyleOnLineOnFullLineAndRemoveSelection = function(line, style, selectTarget, cb) {
|
var applyStyleOnLineOnFullLineAndRemoveSelection = function (line, style, selectTarget, cb) {
|
||||||
// see if line html has changed
|
// see if line html has changed
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var oldLineHTML = inner$.find("div")[line];
|
const oldLineHTML = inner$.find('div')[line];
|
||||||
applyStyleOnLine(style, line);
|
applyStyleOnLine(style, line);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var lineHTML = inner$.find("div")[line];
|
const lineHTML = inner$.find('div')[line];
|
||||||
return lineHTML !== oldLineHTML;
|
return lineHTML !== oldLineHTML;
|
||||||
});
|
});
|
||||||
// remove selection from previous line
|
// remove selection from previous line
|
||||||
selectLine(line + 1);
|
selectLine(line + 1);
|
||||||
//setTimeout(function() {
|
// setTimeout(function() {
|
||||||
// select the text or place the caret on a position that
|
// select the text or place the caret on a position that
|
||||||
// has the formatting text applied previously
|
// has the formatting text applied previously
|
||||||
selectTarget(line);
|
selectTarget(line);
|
||||||
cb();
|
cb();
|
||||||
//}, 1000);
|
// }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
var pressFormattingShortcutOnSelection = function(key) {
|
const pressFormattingShortcutOnSelection = function (key) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = key.charCodeAt(0); // I, U, B, 5
|
e.which = key.charCodeAt(0); // I, U, B, 5
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
}
|
};
|
||||||
|
|
||||||
STYLES.forEach(function(style){
|
STYLES.forEach((style) => {
|
||||||
context('when selection is in a text with ' + style + ' applied', function(){
|
context(`when selection is in a text with ${style} applied`, function () {
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
this.timeout(4000);
|
this.timeout(4000);
|
||||||
applyStyleOnLineAndSelectIt(FIRST_LINE, style, done);
|
applyStyleOnLineAndSelectIt(FIRST_LINE, style, done);
|
||||||
|
@ -112,7 +108,7 @@ describe("select formatting buttons when selection has style applied", function(
|
||||||
testIfFormattingButtonIsSelected(style);
|
testIfFormattingButtonIsSelected(style);
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when caret is in a position with ' + style + ' applied', function(){
|
context(`when caret is in a position with ${style} applied`, function () {
|
||||||
before(function (done) {
|
before(function (done) {
|
||||||
this.timeout(4000);
|
this.timeout(4000);
|
||||||
applyStyleOnLineAndPlaceCaretOnit(FIRST_LINE, style, done);
|
applyStyleOnLineAndPlaceCaretOnit(FIRST_LINE, style, done);
|
||||||
|
@ -122,12 +118,12 @@ describe("select formatting buttons when selection has style applied", function(
|
||||||
undo();
|
undo();
|
||||||
});
|
});
|
||||||
|
|
||||||
testIfFormattingButtonIsSelected(style)
|
testIfFormattingButtonIsSelected(style);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('when user applies a style and the selection does not change', function() {
|
context('when user applies a style and the selection does not change', function () {
|
||||||
var style = STYLES[0]; // italic
|
const style = STYLES[0]; // italic
|
||||||
before(function () {
|
before(function () {
|
||||||
applyStyleOnLine(style, FIRST_LINE);
|
applyStyleOnLine(style, FIRST_LINE);
|
||||||
});
|
});
|
||||||
|
@ -143,16 +139,16 @@ describe("select formatting buttons when selection has style applied", function(
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
SHORTCUT_KEYS.forEach(function(key, index){
|
SHORTCUT_KEYS.forEach((key, index) => {
|
||||||
var styleOfTheShortcut = STYLES[index]; // italic, bold, ...
|
const styleOfTheShortcut = STYLES[index]; // italic, bold, ...
|
||||||
context('when user presses CMD + ' + key, function() {
|
context(`when user presses CMD + ${key}`, function () {
|
||||||
before(function () {
|
before(function () {
|
||||||
pressFormattingShortcutOnSelection(key);
|
pressFormattingShortcutOnSelection(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
testIfFormattingButtonIsSelected(styleOfTheShortcut);
|
testIfFormattingButtonIsSelected(styleOfTheShortcut);
|
||||||
|
|
||||||
context('and user presses CMD + ' + key + ' again', function() {
|
context(`and user presses CMD + ${key} again`, function () {
|
||||||
before(function () {
|
before(function () {
|
||||||
pressFormattingShortcutOnSelection(key);
|
pressFormattingShortcutOnSelection(key);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
describe("strikethrough button", function(){
|
describe('strikethrough button', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("makes text strikethrough", function(done) {
|
it('makes text strikethrough', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
//get the strikethrough button and click it
|
// get the strikethrough button and click it
|
||||||
var $strikethroughButton = chrome$(".buttonicon-strikethrough");
|
const $strikethroughButton = chrome$('.buttonicon-strikethrough');
|
||||||
$strikethroughButton.click();
|
$strikethroughButton.click();
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
// ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var $newFirstTextElement = inner$("div").first();
|
const $newFirstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// is there a <i> element now?
|
// is there a <i> element now?
|
||||||
var isstrikethrough = $newFirstTextElement.find("s").length === 1;
|
const isstrikethrough = $newFirstTextElement.find('s').length === 1;
|
||||||
|
|
||||||
//expect it to be strikethrough
|
// expect it to be strikethrough
|
||||||
expect(isstrikethrough).to.be(true);
|
expect(isstrikethrough).to.be(true);
|
||||||
|
|
||||||
//make sure the text hasn't changed
|
// make sure the text hasn't changed
|
||||||
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
expect($newFirstTextElement.text()).to.eql($firstTextElement.text());
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -1,47 +1,42 @@
|
||||||
//deactivated, we need a nice way to get the timeslider, this is ugly
|
// deactivated, we need a nice way to get the timeslider, this is ugly
|
||||||
xdescribe("timeslider button takes you to the timeslider of a pad", function(){
|
xdescribe('timeslider button takes you to the timeslider of a pad', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb); // creates a new pad
|
helper.newPad(cb); // creates a new pad
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("timeslider contained in URL", function(done){
|
it('timeslider contained in URL', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// get the first text element inside the editable space
|
// get the first text element inside the editable space
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
var originalValue = $firstTextElement.text(); // get the original value
|
const originalValue = $firstTextElement.text(); // get the original value
|
||||||
var newValue = "Testing"+originalValue;
|
const newValue = `Testing${originalValue}`;
|
||||||
$firstTextElement.sendkeys("Testing"); // send line 1 to the pad
|
$firstTextElement.sendkeys('Testing'); // send line 1 to the pad
|
||||||
|
|
||||||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => modifiedValue !== originalValue, // The value has changed so we can..
|
||||||
return modifiedValue !== originalValue; // The value has changed so we can..
|
).done(() => {
|
||||||
}).done(function(){
|
const $timesliderButton = chrome$('#timesliderlink');
|
||||||
|
|
||||||
var $timesliderButton = chrome$("#timesliderlink");
|
|
||||||
$timesliderButton.click(); // So click the timeslider link
|
$timesliderButton.click(); // So click the timeslider link
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var iFrameURL = chrome$.window.location.href;
|
const iFrameURL = chrome$.window.location.href;
|
||||||
if(iFrameURL){
|
if (iFrameURL) {
|
||||||
return iFrameURL.indexOf("timeslider") !== -1;
|
return iFrameURL.indexOf('timeslider') !== -1;
|
||||||
}else{
|
} else {
|
||||||
return false; // the URL hasnt been set yet
|
return false; // the URL hasnt been set yet
|
||||||
}
|
}
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
// click the buttons
|
// click the buttons
|
||||||
var iFrameURL = chrome$.window.location.href; // get the url
|
const iFrameURL = chrome$.window.location.href; // get the url
|
||||||
var inTimeslider = iFrameURL.indexOf("timeslider") !== -1;
|
const inTimeslider = iFrameURL.indexOf('timeslider') !== -1;
|
||||||
expect(inTimeslider).to.be(true); // expect the value to change
|
expect(inTimeslider).to.be(true); // expect the value to change
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
describe("timeslider follow", function(){
|
describe('timeslider follow', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("content as it's added to timeslider", async function() {
|
it("content as it's added to timeslider", async function () {
|
||||||
// send 6 revisions
|
// send 6 revisions
|
||||||
let revs = 6;
|
const revs = 6;
|
||||||
let message = 'a\n\n\n\n\n\n\n\n\n\n';
|
const message = 'a\n\n\n\n\n\n\n\n\n\n';
|
||||||
let newLines = message.split('\n').length
|
const newLines = message.split('\n').length;
|
||||||
for (let i=0;i<revs;i++){
|
for (let i = 0; i < revs; i++) {
|
||||||
await helper.edit(message, newLines*i + 1);
|
await helper.edit(message, newLines * i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await helper.gotoTimeslider(0);
|
await helper.gotoTimeslider(0);
|
||||||
await helper.waitForPromise(function(){return helper.contentWindow().location.hash === '#0'})
|
await helper.waitForPromise(() => helper.contentWindow().location.hash === '#0');
|
||||||
|
|
||||||
let originalTop = helper.contentWindow().$('#innerdocbody').offset();
|
const originalTop = helper.contentWindow().$('#innerdocbody').offset();
|
||||||
|
|
||||||
// set to follow contents as it arrives
|
// set to follow contents as it arrives
|
||||||
helper.contentWindow().$('#options-followContents').prop("checked", true);
|
helper.contentWindow().$('#options-followContents').prop('checked', true);
|
||||||
helper.contentWindow().$('#playpause_button_icon').click();
|
helper.contentWindow().$('#playpause_button_icon').click();
|
||||||
|
|
||||||
let newTop;
|
let newTop;
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => {
|
||||||
newTop = helper.contentWindow().$('#innerdocbody').offset();
|
newTop = helper.contentWindow().$('#innerdocbody').offset();
|
||||||
return newTop.top < originalTop.top;
|
return newTop.top < originalTop.top;
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,31 +35,28 @@ describe("timeslider follow", function(){
|
||||||
* the change is applied.
|
* the change is applied.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
it("only to lines that exist in the current pad view, see #4389", async function(){
|
it('only to lines that exist in the current pad view, see #4389', async function () {
|
||||||
// Select everything and clear via delete key
|
// Select everything and clear via delete key
|
||||||
let e = helper.padInner$.Event(helper.evtType);
|
const e = helper.padInner$.Event(helper.evtType);
|
||||||
e.keyCode = 8; //delete key
|
e.keyCode = 8; // delete key
|
||||||
let lines = helper.linesDiv();
|
const lines = helper.linesDiv();
|
||||||
helper.selectLines(lines[0], lines[lines.length - 1]); // select all lines
|
helper.selectLines(lines[0], lines[lines.length - 1]); // select all lines
|
||||||
// probably unnecessary, but wait for the selection to be Range not Caret
|
// probably unnecessary, but wait for the selection to be Range not Caret
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => !helper.padInner$.document.getSelection().isCollapsed,
|
||||||
return !helper.padInner$.document.getSelection().isCollapsed;
|
// only supported in FF57+
|
||||||
//only supported in FF57+
|
// return helper.padInner$.document.getSelection().type === 'Range';
|
||||||
//return helper.padInner$.document.getSelection().type === 'Range';
|
);
|
||||||
})
|
|
||||||
helper.padInner$('#innerdocbody').trigger(e);
|
helper.padInner$('#innerdocbody').trigger(e);
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => helper.commits.length === 1);
|
||||||
return helper.commits.length === 1;
|
await helper.edit('Test line\n\n');
|
||||||
})
|
await helper.edit('Another test line', 3);
|
||||||
await helper.edit("Test line\n\n")
|
|
||||||
await helper.edit("Another test line", 3)
|
|
||||||
|
|
||||||
await helper.gotoTimeslider();
|
await helper.gotoTimeslider();
|
||||||
|
|
||||||
// set to follow contents as it arrives
|
// set to follow contents as it arrives
|
||||||
helper.contentWindow().$('#options-followContents').prop("checked", true);
|
helper.contentWindow().$('#options-followContents').prop('checked', true);
|
||||||
|
|
||||||
let oldYPosition = helper.contentWindow().$("#editorcontainerbox")[0].scrollTop;
|
const oldYPosition = helper.contentWindow().$('#editorcontainerbox')[0].scrollTop;
|
||||||
expect(oldYPosition).to.be(0);
|
expect(oldYPosition).to.be(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,50 +68,37 @@ describe("timeslider follow", function(){
|
||||||
|
|
||||||
// line 3 changed
|
// line 3 changed
|
||||||
helper.contentWindow().$('#leftstep').click();
|
helper.contentWindow().$('#leftstep').click();
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => hasFollowedToLine(3));
|
||||||
return hasFollowedToLine(3);
|
|
||||||
})
|
|
||||||
|
|
||||||
// line 1 is the first line that changed
|
// line 1 is the first line that changed
|
||||||
helper.contentWindow().$('#leftstep').click();
|
helper.contentWindow().$('#leftstep').click();
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||||
return hasFollowedToLine(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
// line 1 changed
|
// line 1 changed
|
||||||
helper.contentWindow().$('#leftstep').click();
|
helper.contentWindow().$('#leftstep').click();
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||||
return hasFollowedToLine(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
// line 1 changed
|
// line 1 changed
|
||||||
helper.contentWindow().$('#rightstep').click();
|
helper.contentWindow().$('#rightstep').click();
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||||
return hasFollowedToLine(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
// line 1 is the first line that changed
|
// line 1 is the first line that changed
|
||||||
helper.contentWindow().$('#rightstep').click();
|
helper.contentWindow().$('#rightstep').click();
|
||||||
await helper.waitForPromise(function(){
|
await helper.waitForPromise(() => hasFollowedToLine(1));
|
||||||
return hasFollowedToLine(1);
|
|
||||||
})
|
|
||||||
|
|
||||||
// line 3 changed
|
// line 3 changed
|
||||||
helper.contentWindow().$('#rightstep').click();
|
helper.contentWindow().$('#rightstep').click();
|
||||||
return helper.waitForPromise(function(){
|
return helper.waitForPromise(() => hasFollowedToLine(3));
|
||||||
return hasFollowedToLine(3);
|
});
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} lineNum
|
* @param {number} lineNum
|
||||||
* @returns {boolean} scrolled to the lineOffset?
|
* @returns {boolean} scrolled to the lineOffset?
|
||||||
*/
|
*/
|
||||||
function hasFollowedToLine(lineNum) {
|
function hasFollowedToLine(lineNum) {
|
||||||
let scrollPosition = helper.contentWindow().$("#editorcontainerbox")[0].scrollTop;
|
const scrollPosition = helper.contentWindow().$('#editorcontainerbox')[0].scrollTop;
|
||||||
let lineOffset = helper.contentWindow().$('#innerdocbody').find(`div:nth-child(${lineNum})`)[0].offsetTop;
|
const lineOffset = helper.contentWindow().$('#innerdocbody').find(`div:nth-child(${lineNum})`)[0].offsetTop;
|
||||||
|
|
||||||
return Math.abs(scrollPosition - lineOffset) < 1;
|
return Math.abs(scrollPosition - lineOffset) < 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
describe("timeslider", function(){
|
describe('timeslider', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo test authorsList
|
* @todo test authorsList
|
||||||
*/
|
*/
|
||||||
it("Shows a date and time in the timeslider and make sure it doesn't include NaN", async function() {
|
it("Shows a date and time in the timeslider and make sure it doesn't include NaN", async function () {
|
||||||
// make some changes to produce 3 revisions
|
// make some changes to produce 3 revisions
|
||||||
let revs = 3;
|
const revs = 3;
|
||||||
|
|
||||||
for(let i=0; i < revs; i++) {
|
for (let i = 0; i < revs; i++) {
|
||||||
await helper.edit('a\n');
|
await helper.edit('a\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
await helper.gotoTimeslider(revs);
|
await helper.gotoTimeslider(revs);
|
||||||
await helper.waitForPromise(function(){return helper.contentWindow().location.hash === '#'+revs})
|
await helper.waitForPromise(() => helper.contentWindow().location.hash === `#${revs}`);
|
||||||
|
|
||||||
// the datetime of last edit
|
// the datetime of last edit
|
||||||
let timerTimeLast = new Date(helper.timesliderTimerTime()).getTime();
|
const timerTimeLast = new Date(helper.timesliderTimerTime()).getTime();
|
||||||
|
|
||||||
// the day of this revision, e.g. August 12, 2020 (stripped the string "Saved")
|
// the day of this revision, e.g. August 12, 2020 (stripped the string "Saved")
|
||||||
let dateLast = new Date(helper.revisionDateElem().substr(6)).getTime();
|
const dateLast = new Date(helper.revisionDateElem().substr(6)).getTime();
|
||||||
|
|
||||||
// the label/revision, ie Version 3
|
// the label/revision, ie Version 3
|
||||||
let labelLast = helper.revisionLabelElem().text();
|
const labelLast = helper.revisionLabelElem().text();
|
||||||
|
|
||||||
// the datetime should be a date
|
// the datetime should be a date
|
||||||
expect( Number.isNaN(timerTimeLast)).to.eql(false);
|
expect(Number.isNaN(timerTimeLast)).to.eql(false);
|
||||||
|
|
||||||
// the Date object of the day should not be NaN
|
// the Date object of the day should not be NaN
|
||||||
expect( Number.isNaN(dateLast) ).to.eql(false)
|
expect(Number.isNaN(dateLast)).to.eql(false);
|
||||||
|
|
||||||
// the label should be Version `Number`
|
// the label should be Version `Number`
|
||||||
expect(labelLast).to.be(`Version ${revs}`);
|
expect(labelLast).to.be(`Version ${revs}`);
|
||||||
|
@ -40,23 +40,23 @@ describe("timeslider", function(){
|
||||||
helper.sliderClick(1);
|
helper.sliderClick(1);
|
||||||
|
|
||||||
// the datetime of last edit
|
// the datetime of last edit
|
||||||
let timerTime = new Date(helper.timesliderTimerTime()).getTime();
|
const timerTime = new Date(helper.timesliderTimerTime()).getTime();
|
||||||
|
|
||||||
// the day of this revision, e.g. August 12, 2020
|
// the day of this revision, e.g. August 12, 2020
|
||||||
let date = new Date(helper.revisionDateElem().substr(6)).getTime();
|
const date = new Date(helper.revisionDateElem().substr(6)).getTime();
|
||||||
|
|
||||||
// the label/revision, e.g. Version 0
|
// the label/revision, e.g. Version 0
|
||||||
let label = helper.revisionLabelElem().text();
|
const label = helper.revisionLabelElem().text();
|
||||||
|
|
||||||
// the datetime should be a date
|
// the datetime should be a date
|
||||||
expect( Number.isNaN(timerTime)).to.eql(false);
|
expect(Number.isNaN(timerTime)).to.eql(false);
|
||||||
// the last revision should be newer or have the same time
|
// the last revision should be newer or have the same time
|
||||||
expect(timerTimeLast).to.not.be.lessThan(timerTime);
|
expect(timerTimeLast).to.not.be.lessThan(timerTime);
|
||||||
|
|
||||||
// the Date object of the day should not be NaN
|
// the Date object of the day should not be NaN
|
||||||
expect( Number.isNaN(date) ).to.eql(false)
|
expect(Number.isNaN(date)).to.eql(false);
|
||||||
|
|
||||||
// the label should be Version 0
|
// the label should be Version 0
|
||||||
expect( label ).to.be('Version 0');
|
expect(label).to.be('Version 0');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
describe("timeslider", function(){
|
describe('timeslider', function () {
|
||||||
var padId = 735773577357+(Math.round(Math.random()*1000));
|
const padId = 735773577357 + (Math.round(Math.random() * 1000));
|
||||||
|
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb, padId);
|
helper.newPad(cb, padId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Makes sure the export URIs are as expected when the padID is numeric", async function() {
|
it('Makes sure the export URIs are as expected when the padID is numeric', async function () {
|
||||||
await helper.edit('a\n');
|
await helper.edit('a\n');
|
||||||
|
|
||||||
await helper.gotoTimeslider(1);
|
await helper.gotoTimeslider(1);
|
||||||
|
|
||||||
// ensure we are on revision 1
|
// ensure we are on revision 1
|
||||||
await helper.waitForPromise(function(){return helper.contentWindow().location.hash === '#1'})
|
await helper.waitForPromise(() => helper.contentWindow().location.hash === '#1');
|
||||||
|
|
||||||
// expect URI to be similar to
|
// expect URI to be similar to
|
||||||
// http://192.168.1.48:9001/p/2/1/export/html
|
// http://192.168.1.48:9001/p/2/1/export/html
|
||||||
// http://192.168.1.48:9001/p/735773577399/1/export/html
|
// http://192.168.1.48:9001/p/735773577399/1/export/html
|
||||||
let rev1ExportLink = helper.contentWindow().$('#exporthtmla').attr('href');
|
const rev1ExportLink = helper.contentWindow().$('#exporthtmla').attr('href');
|
||||||
expect(rev1ExportLink).to.contain('/1/export/html');
|
expect(rev1ExportLink).to.contain('/1/export/html');
|
||||||
|
|
||||||
// Click somewhere left on the timeslider to go to revision 0
|
// Click somewhere left on the timeslider to go to revision 0
|
||||||
helper.sliderClick(30);
|
helper.sliderClick(30);
|
||||||
|
|
||||||
let rev0ExportLink = helper.contentWindow().$('#exporthtmla').attr('href');
|
const rev0ExportLink = helper.contentWindow().$('#exporthtmla').attr('href');
|
||||||
expect(rev0ExportLink).to.contain('/0/export/html');
|
expect(rev0ExportLink).to.contain('/0/export/html');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
describe("timeslider", function(){
|
describe('timeslider', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("loads adds a hundred revisions", function(done) { // passes
|
it('loads adds a hundred revisions', function (done) { // passes
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// make some changes to produce 100 revisions
|
// make some changes to produce 100 revisions
|
||||||
var timePerRev = 900
|
const timePerRev = 900;
|
||||||
, revs = 99;
|
const revs = 99;
|
||||||
this.timeout(revs*timePerRev+10000);
|
this.timeout(revs * timePerRev + 10000);
|
||||||
for(var i=0; i < revs; i++) {
|
for (let i = 0; i < revs; i++) {
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// enter 'a' in the first text element
|
// enter 'a' in the first text element
|
||||||
inner$("div").first().sendkeys('a');
|
inner$('div').first().sendkeys('a');
|
||||||
}, timePerRev*i);
|
}, timePerRev * i);
|
||||||
}
|
}
|
||||||
chrome$('.buttonicon-savedRevision').click();
|
chrome$('.buttonicon-savedRevision').click();
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// go to timeslider
|
// go to timeslider
|
||||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
$('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider`);
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
const timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
const $sliderBar = timeslider$('#ui-slider-bar');
|
||||||
|
|
||||||
var latestContents = timeslider$('#innerdocbody').text();
|
const latestContents = timeslider$('#innerdocbody').text();
|
||||||
|
|
||||||
// Click somewhere on the timeslider
|
// Click somewhere on the timeslider
|
||||||
var e = new jQuery.Event('mousedown');
|
let e = new jQuery.Event('mousedown');
|
||||||
// sets y co-ordinate of the pad slider modal.
|
// sets y co-ordinate of the pad slider modal.
|
||||||
var base = (timeslider$('#ui-slider-bar').offset().top - 24)
|
const base = (timeslider$('#ui-slider-bar').offset().top - 24);
|
||||||
e.clientX = e.pageX = 150;
|
e.clientX = e.pageX = 150;
|
||||||
e.clientY = e.pageY = base+5;
|
e.clientY = e.pageY = base + 5;
|
||||||
$sliderBar.trigger(e);
|
$sliderBar.trigger(e);
|
||||||
|
|
||||||
e = new jQuery.Event('mousedown');
|
e = new jQuery.Event('mousedown');
|
||||||
|
@ -46,134 +46,127 @@ describe("timeslider", function(){
|
||||||
|
|
||||||
e = new jQuery.Event('mousedown');
|
e = new jQuery.Event('mousedown');
|
||||||
e.clientX = e.pageX = 150;
|
e.clientX = e.pageX = 150;
|
||||||
e.clientY = e.pageY = base-5;
|
e.clientY = e.pageY = base - 5;
|
||||||
$sliderBar.trigger(e);
|
$sliderBar.trigger(e);
|
||||||
|
|
||||||
$sliderBar.trigger('mouseup')
|
$sliderBar.trigger('mouseup');
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
//make sure the text has changed
|
// make sure the text has changed
|
||||||
expect( timeslider$('#innerdocbody').text() ).not.to.eql( latestContents );
|
expect(timeslider$('#innerdocbody').text()).not.to.eql(latestContents);
|
||||||
var starIsVisible = timeslider$('.star').is(":visible");
|
const starIsVisible = timeslider$('.star').is(':visible');
|
||||||
expect( starIsVisible ).to.eql( true );
|
expect(starIsVisible).to.eql(true);
|
||||||
done();
|
done();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
}, 6000);
|
}, 6000);
|
||||||
}, revs*timePerRev);
|
}, revs * timePerRev);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Disabled as jquery trigger no longer works properly
|
// Disabled as jquery trigger no longer works properly
|
||||||
xit("changes the url when clicking on the timeslider", function(done) {
|
xit('changes the url when clicking on the timeslider', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// make some changes to produce 7 revisions
|
// make some changes to produce 7 revisions
|
||||||
var timePerRev = 1000
|
const timePerRev = 1000;
|
||||||
, revs = 20;
|
const revs = 20;
|
||||||
this.timeout(revs*timePerRev+10000);
|
this.timeout(revs * timePerRev + 10000);
|
||||||
for(var i=0; i < revs; i++) {
|
for (let i = 0; i < revs; i++) {
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// enter 'a' in the first text element
|
// enter 'a' in the first text element
|
||||||
inner$("div").first().sendkeys('a');
|
inner$('div').first().sendkeys('a');
|
||||||
}, timePerRev*i);
|
}, timePerRev * i);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// go to timeslider
|
// go to timeslider
|
||||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider');
|
$('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider`);
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
const timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||||
var $sliderBar = timeslider$('#ui-slider-bar');
|
const $sliderBar = timeslider$('#ui-slider-bar');
|
||||||
|
|
||||||
var latestContents = timeslider$('#innerdocbody').text();
|
const latestContents = timeslider$('#innerdocbody').text();
|
||||||
var oldUrl = $('#iframe-container iframe')[0].contentWindow.location.hash;
|
const oldUrl = $('#iframe-container iframe')[0].contentWindow.location.hash;
|
||||||
|
|
||||||
// Click somewhere on the timeslider
|
// Click somewhere on the timeslider
|
||||||
var e = new jQuery.Event('mousedown');
|
const e = new jQuery.Event('mousedown');
|
||||||
e.clientX = e.pageX = 150;
|
e.clientX = e.pageX = 150;
|
||||||
e.clientY = e.pageY = 60;
|
e.clientY = e.pageY = 60;
|
||||||
$sliderBar.trigger(e);
|
$sliderBar.trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => $('#iframe-container iframe')[0].contentWindow.location.hash != oldUrl, 6000).always(() => {
|
||||||
return $('#iframe-container iframe')[0].contentWindow.location.hash != oldUrl;
|
expect($('#iframe-container iframe')[0].contentWindow.location.hash).not.to.eql(oldUrl);
|
||||||
}, 6000).always(function(){
|
|
||||||
expect( $('#iframe-container iframe')[0].contentWindow.location.hash ).not.to.eql( oldUrl );
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}, 6000);
|
}, 6000);
|
||||||
}, revs*timePerRev);
|
}, revs * timePerRev);
|
||||||
});
|
});
|
||||||
it("jumps to a revision given in the url", function(done) {
|
it('jumps to a revision given in the url', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
this.timeout(40000);
|
this.timeout(40000);
|
||||||
|
|
||||||
// wait for the text to be loaded
|
// wait for the text to be loaded
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('body').text().length != 0, 10000).always(() => {
|
||||||
return inner$('body').text().length != 0;
|
const newLines = inner$('body div').length;
|
||||||
}, 10000).always(function() {
|
const oldLength = inner$('body').text().length + newLines / 2;
|
||||||
var newLines = inner$('body div').length;
|
expect(oldLength).to.not.eql(0);
|
||||||
var oldLength = inner$('body').text().length + newLines / 2;
|
inner$('div').first().sendkeys('a');
|
||||||
expect( oldLength ).to.not.eql( 0 );
|
let timeslider$;
|
||||||
inner$("div").first().sendkeys('a');
|
|
||||||
var timeslider$;
|
|
||||||
|
|
||||||
// wait for our additional revision to be added
|
// wait for our additional revision to be added
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
// newLines takes the new lines into account which are strippen when using
|
// newLines takes the new lines into account which are strippen when using
|
||||||
// inner$('body').text(), one <div> is used for one line in ACE.
|
// inner$('body').text(), one <div> is used for one line in ACE.
|
||||||
var lenOkay = inner$('body').text().length + newLines / 2 != oldLength;
|
const lenOkay = inner$('body').text().length + newLines / 2 != oldLength;
|
||||||
// this waits for the color to be added to our <span>, which means that the revision
|
// this waits for the color to be added to our <span>, which means that the revision
|
||||||
// was accepted by the server.
|
// was accepted by the server.
|
||||||
var colorOkay = inner$('span').first().attr('class').indexOf("author-") == 0;
|
const colorOkay = inner$('span').first().attr('class').indexOf('author-') == 0;
|
||||||
return lenOkay && colorOkay;
|
return lenOkay && colorOkay;
|
||||||
}, 10000).always(function() {
|
}, 10000).always(() => {
|
||||||
// go to timeslider with a specific revision set
|
// go to timeslider with a specific revision set
|
||||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0');
|
$('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider#0`);
|
||||||
|
|
||||||
// wait for the timeslider to be loaded
|
// wait for the timeslider to be loaded
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
try {
|
try {
|
||||||
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||||
} catch(e){}
|
} catch (e) {}
|
||||||
if(timeslider$){
|
if (timeslider$) {
|
||||||
return timeslider$('#innerdocbody').text().length == oldLength;
|
return timeslider$('#innerdocbody').text().length == oldLength;
|
||||||
}
|
}
|
||||||
}, 10000).always(function(){
|
}, 10000).always(() => {
|
||||||
expect( timeslider$('#innerdocbody').text().length ).to.eql( oldLength );
|
expect(timeslider$('#innerdocbody').text().length).to.eql(oldLength);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("checks the export url", function(done) {
|
it('checks the export url', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
this.timeout(11000);
|
this.timeout(11000);
|
||||||
inner$("div").first().sendkeys('a');
|
inner$('div').first().sendkeys('a');
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
// go to timeslider
|
// go to timeslider
|
||||||
$('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0');
|
$('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider#0`);
|
||||||
var timeslider$;
|
let timeslider$;
|
||||||
var exportLink;
|
let exportLink;
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
try{
|
try {
|
||||||
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
timeslider$ = $('#iframe-container iframe')[0].contentWindow.$;
|
||||||
}catch(e){}
|
} catch (e) {}
|
||||||
if(!timeslider$)
|
if (!timeslider$) return false;
|
||||||
return false;
|
|
||||||
exportLink = timeslider$('#exportplaina').attr('href');
|
exportLink = timeslider$('#exportplaina').attr('href');
|
||||||
if(!exportLink)
|
if (!exportLink) return false;
|
||||||
return false;
|
return exportLink.substr(exportLink.length - 12) == '0/export/txt';
|
||||||
return exportLink.substr(exportLink.length - 12) == "0/export/txt";
|
}, 6000).always(() => {
|
||||||
}, 6000).always(function(){
|
expect(exportLink.substr(exportLink.length - 12)).to.eql('0/export/txt');
|
||||||
expect( exportLink.substr(exportLink.length - 12) ).to.eql( "0/export/txt" );
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}, 2500);
|
}, 2500);
|
||||||
|
|
|
@ -1,61 +1,54 @@
|
||||||
describe("undo button", function(){
|
describe('undo button', function () {
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb); // creates a new pad
|
helper.newPad(cb); // creates a new pad
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("undo some typing by clicking undo button", function(done){
|
it('undo some typing by clicking undo button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// get the first text element inside the editable space
|
// get the first text element inside the editable space
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
var originalValue = $firstTextElement.text(); // get the original value
|
const originalValue = $firstTextElement.text(); // get the original value
|
||||||
|
|
||||||
$firstTextElement.sendkeys("foo"); // send line 1 to the pad
|
$firstTextElement.sendkeys('foo'); // send line 1 to the pad
|
||||||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||||
|
|
||||||
// get clear authorship button as a variable
|
// get clear authorship button as a variable
|
||||||
var $undoButton = chrome$(".buttonicon-undo");
|
const $undoButton = chrome$('.buttonicon-undo');
|
||||||
// click the button
|
// click the button
|
||||||
$undoButton.click();
|
$undoButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text() === originalValue).done(() => {
|
||||||
return inner$("div span").first().text() === originalValue;
|
const finalValue = inner$('div span').first().text();
|
||||||
}).done(function(){
|
|
||||||
var finalValue = inner$("div span").first().text();
|
|
||||||
expect(finalValue).to.be(originalValue); // expect the value to change
|
expect(finalValue).to.be(originalValue); // expect the value to change
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("undo some typing using a keypress", function(done){
|
it('undo some typing using a keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
// get the first text element inside the editable space
|
// get the first text element inside the editable space
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
var originalValue = $firstTextElement.text(); // get the original value
|
const originalValue = $firstTextElement.text(); // get the original value
|
||||||
|
|
||||||
$firstTextElement.sendkeys("foo"); // send line 1 to the pad
|
$firstTextElement.sendkeys('foo'); // send line 1 to the pad
|
||||||
var modifiedValue = $firstTextElement.text(); // get the modified value
|
const modifiedValue = $firstTextElement.text(); // get the modified value
|
||||||
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
expect(modifiedValue).not.to.be(originalValue); // expect the value to change
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.ctrlKey = true; // Control key
|
e.ctrlKey = true; // Control key
|
||||||
e.which = 90; // z
|
e.which = 90; // z
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text() === originalValue).done(() => {
|
||||||
return inner$("div span").first().text() === originalValue;
|
const finalValue = inner$('div span').first().text();
|
||||||
}).done(function(){
|
|
||||||
var finalValue = inner$("div span").first().text();
|
|
||||||
expect(finalValue).to.be(originalValue); // expect the value to change
|
expect(finalValue).to.be(originalValue); // expect the value to change
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,177 +1,162 @@
|
||||||
describe("assign unordered list", function(){
|
describe('assign unordered list', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("insert unordered list text then removes by outdent", function(done){
|
it('insert unordered list text then removes by outdent', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var originalText = inner$("div").first().text();
|
const originalText = inner$('div').first().text();
|
||||||
|
|
||||||
var $insertunorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertunorderedlistButton.click();
|
$insertunorderedlistButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var newText = inner$("div").first().text();
|
const newText = inner$('div').first().text();
|
||||||
if(newText === originalText){
|
if (newText === originalText) {
|
||||||
return inner$("div").first().find("ul li").length === 1;
|
return inner$('div').first().find('ul li').length === 1;
|
||||||
}
|
}
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
|
|
||||||
// remove indentation by bullet and ensure text string remains the same
|
// remove indentation by bullet and ensure text string remains the same
|
||||||
chrome$(".buttonicon-outdent").click();
|
chrome$('.buttonicon-outdent').click();
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var newText = inner$("div").first().text();
|
const newText = inner$('div').first().text();
|
||||||
return (newText === originalText);
|
return (newText === originalText);
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("unassign unordered list", function(){
|
describe('unassign unordered list', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("insert unordered list text then remove by clicking list again", function(done){
|
it('insert unordered list text then remove by clicking list again', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
var originalText = inner$("div").first().text();
|
const originalText = inner$('div').first().text();
|
||||||
|
|
||||||
var $insertunorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertunorderedlistButton.click();
|
$insertunorderedlistButton.click();
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var newText = inner$("div").first().text();
|
const newText = inner$('div').first().text();
|
||||||
if(newText === originalText){
|
if (newText === originalText) {
|
||||||
return inner$("div").first().find("ul li").length === 1;
|
return inner$('div').first().find('ul li').length === 1;
|
||||||
}
|
}
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
|
|
||||||
// remove indentation by bullet and ensure text string remains the same
|
// remove indentation by bullet and ensure text string remains the same
|
||||||
$insertunorderedlistButton.click();
|
$insertunorderedlistButton.click();
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
var isList = inner$("div").find("ul").length === 1;
|
const isList = inner$('div').find('ul').length === 1;
|
||||||
// sohuldn't be list
|
// sohuldn't be list
|
||||||
return (isList === false);
|
return (isList === false);
|
||||||
}).done(function(){
|
}).done(() => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("keep unordered list on enter key", function(){
|
describe('keep unordered list on enter key', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Keeps the unordered list on enter for the new line", function(done){
|
it('Keeps the unordered list on enter for the new line', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
// type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div span").first();
|
const $firstTextElement = inner$('div span').first();
|
||||||
$firstTextElement.sendkeys('line 1');
|
$firstTextElement.sendkeys('line 1');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
$firstTextElement.sendkeys('line 2');
|
$firstTextElement.sendkeys('line 2');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div span').first().text().indexOf('line 2') === -1).done(() => {
|
||||||
return inner$("div span").first().text().indexOf("line 2") === -1;
|
const $newSecondLine = inner$('div').first().next();
|
||||||
}).done(function(){
|
const hasULElement = $newSecondLine.find('ul li').length === 1;
|
||||||
var $newSecondLine = inner$("div").first().next();
|
|
||||||
var hasULElement = $newSecondLine.find("ul li").length === 1;
|
|
||||||
expect(hasULElement).to.be(true);
|
expect(hasULElement).to.be(true);
|
||||||
expect($newSecondLine.text()).to.be("line 2");
|
expect($newSecondLine.text()).to.be('line 2');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Pressing Tab in an UL increases and decreases indentation", function(){
|
describe('Pressing Tab in an UL increases and decreases indentation', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent and de-indent list item with keypress", function(done){
|
it('indent and de-indent list item with keypress', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
const $insertorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertorderedlistButton.click();
|
$insertorderedlistButton.click();
|
||||||
|
|
||||||
var e = inner$.Event(helper.evtType);
|
const e = inner$.Event(helper.evtType);
|
||||||
e.keyCode = 9; // tab
|
e.keyCode = 9; // tab
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
expect(inner$("div").first().find(".list-bullet2").length === 1).to.be(true);
|
expect(inner$('div').first().find('.list-bullet2').length === 1).to.be(true);
|
||||||
e.shiftKey = true; // shift
|
e.shiftKey = true; // shift
|
||||||
e.keyCode = 9; // tab
|
e.keyCode = 9; // tab
|
||||||
inner$("#innerdocbody").trigger(e);
|
inner$('#innerdocbody').trigger(e);
|
||||||
|
|
||||||
helper.waitFor(function(){
|
|
||||||
return inner$("div").first().find(".list-bullet1").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
|
|
||||||
|
helper.waitFor(() => 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(){
|
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
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent and de-indent list item with indent button", function(done){
|
it('indent and de-indent list item with indent button', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var $firstTextElement = inner$("div").first();
|
const $firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
//select this text element
|
// select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
var $insertunorderedlistButton = chrome$(".buttonicon-insertunorderedlist");
|
const $insertunorderedlistButton = chrome$('.buttonicon-insertunorderedlist');
|
||||||
$insertunorderedlistButton.click();
|
$insertunorderedlistButton.click();
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
const $indentButton = chrome$('.buttonicon-indent');
|
||||||
$indentButton.click(); // make it indented twice
|
$indentButton.click(); // make it indented twice
|
||||||
|
|
||||||
expect(inner$("div").first().find(".list-bullet2").length === 1).to.be(true);
|
expect(inner$('div').first().find('.list-bullet2').length === 1).to.be(true);
|
||||||
var $outdentButton = chrome$(".buttonicon-outdent");
|
const $outdentButton = chrome$('.buttonicon-outdent');
|
||||||
$outdentButton.click(); // make it deindented to 1
|
$outdentButton.click(); // make it deindented to 1
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('.list-bullet1').length === 1).done(done);
|
||||||
return inner$("div").first().find(".list-bullet1").length === 1;
|
|
||||||
}).done(done);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,54 @@
|
||||||
describe("urls", function(){
|
describe('urls', function () {
|
||||||
//create a new pad before each test run
|
// create a new pad before each test run
|
||||||
beforeEach(function(cb){
|
beforeEach(function (cb) {
|
||||||
helper.newPad(cb);
|
helper.newPad(cb);
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when you enter an url, it becomes clickable", function(done) {
|
it('when you enter an url, it becomes clickable', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var firstTextElement = inner$("div").first();
|
const firstTextElement = inner$('div').first();
|
||||||
|
|
||||||
// simulate key presses to delete content
|
// simulate key presses to delete content
|
||||||
firstTextElement.sendkeys('{selectall}'); // select all
|
firstTextElement.sendkeys('{selectall}'); // select all
|
||||||
firstTextElement.sendkeys('{del}'); // clear the first line
|
firstTextElement.sendkeys('{del}'); // clear the first line
|
||||||
firstTextElement.sendkeys('https://etherpad.org'); // insert a URL
|
firstTextElement.sendkeys('https://etherpad.org'); // insert a URL
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => inner$('div').first().find('a').length === 1, 2000).done(done);
|
||||||
return inner$("div").first().find("a").length === 1;
|
|
||||||
}, 2000).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when you enter a url containing a !, it becomes clickable and contains the whole URL", function(done) {
|
it('when you enter a url containing a !, it becomes clickable and contains the whole URL', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var firstTextElement = inner$("div").first();
|
const firstTextElement = inner$('div').first();
|
||||||
var url = "https://etherpad.org/!foo";
|
const url = 'https://etherpad.org/!foo';
|
||||||
|
|
||||||
// simulate key presses to delete content
|
// simulate key presses to delete content
|
||||||
firstTextElement.sendkeys('{selectall}'); // select all
|
firstTextElement.sendkeys('{selectall}'); // select all
|
||||||
firstTextElement.sendkeys('{del}'); // clear the first line
|
firstTextElement.sendkeys('{del}'); // clear the first line
|
||||||
firstTextElement.sendkeys(url); // insert a URL
|
firstTextElement.sendkeys(url); // insert a URL
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
if(inner$("div").first().find("a").length === 1){ // if it contains an A link
|
if (inner$('div').first().find('a').length === 1) { // if it contains an A link
|
||||||
if(inner$("div").first().find("a")[0].href === url){
|
if (inner$('div').first().find('a')[0].href === url) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, 2000).done(done);
|
}, 2000).done(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("when you enter a url followed by a ], the ] is not included in the URL", function(done) {
|
it('when you enter a url followed by a ], the ] is not included in the URL', function (done) {
|
||||||
var inner$ = helper.padInner$;
|
const inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
const chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
// get the first text element out of the inner iframe
|
||||||
var firstTextElement = inner$("div").first();
|
const firstTextElement = inner$('div').first();
|
||||||
var url = "https://etherpad.org/";
|
const url = 'https://etherpad.org/';
|
||||||
|
|
||||||
// simulate key presses to delete content
|
// simulate key presses to delete content
|
||||||
firstTextElement.sendkeys('{selectall}'); // select all
|
firstTextElement.sendkeys('{selectall}'); // select all
|
||||||
|
@ -58,13 +56,12 @@ describe("urls", function(){
|
||||||
firstTextElement.sendkeys(url); // insert a URL
|
firstTextElement.sendkeys(url); // insert a URL
|
||||||
firstTextElement.sendkeys(']'); // put a ] after it
|
firstTextElement.sendkeys(']'); // put a ] after it
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(() => {
|
||||||
if(inner$("div").first().find("a").length === 1){ // if it contains an A link
|
if (inner$('div').first().find('a').length === 1) { // if it contains an A link
|
||||||
if(inner$("div").first().find("a")[0].href === url){
|
if (inner$('div').first().find('a')[0].href === url) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, 2000).done(done);
|
}, 2000).done(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,48 +1,46 @@
|
||||||
describe('Automatic pad reload on Force Reconnect message', function() {
|
describe('Automatic pad reload on Force Reconnect message', function () {
|
||||||
var padId, $originalPadFrame;
|
let padId, $originalPadFrame;
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function (done) {
|
||||||
padId = helper.newPad(function() {
|
padId = helper.newPad(() => {
|
||||||
// enable userdup error to have timer to force reconnect
|
// enable userdup error to have timer to force reconnect
|
||||||
var $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
const $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
||||||
$errorMessageModal.addClass('with_reconnect_timer');
|
$errorMessageModal.addClass('with_reconnect_timer');
|
||||||
|
|
||||||
// make sure there's a timeout set, otherwise automatic reconnect won't be enabled
|
// make sure there's a timeout set, otherwise automatic reconnect won't be enabled
|
||||||
helper.padChrome$.window.clientVars.automaticReconnectionTimeout = 2;
|
helper.padChrome$.window.clientVars.automaticReconnectionTimeout = 2;
|
||||||
|
|
||||||
// open same pad on another iframe, to force userdup error
|
// open same pad on another iframe, to force userdup error
|
||||||
var $otherIframeWithSamePad = $('<iframe src="/p/' + padId + '" style="height: 1px;"></iframe>');
|
const $otherIframeWithSamePad = $(`<iframe src="/p/${padId}" style="height: 1px;"></iframe>`);
|
||||||
$originalPadFrame = $('#iframe-container iframe');
|
$originalPadFrame = $('#iframe-container iframe');
|
||||||
$otherIframeWithSamePad.insertAfter($originalPadFrame);
|
$otherIframeWithSamePad.insertAfter($originalPadFrame);
|
||||||
|
|
||||||
// wait for modal to be displayed
|
// wait for modal to be displayed
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => $errorMessageModal.is(':visible'), 50000).done(done);
|
||||||
return $errorMessageModal.is(':visible');
|
|
||||||
}, 50000).done(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.timeout(60000);
|
this.timeout(60000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays a count down timer to automatically reconnect', function(done) {
|
it('displays a count down timer to automatically reconnect', function (done) {
|
||||||
var $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
const $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
||||||
var $countDownTimer = $errorMessageModal.find('.reconnecttimer');
|
const $countDownTimer = $errorMessageModal.find('.reconnecttimer');
|
||||||
|
|
||||||
expect($countDownTimer.is(':visible')).to.be(true);
|
expect($countDownTimer.is(':visible')).to.be(true);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user clicks on Cancel', function() {
|
context('and user clicks on Cancel', function () {
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
var $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
const $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
||||||
$errorMessageModal.find('#cancelreconnect').click();
|
$errorMessageModal.find('#cancelreconnect').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not show Cancel button nor timer anymore', function(done) {
|
it('does not show Cancel button nor timer anymore', function (done) {
|
||||||
var $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
const $errorMessageModal = helper.padChrome$('#connectivity .userdup');
|
||||||
var $countDownTimer = $errorMessageModal.find('.reconnecttimer');
|
const $countDownTimer = $errorMessageModal.find('.reconnecttimer');
|
||||||
var $cancelButton = $errorMessageModal.find('#cancelreconnect');
|
const $cancelButton = $errorMessageModal.find('#cancelreconnect');
|
||||||
|
|
||||||
expect($countDownTimer.is(':visible')).to.be(false);
|
expect($countDownTimer.is(':visible')).to.be(false);
|
||||||
expect($cancelButton.is(':visible')).to.be(false);
|
expect($cancelButton.is(':visible')).to.be(false);
|
||||||
|
@ -51,19 +49,17 @@ describe('Automatic pad reload on Force Reconnect message', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
context('and user does not click on Cancel until timer expires', function() {
|
context('and user does not click on Cancel until timer expires', function () {
|
||||||
var padWasReloaded = false;
|
let padWasReloaded = false;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function () {
|
||||||
$originalPadFrame.one('load', function() {
|
$originalPadFrame.one('load', () => {
|
||||||
padWasReloaded = true;
|
padWasReloaded = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reloads the pad', function(done) {
|
it('reloads the pad', function (done) {
|
||||||
helper.waitFor(function() {
|
helper.waitFor(() => padWasReloaded, 5000).done(done);
|
||||||
return padWasReloaded;
|
|
||||||
}, 5000).done(done);
|
|
||||||
|
|
||||||
this.timeout(5000);
|
this.timeout(5000);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
var srcFolder = "../../../src/node_modules/";
|
var srcFolder = '../../../src/node_modules/';
|
||||||
var wd = require(srcFolder + "wd");
|
var wd = require(`${srcFolder}wd`);
|
||||||
var async = require(srcFolder + "async");
|
var async = require(`${srcFolder}async`);
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
host: "ondemand.saucelabs.com"
|
host: 'ondemand.saucelabs.com',
|
||||||
, port: 80
|
port: 80,
|
||||||
, username: process.env.SAUCE_USER
|
username: process.env.SAUCE_USER,
|
||||||
, accessKey: process.env.SAUCE_ACCESS_KEY
|
accessKey: process.env.SAUCE_ACCESS_KEY,
|
||||||
}
|
};
|
||||||
|
|
||||||
var allTestsPassed = true;
|
var allTestsPassed = true;
|
||||||
// overwrite the default exit code
|
// overwrite the default exit code
|
||||||
|
@ -20,111 +20,108 @@ process.on('exit', (code) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
var sauceTestWorker = async.queue(function (testSettings, callback) {
|
var sauceTestWorker = async.queue((testSettings, callback) => {
|
||||||
var browser = wd.promiseChainRemote(config.host, config.port, config.username, config.accessKey);
|
const browser = wd.promiseChainRemote(config.host, config.port, config.username, config.accessKey);
|
||||||
var name = process.env.GIT_HASH + " - " + testSettings.browserName + " " + testSettings.version + ", " + testSettings.platform;
|
const name = `${process.env.GIT_HASH} - ${testSettings.browserName} ${testSettings.version}, ${testSettings.platform}`;
|
||||||
testSettings.name = name;
|
testSettings.name = name;
|
||||||
testSettings["public"] = true;
|
testSettings.public = true;
|
||||||
testSettings["build"] = process.env.GIT_HASH;
|
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.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;
|
testSettings.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||||
|
|
||||||
browser.init(testSettings).get("http://localhost:9001/tests/frontend/", function(){
|
browser.init(testSettings).get('http://localhost:9001/tests/frontend/', () => {
|
||||||
var url = "https://saucelabs.com/jobs/" + browser.sessionID;
|
const url = `https://saucelabs.com/jobs/${browser.sessionID}`;
|
||||||
console.log("Remote sauce test '" + name + "' started! " + url);
|
console.log(`Remote sauce test '${name}' started! ${url}`);
|
||||||
|
|
||||||
//tear down the test excecution
|
// tear down the test excecution
|
||||||
var stopSauce = function(success,timesup){
|
const stopSauce = function (success, timesup) {
|
||||||
clearInterval(getStatusInterval);
|
clearInterval(getStatusInterval);
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|
||||||
browser.quit(function(){
|
browser.quit(() => {
|
||||||
if(!success){
|
if (!success) {
|
||||||
allTestsPassed = false;
|
allTestsPassed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if stopSauce is called via timeout (in contrast to via getStatusInterval) than the log of up to the last
|
// 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.
|
// five seconds may not be available here. It's an error anyway, so don't care about it.
|
||||||
printLog(logIndex);
|
printLog(logIndex);
|
||||||
|
|
||||||
if (timesup) {
|
if (timesup) {
|
||||||
console.log("[" + testSettings.browserName + " " + testSettings.platform + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] \x1B[31mFAILED\x1B[39m allowed test duration exceeded");
|
console.log(`[${testSettings.browserName} ${testSettings.platform}${testSettings.version === '' ? '' : (` ${testSettings.version}`)}] \x1B[31mFAILED\x1B[39m allowed test duration exceeded`);
|
||||||
}
|
}
|
||||||
console.log("Remote sauce test '" + name + "' finished! " + url);
|
console.log(`Remote sauce test '${name}' finished! ${url}`);
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* timeout if a test hangs or the job exceeds 14.5 minutes
|
* timeout if a test hangs or the job exceeds 14.5 minutes
|
||||||
* It's necessary because if travis kills the saucelabs session due to inactivity, we don't get any output
|
* 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
|
* @todo this should be configured in testSettings, see https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts
|
||||||
*/
|
*/
|
||||||
var timeout = setTimeout(function(){
|
var timeout = setTimeout(() => {
|
||||||
stopSauce(false,true);
|
stopSauce(false, true);
|
||||||
}, 870000); // travis timeout is 15 minutes, set this to a slightly lower value
|
}, 870000); // travis timeout is 15 minutes, set this to a slightly lower value
|
||||||
|
|
||||||
var knownConsoleText = "";
|
let knownConsoleText = '';
|
||||||
// how many characters of the log have been sent to travis
|
// how many characters of the log have been sent to travis
|
||||||
let logIndex = 0;
|
let logIndex = 0;
|
||||||
var getStatusInterval = setInterval(function(){
|
var getStatusInterval = setInterval(() => {
|
||||||
browser.eval("$('#console').text()", function(err, consoleText){
|
browser.eval("$('#console').text()", (err, consoleText) => {
|
||||||
if(!consoleText || err){
|
if (!consoleText || err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
knownConsoleText = consoleText;
|
knownConsoleText = consoleText;
|
||||||
|
|
||||||
if(knownConsoleText.indexOf("FINISHED") > 0){
|
if (knownConsoleText.indexOf('FINISHED') > 0) {
|
||||||
let match = knownConsoleText.match(/FINISHED.*([0-9]+) tests passed, ([0-9]+) tests failed/);
|
const match = knownConsoleText.match(/FINISHED.*([0-9]+) tests passed, ([0-9]+) tests failed/);
|
||||||
// finished without failures
|
// finished without failures
|
||||||
if (match[2] && match[2] == '0'){
|
if (match[2] && match[2] == '0') {
|
||||||
stopSauce(true);
|
stopSauce(true);
|
||||||
|
|
||||||
// finished but some tests did not return or some tests failed
|
// finished but some tests did not return or some tests failed
|
||||||
} else {
|
|
||||||
stopSauce(false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// not finished yet
|
stopSauce(false);
|
||||||
printLog(logIndex);
|
|
||||||
logIndex = knownConsoleText.length;
|
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
}, 5000);
|
// not finished yet
|
||||||
|
printLog(logIndex);
|
||||||
|
logIndex = knownConsoleText.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces color codes in the test runners log, appends
|
* Replaces color codes in the test runners log, appends
|
||||||
* browser name, platform etc. to every line and prints them.
|
* browser name, platform etc. to every line and prints them.
|
||||||
*
|
*
|
||||||
* @param {number} index offset from where to start
|
* @param {number} index offset from where to start
|
||||||
*/
|
*/
|
||||||
function printLog(index){
|
function printLog(index) {
|
||||||
let testResult = knownConsoleText.substring(index).replace(/\[red\]/g,'\x1B[31m').replace(/\[yellow\]/g,'\x1B[33m')
|
let testResult = knownConsoleText.substring(index).replace(/\[red\]/g, '\x1B[31m').replace(/\[yellow\]/g, '\x1B[33m')
|
||||||
.replace(/\[green\]/g,'\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
|
.replace(/\[green\]/g, '\x1B[32m').replace(/\[clear\]/g, '\x1B[39m');
|
||||||
testResult = testResult.split("\\n").map(function(line){
|
testResult = testResult.split('\\n').map((line) => `[${testSettings.browserName} ${testSettings.platform}${testSettings.version === '' ? '' : (` ${testSettings.version}`)}] ${line}`).join('\n');
|
||||||
return "[" + testSettings.browserName + " " + testSettings.platform + (testSettings.version === "" ? '' : (" " + testSettings.version)) + "] " + line;
|
|
||||||
}).join("\n");
|
|
||||||
|
|
||||||
console.log(testResult);
|
console.log(testResult);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}, 6); // run 6 tests in parrallel
|
||||||
}, 6); //run 6 tests in parrallel
|
|
||||||
|
|
||||||
// 1) Firefox on Linux
|
// 1) Firefox on Linux
|
||||||
sauceTestWorker.push({
|
sauceTestWorker.push({
|
||||||
'platform' : 'Windows 7'
|
platform: 'Windows 7',
|
||||||
, 'browserName' : 'firefox'
|
browserName: 'firefox',
|
||||||
, 'version' : '52.0'
|
version: '52.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 2) Chrome on Linux
|
// 2) Chrome on Linux
|
||||||
sauceTestWorker.push({
|
sauceTestWorker.push({
|
||||||
'platform' : 'Windows 7'
|
platform: 'Windows 7',
|
||||||
, 'browserName' : 'chrome'
|
browserName: 'chrome',
|
||||||
, 'version' : '55.0'
|
version: '55.0',
|
||||||
, 'args' : ['--use-fake-device-for-media-stream']
|
args: ['--use-fake-device-for-media-stream'],
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -138,9 +135,9 @@ sauceTestWorker.push({
|
||||||
|
|
||||||
// 4) Safari on OSX 10.14
|
// 4) Safari on OSX 10.14
|
||||||
sauceTestWorker.push({
|
sauceTestWorker.push({
|
||||||
'platform' : 'OS X 10.15'
|
platform: 'OS X 10.15',
|
||||||
, 'browserName' : 'safari'
|
browserName: 'safari',
|
||||||
, 'version' : '13.1'
|
version: '13.1',
|
||||||
});
|
});
|
||||||
// IE 10 doesn't appear to be working anyway
|
// IE 10 doesn't appear to be working anyway
|
||||||
/*
|
/*
|
||||||
|
@ -153,17 +150,17 @@ sauceTestWorker.push({
|
||||||
*/
|
*/
|
||||||
// 5) Edge on Win 10
|
// 5) Edge on Win 10
|
||||||
sauceTestWorker.push({
|
sauceTestWorker.push({
|
||||||
'platform' : 'Windows 10'
|
platform: 'Windows 10',
|
||||||
, 'browserName' : 'microsoftedge'
|
browserName: 'microsoftedge',
|
||||||
, 'version' : '83.0'
|
version: '83.0',
|
||||||
});
|
});
|
||||||
// 6) Firefox on Win 7
|
// 6) Firefox on Win 7
|
||||||
sauceTestWorker.push({
|
sauceTestWorker.push({
|
||||||
'platform' : 'Windows 7'
|
platform: 'Windows 7',
|
||||||
, 'browserName' : 'firefox'
|
browserName: 'firefox',
|
||||||
, 'version' : '78.0'
|
version: '78.0',
|
||||||
});
|
});
|
||||||
|
|
||||||
sauceTestWorker.drain(function() {
|
sauceTestWorker.drain(() => {
|
||||||
process.exit(allTestsPassed ? 0 : 1);
|
process.exit(allTestsPassed ? 0 : 1);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
try{
|
try {
|
||||||
var etherpad = require("../../src/node_modules/etherpad-cli-client");
|
var etherpad = require('../../src/node_modules/etherpad-cli-client');
|
||||||
//ugly
|
// ugly
|
||||||
} catch {
|
} catch {
|
||||||
var etherpad = require("etherpad-cli-client")
|
var etherpad = require('etherpad-cli-client');
|
||||||
}
|
}
|
||||||
var pad = etherpad.connect(process.argv[2]);
|
const pad = etherpad.connect(process.argv[2]);
|
||||||
pad.on("connected", function(){
|
pad.on('connected', () => {
|
||||||
|
setTimeout(() => {
|
||||||
setTimeout(function(){
|
setInterval(() => {
|
||||||
setInterval(function(){
|
pad.append('1');
|
||||||
pad.append("1");
|
|
||||||
}, process.argv[3]);
|
}, process.argv[3]);
|
||||||
},500); // wait because CLIENT_READY message is included in ratelimit
|
}, 500); // wait because CLIENT_READY message is included in ratelimit
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(() => {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
},11000)
|
}, 11000);
|
||||||
});
|
});
|
||||||
// in case of disconnect exit code 1
|
// in case of disconnect exit code 1
|
||||||
pad.on("message", function(message){
|
pad.on('message', (message) => {
|
||||||
if(message.disconnect == 'rateLimited'){
|
if (message.disconnect == 'rateLimited') {
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
Loading…
Reference in a new issue