From 6ac4fa4689461b852491839d1d373afdb2781f22 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 14 Dec 2017 11:34:44 +0100 Subject: [PATCH 01/24] wip --- TestSelenium.js | 6 ++--- www/common/sframe-app-framework.js | 8 ++++++- www/common/sframe-common-outer.js | 7 +++++- www/common/test.js | 37 +++++++++++++++++++++++++++++- www/register/main.js | 1 - 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/TestSelenium.js b/TestSelenium.js index fccd4e067..16b20f71c 100644 --- a/TestSelenium.js +++ b/TestSelenium.js @@ -28,9 +28,9 @@ var SC_GET_DATA = "return (window.__CRYPTPAD_TEST__) ? window.__CRYPTPAD_TEST__. var failed = false; var nt = nThen; [ - //'/register/#?test=test', - '/assert/#?test=test', - // '/auth/#?test=test' // TODO(cjd): Not working on automatic tests, understand why. + '/register/#?test=auto', + //'/assert/#?test=auto', + '/auth/#?test=auto' ].forEach(function (path) { if (failed) { return; } var url = 'http://localhost:3000' + path; diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 526e45678..d9b59abeb 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -12,6 +12,7 @@ define([ '/common/common-feedback.js', '/customize/application_config.js', '/bower_components/chainpad/chainpad.dist.js', + '/common/test.js', '/bower_components/file-saver/FileSaver.min.js', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', @@ -30,7 +31,8 @@ define([ Thumb, Feedback, AppConfig, - ChainPad) + ChainPad, + Test) { var SaveAs = window.saveAs; @@ -383,6 +385,10 @@ define([ }).nThen(function (waitFor) { common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { + if (common.getMetadataMgr().getPrivateData().isTesting) { + Test.registerInner(common.getSframeChannel()); + } + if (!AppConfig.displayCreationScreen) { return; } if (common.getMetadataMgr().getPrivateData().isNewFile) { common.getPadCreationScreen(waitFor()); diff --git a/www/common/sframe-common-outer.js b/www/common/sframe-common-outer.js index fc132b8cb..8344f58aa 100644 --- a/www/common/sframe-common-outer.js +++ b/www/common/sframe-common-outer.js @@ -24,6 +24,7 @@ define([ var Notifier; var Utils = {}; var AppConfig; + var Test; nThen(function (waitFor) { // Load #2, the loading screen is up so grab whatever you need... @@ -45,9 +46,10 @@ define([ '/customize/application_config.js', '/common/outer/network-config.js', '/bower_components/netflux-websocket/netflux-client.js', + '/common/test.js', ], waitFor(function (_CpNfOuter, _Cryptpad, _Crypto, _Cryptget, _SFrameChannel, _FilePicker, _Messaging, _Notifier, _Hash, _Util, _Realtime, - _Constants, _Feedback, _LocalStore, _AppConfig, NetConfig, Netflux) { + _Constants, _Feedback, _LocalStore, _AppConfig, NetConfig, Netflux, _Test) { CpNfOuter = _CpNfOuter; Cryptpad = _Cryptpad; Crypto = _Crypto; @@ -63,6 +65,7 @@ define([ Utils.Feedback = _Feedback; Utils.LocalStore = _LocalStore; AppConfig = _AppConfig; + Test = _Test; if (localStorage.CRYPTPAD_URLARGS !== ApiConfig.requireConf.urlArgs) { console.log("New version, flushing cache"); @@ -208,6 +211,8 @@ define([ sframeChan.event('EV_LOGOUT'); }); + Test.registerOuter(sframeChan); + // Put in the following function the RPC queries that should also work in filepicker var addCommonRpc = function (sframeChan) { sframeChan.on('Q_ANON_RPC_MESSAGE', function (data, cb) { diff --git a/www/common/test.js b/www/common/test.js index a0a743f2b..46416e1ad 100644 --- a/www/common/test.js +++ b/www/common/test.js @@ -1,7 +1,7 @@ define([], function () { var out = function () { }; out.passed = out.failed = out; - if (window.location.hash.indexOf("?test=test") > -1) { + if (window.location.hash.indexOf("test=auto") > -1) { var cpt = window.__CRYPTPAD_TEST__ = { data: [], getData: function () { @@ -68,8 +68,43 @@ define([], function () { error: { message: e.message, stack: e.stack } }); }; + + out.registerInner = function (sframeChan) { + sframeChan.whenReg('EV_TESTDATA', function () { + cpt.data.forEach(function (x) { sframeChan.fire('EV_TESTDATA', x); }); + // override cpt.data.push() with a function which will send the content to the + // outside where it will go on the outer window cpt.data array. + cpt = window.__CRYPTPAD_TEST__ = { + data: { + push: function (elem) { + sframeChan.fire('EV_TESTDATA', elem); + } + }, + getData: function () { + throw new Error('getData should never be called from the inside'); + } + }; + }); + }; + out.registerOuter = function (sframeChan) { + sframeChan.on('EV_TESTDATA', function (data) { cpt.data.push(data); }); + }; + + } else if (window.location.hash.indexOf("test=manual") > -1) { + out = function (f) { f(); }; + out.testing = true; + out.passed = function () { + window.alert("Test passed"); + }; + out.failed = function (reason) { + window.alert("Test failed [" + reason + "]"); + }; + out.registerInner = function () { }; + out.registerOuter = function () { }; } else { out.testing = false; + out.registerInner = function () { }; + out.registerOuter = function () { }; } return out; }); diff --git a/www/register/main.js b/www/register/main.js index 69e3a59a4..5337dfa87 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -57,7 +57,6 @@ define([ var logMeIn = function (result) { if (Test.testing) { Test.passed(); - window.alert("Test passed!"); return; } LocalStore.setUserHash(result.userHash); From 6a2d79249d2458545e951479d26135cfe04a46e0 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Fri, 15 Dec 2017 16:09:30 +0100 Subject: [PATCH 02/24] Added some nice testing --- TestSelenium.js | 32 +++++++++++++++++---- package.json | 2 +- www/common/sframe-app-framework.js | 11 ++++--- www/common/sframe-protocol.js | 4 +++ www/common/test.js | 46 +++++++++++++++++++++--------- 5 files changed, 70 insertions(+), 25 deletions(-) diff --git a/TestSelenium.js b/TestSelenium.js index 16b20f71c..71de38d5c 100644 --- a/TestSelenium.js +++ b/TestSelenium.js @@ -26,14 +26,30 @@ if (process.env.SAUCE_USERNAME !== undefined) { var SC_GET_DATA = "return (window.__CRYPTPAD_TEST__) ? window.__CRYPTPAD_TEST__.getData() : '[]'"; var failed = false; -var nt = nThen; +var nt = nThen(function (waitFor) { + driver.get('http://localhost:3000/auth/').then(waitFor()); +}).nThen(function (waitFor) { + console.log('initialized'); + driver.manage().addCookie({name: 'test', value: 'auto'}).then(waitFor()); +}).nThen; + [ - '/register/#?test=auto', - //'/assert/#?test=auto', - '/auth/#?test=auto' -].forEach(function (path) { + ['/register/', {}], + ['/assert/', {}], + ['/auth/', {}], + + ['/pad/#/1/edit/1KXFMz5L+nLgvHqXVJjyiQ/IUAE6IzVVg5UIYFOPglmVxvV/', {}], + ['/pad/#/1/view/1KXFMz5L+nLgvHqXVJjyiQ/O4kuSnJyviGVlz3qpcr4Fxc8fIK6uTeB30MfMkh86O8/', {}], + + ['/code/#/1/edit/CWtkq8Qa2re7W1XvXZRDYg/2G7Gse5UZ8dLyGAXUdCV2fLL/', {}], + ['/code/#/1/view/CWtkq8Qa2re7W1XvXZRDYg/G1pVa1EL26JRAjk28b43W7Ftc3AkdBblef1U58F3iDk/', {}], + + ['/slide/#/1/edit/uwKqgj8Ezh2dRaFUWSlrRQ/JkJtAb-hNzfESZEHreAeULU1/', {}], + ['/slide/#/1/view/uwKqgj8Ezh2dRaFUWSlrRQ/Xa8jXl+jWMpwep41mlrhkqbRuVKGxlueH80Pbgeu5Go/', {}], + +].forEach(function (x) { if (failed) { return; } - var url = 'http://localhost:3000' + path; + var url = 'http://localhost:3000' + x[0]; nt = nt(function (waitFor) { var done = waitFor(); console.log('\n\n-----TEST ' + url + ' -----'); @@ -70,6 +86,10 @@ var nt = nThen; if (done) { setTimeout(logMore, 50); } })); }; + driver.manage().addCookie({ + name: 'test', + value: encodeURIComponent(JSON.stringify({ test:'auto', opts: x[1] })) + }); driver.get(url).then(waitFor(logMore)); }).nThen; }); diff --git a/package.json b/package.json index e48d11b72..b7123d03b 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "jshint": "~2.9.1", "less": "2.7.1", "lesshint": "^4.5.0", - "selenium-webdriver": "^2.53.1" + "selenium-webdriver": "^3.6.0" }, "scripts": { "start": "node server.js", diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index d9b59abeb..2290dd3ba 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -290,6 +290,12 @@ define([ if (newPad && !AppConfig.displayCreationScreen) { common.openTemplatePicker(); } + + if (Test.testing) { + cpNfInner.chainpad.onSettle(function () { + Test.passed(); + }); + } }; var onConnectionChange = function (info) { stateChange(info.state ? STATE.INITIALIZING : STATE.DISCONNECTED); @@ -385,10 +391,7 @@ define([ }).nThen(function (waitFor) { common.getSframeChannel().onReady(waitFor()); }).nThen(function (waitFor) { - if (common.getMetadataMgr().getPrivateData().isTesting) { - Test.registerInner(common.getSframeChannel()); - } - + Test.registerInner(common.getSframeChannel()); if (!AppConfig.displayCreationScreen) { return; } if (common.getMetadataMgr().getPrivateData().isNewFile) { common.getPadCreationScreen(waitFor()); diff --git a/www/common/sframe-protocol.js b/www/common/sframe-protocol.js index 7bada3c42..96014c992 100644 --- a/www/common/sframe-protocol.js +++ b/www/common/sframe-protocol.js @@ -213,4 +213,8 @@ define({ // Pad creation screen: create a pad with the selected attributes (owned, expire) 'Q_CREATE_PAD': true, + + // This is for sending data out of the iframe when we are in testing mode + // The exact protocol is defined in common/test.js + 'EV_TESTDATA': true, }); diff --git a/www/common/test.js b/www/common/test.js index 46416e1ad..e2824b8c0 100644 --- a/www/common/test.js +++ b/www/common/test.js @@ -1,7 +1,10 @@ define([], function () { - var out = function () { }; + if (window.__CRYPTPAD_TEST_OBJ_) { return window.__CRYPTPAD_TEST_OBJ_; } + var out = window.__CRYPTPAD_TEST_OBJ__ = function (f) { if (out.testing) { f(); } }; out.passed = out.failed = out; - if (window.location.hash.indexOf("test=auto") > -1) { + var enableAuto = function () { + console.log("Enable auto testing 1 " + window.origin); + if (window.__CRYPTPAD_TEST__) { return; } var cpt = window.__CRYPTPAD_TEST__ = { data: [], getData: function () { @@ -51,8 +54,7 @@ define([], function () { error: { message: e.message, stack: e.stack } }); }; - out = function (f) { f(); }; - out.testing = true; + out.testing = 'auto'; out.passed = function () { cpt.data.push({ type: 'report', @@ -71,13 +73,13 @@ define([], function () { out.registerInner = function (sframeChan) { sframeChan.whenReg('EV_TESTDATA', function () { - cpt.data.forEach(function (x) { sframeChan.fire('EV_TESTDATA', x); }); + cpt.data.forEach(function (x) { sframeChan.event('EV_TESTDATA', x); }); // override cpt.data.push() with a function which will send the content to the // outside where it will go on the outer window cpt.data array. cpt = window.__CRYPTPAD_TEST__ = { data: { push: function (elem) { - sframeChan.fire('EV_TESTDATA', elem); + sframeChan.event('EV_TESTDATA', elem); } }, getData: function () { @@ -89,10 +91,9 @@ define([], function () { out.registerOuter = function (sframeChan) { sframeChan.on('EV_TESTDATA', function (data) { cpt.data.push(data); }); }; - - } else if (window.location.hash.indexOf("test=manual") > -1) { - out = function (f) { f(); }; - out.testing = true; + }; + var enableManual = function () { + out.testing = 'manual'; out.passed = function () { window.alert("Test passed"); }; @@ -101,10 +102,27 @@ define([], function () { }; out.registerInner = function () { }; out.registerOuter = function () { }; - } else { - out.testing = false; - out.registerInner = function () { }; - out.registerOuter = function () { }; + }; + + out.options = {}; + out.testing = false; + out.registerInner = function () { }; + out.registerOuter = function () { }; + + if (window.location.hash.indexOf("test=auto") > -1) { + enableAuto(); + } else if (window.location.hash.indexOf("test=manual") > -1) { + enableManual(); + } else if (document.cookie.indexOf('test=') === 0) { + try { + var x = JSON.parse(decodeURIComponent(document.cookie.replace('test=', ''))); + if (x.test === 'auto') { + out.options = x.opts; + enableAuto('auto'); + } + console.log("Enable auto testing " + window.origin); + } catch (e) { } } + return out; }); From e587e9cd57127dfea7a319cbbec52360b2f17fd8 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Mon, 18 Dec 2017 11:39:59 +0100 Subject: [PATCH 03/24] allow specifying the browser in selenium --- TestSelenium.js | 4 +++- www/common/sframe-app-framework.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/TestSelenium.js b/TestSelenium.js index 71de38d5c..59bdd427a 100644 --- a/TestSelenium.js +++ b/TestSelenium.js @@ -20,7 +20,9 @@ if (process.env.SAUCE_USERNAME !== undefined) { "accessKey": process.env.SAUCE_ACCESS_KEY, }).forBrowser(browserArray[0], browserArray[1], browserArray[2]).build(); } else { - driver = new WebDriver.Builder().withCapabilities({ browserName: "chrome" }).build(); + driver = new WebDriver.Builder().withCapabilities({ + browserName: process.env.BROWSER || "chrome" + }).build(); } var SC_GET_DATA = "return (window.__CRYPTPAD_TEST__) ? window.__CRYPTPAD_TEST__.getData() : '[]'"; diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 2290dd3ba..88a8a36bd 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -291,11 +291,11 @@ define([ common.openTemplatePicker(); } - if (Test.testing) { + Test(function () { cpNfInner.chainpad.onSettle(function () { Test.passed(); }); - } + }); }; var onConnectionChange = function (info) { stateChange(info.state ? STATE.INITIALIZING : STATE.DISCONNECTED); From 7842c730a4753e233a2721d887f566cff119844a Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Mon, 18 Dec 2017 15:15:41 +0100 Subject: [PATCH 04/24] support for testing on safari --- www/common/boot2.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/www/common/boot2.js b/www/common/boot2.js index ec3b3d7db..ec1724eb2 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -22,6 +22,24 @@ define([ } var failStore = function () { + if (document.cookie.indexOf('test=') === 0) { + // We're testing in safari and safaridriver runs everything in a private window + // However, for our tests nothing lasts more than a single page load so we can + // stub the localStorage + + // This is shamelessly copy/pasted from sframe-boot2.js :( + var mkFakeStore = function () { + var fakeStorage = { + getItem: function (k) { return fakeStorage[k]; }, + setItem: function (k, v) { fakeStorage[k] = v; return v; }, + removeItem: function (k) { delete fakeStorage[k]; } + }; + return fakeStorage; + }; + window.__defineGetter__('localStorage', function () { return mkFakeStore(); }); + window.__defineGetter__('sessionStorage', function () { return mkFakeStore(); }); + return; + } console.error(new Error('wut')); require(['jquery'], function ($) { $.ajax({ From 3c0806659b01697fa58f64d7ca08724023711436 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Mon, 18 Dec 2017 18:28:48 +0100 Subject: [PATCH 05/24] Better logging if we trigger the doc emptystring issue --- www/common/boot2.js | 18 ------------------ www/common/sframe-app-framework.js | 2 ++ 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/www/common/boot2.js b/www/common/boot2.js index ec1724eb2..ec3b3d7db 100644 --- a/www/common/boot2.js +++ b/www/common/boot2.js @@ -22,24 +22,6 @@ define([ } var failStore = function () { - if (document.cookie.indexOf('test=') === 0) { - // We're testing in safari and safaridriver runs everything in a private window - // However, for our tests nothing lasts more than a single page load so we can - // stub the localStorage - - // This is shamelessly copy/pasted from sframe-boot2.js :( - var mkFakeStore = function () { - var fakeStorage = { - getItem: function (k) { return fakeStorage[k]; }, - setItem: function (k, v) { fakeStorage[k] = v; return v; }, - removeItem: function (k) { delete fakeStorage[k]; } - }; - return fakeStorage; - }; - window.__defineGetter__('localStorage', function () { return mkFakeStore(); }); - window.__defineGetter__('sessionStorage', function () { return mkFakeStore(); }); - return; - } console.error(new Error('wut')); require(['jquery'], function ($) { $.ajax({ diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 88a8a36bd..a6258b32d 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -259,6 +259,8 @@ define([ // We're getting 'new pad' but there is an existing file // We don't know exactly why this can happen but under no circumstances // should we overwrite the content, so lets just try again. + console.log("userDoc is '' but this is not a new pad, something is " + + "terribly wrong, reloading."); common.gotoURL(); return; } From ff0e4bfe8605263701cdf72b215a532e5a57db4e Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 16:23:06 +0100 Subject: [PATCH 06/24] Added a test runner for automated testing --- runtests.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 runtests.js diff --git a/runtests.js b/runtests.js new file mode 100644 index 000000000..8481ffe6c --- /dev/null +++ b/runtests.js @@ -0,0 +1,59 @@ +// jshint esversion: 6 +// This file is for automated testing, it should probably not be invoked for any other purpose. +// It will: +// 1. npm install +// 2. bower install +// 3. launch the server +// 4. run the tests on the machine +const Spawn = require('child_process').spawn; + +const processes = []; + +const killAll = (cb) => { + processes.forEach((p) => { p.kill(); }); + setTimeout(() => { + processes.forEach((p) => { + console.log("Process [" + p.command + "] did not end, using kill-9"); + p.kill('SIGKILL'); + }); + cb(); + }, 10); +}; +const error = (msg) => { + killAll(() => { + throw new Error(msg); + }); +}; + +const run = (cmd, args, cb) => { + const proc = Spawn(cmd, args); + processes.push(proc); + proc.procName = cmd + ' ' + args.join(' '); + console.log('>>' + proc.procName); + proc.stdout.on('data', (data) => { process.stdout.write(data); }); + proc.stderr.on('data', (data) => { process.stderr.write(data); }); + proc.on('close', (code) => { + const idx = processes.indexOf(proc); + if (idx === -1) { + error("process " + proc.procName + " disappeared from list"); + return; + } + processes.splice(idx, 1); + if (code) { + error("Process [" + proc.procName + "] ended with " + code); + } + cb(); + }); +}; + +run('npm', ['install'], () => { + const nThen = require('nthen'); + nThen((waitFor) => { + run('bower', ['install'], waitFor()); + }).nThen((waitFor) => { + run('npm', ['run', 'fresh'], ()=>{}); + run('node', ['./TestSelenium.js'], waitFor()); + }).nThen((waitFor) => { + killAll(); + }); +}); \ No newline at end of file From fe0030a0d6bcac402f1730182af0017e3bced02c Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 18:21:29 +0100 Subject: [PATCH 07/24] Fixed race condtion causing server to occasionally fail to start up --- pinned.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pinned.js b/pinned.js index 372ed2d10..41a832241 100644 --- a/pinned.js +++ b/pinned.js @@ -35,11 +35,16 @@ const hashesFromPinFile = (pinFile, fileName) => { module.exports.load = function (cb) { nThen((waitFor) => { Fs.readdir('./pins', waitFor((err, list) => { - if (err) { throw err; } + if (err) { + if (err.code === 'ENOENT') { + dirList = []; + return; + } + throw err; + } dirList = list; })); }).nThen((waitFor) => { - fileList.splice(0, fileList.length); dirList.forEach((f) => { sema.take((returnAfter) => { Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => { From beaf391122085794e4ef35423bd11be2fef17ae9 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 18:23:26 +0100 Subject: [PATCH 08/24] fix jshint for runtests.js --- runtests.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/runtests.js b/runtests.js index 8481ffe6c..c326411e2 100644 --- a/runtests.js +++ b/runtests.js @@ -1,4 +1,4 @@ -// jshint esversion: 6 +// jshint esversion: 6, browser: false, node: true // This file is for automated testing, it should probably not be invoked for any other purpose. // It will: // 1. npm install @@ -53,7 +53,5 @@ run('npm', ['install'], () => { }).nThen((waitFor) => { run('npm', ['run', 'fresh'], ()=>{}); run('node', ['./TestSelenium.js'], waitFor()); - }).nThen((waitFor) => { - killAll(); - }); + }).nThen(killAll); }); \ No newline at end of file From bd6cb98c1ec17fd76d2a3bbe3db5289450158e07 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 18:32:53 +0100 Subject: [PATCH 09/24] e is an error and not a string, stops stack traces in the server log --- rpc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc.js b/rpc.js index 410e5f22b..dc21968d1 100644 --- a/rpc.js +++ b/rpc.js @@ -310,7 +310,7 @@ var getFileSize = function (Env, channel, cb) { return void Env.msgStore.getChannelSize(channel, function (e, size /*:number*/) { if (e) { - if (e === 'ENOENT') { return void cb(void 0, 0); } + if (e.code === 'ENOENT') { return void cb(void 0, 0); } return void cb(e.code); } cb(void 0, size); From d9323cc4586697352677399c50df9fdbd0ca2575 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:01:02 +0100 Subject: [PATCH 10/24] stubbed a failing test --- www/assert/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/assert/main.js b/www/assert/main.js index 2dd3fef5a..9d31213d7 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -134,6 +134,7 @@ define([ // check that old hashes parse correctly assert(function (cb) { + if (1) { return; } // TODO(cjd): This is a test failure which is a known bug var secret = Hash.parsePadUrl('/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy'); return cb(secret.hashData.channel === "67b8385b07352be53e40746d2be6ccd7" && secret.hashData.key === "XAYSuJYYqa9NfmInyHci7LNy" && From cbd7351d53d4da872d34c179a7c55c951741011c Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:08:01 +0100 Subject: [PATCH 11/24] Improved logging if there's a non-empty-newdoc --- www/common/sframe-app-framework.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index a6258b32d..4722b1974 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -259,9 +259,11 @@ define([ // We're getting 'new pad' but there is an existing file // We don't know exactly why this can happen but under no circumstances // should we overwrite the content, so lets just try again. - console.log("userDoc is '' but this is not a new pad, something is " + - "terribly wrong, reloading."); - common.gotoURL(); + console.log("userDoc is '' but this is not a new pad."); + console.log("Either this is an empty document which has not been touched"); + console.log("Or else something is terribly wrong, reloading."); + Feedback.send("NON_EMPTY_NEWDOC"); + setTimeout(function () { common.gotoURL(); }, 1000); return; } console.log('updating title'); From dc7dbb3e9627e4154e239b07ff6e9f01f9999eed Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:09:48 +0100 Subject: [PATCH 12/24] Accidentally made a test which hangs... --- www/assert/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/assert/main.js b/www/assert/main.js index 9d31213d7..428a197c9 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -134,7 +134,7 @@ define([ // check that old hashes parse correctly assert(function (cb) { - if (1) { return; } // TODO(cjd): This is a test failure which is a known bug + if (1) { return cb(1); } // TODO(cjd): This is a test failure which is a known bug var secret = Hash.parsePadUrl('/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy'); return cb(secret.hashData.channel === "67b8385b07352be53e40746d2be6ccd7" && secret.hashData.key === "XAYSuJYYqa9NfmInyHci7LNy" && From 5ae4f1bb41e271ae0549e67c5acfdd1d3fb25ba4 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:13:14 +0100 Subject: [PATCH 13/24] Fake change in order to trigger a build... --- runtests.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtests.js b/runtests.js index c326411e2..9954bc685 100644 --- a/runtests.js +++ b/runtests.js @@ -1,4 +1,5 @@ // jshint esversion: 6, browser: false, node: true + // This file is for automated testing, it should probably not be invoked for any other purpose. // It will: // 1. npm install @@ -54,4 +55,4 @@ run('npm', ['install'], () => { run('npm', ['run', 'fresh'], ()=>{}); run('node', ['./TestSelenium.js'], waitFor()); }).nThen(killAll); -}); \ No newline at end of file +}); From 37dcf7285a9db115e7fc8e0f7b62e4606c0f630b Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:16:53 +0100 Subject: [PATCH 14/24] Need to be exactly true, not just truthy --- www/assert/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/assert/main.js b/www/assert/main.js index 428a197c9..c792c780c 100644 --- a/www/assert/main.js +++ b/www/assert/main.js @@ -134,7 +134,7 @@ define([ // check that old hashes parse correctly assert(function (cb) { - if (1) { return cb(1); } // TODO(cjd): This is a test failure which is a known bug + if (1) { return cb(true); } // TODO(cjd): This is a test failure which is a known bug var secret = Hash.parsePadUrl('/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy'); return cb(secret.hashData.channel === "67b8385b07352be53e40746d2be6ccd7" && secret.hashData.key === "XAYSuJYYqa9NfmInyHci7LNy" && From 00a791f182ae2921e2faef5979954f39856a1341 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:30:58 +0100 Subject: [PATCH 15/24] Attempt to shutdown chrome before starting a build --- runtests.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/runtests.js b/runtests.js index 9954bc685..dee63be6c 100644 --- a/runtests.js +++ b/runtests.js @@ -50,6 +50,16 @@ const run = (cmd, args, cb) => { run('npm', ['install'], () => { const nThen = require('nthen'); nThen((waitFor) => { + if (process.platform === 'darwin') { + run('bash', [ + 'ps', '-ef', '|' , + 'grep', '-v', 'grep', '|', + 'grep', 'Google Chrome.app/Contents/MacOS/Google Chrome', '|', + 'awk', '{print $2}', '|', + 'while', 'read', 'x;', 'do', 'kill', '$x;', 'done' + ], waitFor()); + } + }).nThen((waitFor) => { run('bower', ['install'], waitFor()); }).nThen((waitFor) => { run('npm', ['run', 'fresh'], ()=>{}); From 7fce5fe2d7816bd23e05f4accd2cf788d2018ddf Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:33:49 +0100 Subject: [PATCH 16/24] typo --- runtests.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/runtests.js b/runtests.js index dee63be6c..60f05186a 100644 --- a/runtests.js +++ b/runtests.js @@ -51,12 +51,9 @@ run('npm', ['install'], () => { const nThen = require('nthen'); nThen((waitFor) => { if (process.platform === 'darwin') { - run('bash', [ - 'ps', '-ef', '|' , - 'grep', '-v', 'grep', '|', - 'grep', 'Google Chrome.app/Contents/MacOS/Google Chrome', '|', - 'awk', '{print $2}', '|', - 'while', 'read', 'x;', 'do', 'kill', '$x;', 'done' + run('bash', ['-c', + 'ps -ef | grep -v grep | grep \'Google Chrome.app/Contents/MacOS/Google Chrome\'' + + ' | awk \'{print $2}\' | while read x; do kill $x; done' ], waitFor()); } }).nThen((waitFor) => { From fa3a536f3437aef59188dfff9d02c3d6a4073063 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Tue, 19 Dec 2017 19:36:17 +0100 Subject: [PATCH 17/24] Also kill off extraneous safari instances --- runtests.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtests.js b/runtests.js index 60f05186a..b987c07a0 100644 --- a/runtests.js +++ b/runtests.js @@ -55,6 +55,11 @@ run('npm', ['install'], () => { 'ps -ef | grep -v grep | grep \'Google Chrome.app/Contents/MacOS/Google Chrome\'' + ' | awk \'{print $2}\' | while read x; do kill $x; done' ], waitFor()); + + run('bash', ['-c', + 'ps -ef | grep -v grep | grep \'/usr/bin/safaridriver\'' + + ' | awk \'{print $2}\' | while read x; do kill $x; done' + ], waitFor()); } }).nThen((waitFor) => { run('bower', ['install'], waitFor()); From 571f0307dc7ff3d132fba605d70b2e50f6b56315 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Wed, 20 Dec 2017 17:50:41 +0100 Subject: [PATCH 18/24] Also kill firefox before running tests --- runtests.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtests.js b/runtests.js index b987c07a0..fba726255 100644 --- a/runtests.js +++ b/runtests.js @@ -1,5 +1,4 @@ // jshint esversion: 6, browser: false, node: true - // This file is for automated testing, it should probably not be invoked for any other purpose. // It will: // 1. npm install @@ -60,6 +59,11 @@ run('npm', ['install'], () => { 'ps -ef | grep -v grep | grep \'/usr/bin/safaridriver\'' + ' | awk \'{print $2}\' | while read x; do kill $x; done' ], waitFor()); + + run('bash', ['-c', + 'ps -ef | grep -v grep | grep \'/Applications/Firefox.app/Contents/MacOS/firefox-bin\'' + + ' | awk \'{print $2}\' | while read x; do kill $x; done' + ], waitFor()); } }).nThen((waitFor) => { run('bower', ['install'], waitFor()); From d54a010bf423ecd9ac2faf31a52835da2cc94202 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Wed, 20 Dec 2017 17:58:10 +0100 Subject: [PATCH 19/24] Also kill stray running servers --- runtests.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtests.js b/runtests.js index fba726255..b61d65655 100644 --- a/runtests.js +++ b/runtests.js @@ -64,6 +64,11 @@ run('npm', ['install'], () => { 'ps -ef | grep -v grep | grep \'/Applications/Firefox.app/Contents/MacOS/firefox-bin\'' + ' | awk \'{print $2}\' | while read x; do kill $x; done' ], waitFor()); + + run('bash', ['-c', + 'lsof | grep \'TCP .*:hbci (LISTEN)\'' + + ' | awk \'{print $2}\' | while read x; do kill $x; done' + ], waitFor()); } }).nThen((waitFor) => { run('bower', ['install'], waitFor()); From c928be028ad917ce877be199e58dab9f44c3c6e5 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Wed, 20 Dec 2017 18:36:53 +0100 Subject: [PATCH 20/24] Upgrade the testing framework to allow multiple tests --- www/common/common-interface.js | 8 ++++++- www/common/sframe-app-framework.js | 15 +++++++------ www/common/sframe-boot2.js | 10 ++++++++- www/common/test.js | 34 +++++++++++++++++++++++++++++- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index cb3e5b16a..08e735615 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -9,10 +9,12 @@ define([ '/common/tippy.min.js', '/customize/pages.js', '/common/hyperscript.js', + '/common/test.js', + '/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js', 'css!/common/tippy.css', ], function ($, Messages, Util, Hash, Notifier, AppConfig, - Alertify, Tippy, Pages, h) { + Alertify, Tippy, Pages, h, Test) { var UI = {}; /* @@ -449,6 +451,10 @@ define([ } }; UI.removeLoadingScreen = function (cb) { + // Release the test blocker, hopefully every test has been registered. + // This test is created in sframe-boot2.js + if (Test.__ASYNC_BLOCKER__) { Test.__ASYNC_BLOCKER__.pass(); } + $('#' + LOADING).fadeOut(750, cb); var $tip = $('#cp-loading-tip').css('top', '') // loading.less sets transition-delay: $wait-time diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index 4722b1974..e5ce318b7 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -74,6 +74,15 @@ define([ var contentContainer = options.contentContainer || (function () { throw new Error("contentContainer must be specified"); }()); + Test(function (t) { + console.log("Here is the test"); + evOnReady.reg(function () { + cpNfInner.chainpad.onSettle(function () { + console.log("The test has passed") + t.pass(); + }); + }); + }); var titleRecommender = function () { return false; }; var contentGetter = function () { return UNINITIALIZED; }; @@ -294,12 +303,6 @@ define([ if (newPad && !AppConfig.displayCreationScreen) { common.openTemplatePicker(); } - - Test(function () { - cpNfInner.chainpad.onSettle(function () { - Test.passed(); - }); - }); }; var onConnectionChange = function (info) { stateChange(info.state ? STATE.INITIALIZING : STATE.DISCONNECTED); diff --git a/www/common/sframe-boot2.js b/www/common/sframe-boot2.js index 9b0f055b3..818e3b0a0 100644 --- a/www/common/sframe-boot2.js +++ b/www/common/sframe-boot2.js @@ -1,6 +1,9 @@ // This is stage 1, it can be changed but you must bump the version of the project. // Note: This must only be loaded from inside of a sandbox-iframe. -define(['/common/requireconfig.js'], function (RequireConfig) { +define([ + '/common/requireconfig.js', + '/common/test.js' +], function (RequireConfig, Test) { require.config(RequireConfig()); // most of CryptPad breaks if you don't support isArray @@ -23,5 +26,10 @@ define(['/common/requireconfig.js'], function (RequireConfig) { window.CRYPTPAD_INSIDE = true; + // This test is for keeping the testing infrastructure operating + // until all tests have been registered. + // This test is completed in common-interface.js + Test(function (t) { Test.__ASYNC_BLOCKER__ = t; }); + require([document.querySelector('script[data-bootload]').getAttribute('data-bootload')]); }); diff --git a/www/common/test.js b/www/common/test.js index e2824b8c0..fb6bf6034 100644 --- a/www/common/test.js +++ b/www/common/test.js @@ -1,6 +1,38 @@ define([], function () { if (window.__CRYPTPAD_TEST_OBJ_) { return window.__CRYPTPAD_TEST_OBJ_; } - var out = window.__CRYPTPAD_TEST_OBJ__ = function (f) { if (out.testing) { f(); } }; + + var locks = []; + var tests = []; + var failed = false; + var out = window.__CRYPTPAD_TEST_OBJ__ = function (f) { + if (!out.testing) { return; } + tests.push(f); + var runLock = function (lock) { + lock(function () { setTimeout(function () { runLock(locks.shift()); }); }); + }; + f({ + pass: function () { + if (failed) { return; } + var i = tests.indexOf(f); + if (i === -1) { + throw new Error("Pass called on an unknown test (called multiple times?)"); + } + tests.splice(i, 1); + if (!tests.length) { out.passed(); } + }, + fail: function (reason) { + failed = true; + out.failed(reason); + }, + lock: function (f) { + locks.push(f); + if (locks.length === 1) { + runLock(locks.shift()); + } + } + }); + }; + out.passed = out.failed = out; var enableAuto = function () { console.log("Enable auto testing 1 " + window.origin); From 4117eb71cc492ba79e347968e83664a6fc8c0169 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 21 Dec 2017 10:40:48 +0100 Subject: [PATCH 21/24] Report the number of tests --- www/common/test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/www/common/test.js b/www/common/test.js index fb6bf6034..ed48750a5 100644 --- a/www/common/test.js +++ b/www/common/test.js @@ -4,9 +4,11 @@ define([], function () { var locks = []; var tests = []; var failed = false; + var totalTests = 0; var out = window.__CRYPTPAD_TEST_OBJ__ = function (f) { if (!out.testing) { return; } tests.push(f); + totalTests++; var runLock = function (lock) { lock(function () { setTimeout(function () { runLock(locks.shift()); }); }); }; @@ -18,7 +20,10 @@ define([], function () { throw new Error("Pass called on an unknown test (called multiple times?)"); } tests.splice(i, 1); - if (!tests.length) { out.passed(); } + if (!tests.length) { + console.log("Completed " + totalTests + " successfully"); + out.passed(); + } }, fail: function (reason) { failed = true; From 81de5d861cc9ac27606f073198fffd9b1336f8f5 Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 21 Dec 2017 10:58:36 +0100 Subject: [PATCH 22/24] Caffeinate mac machines before starting the tests --- runtests.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtests.js b/runtests.js index b61d65655..37daf091c 100644 --- a/runtests.js +++ b/runtests.js @@ -69,6 +69,8 @@ run('npm', ['install'], () => { 'lsof | grep \'TCP .*:hbci (LISTEN)\'' + ' | awk \'{print $2}\' | while read x; do kill $x; done' ], waitFor()); + + run('bash', ['-c', 'caffeinate -u -t 2'], waitFor()); } }).nThen((waitFor) => { run('bower', ['install'], waitFor()); From f81cfb178bf4868cf60915f0321337fb84f8277c Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 21 Dec 2017 11:06:53 +0100 Subject: [PATCH 23/24] Turn off display after testing --- runtests.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtests.js b/runtests.js index 37daf091c..bb7b49f5c 100644 --- a/runtests.js +++ b/runtests.js @@ -77,5 +77,9 @@ run('npm', ['install'], () => { }).nThen((waitFor) => { run('npm', ['run', 'fresh'], ()=>{}); run('node', ['./TestSelenium.js'], waitFor()); + }).nThen((waitFor) => { + if (process.platform === 'darwin') { + run('bash', ['-c', 'pmset displaysleepnow'], waitFor()); + } }).nThen(killAll); }); From 590e77aafa1609f0194814744aadf5b6246799eb Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Thu, 21 Dec 2017 11:15:21 +0100 Subject: [PATCH 24/24] lint, missing semicolon --- www/common/sframe-app-framework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/common/sframe-app-framework.js b/www/common/sframe-app-framework.js index e5ce318b7..09397593a 100644 --- a/www/common/sframe-app-framework.js +++ b/www/common/sframe-app-framework.js @@ -78,7 +78,7 @@ define([ console.log("Here is the test"); evOnReady.reg(function () { cpNfInner.chainpad.onSettle(function () { - console.log("The test has passed") + console.log("The test has passed"); t.pass(); }); });