diff --git a/js/test/Alert.js b/js/test/Alert.js new file mode 100644 index 00000000..2ee42de6 --- /dev/null +++ b/js/test/Alert.js @@ -0,0 +1,223 @@ +'use strict'; +var common = require('../common'); + +describe('Alert', function () { + describe('showStatus', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows a status message', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showStatus(message, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('showError', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows an error message', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + function (icon, message) { + icon = icon.join(''); + message = message.join(''); + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showError(message, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('showRemaining', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows remaining time', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + 'integer', + function (message, string, number) { + message = message.join(''); + string = string.join(''); + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('showLoading', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'shows a loading message', + jsc.array(common.jscAlnumString()), + jsc.array(common.jscAlnumString()), + 'integer', + function (icon, message, number) { + icon = icon.join(''); + message = message.join(''); + var default_message = 'Loading…'; + if (message.length == 0) { + message = default_message; + } + var expected = ''; + $('body').html( + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.showLoading(message, number, icon); + var result = $('body').html(); + return expected === result; + } + ); + }); + + describe('hideLoading', function () { + before(function () { + cleanup(); + }); + + it( + 'hides the loading message', + function() { + $('body').html( + '' + ); + $('body').addClass('loading'); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.hideLoading(); + return !$('body').hasClass('loading') && + $('#loadingindicator').hasClass('hidden'); + } + ); + }); + + describe('hideMessages', function () { + before(function () { + cleanup(); + }); + + it( + 'hides all messages', + function() { + $('body').html( + '' + + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.hideMessages(); + return $('#statusmessage').hasClass('hidden') && + $('#errormessage').hasClass('hidden'); + } + ); + }); + + describe('setCustomHandler', function () { + before(function () { + cleanup(); + }); + + jsc.property( + 'calls a given handler function', + 'nat 3', + jsc.array(common.jscAlnumString()), + function (trigger, message) { + message = message.join(''); + var handlerCalled = false, + default_message = 'Loading…', + functions = [ + $.PrivateBin.Alert.showStatus, + $.PrivateBin.Alert.showError, + $.PrivateBin.Alert.showRemaining, + $.PrivateBin.Alert.showLoading + ]; + if (message.length == 0) { + message = default_message; + } + $('body').html( + '' + + '' + + '' + + '' + ); + $.PrivateBin.Alert.init(); + $.PrivateBin.Alert.setCustomHandler(function(id, $element) { + handlerCalled = true; + return jsc.random(0, 1) ? true : $element; + }); + functions[trigger](message); + return handlerCalled; + } + ); + }); +}); + diff --git a/js/test/Editor.js b/js/test/Editor.js new file mode 100644 index 00000000..60e424f1 --- /dev/null +++ b/js/test/Editor.js @@ -0,0 +1,74 @@ +'use strict'; +var common = require('../common'); + +describe('Editor', function () { + describe('show, hide, getText, setText & isPreview', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'returns text fed into the textarea, handles editor tabs', + 'string', + function (text) { + var clean = jsdom(), + results = []; + $('body').html( + '' + + '

' + ); + $.PrivateBin.Editor.init(); + results.push( + $('#editorTabs').hasClass('hidden') && + $('#message').hasClass('hidden') + ); + $.PrivateBin.Editor.show(); + results.push( + !$('#editorTabs').hasClass('hidden') && + !$('#message').hasClass('hidden') + ); + $.PrivateBin.Editor.hide(); + results.push( + $('#editorTabs').hasClass('hidden') && + $('#message').hasClass('hidden') + ); + $.PrivateBin.Editor.show(); + $.PrivateBin.Editor.focusInput(); + results.push( + $.PrivateBin.Editor.getText().length == 0 + ); + $.PrivateBin.Editor.setText(text); + results.push( + $.PrivateBin.Editor.getText() == $('#message').val() + ); + $.PrivateBin.Editor.setText(); + results.push( + !$.PrivateBin.Editor.isPreview() && + !$('#message').hasClass('hidden') + ); + $('#messagepreview').click(); + results.push( + $.PrivateBin.Editor.isPreview() && + $('#message').hasClass('hidden') + ); + $('#messageedit').click(); + results.push( + !$.PrivateBin.Editor.isPreview() && + !$('#message').hasClass('hidden') + ); + clean(); + return results.every(element => element); + } + ); + }); +}); + diff --git a/js/test/PasteStatus.js b/js/test/PasteStatus.js new file mode 100644 index 00000000..dbc21483 --- /dev/null +++ b/js/test/PasteStatus.js @@ -0,0 +1,104 @@ +'use strict'; +var common = require('../common'); + +describe('PasteStatus', function () { + describe('createPasteNotification', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'creates a notification after a successfull paste upload', + common.jscSchemas(), + jsc.nearray(common.jscA2zString()), + jsc.array(common.jscQueryString()), + 'string', + common.jscSchemas(), + jsc.nearray(common.jscA2zString()), + jsc.array(common.jscQueryString()), + function ( + schema1, address1, query1, fragment1, + schema2, address2, query2 + ) { + var expected1 = schema1 + '://' + address1.join('') + '/?' + + encodeURI(query1.join('').replace(/^&+|&+$/gm,'') + '#' + fragment1), + expected2 = schema2 + '://' + address2.join('') + '/?' + + encodeURI(query2.join('')), + clean = jsdom(); + $('body').html('
'); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2); + var result1 = $('#pasteurl')[0].href, + result2 = $('#deletelink a')[0].href; + clean(); + return result1 == expected1 && result2 == expected2; + } + ); + }); + + describe('showRemainingTime', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'shows burn after reading message or remaining time', + 'bool', + 'nat', + jsc.nearray(common.jscA2zString()), + jsc.nearray(common.jscA2zString()), + jsc.nearray(common.jscQueryString()), + 'string', + function ( + burnafterreading, remaining_time, + schema, address, query, fragment + ) { + var clean = jsdom('', { + url: schema.join('') + '://' + address.join('') + + '/?' + query.join('') + '#' + fragment + }); + $('body').html(''); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.showRemainingTime({ + 'burnafterreading': burnafterreading, + 'remaining_time': remaining_time, + 'expire_date': remaining_time ? ((new Date()).getTime() / 1000) + remaining_time : 0 + }); + if (burnafterreading) { + var result = $('#remainingtime').hasClass('foryoureyesonly') && + !$('#remainingtime').hasClass('hidden'); + } else if (remaining_time) { + var result =!$('#remainingtime').hasClass('foryoureyesonly') && + !$('#remainingtime').hasClass('hidden'); + } else { + var result = $('#remainingtime').hasClass('hidden') && + !$('#remainingtime').hasClass('foryoureyesonly'); + } + clean(); + return result; + } + ); + }); + + describe('hideMessages', function () { + before(function () { + cleanup(); + }); + + it( + 'hides all messages', + function() { + $('body').html( + '
' + ); + $.PrivateBin.PasteStatus.init(); + $.PrivateBin.PasteStatus.hideMessages(); + return $('#remainingtime').hasClass('hidden') && + $('#pastesuccess').hasClass('hidden'); + } + ); + }); +}); + diff --git a/js/test/Prompt.js b/js/test/Prompt.js new file mode 100644 index 00000000..d093b716 --- /dev/null +++ b/js/test/Prompt.js @@ -0,0 +1,40 @@ +'use strict'; +var common = require('../common'); + +describe('Prompt', function () { + // TODO: this does not test the prompt() fallback, since that isn't available + // in nodejs -> replace the prompt in the "page" template with a modal + describe('requestPassword & getPassword', function () { + this.timeout(30000); + before(function () { + cleanup(); + }); + + jsc.property( + 'returns the password fed into the dialog', + 'string', + function (password) { + password = password.replace(/\r+/g, ''); + var clean = jsdom('', {url: 'ftp://example.com/#0'}); + $('body').html( + '
{}
' + ); + $.PrivateBin.Model.init(); + $.PrivateBin.Prompt.init(); + $.PrivateBin.Prompt.requestPassword(); + $('#passworddecrypt').val(password); + $('#passwordform').submit(); + var result = $.PrivateBin.Prompt.getPassword(); + clean(); + return result == password; + } + ); + }); +}); + diff --git a/js/test/UiHelper.js b/js/test/UiHelper.js new file mode 100644 index 00000000..013d062f --- /dev/null +++ b/js/test/UiHelper.js @@ -0,0 +1,124 @@ +'use strict'; +var common = require('../common'); + +describe('UiHelper', function () { + // TODO: As per https://github.com/tmpvar/jsdom/issues/1565 there is no navigation support in jsdom, yet. + // for now we use a mock function to trigger the event + describe('historyChange', function () { + this.timeout(30000); + before(function () { + $.PrivateBin.Helper.reset(); + cleanup(); + }); + + jsc.property( + 'redirects to home, when the state is null', + common.jscSchemas(), + jsc.nearray(common.jscA2zString()), + function (schema, address) { + var expected = schema + '://' + address.join('') + '/', + clean = jsdom('', {url: expected}); + + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); + $.PrivateBin.UiHelper.mockHistoryChange(); + $.PrivateBin.Helper.reset(); + var result = window.location.href; + clean(); + return expected === result; + } + ); + + jsc.property( + 'does not redirect to home, when a new paste is created', + common.jscSchemas(), + jsc.nearray(common.jscA2zString()), + jsc.array(common.jscQueryString()), + jsc.nearray(common.jscBase64String()), + function (schema, address, query, fragment) { + var expected = schema + '://' + address.join('') + '/' + '?' + + query.join('') + '#' + fragment.join(''), + clean = jsdom('', {url: expected}); + + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); + $.PrivateBin.UiHelper.mockHistoryChange([ + {type: 'newpaste'}, '', expected + ]); + $.PrivateBin.Helper.reset(); + var result = window.location.href; + clean(); + return expected === result; + } + ); + }); + + describe('reloadHome', function () { + this.timeout(30000); + before(function () { + $.PrivateBin.Helper.reset(); + }); + + jsc.property( + 'redirects to home', + common.jscSchemas(), + jsc.nearray(common.jscA2zString()), + jsc.array(common.jscQueryString()), + jsc.nearray(common.jscBase64String()), + function (schema, address, query, fragment) { + var expected = schema + '://' + address.join('') + '/', + clean = jsdom('', { + url: expected + '?' + query.join('') + '#' + fragment.join('') + }); + + // make window.location.href writable + Object.defineProperty(window.location, 'href', { + writable: true, + value: window.location.href + }); + $.PrivateBin.UiHelper.reloadHome(); + $.PrivateBin.Helper.reset(); + var result = window.location.href; + clean(); + return expected === result; + } + ); + }); + + describe('isVisible', function () { + // TODO As per https://github.com/tmpvar/jsdom/issues/1048 there is no layout support in jsdom, yet. + // once it is supported or a workaround is found, uncomment the section below + /* + before(function () { + $.PrivateBin.Helper.reset(); + }); + + jsc.property( + 'detect visible elements', + jsc.nearray(common.jscAlnumString()), + jsc.nearray(common.jscA2zString()), + function (id, element) { + id = id.join(''); + element = element.join(''); + var clean = jsdom( + '<' + element + ' id="' + id + '">' + ); + var result = $.PrivateBin.UiHelper.isVisible($('#' + id)); + clean(); + return result; + } + ); + */ + }); + + describe('scrollTo', function () { + // TODO Did not find a way to test that, see isVisible test above + }); +}); +