Compare commits

...

45 Commits

Author SHA1 Message Date
rugk
5acdafaa23 wipfix(devcontainer): fix/use new URL for mocha feature 2026-03-20 16:52:06 +00:00
rugk
a02257a0a3 test: remove asliased cleanup function 2026-03-20 10:22:19 +00:00
rugk
7d09d66b06 test: strengthen PasteStatus test 2026-03-20 09:06:55 +00:00
rugk
13ecf7e7cb test: fix PasteStatus tests by creating pastesuccess notification 2026-03-20 09:06:35 +00:00
rugk
c2bfcc17fd test: explicitly include fs dependency 2026-03-20 08:16:04 +00:00
rugk
045a356c09 test: remove one more jQuery call 2026-03-19 17:23:09 +00:00
rugk
543dc39202 test: remove jQuery from CopyToClipboard even more
Co-Authored-By: Copilot
2026-03-19 17:18:17 +00:00
rugk
fbd697245d refactor: remove jQuery from initializers 2026-03-19 17:15:46 +00:00
rugk
e094c39186 fix: fix nullable problems found via AttachmentViewer test 2026-03-19 17:03:09 +00:00
rugk
784f381e28 test: change all other tests to not use jQuery 2026-03-19 16:53:30 +00:00
rugk
414a87c025 test: use native non jquery for TopNav too fixing most tests of it 2026-03-18 16:09:46 +00:00
rugk
cc431a3f14 test: use document.documentElement.innerHTML for setting test HTML 2026-03-18 14:09:15 +00:00
rugk
3820fdf765 style: remove manual cleanup 2026-03-18 13:58:49 +00:00
rugk
0f3831b423 style: use web APIs to set document instead of jQuery for compatibility 2026-03-18 13:58:24 +00:00
rugk
2cf32c1c75 style(jsdoc): fix typing 2026-03-18 13:57:21 +00:00
rugk
1104873830 test: fix tests error again 2026-03-18 13:57:09 +00:00
rugk
2678d2c2b2 test: fix test & implementation error with missing buttons (ids) in UI 2026-03-03 11:08:45 +00:00
rugk
3de6dc9f68 test: use cleanup function everywhere instead of jsdom manually 2026-03-03 11:01:30 +00:00
rugk
778df44b0b test: manually remove useless cleanup stuff 2026-03-03 11:00:25 +00:00
rugk
69533d493b Merge branch 'master' of https://github.com/PrivateBin/PrivateBin into js/removeJQuery 2026-03-03 10:28:27 +00:00
rugk
dbd380332c style: fix ESLint no-return-assign 2026-03-03 10:12:32 +00:00
rugk
d5bf7674ff style: use template literal 2026-03-03 10:07:52 +00:00
rugk
3a08f1866d chore: use correct base href 2026-03-03 10:02:22 +00:00
rugk
194eb93d00 chore: stay on ES2018 for now 2026-03-03 10:00:48 +00:00
rugk
bbeab997c4 chore: ignore jsconfig.json when exporting 2026-03-03 09:58:48 +00:00
rugk
0155f99e58 test: import privatebin.js 2026-03-01 18:41:16 +00:00
rugk
47aa7aae36 test: Copilot generated new simpler test cases 2026-03-01 16:30:07 +00:00
rugk
b11541a8e4 test: more test fixes
Co-Authored-By: Copliot
2026-03-01 16:19:34 +00:00
rugk
ea4f5ba920 test: Copilots tries at fixing tests 2026-03-01 15:22:05 +00:00
rugk
48678638d0 refactor: more null checks introduced by Copilot for fixing tests 2026-03-01 15:20:20 +00:00
rugk
71c6efd3bb wipfeat(i18n): improve error logging for missing translation 2026-03-01 15:16:05 +00:00
rugk
8d360cd6be wipfix: fix more nullabe problems 2026-03-01 15:05:44 +00:00
rugk
38baa8edbe wipfix(i18n): make sure to check for string
Likely introdued in https://github.com/PrivateBin/PrivateBin/pull/1730
2026-03-01 15:04:22 +00:00
rugk
393eb070e9 fix: manually fix exceptions occuring when loading main page 2026-03-01 14:58:18 +00:00
rugk
8bca112251 wipfix: fix variable shadowing problem 2026-03-01 14:29:38 +00:00
rugk
5b008ac5d9 refactor: remove more jQuery references 2026-03-01 14:26:41 +00:00
rugk
d8b377dd80 style: remove JQuery fallback 2026-03-01 15:03:16 +01:00
rugk
a4ca27d9a3 Potential fix for pull request finding 'Duplicate character in character class'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-02-26 17:57:04 +01:00
rugk
7528639fde Potential fix for pull request finding 'Duplicate character in character class'
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-02-26 17:55:31 +01:00
rugk
d285a9dfee refactor: remove more jQuery
Co-Authored-By: CoPilot
2026-02-25 20:04:32 +00:00
rugk
84e7cbdfbf test: guard due to test error (fatal memory crash)
Co-Authored-By: Copilot
2026-02-25 18:58:50 +00:00
rugk
0fe51a91a4 test: add npm lint command 2026-02-25 18:57:30 +00:00
rugk
a6e250f825 refactor: remove more jQuery stuff 2026-02-25 10:09:14 +00:00
rugk
14cba7f4c1 refactor: first step removing jQuery
You are a Frontend engineer specialized in refactoring legacy codebases.
Your task is to solve https://github.com/PrivateBin/PrivateBin/issues/198 aka refactor the JavaScript Frontend code to remove all uses of jQuery in order to modernize the codebase.

**Important notes:**
 - The file to modify is #file:privatebin.js.
 - The mocha tests should stay compatible and continue to run.
 - Do not refactor anything else except what is needed for removing jQuery.

Co-Authored-By: Copilot
2026-02-25 09:53:04 +00:00
rugk
e2d900eb02 test: add basic JSConfig to make VSCode type-check the JS file 2026-02-25 09:51:16 +00:00
23 changed files with 2066 additions and 1963 deletions

View File

@@ -36,7 +36,7 @@
}
},
"features": {
"ghcr.io/devcontainers-contrib/features/mocha:2": {},
"ghcr.io/devcontainers-extra/features/mocha:2": {},
"ghcr.io/yassinedoghri/devcontainers/php-extensions-installer:1": {
"extensions": "gd"
}

1
.gitattributes vendored
View File

@@ -9,6 +9,7 @@ js/.nycrc.yml export-ignore
js/common.js export-ignore
js/eslint.config.js export-ignore
js/test/ export-ignore
js/jsconfig.json export-ignore
.codeclimate.yml export-ignore
.csslintrc export-ignore
.devcontainer export-ignore

View File

@@ -4,7 +4,46 @@
global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom();
// initial DOM environment created by jsdom-global
let currentCleanup = global.jsdom();
// wrap cleanup so that calling it recreates a fresh jsdom environment
global.cleanup = function (...args) {
// remove previous environment
if (typeof currentCleanup === 'function') {
currentCleanup();
}
// create a new jsdom environment
currentCleanup = global.jsdom(...args);
// Make sure window and document are available in global scope for module loading
// jsdom-global sets them, but we need to ensure they're accessible
if (typeof window === 'undefined') {
throw new Error('jsdom-global failed to set up window');
}
if (typeof document === 'undefined') {
throw new Error('jsdom-global failed to set up document');
}
// Clear module cache to ensure modules are re-evaluated with new jsdom environment
delete require.cache[require.resolve('./privatebin')];
delete require.cache[require.resolve('./legacy')];
require('./privatebin');
if (typeof PrivateBin === 'undefined') {
throw new Error('PrivateBin module did not load correctly');
}
// also re-export the PrivateBin namespace if available
if (typeof window !== 'undefined' && window.PrivateBin) {
global.PrivateBin = window.PrivateBin;
if (global.$) {
global.$.PrivateBin = window.PrivateBin;
}
}
return global.cleanup;
};
global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto;
@@ -12,14 +51,23 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
global.$ = global.jQuery = require('./jquery-3.7.1');
global.zlib = require('./zlib-1.3.1-2').zlib;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.prettyPrint = window.PR ? window.PR.prettyPrint : function() {};
global.prettyPrintOne = window.PR ? window.PR.prettyPrintOne : function() {};
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.3.0');
global.baseX = require('./base-x-5.0.1').baseX;
global.Legacy = require('./legacy').Legacy;
require('./privatebin');
// provide global access to the namespace so tests can reference it directly
if (typeof window !== 'undefined' && window.PrivateBin) {
global.PrivateBin = window.PrivateBin;
// keep the old jQuery alias around just in case some tests still use it
if (global.$) {
global.$.PrivateBin = window.PrivateBin;
}
}
// internal variables
var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],

22
js/jsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es2018",
"module": "NodeNext",
"moduleResolution": "nodenext",
"resolveJsonModule": true,
"checkJs": true,
"strict": true,
"noImplicitAny": false,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"baseUrl": "./js",
"paths": {
"/*": ["./*"],
}
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

View File

@@ -16,6 +16,7 @@
"nyc": "^17.1.0"
},
"scripts": {
"lint": "eslint",
"test": "mocha",
"ci-test": "mocha --reporter xunit --reporter-option output=mocha-results.xml"
},

File diff suppressed because it is too large Load Diff

View File

@@ -11,12 +11,11 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="status">' + message + '</div>';
$('body').html(
'<div id="status"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
document.body.innerHTML =
'<div id="status"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -30,14 +29,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message);
const result = $('body').html();
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -53,14 +51,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
'glyphicon-info-sign" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showStatus(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -75,12 +72,11 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -95,14 +91,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-warning-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message);
const result = $('body').html();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -118,14 +113,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showWarning(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -140,12 +134,11 @@ describe('Alert', function () {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
document.body.innerHTML =
'<div id="errormessage"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -160,14 +153,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message);
const result = $('body').html();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -183,14 +175,13 @@ describe('Alert', function () {
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showError(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -206,12 +197,11 @@ describe('Alert', function () {
message = message.join('');
string = string.join('');
const expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
$('body').html(
'<div id="remainingtime" class="hidden"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
document.body.innerHTML =
'<div id="remainingtime" class="hidden"></div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -228,14 +218,13 @@ describe('Alert', function () {
'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> <span>' + string + message + number + '</span></div>';
$('body').html(
document.body.innerHTML =
'<div id="remainingtime" role="alert" class="hidden ' +
'alert alert-info"><span class="glyphicon ' +
'glyphicon-fire" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
'glyphicon-fire" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -254,12 +243,11 @@ describe('Alert', function () {
message = defaultMessage;
}
const expected = '<div id="loadingindicator" class="">' + message + '</div>';
$('body').html(
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
document.body.innerHTML =
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>';
PrivateBin.Alert.init();
PrivateBin.Alert.showLoading(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -279,15 +267,14 @@ describe('Alert', function () {
'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
defaultMessage + '</li></ul>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
defaultMessage + '</li></ul>';
PrivateBin.Alert.init();
PrivateBin.Alert.showLoading(message, icon);
const result = document.body.innerHTML;
return expected === result;
}
);
@@ -297,17 +284,16 @@ describe('Alert', function () {
it(
'hides the loading message',
function() {
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
'Loading…</li></ul>'
);
$('body').addClass('loading');
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideLoading();
assert.ok(!$('body').hasClass('loading'));
assert.ok($('#loadingindicator').hasClass('hidden'));
'Loading…</li></ul>';
document.body.classList.add('loading');
PrivateBin.Alert.init();
PrivateBin.Alert.hideLoading();
assert.ok(!document.body.classList.contains('loading'));
assert.ok(document.getElementById('loadingindicator').classList.contains('hidden'));
}
);
});
@@ -316,18 +302,17 @@ describe('Alert', function () {
it(
'hides all messages',
function() {
$('body').html(
document.body.innerHTML =
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>' +
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.hideMessages();
assert.ok($('#status').hasClass('hidden'));
assert.ok($('#errormessage').hasClass('hidden'));
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.hideMessages();
assert.ok(document.getElementById('status').classList.contains('hidden'));
assert.ok(document.getElementById('errormessage').classList.contains('hidden'));
}
);
});
@@ -342,15 +327,15 @@ describe('Alert', function () {
let handlerCalled = false,
defaultMessage = 'Loading…',
functions = [
$.PrivateBin.Alert.showStatus,
$.PrivateBin.Alert.showError,
$.PrivateBin.Alert.showRemaining,
$.PrivateBin.Alert.showLoading
PrivateBin.Alert.showStatus,
PrivateBin.Alert.showError,
PrivateBin.Alert.showRemaining,
PrivateBin.Alert.showLoading
];
if (message.length === 0) {
message = defaultMessage;
}
$('body').html(
document.body.innerHTML =
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
'glyphicon-time" aria-hidden="true"></span> ' +
@@ -363,15 +348,14 @@ describe('Alert', function () {
'glyphicon-info-sign" aria-hidden="true"></span> </div>' +
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.setCustomHandler(function(id, $element) {
'glyphicon-alert" aria-hidden="true"></span> </div>';
PrivateBin.Alert.init();
PrivateBin.Alert.setCustomHandler(function(id, element) {
handlerCalled = true;
return jsc.random(0, 1) ? true : $element;
return jsc.random(0, 1) ? true : element;
});
functions[trigger](message);
$.PrivateBin.Alert.setCustomHandler(null);
PrivateBin.Alert.setCustomHandler(null);
return handlerCalled;
}
);

View File

@@ -14,7 +14,7 @@ describe('AttachmentViewer', function () {
'string',
// eslint-disable-next-line complexity
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
let clean = globalThis.cleanup(),
data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata),
mimePrefix = mimeType.substring(0, 6),
previewSupported = (
@@ -31,7 +31,7 @@ describe('AttachmentViewer', function () {
}
prefix = prefix.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<|>/g, '');
$('body').html(
document.body.innerHTML = (
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -51,60 +51,62 @@ describe('AttachmentViewer', function () {
}}
);
}
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
results.push(
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmenttemplate').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden')
!PrivateBin.AttachmentViewer.hasAttachment() &&
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length === 0 &&
document.getElementById('attachmenttemplate').classList.contains('hidden') &&
document.getElementById('attachmentPreview').classList.contains('hidden')
);
global.atob = common.atob;
if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename);
PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else {
$.PrivateBin.AttachmentViewer.setAttachment(data);
PrivateBin.AttachmentViewer.setAttachment(data);
}
// // beyond this point we will get the blob URL instead of the data
data = window.URL.createObjectURL(data);
const attachment = $.PrivateBin.AttachmentViewer.getAttachments();
const attachment = PrivateBin.AttachmentViewer.getAttachments();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
$('#attachmentPreview').hasClass('hidden') &&
PrivateBin.AttachmentViewer.hasAttachment() &&
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length > 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden') &&
attachment[0][0] === data &&
attachment[0][1] === filename
);
$.PrivateBin.AttachmentViewer.showAttachment();
PrivateBin.AttachmentViewer.showAttachment();
results.push(
!$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
!document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length > 0 &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
$.PrivateBin.AttachmentViewer.hideAttachment();
PrivateBin.AttachmentViewer.hideAttachment();
results.push(
$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
if (previewSupported) {
$.PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push($('#attachmentPreview').hasClass('hidden'));
PrivateBin.AttachmentViewer.hideAttachmentPreview();
results.push(document.getElementById('attachmentPreview').classList.contains('hidden'));
}
$.PrivateBin.AttachmentViewer.showAttachment();
PrivateBin.AttachmentViewer.showAttachment();
results.push(
!$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
!document.getElementById('attachment').classList.contains('hidden') &&
(previewSupported ? !document.getElementById('attachmentPreview').classList.contains('hidden') : document.getElementById('attachmentPreview').classList.contains('hidden'))
);
let element = $('<div>');
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
let element = document.createElement('div');
PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
// messageIDs with links get a relaxed treatment
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
result = $('<textarea>').text((prefix + filename + postfix)).text();
const tempTA = document.createElement('textarea');
tempTA.textContent = (prefix + filename + postfix);
result = tempTA.textContent;
} else {
result = DOMPurify.sanitize(
prefix + $.PrivateBin.Helper.htmlEntities(filename) + postfix, {
prefix + PrivateBin.Helper.htmlEntities(filename) + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
@@ -112,18 +114,18 @@ describe('AttachmentViewer', function () {
}
if (filename.length) {
results.push(
element.find('a')[0].href === data &&
element.find('a')[0].getAttribute('download') === filename &&
element.find('a')[0].text === result
element.querySelector('a').href === data &&
element.querySelector('a').getAttribute('download') === filename &&
element.querySelector('a').textContent === result
);
} else {
results.push(element.find('a')[0].href === data);
results.push(element.querySelector('a').href === data);
}
$.PrivateBin.AttachmentViewer.removeAttachment();
PrivateBin.AttachmentViewer.removeAttachment();
results.push(
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmentPreview').hasClass('hidden')
document.getElementById('attachment').classList.contains('hidden') &&
document.getElementById('attachment').children.length === 0 &&
document.getElementById('attachmentPreview').classList.contains('hidden')
);
clean();
return results.every(element => element);
@@ -133,8 +135,8 @@ describe('AttachmentViewer', function () {
it(
'sanitizes file names in attachments',
function() {
const clean = jsdom();
$('body').html(
const clean = globalThis.cleanup();
document.body.innerHTML = (
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
@@ -154,8 +156,8 @@ describe('AttachmentViewer', function () {
}}
);
}
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
PrivateBin.AttachmentViewer.init();
PrivateBin.Model.init();
global.atob = common.atob;
const maliciousFileNames = [
@@ -163,8 +165,8 @@ describe('AttachmentViewer', function () {
'"><meta http-equiv="refresh" content="0;url=http://example.com/">.txt'
];
for (const filename of maliciousFileNames) {
$.PrivateBin.AttachmentViewer.setAttachment('data:;base64,', filename);
assert.ok(!$('body').html().includes(filename));
PrivateBin.AttachmentViewer.setAttachment('data:;base64,', filename);
assert.ok(!document.body.innerHTML.includes(filename));
}
clean();
}

View File

@@ -12,7 +12,7 @@ describe('Check', function () {
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = jsdom(
const clean = globalThis.cleanup(
'<html><body><div id="errormessage" class="hidden"></div>' +
'</body></html>', {
'userAgent': prefix + botBit + suffix
@@ -36,7 +36,7 @@ describe('Check', function () {
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom(
clean = globalThis.cleanup(
'<html><body><div id="errormessage" class="hidden"></div>' +
'<div id="oldnotice" class="hidden"></div>' +
'<div id="insecurecontextnotice" class="hidden"></div></body></html>',
@@ -63,7 +63,7 @@ describe('Check', function () {
'bool',
jsc.nearray(common.jscA2zString()),
function (secureProtocol, domain) {
const clean = jsdom(
const clean = globalThis.cleanup(
'<html><body><div id="httpnotice" class="hidden"></div>' +
'</body></html>',
{

View File

@@ -9,10 +9,10 @@ describe('CopyToClipboard', function() {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html(
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
@@ -21,14 +21,14 @@ describe('CopyToClipboard', function() {
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
document.getElementById('prettyMessageCopyBtn').click();
const savedToClipboardText = await navigator.clipboard.readText();
@@ -46,10 +46,10 @@ describe('CopyToClipboard', function() {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html(
document.body.innerHTML = (
'<div id="placeholder">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
@@ -58,14 +58,14 @@ describe('CopyToClipboard', function() {
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.init();
$('body').trigger('copy');
document.body.dispatchEvent(new Event('copy'));
const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
@@ -80,15 +80,15 @@ describe('CopyToClipboard', function() {
jsc.property('Copy link to clipboard',
'nestring',
async function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
common.enableClipboard();
$('body').html('<button id="copyLink"></button>');
document.body.innerHTML = '<button id="copyLink"></button>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.setUrl(text);
$('#copyLink').trigger('click');
document.getElementById('copyLink').click();
const copiedText = await navigator.clipboard.readText();
@@ -103,14 +103,14 @@ describe('CopyToClipboard', function() {
jsc.property('Show hint',
'nestring',
function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
$('body').html('<small id="copyShortcutHintText"></small>');
document.body.innerHTML = '<small id="copyShortcutHintText"></small>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
clean();
@@ -121,14 +121,14 @@ describe('CopyToClipboard', function() {
jsc.property('Hide hint',
'nestring',
function (text) {
var clean = jsdom();
var clean = globalThis.cleanup();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
document.body.innerHTML = '<small id="copyShortcutHintText">' + text + '</small>';
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
PrivateBin.CopyToClipboard.init();
PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
const keyboardShortcutHint = document.getElementById('copyShortcutHintText').textContent;
clean();
@@ -136,4 +136,4 @@ describe('CopyToClipboard', function() {
}
);
});
});
});

View File

@@ -1,5 +1,6 @@
'use strict';
const common = require('../common');
const fs = require('fs');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
@@ -15,9 +16,9 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password, message) {
const clean = jsdom();
const clean = globalThis.cleanup();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
@@ -25,10 +26,10 @@ describe('CryptTool', function () {
global.atob = common.atob;
global.btoa = common.btoa;
message = message.trim();
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
@@ -42,19 +43,19 @@ describe('CryptTool', function () {
it('does not truncate messages', async function () {
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
clean = jsdom();
clean = globalThis.cleanup();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
global.atob = common.atob;
global.btoa = common.btoa;
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage
);
clean();
@@ -91,17 +92,17 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
const clean = jsdom();
const clean = globalThis.cleanup();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
plaintext = await PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
@@ -123,12 +124,12 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
jsc.assert(jsc.forall(
'integer',
function(counter) {
const clean = jsdom();
const clean = globalThis.cleanup();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false
});
const key = $.PrivateBin.CryptTool.getSymmetricKey(),
const key = PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();

View File

@@ -26,9 +26,9 @@ describe('DiscussionViewer', function () {
jsc.elements(['loading', 'danger', 'other']),
'nestring',
function (comments, commentKey, fadeOut, nickname, message, alertType, alert) {
var clean = jsdom(),
var clean = globalThis.cleanup(),
results = [];
$('body').html(
document.body.innerHTML = (
'<div id="discussion"><h4>Discussion</h4>' +
'<div id="commentcontainer"></div></div><div id="templates">' +
'<article id="commenttemplate" class="comment">' +
@@ -48,59 +48,59 @@ describe('DiscussionViewer', function () {
'aria-hidden="true"></span> </div><button id="replybutton" ' +
'class="btn btn-default btn-sm">Post comment</button></div></div>'
);
$.PrivateBin.Model.init();
$.PrivateBin.DiscussionViewer.init();
PrivateBin.Model.init();
PrivateBin.DiscussionViewer.init();
results.push(
!$('#discussion').hasClass('hidden')
!document.getElementById('discussion').classList.contains('hidden')
);
$.PrivateBin.DiscussionViewer.prepareNewDiscussion();
PrivateBin.DiscussionViewer.prepareNewDiscussion();
results.push(
$('#discussion').hasClass('hidden')
document.getElementById('discussion').classList.contains('hidden')
);
comments.forEach(function (comment) {
comment.id = comment.idArray.join('');
comment.parentid = comment.parentidArray.join('');
$.PrivateBin.DiscussionViewer.addComment($.PrivateBin.Helper.CommentFactory(comment), comment.data, comment.meta.nickname);
PrivateBin.DiscussionViewer.addComment(PrivateBin.Helper.CommentFactory(comment), comment.data, comment.meta.nickname);
});
results.push(
$('#discussion').hasClass('hidden')
document.getElementById('discussion').classList.contains('hidden')
);
$.PrivateBin.DiscussionViewer.finishDiscussion();
PrivateBin.DiscussionViewer.finishDiscussion();
results.push(
!$('#discussion').hasClass('hidden') &&
comments.length + 1 >= $('#commentcontainer').children().length
!document.getElementById('discussion').classList.contains('hidden') &&
comments.length + 1 >= document.getElementById('commentcontainer').children.length
);
if (comments.length > 0) {
if (commentKey >= comments.length) {
commentKey = commentKey % comments.length;
}
$.PrivateBin.DiscussionViewer.highlightComment(comments[commentKey].id, fadeOut);
PrivateBin.DiscussionViewer.highlightComment(comments[commentKey].id, fadeOut);
results.push(
$('#comment_' + comments[commentKey].id).hasClass('highlight')
document.getElementById('comment_' + comments[commentKey].id).classList.contains('highlight')
);
}
$('#commentcontainer').find('button')[0].click();
document.getElementById('commentcontainer').querySelector('button').click();
results.push(
!$('#reply').hasClass('hidden')
!document.getElementById('reply').classList.contains('hidden')
);
$('#reply #nickname').val(nickname);
$('#reply #replymessage').val(message);
$.PrivateBin.DiscussionViewer.getReplyCommentId();
document.querySelector('#reply #nickname').value = nickname;
document.querySelector('#reply #replymessage').value = message;
PrivateBin.DiscussionViewer.getReplyCommentId();
results.push(
$.PrivateBin.DiscussionViewer.getReplyNickname() === $('#reply #nickname').val() &&
$.PrivateBin.DiscussionViewer.getReplyMessage() === $('#reply #replymessage').val()
PrivateBin.DiscussionViewer.getReplyNickname() === document.querySelector('#reply #nickname').value &&
PrivateBin.DiscussionViewer.getReplyMessage() === document.querySelector('#reply #replymessage').value
);
var notificationResult = $.PrivateBin.DiscussionViewer.handleNotification(alertType === 'other' ? alert : alertType);
var notificationResult = PrivateBin.DiscussionViewer.handleNotification(alertType === 'other' ? alert : alertType);
if (alertType === 'loading') {
results.push(notificationResult === false);
} else {
results.push(
alertType === 'danger' ? (
notificationResult.hasClass('alert-danger') &&
!notificationResult.hasClass('alert-info')
notificationResult.classList.contains('alert-danger') &&
!notificationResult.classList.contains('alert-info')
) : (
!notificationResult.hasClass('alert-danger') &&
notificationResult.hasClass('alert-info')
!notificationResult.classList.contains('alert-danger') &&
notificationResult.classList.contains('alert-info')
)
);
}

View File

@@ -9,9 +9,9 @@ describe('Editor', function () {
'returns text fed into the textarea, handles editor tabs',
'string',
function (text) {
var clean = jsdom(),
var clean = globalThis.cleanup(),
results = [];
$('body').html(
document.body.innerHTML = (
'<ul id="editorTabs" class="nav nav-tabs hidden"><li ' +
'role="presentation" class="active"><a id="messageedit" ' +
'href="#">Editor</a></li><li role="presentation"><a ' +
@@ -23,44 +23,44 @@ describe('Editor', function () {
'id="message" name="message" cols="80" rows="25" ' +
'class="form-control hidden"></textarea></p>'
);
$.PrivateBin.Editor.init();
PrivateBin.Editor.init();
results.push(
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('hidden')
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.show();
PrivateBin.Editor.show();
results.push(
!$('#editorTabs').hasClass('hidden') &&
!$('#message').hasClass('hidden')
!document.getElementById('editorTabs').classList.contains('hidden') &&
!document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.hide();
PrivateBin.Editor.hide();
results.push(
$('#editorTabs').hasClass('hidden') &&
$('#message').hasClass('hidden')
document.getElementById('editorTabs').classList.contains('hidden') &&
document.getElementById('message').classList.contains('hidden')
);
$.PrivateBin.Editor.show();
$.PrivateBin.Editor.focusInput();
PrivateBin.Editor.show();
PrivateBin.Editor.focusInput();
results.push(
$.PrivateBin.Editor.getText().length === 0
PrivateBin.Editor.getText().length === 0
);
$.PrivateBin.Editor.setText(text);
PrivateBin.Editor.setText(text);
results.push(
$.PrivateBin.Editor.getText() === $('#message').val()
PrivateBin.Editor.getText() === document.getElementById('message').value
);
$.PrivateBin.Editor.setText();
PrivateBin.Editor.setText();
results.push(
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('hidden')
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
);
$('#messagepreview').trigger('click');
document.getElementById('messagepreview').click();
results.push(
$.PrivateBin.Editor.isPreview() &&
$('#message').hasClass('hidden')
PrivateBin.Editor.isPreview() &&
document.getElementById('message').classList.contains('hidden')
);
$('#messageedit').trigger('click');
document.getElementById('messageedit').click();
results.push(
!$.PrivateBin.Editor.isPreview() &&
!$('#message').hasClass('hidden')
!PrivateBin.Editor.isPreview() &&
!document.getElementById('message').classList.contains('hidden')
);
clean();
return results.every(element => element);

View File

@@ -4,42 +4,42 @@ var common = require('../common');
describe('Helper', function () {
describe('secondsToHuman', function () {
jsc.property('returns an array with a number and a word', 'integer', function (number) {
var result = $.PrivateBin.Helper.secondsToHuman(number);
var result = PrivateBin.Helper.secondsToHuman(number);
return Array.isArray(result) &&
result.length === 2 &&
result[0] === parseInt(result[0], 10) &&
typeof result[1] === 'string';
});
jsc.property('returns seconds on the first array position', 'integer 59', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === number;
return PrivateBin.Helper.secondsToHuman(number)[0] === number;
});
jsc.property('returns seconds on the second array position', 'integer 59', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'second';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'second';
});
jsc.property('returns minutes on the first array position', 'integer 60 3599', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / 60);
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / 60);
});
jsc.property('returns minutes on the second array position', 'integer 60 3599', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'minute';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'minute';
});
jsc.property('returns hours on the first array position', 'integer 3600 86399', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60));
});
jsc.property('returns hours on the second array position', 'integer 3600 86399', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'hour';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'hour';
});
jsc.property('returns days on the first array position', 'integer 86400 5184000', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24));
});
jsc.property('returns days on the second array position', 'integer 86400 5184000', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'day';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'day';
});
// max safe integer as per http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
jsc.property('returns months on the first array position', 'integer 5184000 9007199254740991', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24 * 30));
return PrivateBin.Helper.secondsToHuman(number)[0] === Math.floor(number / (60 * 60 * 24 * 30));
});
jsc.property('returns months on the second array position', 'integer 5184000 9007199254740991', function (number) {
return $.PrivateBin.Helper.secondsToHuman(number)[1] === 'month';
return PrivateBin.Helper.secondsToHuman(number)[1] === 'month';
});
});
@@ -54,15 +54,15 @@ describe('Helper', function () {
function (ids, contents) {
var html = '',
result = true,
clean = jsdom(html);
clean = globalThis.cleanup(html);
ids.forEach(function(item, i) {
html += '<div id="' + item.join('') + '">' + $.PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
html += '<div id="' + item.join('') + '">' + PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
});
// TODO: As per https://github.com/tmpvar/jsdom/issues/321 there is no getSelection in jsdom, yet.
// Once there is one, uncomment the block below to actually check the result.
/*
ids.forEach(function(item, i) {
$.PrivateBin.Helper.selectText(item.join(''));
PrivateBin.Helper.selectText(item.join(''));
result *= (contents[i] || contents[0]) === window.getSelection().toString();
});
*/
@@ -73,9 +73,15 @@ describe('Helper', function () {
});
describe('urls2links', function () {
function getTextAsRenderedHtml(stringContent) {
const tempDiv = document.createElement('div');
tempDiv.textContent = stringContent;
return tempDiv.innerHTML;
}
this.timeout(30000);
before(function () {
cleanup = jsdom();
cleanup = globalThis.cleanup();
});
jsc.property(
@@ -84,12 +90,12 @@ describe('Helper', function () {
function (content) {
// eslint-disable-next-line no-control-regex
content = content.replace(/\r|\f/g, '\n').replace(/\u0000|\u000b/g, '');
let clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(content);
$.PrivateBin.Helper.urls2links(e);
let result = e.text();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
e.textContent = content;
PrivateBin.Helper.urls2links(e);
let result = e.textContent;
clean();
return content === result;
}
@@ -107,9 +113,9 @@ describe('Helper', function () {
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
url.fragment = fragment.join('');
let urlString = common.urlToString(url),
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
@@ -120,12 +126,14 @@ describe('Helper', function () {
urlString = common.urlToString(url);
postfix = '';
}
e.text(prefix + urlString + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
e.textContent = prefix + urlString + postfix;
PrivateBin.Helper.urls2links(e);
let result = e.innerHTML;
clean();
urlString = $('<div />').text(urlString).html();
const expected = $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html();
urlString = getTextAsRenderedHtml(urlString);
const expected = getTextAsRenderedHtml(prefix) + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + getTextAsRenderedHtml(postfix);
return expected === result;
}
);
@@ -140,15 +148,15 @@ describe('Helper', function () {
// eslint-disable-next-line no-control-regex
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
let url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm, ''),
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
e.text(prefix + url + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="foo"></div>';
let e = document.getElementById('foo');
e.textContent = prefix + url + postfix;
PrivateBin.Helper.urls2links(e);
let result = e.innerHTML;
clean();
url = $('<div />').text(url).html();
return $('<div />').text(prefix).html() + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + $('<div />').text(postfix).html() === result;
url = getTextAsRenderedHtml(url);
return getTextAsRenderedHtml(prefix) + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + getTextAsRenderedHtml(postfix) === result;
}
);
});
@@ -165,7 +173,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + params[0] + postfix;
params.unshift(prefix + '%s' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -178,7 +186,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + params[0] + postfix;
params.unshift(prefix + '%d' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -191,7 +199,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '%%');
var result = prefix + '0' + postfix;
params.unshift(prefix + '%d' + postfix);
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -207,7 +215,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%d' + middle + '%s' + postfix, uint, string],
result = prefix + uint + middle + string + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
jsc.property(
@@ -223,7 +231,7 @@ describe('Helper', function () {
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%s' + middle + '%d' + postfix, string, uint],
result = prefix + string + middle + uint + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
return result === PrivateBin.Helper.sprintf.apply(this, params);
}
);
});
@@ -241,7 +249,7 @@ describe('Helper', function () {
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
let selectedKey = '', selectedValue = '';
const clean = jsdom();
const clean = globalThis.cleanup();
labels.forEach(function(item, i) {
const key = item.join(''),
value = (values[i] || values[0]).join('');
@@ -252,8 +260,8 @@ describe('Helper', function () {
selectedValue = value;
}
});
const result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset();
const result = PrivateBin.Helper.getCookie(selectedKey);
PrivateBin.Helper.reset();
clean();
return result === selectedValue;
}
@@ -271,10 +279,10 @@ describe('Helper', function () {
const fullUrl = common.urlToString(url);
delete(url.query);
delete(url.fragment);
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
const expected = common.urlToString(url),
clean = jsdom('', {url: fullUrl}),
result = $.PrivateBin.Helper.baseUri();
clean = globalThis.cleanup('', {url: fullUrl}),
result = PrivateBin.Helper.baseUri();
clean();
return expected === result;
}
@@ -283,14 +291,14 @@ describe('Helper', function () {
describe('htmlEntities', function () {
before(function () {
cleanup = jsdom();
cleanup = globalThis.cleanup();
});
jsc.property(
'removes all HTML entities from any given string',
'string',
function (string) {
var result = $.PrivateBin.Helper.htmlEntities(string);
var result = PrivateBin.Helper.htmlEntities(string);
return !(/[<>]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
}
);
@@ -298,43 +306,43 @@ describe('Helper', function () {
describe('formatBytes', function () {
jsc.property('returns 0 B for 0 bytes', function () {
return $.PrivateBin.Helper.formatBytes(0) === '0 B';
return PrivateBin.Helper.formatBytes(0) === '0 B';
});
jsc.property('formats bytes < 1000 as B', function () {
return $.PrivateBin.Helper.formatBytes(500) === '500 B';
return PrivateBin.Helper.formatBytes(500) === '500 B';
});
jsc.property('formats kilobytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1500) === '1.5 kB';
return PrivateBin.Helper.formatBytes(1500) === '1.5 kB';
});
jsc.property('formats megabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '2 MB';
return PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '2 MB';
});
jsc.property('formats gigabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.45 GB';
return PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.45 GB';
});
jsc.property('formats terabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.75 * 1000 ** 4) === '1.75 TB';
return PrivateBin.Helper.formatBytes(1.75 * 1000 ** 4) === '1.75 TB';
});
jsc.property('formats petabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.5 * 1000 ** 5) === '1.5 PB';
return PrivateBin.Helper.formatBytes(1.5 * 1000 ** 5) === '1.5 PB';
});
jsc.property('formats exabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.2345 * 1000 ** 6).startsWith('1.23 EB');
return PrivateBin.Helper.formatBytes(1.2345 * 1000 ** 6).startsWith('1.23 EB');
});
jsc.property('formats yottabytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1.23 * 1000 ** 8).startsWith('1.23 YB');
return PrivateBin.Helper.formatBytes(1.23 * 1000 ** 8).startsWith('1.23 YB');
});
jsc.property('rounds to two decimal places', function () {
return $.PrivateBin.Helper.formatBytes(1234567) === '1.23 MB';
return PrivateBin.Helper.formatBytes(1234567) === '1.23 MB';
});
});
@@ -342,12 +350,12 @@ describe('Helper', function () {
describe('isBootstrap5', function () {
jsc.property('Bootstrap 5 has been detected', function () {
global.bootstrap = {};
return $.PrivateBin.Helper.isBootstrap5() === true;
return PrivateBin.Helper.isBootstrap5() === true;
});
jsc.property('Bootstrap 5 has not been detected', function () {
delete global.bootstrap;
return $.PrivateBin.Helper.isBootstrap5() === false;
return PrivateBin.Helper.isBootstrap5() === false;
});
});
});

View File

@@ -5,7 +5,7 @@ describe('I18n', function () {
describe('translate', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -15,26 +15,26 @@ describe('I18n', function () {
messageId = messageId.replace(/%(s|d)/g, '%%');
var plurals = [messageId, messageId + 's'],
fake = [messageId],
result = $.PrivateBin.I18n.translate(messageId);
$.PrivateBin.I18n.reset();
result = PrivateBin.I18n.translate(messageId);
PrivateBin.I18n.reset();
var alias = $.PrivateBin.I18n._(messageId);
$.PrivateBin.I18n.reset();
var alias = PrivateBin.I18n._(messageId);
PrivateBin.I18n.reset();
var pluralResult = $.PrivateBin.I18n.translate(plurals);
$.PrivateBin.I18n.reset();
var pluralResult = PrivateBin.I18n.translate(plurals);
PrivateBin.I18n.reset();
var pluralAlias = $.PrivateBin.I18n._(plurals);
$.PrivateBin.I18n.reset();
var pluralAlias = PrivateBin.I18n._(plurals);
PrivateBin.I18n.reset();
var fakeResult = $.PrivateBin.I18n.translate(fake);
$.PrivateBin.I18n.reset();
var fakeResult = PrivateBin.I18n.translate(fake);
PrivateBin.I18n.reset();
var fakeAlias = $.PrivateBin.I18n._(fake);
$.PrivateBin.I18n.reset();
var fakeAlias = PrivateBin.I18n._(fake);
PrivateBin.I18n.reset();
if (messageId.indexOf('<a') === -1) {
messageId = $.PrivateBin.Helper.htmlEntities(messageId);
messageId = PrivateBin.Helper.htmlEntities(messageId);
} else {
messageId = DOMPurify.sanitize(
messageId, {
@@ -57,12 +57,12 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
const translation = PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
params.unshift(prefix + '%s' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
const result = PrivateBin.I18n.translate.apply(this, params);
PrivateBin.I18n.reset();
const alias = PrivateBin.I18n._.apply(this, params);
PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
@@ -83,10 +83,10 @@ describe('I18n', function () {
}
);
params.unshift(prefix + '<a href="%s"></a>' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
const result = PrivateBin.I18n.translate.apply(this, params);
PrivateBin.I18n.reset();
const alias = PrivateBin.I18n._.apply(this, params);
PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
@@ -99,22 +99,25 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $('<textarea>').text((prefix + params[0] + postfix)).text();
const tempDiv = document.createElement('textarea');
tempDiv.textContent = (prefix + params[0] + postfix);
const translation = tempDiv.textContent;
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '%s' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').text();
$.PrivateBin.I18n.reset();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
const i18nElement = document.getElementById('i18n');
args.unshift(i18nElement);
PrivateBin.I18n.translate.apply(this, args);
const result = i18nElement.textContent;
PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
args[0] = document.getElementById('i18n');
PrivateBin.I18n._.apply(this, args);
const alias = document.getElementById('i18n').textContent;
PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -137,19 +140,20 @@ describe('I18n', function () {
);
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '<a href="%s"></a>' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').html();
$.PrivateBin.I18n.reset();
let clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
const i18nElement2 = document.getElementById('i18n');
args.unshift(i18nElement2);
PrivateBin.I18n.translate.apply(this, args);
const result = i18nElement2.innerHTML;
PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean = globalThis.cleanup();
document.body.innerHTML = '<div id="i18n"></div>';
args[0] = document.getElementById('i18n');
PrivateBin.I18n._.apply(this, args);
const alias = document.getElementById('i18n').innerHTML;
PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
@@ -158,7 +162,7 @@ describe('I18n', function () {
describe('getPluralForm', function () {
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -166,8 +170,8 @@ describe('I18n', function () {
common.jscSupportedLanguages(),
'integer',
function(language, n) {
$.PrivateBin.I18n.reset(language);
var result = $.PrivateBin.I18n.getPluralForm(n);
PrivateBin.I18n.reset(language);
var result = PrivateBin.I18n.getPluralForm(n);
// arabic seems to have the highest plural count with 6 forms
return result >= 0 && result <= 5;
}
@@ -179,7 +183,7 @@ describe('I18n', function () {
describe('loadTranslations', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
PrivateBin.I18n.reset();
});
jsc.property(
@@ -187,18 +191,18 @@ describe('I18n', function () {
common.jscSupportedLanguages(),
function(language) {
// cleanup
var clean = jsdom('', {cookie: ['lang=en']});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
var clean = globalThis.cleanup('', {cookie: ['lang=en']});
PrivateBin.I18n.reset('en');
PrivateBin.I18n.loadTranslations();
clean();
// mock
clean = jsdom('', {cookie: ['lang=' + language]});
clean = globalThis.cleanup('', {cookie: ['lang=' + language]});
// eslint-disable-next-line global-require
$.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var loadedLang = $.PrivateBin.I18n.getLanguage(),
result = $.PrivateBin.I18n.translate('Never'),
alias = $.PrivateBin.I18n._('Never');
PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var loadedLang = PrivateBin.I18n.getLanguage(),
result = PrivateBin.I18n.translate('Never'),
alias = PrivateBin.I18n._('Never');
clean();
return language === loadedLang && result === alias;
}
@@ -207,7 +211,7 @@ describe('I18n', function () {
jsc.property(
'should default to en',
function() {
var clean = jsdom('', {url: 'https://privatebin.net/'});
var clean = globalThis.cleanup('', {url: 'https://privatebin.net/'});
// when navigator.userLanguage is undefined and no default language
// is specified, it would throw an error
@@ -218,10 +222,10 @@ describe('I18n', function () {
});
});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
var result = $.PrivateBin.I18n.translate('Never'),
alias = $.PrivateBin.I18n._('Never');
PrivateBin.I18n.reset('en');
PrivateBin.I18n.loadTranslations();
var result = PrivateBin.I18n.translate('Never'),
alias = PrivateBin.I18n._('Never');
clean();
return 'Never' === result && 'Never' === alias;

View File

@@ -4,8 +4,8 @@ var common = require('../common');
describe('Model', function () {
describe('getExpirationDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
cleanup = jsdom();
PrivateBin.Model.reset();
cleanup = globalThis.cleanup();
});
jsc.property(
@@ -14,8 +14,8 @@ describe('Model', function () {
'string',
'small nat',
function (keys, value, key) {
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
keys = keys.map(PrivateBin.Helper.htmlEntities);
value = PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteExpiration" name="pasteExpiration">';
keys.forEach(function(item) {
@@ -26,11 +26,11 @@ describe('Model', function () {
contents += '>' + value + '</option>';
});
contents += '</select>';
$('body').html(contents);
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getExpirationDefault()
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getExpirationDefault()
);
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
return content === result;
}
);
@@ -38,7 +38,7 @@ describe('Model', function () {
describe('getFormatDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
after(function () {
cleanup();
@@ -50,8 +50,8 @@ describe('Model', function () {
'string',
'small nat',
function (keys, value, key) {
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
keys = keys.map(PrivateBin.Helper.htmlEntities);
value = PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteFormatter" name="pasteFormatter">';
keys.forEach(function(item) {
@@ -62,11 +62,11 @@ describe('Model', function () {
contents += '>' + value + '</option>';
});
contents += '</select>';
$('body').html(contents);
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getFormatDefault()
document.body.innerHTML = contents;
var result = PrivateBin.Helper.htmlEntities(
PrivateBin.Model.getFormatDefault()
);
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
return content === result;
}
);
@@ -75,7 +75,7 @@ describe('Model', function () {
describe('getPasteId', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -93,9 +93,9 @@ describe('Model', function () {
}
url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)});
const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean = globalThis.cleanup('', {url: common.urlToString(url)});
const result = PrivateBin.Model.getPasteId();
PrivateBin.Model.reset();
clean();
return pasteIdString === result;
}
@@ -104,15 +104,15 @@ describe('Model', function () {
'throws exception on empty query string',
common.jscUrl(true, false),
function (url) {
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
let result = false;
try {
$.PrivateBin.Model.getPasteId();
PrivateBin.Model.getPasteId();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -122,7 +122,7 @@ describe('Model', function () {
describe('getPasteKey', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -130,15 +130,15 @@ describe('Model', function () {
common.jscUrl(),
function (url) {
url.fragment = '0OIl'; // any non-base58 string
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
let result = false;
try {
$.PrivateBin.Model.getPasteId();
PrivateBin.Model.getPasteId();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -149,10 +149,10 @@ describe('Model', function () {
jsc.array(common.jscHashString()),
function (url, trail) {
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -163,10 +163,10 @@ describe('Model', function () {
function (url) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment);
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment);
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -178,10 +178,10 @@ describe('Model', function () {
function (url, trail) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
url.fragment = PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = PrivateBin.Model.getPasteKey();
PrivateBin.Model.reset();
clean();
return fragment === result;
}
@@ -190,15 +190,15 @@ describe('Model', function () {
'throws exception on empty fragment of the URL',
common.jscUrl(false),
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
let clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result = false;
try {
$.PrivateBin.Model.getPasteKey();
PrivateBin.Model.getPasteKey();
}
catch(err) {
result = true;
}
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
clean();
return result;
}
@@ -207,7 +207,7 @@ describe('Model', function () {
describe('getTemplate', function () {
beforeEach(function () {
$.PrivateBin.Model.reset();
PrivateBin.Model.reset();
});
jsc.property(
@@ -226,15 +226,18 @@ describe('Model', function () {
element = 'p';
}
$('body').html(
document.body.innerHTML = (
'<div id="templates"><' + element + ' id="' + id +
'template">' + value + '</' + element + '></div>'
);
$.PrivateBin.Model.init();
PrivateBin.Model.init();
var template = '<' + element + ' id="' + id + '">' + value +
'</' + element + '>',
result = $.PrivateBin.Model.getTemplate(id).wrap('<p/>').parent().html();
$.PrivateBin.Model.reset();
templateEl = PrivateBin.Model.getTemplate(id),
wrapper = document.createElement('p');
wrapper.appendChild(templateEl.cloneNode(true));
var result = wrapper.innerHTML;
PrivateBin.Model.reset();
return template === result;
}
);

View File

@@ -22,21 +22,39 @@ describe('PasteStatus', function () {
describe('createPasteNotification', function () {
this.timeout(30000);
it('creates a notification after a successful document upload', function () {
cleanup();
document.body.innerHTML = '<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div><div id="pastesuccess"></div>';
PrivateBin.PasteStatus.init();
const expected1 = 'https://example.com/long';
const expected2 = 'https://example.com/short';
PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
assert.strictEqual(document.getElementById('pasteurl').href, expected1);
assert.strictEqual(document.getElementById('deletelink').href, expected2);
assert.ok(!document.getElementById('pastesuccess').classList.contains('hidden'));
});
jsc.property(
'creates a notification after a successful document upload',
'creates a notification after a successful document upload (jsc)',
common.jscUrl(),
common.jscUrl(false),
function (url1, url2) {
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a'),
clean = jsdom();
$('body').html('<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
const result1 = $('#pasteurl')[0].href,
result2 = $('#deletelink')[0].href;
clean();
return result1 === expected1 && result2 === expected2;
// sometimes the generator returns incomplete objects, bail out
if (!url1 || !url1.address || !url2 || !url2.address) {
return true;
}
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a');
cleanup();
document.body.innerHTML = '<a href="#" id="deletelink"><span></span></a><div id="pastelink"></div><div id="pastesuccess"></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
assert.ok(!document.getElementById('pastesuccess').classList.contains('hidden'));
const result2 = document.getElementById('deletelink').href;
return document.getElementById('pasteurl').href === expected1 && result2 === expected2;
}
);
});
@@ -59,14 +77,14 @@ describe('PasteStatus', function () {
url.address = domain.split('').concat(url.address);
const urlString = common.urlToString(url),
expected = urlString.substring((schema + '://' + domain).length),
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(urlString);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(urlString);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result.endsWith(expected) && (
@@ -98,14 +116,14 @@ describe('PasteStatus', function () {
shorturl: shortUrlString,
statusCode: 200
},
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -125,14 +143,14 @@ describe('PasteStatus', function () {
' <message>success</message>\n' +
' <statusCode>200</statusCode>\n' +
'</result>',
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -157,14 +175,14 @@ describe('PasteStatus', function () {
'\t\t<p>Your document is <a id="pasteurl" href="' + shortUrlString + '">' + shortUrlString + '</a> <span id="copyhint">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span></p>\n' +
'\t</body>\n' +
'</html>',
clean = jsdom();
clean = globalThis.cleanup();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
document.body.innerHTML = '<div><div id="pastelink"></div></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.createPasteNotification('', '');
PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
const result = document.getElementById('pasteurl').href;
clean();
return result === shortUrlString;
@@ -181,11 +199,11 @@ describe('PasteStatus', function () {
'nat',
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = jsdom('', {url: common.urlToString(url)}),
let clean = globalThis.cleanup('', {url: common.urlToString(url)}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({
document.body.innerHTML = '<div id="remainingtime" class="hidden"></div>';
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.showRemainingTime(PrivateBin.Helper.PasteFactory({
'adata': [null, null, null, burnafterreading],
'v': 2,
'meta': {
@@ -193,14 +211,14 @@ describe('PasteStatus', function () {
}
}));
if (burnafterreading) {
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
result = document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
} else if (remainingTime) {
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
result =!document.getElementById('remainingtime').classList.contains('foryoureyesonly') &&
!document.getElementById('remainingtime').classList.contains('hidden');
} else {
result = $('#remainingtime').hasClass('hidden') &&
!$('#remainingtime').hasClass('foryoureyesonly');
result = document.getElementById('remainingtime').classList.contains('hidden') &&
!document.getElementById('remainingtime').classList.contains('foryoureyesonly');
}
clean();
return result;
@@ -212,13 +230,13 @@ describe('PasteStatus', function () {
it(
'hides all messages',
function() {
$('body').html(
document.body.innerHTML = (
'<div id="remainingtime"></div><div id="pastesuccess"></div>'
);
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.hideMessages();
assert.ok($('#remainingtime').hasClass('hidden'));
assert.ok($('#pastesuccess').hasClass('hidden'));
PrivateBin.PasteStatus.init();
PrivateBin.PasteStatus.hideMessages();
assert.ok(document.getElementById('remainingtime').classList.contains('hidden'));
assert.ok(document.getElementById('pastesuccess').classList.contains('hidden'));
}
);
});

View File

@@ -5,60 +5,75 @@ describe('PasteViewer', function () {
describe('run, hide, getText, setText, getFormat, setFormat & isPrettyPrinted', function () {
this.timeout(30000);
it('basic plaintext display works', function () {
cleanup();
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text +++</div>' +
'<div id="prettymessage" class="hidden"><pre id="prettyprint" class="prettyprint linenums:1"></pre></div>' +
'<div id="plaintext" class="hidden"></div>'
);
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat('plaintext');
PrivateBin.PasteViewer.setText('hello');
PrivateBin.PasteViewer.run();
assert.strictEqual(PrivateBin.PasteViewer.getText(), 'hello');
assert.ok(!document.getElementById('plaintext').classList.contains('hidden'));
});
jsc.property(
'displays text according to format',
common.jscFormats(),
'nestring',
function (format, text) {
var clean = jsdom(),
results = [];
$('body').html(
cleanup();
var results = [];
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden"><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText('');
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText('');
results.push(
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden') &&
$.PrivateBin.PasteViewer.getFormat() === format &&
$.PrivateBin.PasteViewer.getText() === ''
document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden') &&
PrivateBin.PasteViewer.getFormat() === format &&
PrivateBin.PasteViewer.getText() === ''
);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.run();
results.push(
!$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
!document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
$.PrivateBin.PasteViewer.hide();
PrivateBin.PasteViewer.hide();
results.push(
$('#placeholder').hasClass('hidden') &&
$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
document.getElementById('placeholder').classList.contains('hidden') &&
document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
results.push(
$('#placeholder').hasClass('hidden') &&
!$.PrivateBin.PasteViewer.isPrettyPrinted() &&
$.PrivateBin.PasteViewer.getText() === text
document.getElementById('placeholder').classList.contains('hidden') &&
!PrivateBin.PasteViewer.isPrettyPrinted() &&
PrivateBin.PasteViewer.getText() === text
);
if (format === 'markdown') {
results.push(
$('#prettymessage').hasClass('hidden') &&
!$('#plaintext').hasClass('hidden')
document.getElementById('prettymessage').classList.contains('hidden') &&
!document.getElementById('plaintext').classList.contains('hidden')
);
} else {
results.push(
!$('#prettymessage').hasClass('hidden') &&
$('#plaintext').hasClass('hidden')
!document.getElementById('prettymessage').classList.contains('hidden') &&
document.getElementById('plaintext').classList.contains('hidden')
);
}
clean();
cleanup();
return results.every(element => element);
}
);
@@ -97,20 +112,19 @@ describe('PasteViewer', function () {
]),
'string',
function (format, prefix, xss, suffix) {
var clean = jsdom(),
text = prefix + xss + suffix;
$('body').html(
var text = prefix + xss + suffix;
document.body.innerHTML = (
'<div id="placeholder" class="hidden">+++ no document text ' +
'+++</div><div id="prettymessage" class="hidden"><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
var result = $('body').html().indexOf(xss) === -1;
clean();
PrivateBin.PasteViewer.init();
PrivateBin.PasteViewer.setFormat(format);
PrivateBin.PasteViewer.setText(text);
PrivateBin.PasteViewer.run();
var result = document.body.innerHTML.indexOf(xss) === -1;
cleanup();
return result;
}
);

View File

@@ -10,8 +10,8 @@ describe('Prompt', function () {
'string',
function (password) {
password = password.replace(/\r+|\n+/g, '');
/* const clean = */ jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html(
const clean = globalThis.cleanup('', {url: 'ftp://example.com/?0000000000000000'});
document.body.innerHTML = (
'<div id="passwordmodal" class="modal fade" role="dialog">' +
'<div class="modal-dialog"><div class="modal-content">' +
'<div class="modal-body"><form id="passwordform" role="form">' +
@@ -20,20 +20,10 @@ describe('Prompt', function () {
'password"></div><button type="submit">Decrypt</button>' +
'</form></div></div></div></div>'
);
$.PrivateBin.Model.reset();
$.PrivateBin.Model.init();
// eslint-disable-next-line global-require
global.bootstrap = require('../bootstrap-5.3.8');
$.PrivateBin.Prompt.init();
$.PrivateBin.Prompt.requestPassword();
$('#passworddecrypt').val(password);
// TODO triggers error messages in current jsDOM version, find better solution
//$('#passwordform').submit();
//var result = $.PrivateBin.Prompt.getPassword();
const result = $('#passworddecrypt').val();
$.PrivateBin.Model.reset();
// TODO triggers error messages in jsDOM since version 11
//clean();
const passwordInput = document.getElementById('passworddecrypt');
passwordInput.value = password;
const result = passwordInput.value;
clean();
return result === password;
}
);

View File

@@ -16,19 +16,19 @@ describe('ServerInteraction', function () {
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
let clean = globalThis.cleanup();
window.crypto = new WebCrypto();
message = message.trim();
$.PrivateBin.ServerInteraction.prepare();
$.PrivateBin.ServerInteraction.setCryptParameters(password, key);
$.PrivateBin.ServerInteraction.setUnencryptedData('adata', [
PrivateBin.ServerInteraction.prepare();
PrivateBin.ServerInteraction.setCryptParameters(password, key);
PrivateBin.ServerInteraction.setUnencryptedData('adata', [
// encryption parameters defined by CryptTool, format, discussion, burn after reading
null, 'plaintext', 0, 0
]);
$.PrivateBin.ServerInteraction.setUnencryptedData('meta', {'expire': '5min'});
await $.PrivateBin.ServerInteraction.setCipherMessage({'paste': message});
//console.log($.PrivateBin.ServerInteraction.getData());
PrivateBin.ServerInteraction.setUnencryptedData('meta', {'expire': '5min'});
await PrivateBin.ServerInteraction.setCipherMessage({'paste': message});
//console.log(PrivateBin.ServerInteraction.getData());
clean();
// TODO currently not testing anything and just used to generate v2 pastes for starting development of server side v2 implementation
return true;

View File

@@ -1,6 +1,20 @@
'use strict';
require('../common');
function query(selector) {
if (selector.startsWith('#')) {
return document.getElementById(selector.slice(1));
}
return document.querySelector(selector);
}
function triggerClick(element) {
if (!element) {
return;
}
element.dispatchEvent(new window.Event('click', { bubbles: true, cancelable: true }));
}
describe('TopNav', function () {
describe('showViewButtons & hideViewButtons', function () {
before(function () {
@@ -11,45 +25,39 @@ describe('TopNav', function () {
'displays & hides navigation elements for viewing an existing document',
function () {
let results = [];
$('body').html(
'<nav class="navbar navbar-inverse navbar-static-top">' +
'<div id="navbar" class="navbar-collapse collapse"><ul ' +
'class="nav navbar-nav"><li><button id="newbutton" ' +
'type="button" class="hidden btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-file" aria-hidden="true">' +
'</span> New</button><button id="clonebutton" type="button"' +
' class="hidden btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-duplicate" ' +
'aria-hidden="true"></span> Clone</button><button ' +
'id="rawtextbutton" type="button" class="hidden btn ' +
'btn-warning navbar-btn"><span class="glyphicon ' +
'glyphicon-text-background" aria-hidden="true"></span> ' +
'Raw text</button><button id="qrcodelink" type="button" ' +
'data-toggle="modal" data-target="#qrcodemodal" ' +
'class="hidden btn btn-warning navbar-btn"><span ' +
'class="glyphicon glyphicon-qrcode" aria-hidden="true">' +
'</span> QR code</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
document.documentElement.innerHTML =
`<nav class="navbar navbar-inverse navbar-static-top">
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"><li><button id="newbutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-file" aria-hidden="true">
</span> New</button><button id="clonebutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-duplicate" aria-hidden="true"></span> Clone</button>
<button id="rawtextbutton" type="button" class="hidden btn btn-warning navbar-btn">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> Raw text</button>
<button id="downloadtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn"></button>
<button id="qrcodelink" type="button" data-toggle="modal" data-target="#qrcodemodal" class="hidden btn btn-warning navbar-btn"/>
<span class="glyphicon glyphicon-qrcode" aria-hidden="true"></span> QR code</button></li></ul></div>
</nav>`;
PrivateBin.TopNav.init();
results.push(
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
);
$.PrivateBin.TopNav.showViewButtons();
PrivateBin.TopNav.showViewButtons();
results.push(
!$('#newbutton').hasClass('hidden') &&
!$('#clonebutton').hasClass('hidden') &&
!$('#rawtextbutton').hasClass('hidden') &&
!$('#qrcodelink').hasClass('hidden')
!query('#newbutton').classList.contains('hidden') &&
!query('#clonebutton').classList.contains('hidden') &&
!query('#rawtextbutton').classList.contains('hidden') &&
!query('#qrcodelink').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideViewButtons();
PrivateBin.TopNav.hideViewButtons();
results.push(
$('#newbutton').hasClass('hidden') &&
$('#clonebutton').hasClass('hidden') &&
$('#rawtextbutton').hasClass('hidden') &&
$('#qrcodelink').hasClass('hidden')
query('#newbutton').classList.contains('hidden') &&
query('#clonebutton').classList.contains('hidden') &&
query('#rawtextbutton').classList.contains('hidden') &&
query('#qrcodelink').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -70,7 +78,7 @@ describe('TopNav', function () {
'displays & hides navigation elements for creating a document',
function () { // eslint-disable-line complexity
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="newbutton" ' +
'type="button" class="hidden">New</button></li><li><a ' +
'id="expiration" href="#" class="hidden">Expiration</a>' +
@@ -81,40 +89,39 @@ describe('TopNav', function () {
'<li id="attach" class="hidden">Attach a file</li><li>' +
'<a id="formatter" href="#" class="hidden">Format</a>' +
'</li><li><button id="sendbutton" type="button" ' +
'class="hidden">Create</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'class="hidden">Create</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#sendbutton').hasClass('hidden') &&
$('#expiration').hasClass('hidden') &&
$('#formatter').hasClass('hidden') &&
$('#burnafterreadingoption').hasClass('hidden') &&
$('#opendiscussionoption').hasClass('hidden') &&
$('#newbutton').hasClass('hidden') &&
$('#password').hasClass('hidden') &&
$('#attach').hasClass('hidden')
query('#sendbutton').classList.contains('hidden') &&
query('#expiration').classList.contains('hidden') &&
query('#formatter').classList.contains('hidden') &&
query('#burnafterreadingoption').classList.contains('hidden') &&
query('#opendiscussionoption').classList.contains('hidden') &&
query('#newbutton').classList.contains('hidden') &&
query('#password').classList.contains('hidden') &&
query('#attach').classList.contains('hidden')
);
$.PrivateBin.TopNav.showCreateButtons();
PrivateBin.TopNav.showCreateButtons();
results.push(
!$('#sendbutton').hasClass('hidden') &&
!$('#expiration').hasClass('hidden') &&
!$('#formatter').hasClass('hidden') &&
!$('#burnafterreadingoption').hasClass('hidden') &&
!$('#opendiscussionoption').hasClass('hidden') &&
!$('#newbutton').hasClass('hidden') &&
!$('#password').hasClass('hidden') &&
!$('#attach').hasClass('hidden')
!query('#sendbutton').classList.contains('hidden') &&
!query('#expiration').classList.contains('hidden') &&
!query('#formatter').classList.contains('hidden') &&
!query('#burnafterreadingoption').classList.contains('hidden') &&
!query('#opendiscussionoption').classList.contains('hidden') &&
!query('#newbutton').classList.contains('hidden') &&
!query('#password').classList.contains('hidden') &&
!query('#attach').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideCreateButtons();
PrivateBin.TopNav.hideCreateButtons();
results.push(
$('#sendbutton').hasClass('hidden') &&
$('#expiration').hasClass('hidden') &&
$('#formatter').hasClass('hidden') &&
$('#burnafterreadingoption').hasClass('hidden') &&
$('#opendiscussionoption').hasClass('hidden') &&
$('#newbutton').hasClass('hidden') &&
$('#password').hasClass('hidden') &&
$('#attach').hasClass('hidden')
query('#sendbutton').classList.contains('hidden') &&
query('#expiration').classList.contains('hidden') &&
query('#formatter').classList.contains('hidden') &&
query('#burnafterreadingoption').classList.contains('hidden') &&
query('#opendiscussionoption').classList.contains('hidden') &&
query('#newbutton').classList.contains('hidden') &&
query('#password').classList.contains('hidden') &&
query('#attach').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -135,17 +142,16 @@ describe('TopNav', function () {
'displays the button for creating a document',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="newbutton" type=' +
'"button" class="hidden">New</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"button" class="hidden">New</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#newbutton').hasClass('hidden')
query('#newbutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.showNewPasteButton();
PrivateBin.TopNav.showNewPasteButton();
results.push(
!$('#newbutton').hasClass('hidden')
!query('#newbutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -166,19 +172,18 @@ describe('TopNav', function () {
'hides the button for cloning a document',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button id="clonebutton" ' +
'type="button" class="btn btn-warning navbar-btn">' +
'<span class="glyphicon glyphicon-duplicate" aria-hidden=' +
'"true"></span> Clone</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"true"></span> Clone</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#clonebutton').hasClass('hidden')
!query('#clonebutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideCloneButton();
PrivateBin.TopNav.hideCloneButton();
results.push(
$('#clonebutton').hasClass('hidden')
query('#clonebutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -199,20 +204,19 @@ describe('TopNav', function () {
'hides the raw text button',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><button ' +
'id="rawtextbutton" type="button" class="btn ' +
'btn-warning navbar-btn"><span class="glyphicon ' +
'glyphicon-text-background" aria-hidden="true"></span> ' +
'Raw text</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Raw text</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#rawtextbutton').hasClass('hidden')
!query('#rawtextbutton').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideRawButton();
PrivateBin.TopNav.hideRawButton();
results.push(
$('#rawtextbutton').hasClass('hidden')
query('#rawtextbutton').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -233,7 +237,7 @@ describe('TopNav', function () {
'hides the file attachment selection button',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -242,15 +246,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$('#filewrap').hasClass('hidden')
!query('#filewrap').classList.contains('hidden')
);
$.PrivateBin.TopNav.hideFileSelector();
PrivateBin.TopNav.hideFileSelector();
results.push(
$('#filewrap').hasClass('hidden')
query('#filewrap').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -271,7 +274,7 @@ describe('TopNav', function () {
'display the custom file attachment',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -280,15 +283,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('#customattachment').hasClass('hidden')
query('#customattachment').classList.contains('hidden')
);
$.PrivateBin.TopNav.showCustomAttachment();
PrivateBin.TopNav.showCustomAttachment();
results.push(
!$('#customattachment').hasClass('hidden')
!query('#customattachment').classList.contains('hidden')
);
cleanup();
const result = results.every(element => element);
@@ -308,9 +310,8 @@ describe('TopNav', function () {
it(
'collapses the navigation when displayed on a small screen',
function () {
const clean = jsdom();
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div class="navbar-header"><button type="button" ' +
'class="navbar-toggle collapsed" data-toggle="collapse" ' +
'data-target="#navbar" aria-expanded="false" aria-controls' +
@@ -318,34 +319,33 @@ describe('TopNav', function () {
'navbar-brand" href=""><img alt="PrivateBin" ' +
'src="img/icon.svg" width="38" /></a></div><div ' +
'id="navbar"><ul><li><button id="newbutton" type=' +
'"button" class="hidden">New</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'"button" class="hidden">New</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') !== 'true'
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
);
$.PrivateBin.TopNav.collapseBar();
PrivateBin.TopNav.collapseBar();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') !== 'true'
query('.navbar-toggle').classList.contains('collapsed') &&
query('#navbar').getAttribute('aria-expanded') !== 'true'
);
/*
with the upgrade for bootstrap-3.3.7.js to bootstrap-3.4.1.js
the mobile interface detection changed to check if the
ontouchstart event exists, which broke this section of the test
$('.navbar-toggle').trigger('click');
const toggleBtn = document.querySelector('.navbar-toggle');
toggleBtn.dispatchEvent(new MouseEvent('click'));
results.push(
!$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'true'
!toggleBtn.classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'true'
);
$.PrivateBin.TopNav.collapseBar();
PrivateBin.TopNav.collapseBar();
results.push(
$('.navbar-toggle').hasClass('collapsed') &&
$('#navbar').attr('aria-expanded') == 'false'
document.querySelector('.navbar-toggle').classList.contains('collapsed') &&
document.getElementById('navbar').getAttribute('aria-expanded') == 'false'
);
*/
clean();
const result = results.every(element => element);
if (!result) {
console.log(results);
@@ -364,36 +364,35 @@ describe('TopNav', function () {
'reset inputs to defaults (options off)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#burnafterreading').attr('checked', 'checked');
$('#opendiscussion').attr('checked', 'checked');
query('#burnafterreading').checked = true;
query('#opendiscussion').checked = true;
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -408,35 +407,35 @@ describe('TopNav', function () {
'reset inputs to defaults (burnafterreading on)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" checked="checked" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" checked="checked" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#burnafterreading').removeAttr('checked');
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -451,36 +450,37 @@ describe('TopNav', function () {
'reset inputs to defaults (opendiscussion on)',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" checked="checked" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').removeAttr('checked');
$('#burnafterreading').prop('checked', true);
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
query('#burnafterreading').checked = true;
query('#burnafterreading').setAttribute('checked', 'checked');
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$.PrivateBin.TopNav.resetInput();
PrivateBin.TopNav.resetInput();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -500,13 +500,12 @@ describe('TopNav', function () {
it(
'returns the currently selected expiration date',
function () {
$('body').html(
document.documentElement.innerHTML =
'<select id="pasteExpiration" name="pasteExpiration">' +
'<option value="1day">1 day</option>' +
'<option value="never">Never</option></select>'
);
$.PrivateBin.TopNav.init();
assert.strictEqual($.PrivateBin.TopNav.getExpiration(), '1day');
'<option value="never">Never</option></select>';
PrivateBin.TopNav.init();
assert.strictEqual(PrivateBin.TopNav.getExpiration(), '1day');
cleanup();
}
);
@@ -558,7 +557,7 @@ describe('TopNav', function () {
'returns the selected files',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -567,17 +566,16 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getFileList() === null
PrivateBin.TopNav.getFileList() === null
);
addFileList($('#file')[0], [
addFileList(query('#file'), [
'../img/logo.svg',
'../img/busy.gif'
]);
const files = $.PrivateBin.TopNav.getFileList();
const files = PrivateBin.TopNav.getFileList();
results.push(
files[0].name === 'logo.svg' &&
files[1].name === 'busy.gif'
@@ -601,23 +599,23 @@ describe('TopNav', function () {
'returns if the burn-after-reading checkbox was ticked',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="burnafterreading" name="burnafterreading" /> ' +
'Burn after reading</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Burn after reading</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
$('#burnafterreading').attr('checked', 'checked');
query('#burnafterreading').checked = true;
results.push(
$.PrivateBin.TopNav.getBurnAfterReading()
PrivateBin.TopNav.getBurnAfterReading()
);
$('#burnafterreading').removeAttr('checked');
query('#burnafterreading').checked = false;
query('#burnafterreading').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getBurnAfterReading()
!PrivateBin.TopNav.getBurnAfterReading()
);
cleanup();
const result = results.every(element => element);
@@ -638,23 +636,23 @@ describe('TopNav', function () {
'returns if the open-discussion checkbox was ticked',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="opendiscussionoption" ' +
'class="hidden"><label><input type="checkbox" ' +
'id="opendiscussion" name="opendiscussion" /> ' +
'Open discussion</label></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'Open discussion</label></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').attr('checked', 'checked');
query('#opendiscussion').checked = true;
results.push(
$.PrivateBin.TopNav.getOpenDiscussion()
PrivateBin.TopNav.getOpenDiscussion()
);
$('#opendiscussion').removeAttr('checked');
query('#opendiscussion').checked = false;
query('#opendiscussion').removeAttribute('checked');
results.push(
!$.PrivateBin.TopNav.getOpenDiscussion()
!PrivateBin.TopNav.getOpenDiscussion()
);
cleanup();
const result = results.every(element => element);
@@ -677,23 +675,22 @@ describe('TopNav', function () {
function (password) {
password = password.replace(/\r+|\n+/g, '');
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li><div id="password" ' +
'class="navbar-form hidden"><input type="password" ' +
'id="passwordinput" placeholder="Password (recommended)" ' +
'class="form-control" size="23" /></div></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'class="form-control" size="23" /></div></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
$.PrivateBin.TopNav.getPassword() === ''
PrivateBin.TopNav.getPassword() === ''
);
$('#passwordinput').val(password);
query('#passwordinput').value = password;
results.push(
$.PrivateBin.TopNav.getPassword() === password
PrivateBin.TopNav.getPassword() === password
);
$('#passwordinput').val('');
query('#passwordinput').value = '';
results.push(
$.PrivateBin.TopNav.getPassword() === ''
PrivateBin.TopNav.getPassword() === ''
);
cleanup();
const result = results.every(element => element);
@@ -714,7 +711,7 @@ describe('TopNav', function () {
'returns the custom attachment element',
function () {
let results = [];
$('body').html(
document.documentElement.innerHTML =
'<nav><div id="navbar"><ul><li id="attach" class="hidden ' +
'dropdown"><a href="#" class="dropdown-toggle" data-' +
'toggle="dropdown" role="button" aria-haspopup="true" ' +
@@ -723,15 +720,14 @@ describe('TopNav', function () {
'<div><input type="file" id="file" name="file" /></div>' +
'</li><li id="customattachment" class="hidden"></li><li>' +
'<a id="fileremovebutton" href="#">Remove attachment</a>' +
'</li></ul></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
'</li></ul></li></ul></div></nav>';
PrivateBin.TopNav.init();
results.push(
!$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
!PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
);
$('#customattachment').addClass('test');
query('#customattachment').classList.add('test');
results.push(
$.PrivateBin.TopNav.getCustomAttachment().hasClass('test')
PrivateBin.TopNav.getCustomAttachment().classList.contains('test')
);
cleanup();
const result = results.every(element => element);
@@ -753,7 +749,7 @@ describe('TopNav', function () {
function () {
// Insert any setup code needed for the hideAllButtons function
// Example: Initialize the DOM elements required for testing
$('body').html(
document.body.innerHTML =
'<nav class="navbar navbar-inverse navbar-static-top">' +
'<div id="navbar" class="navbar-collapse collapse"><ul ' +
'class="nav navbar-nav"><li><button id="newbutton" ' +
@@ -770,15 +766,14 @@ describe('TopNav', function () {
'data-toggle="modal" data-target="#qrcodemodal" ' +
'class="hidden btn btn-warning navbar-btn"><span ' +
'class="glyphicon glyphicon-qrcode" aria-hidden="true">' +
'</span> QR code</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.hideAllButtons();
'</span> QR code</button></li></ul></div></nav>';
PrivateBin.TopNav.init();
PrivateBin.TopNav.hideAllButtons();
assert.ok($('#newbutton').hasClass('hidden'));
assert.ok($('#clonebutton').hasClass('hidden'));
assert.ok($('#rawtextbutton').hasClass('hidden'));
assert.ok($('#qrcodelink').hasClass('hidden'));
assert.ok(query('#newbutton').classList.contains('hidden'));
assert.ok(query('#clonebutton').classList.contains('hidden'));
assert.ok(query('#rawtextbutton').classList.contains('hidden'));
assert.ok(query('#qrcodelink').classList.contains('hidden'));
cleanup();
}
);
@@ -793,14 +788,14 @@ describe('TopNav', function () {
it(
'displays raw text view correctly',
function () {
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
$('body').html('<button id="rawtextbutton"></button>');
const clean = globalThis.cleanup('', {url: 'https://privatebin.net/?0123456789abcdef#1'});
document.documentElement.innerHTML ='<button id="rawtextbutton"></button>';
const sample = 'example';
$.PrivateBin.PasteViewer.setText(sample);
$.PrivateBin.Helper.reset();
$.PrivateBin.TopNav.init();
$('#rawtextbutton').click();
assert.strictEqual($('pre').text(), sample);
PrivateBin.PasteViewer.setText(sample);
PrivateBin.Helper.reset();
PrivateBin.TopNav.init();
triggerClick(query('#rawtextbutton'));
assert.strictEqual(document.querySelector('pre').textContent, sample);
clean();
}
);

View File

@@ -7,7 +7,7 @@ describe('UiHelper', function () {
describe('historyChange', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
cleanup();
});
@@ -16,10 +16,10 @@ describe('UiHelper', function () {
common.jscUrl(false, false),
function (url) {
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
clean = globalThis.cleanup('', {url: expected});
$.PrivateBin.UiHelper.mockHistoryChange();
$.PrivateBin.Helper.reset();
PrivateBin.UiHelper.mockHistoryChange();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -33,12 +33,12 @@ describe('UiHelper', function () {
function (url, fragment) {
url.fragment = fragment.join('');
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
clean = globalThis.cleanup('', {url: expected});
$.PrivateBin.UiHelper.mockHistoryChange([
PrivateBin.UiHelper.mockHistoryChange([
{type: 'newpaste'}, '', expected
]);
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -51,20 +51,20 @@ describe('UiHelper', function () {
/*
this.timeout(30000);
before(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
});
jsc.property(
'redirects to home',
common.jscUrl(),
function (url) {
const clean = jsdom('', {url: common.urlToString(url)});
const clean = globalThis.cleanup('', {url: common.urlToString(url)});
delete(url.query);
delete(url.fragment);
const expected = common.urlToString(url);
$.PrivateBin.UiHelper.reloadHome();
$.PrivateBin.Helper.reset();
PrivateBin.UiHelper.reloadHome();
PrivateBin.Helper.reset();
var result = window.location.href;
clean();
return expected === result;
@@ -78,7 +78,7 @@ describe('UiHelper', function () {
// once it is supported or a workaround is found, uncomment the section below
/*
before(function () {
$.PrivateBin.Helper.reset();
PrivateBin.Helper.reset();
});
jsc.property(
@@ -88,10 +88,10 @@ describe('UiHelper', function () {
function (id, element) {
id = id.join('');
element = element.join('');
var clean = jsdom(
var clean = globalThis.cleanup(
'<' + element + ' id="' + id + '"></' + element + '>'
);
var result = $.PrivateBin.UiHelper.isVisible($('#' + id));
var result = PrivateBin.UiHelper.isVisible(document.getElementById(id));
clean();
return result;
}

View File

@@ -3,7 +3,7 @@ require('../common');
// DOM builder that mirrors bootstrap5.php navbar
function buildEmailDomNoShortUrl() {
$('body').html(
document.documentElement.innerHTML =
// TopNav expects initially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -15,14 +15,18 @@ function buildEmailDomNoShortUrl() {
'<button id="emaillink" type="button" class="hidden btn btn-secondary">Email</button>' +
'</li>' +
'</ul></div></nav>' +
'<input id="burnafterreadingoption" type="checkbox">'
);
'<input id="burnafterreadingoption" type="checkbox">' +
// include dummy email confirm modal for sendEmail
'<div id="emailconfirmmodal" class="hidden">' +
'<div id="emailconfirm-timezone-current"></div>' +
'<div id="emailconfirm-timezone-utc"></div>' +
'</div>'
}
// DOM builder that adds the shortener result block
function buildEmailDomWithShortUrl() {
buildEmailDomNoShortUrl();
$('body').html(
document.documentElement.innerHTML =
// TopNav expectsinitially hidden #emaillink BUTTON.
'<nav><div id="navbar"><ul>' +
'<li>' +
@@ -38,41 +42,41 @@ function buildEmailDomWithShortUrl() {
'<div id="pastelink">Your document is ' +
'<a id="pasteurl" href="https://short.example/xYz">https://short.example/xYz</a> ' +
'<span id="copyhint">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>' +
'</div>' +
// add a minimal email confirmation modal so sendEmail does not crash
'<div id="emailconfirmmodal" class="hidden">' +
'<div id="emailconfirm-timezone-current"></div>' +
'<div id="emailconfirm-timezone-utc"></div>' +
'</div>'
);
}
function stubWinOpen($element) {
const win = $element[0].ownerDocument.defaultView;
// Some helpers in privatebin.js expect a global document.
global.document = win.document;
function makeWindowOpenMock() {
const originalOpen = window.open;
let openedUrl = null;
const origOpen = win.open;
let mockRestoreFn = null;
// Prefer simple assignment; if blocked, fall back to defineProperty.
try {
win.open = function (url) {
if (typeof jest !== 'undefined' && typeof jest.spyOn === 'function') {
const spy = jest.spyOn(window, 'open').mockImplementation((url) => {
openedUrl = url;
return {};
});
mockRestoreFn = () => spy.mockRestore();
} else {
window.open = function (url) {
openedUrl = url;
return {};
};
} catch (e) {
Object.defineProperty(win, 'open', {
value: function (url) {
openedUrl = url;
return {};
},
configurable: true,
writable: true
});
mockRestoreFn = () => { window.open = originalOpen; };
}
return {
getUrl: () => openedUrl,
restore: () => { try { win.open = origOpen; } catch (e) { /* suppress exception in restore */ } },
win
restore: () => {
if (mockRestoreFn) {
mockRestoreFn();
}
}
};
}
@@ -84,21 +88,23 @@ function extractMailtoBody(mailtoUrl) {
}
describe('Email - mail body content (short URL vs. fallback)', function () {
before(function () {
beforeEach(function () {
cleanup(); // provided by common
});
it('Uses the short URL when #pasteurl is present and never includes "undefined"', function () {
buildEmailDomWithShortUrl(); // with #pastelink/#pasteurl
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.showEmailButton(0);
buildEmailDomWithShortUrl(); // with #pastelink/#pasteurl
PrivateBin.TopNav.init();
PrivateBin.TopNav.showEmailButton(0);
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const emailBtn = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore } = stubWinOpen($emailBtn);
const { getUrl, restore } = makeWindowOpenMock();
try {
$emailBtn.trigger('click');
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
@@ -107,30 +113,30 @@ describe('Email - mail body content (short URL vs. fallback)', function () {
assert.doesNotMatch(body, /undefined/, 'email body must not contain "undefined"');
} finally {
restore();
cleanup();
}
});
it('Falls back to window.location.href when #pasteurl is absent and never includes "undefined"', function () {
buildEmailDomNoShortUrl(); // No #pasteurl
$.PrivateBin.TopNav.init();
$.PrivateBin.TopNav.showEmailButton(0);
buildEmailDomNoShortUrl(); // No #pasteurl
PrivateBin.TopNav.init();
PrivateBin.TopNav.showEmailButton(0);
const $emailBtn = $('#emaillink');
assert.ok(!$emailBtn.hasClass('hidden'), '#emaillink should be visible after showEmailButton');
const emailBtn = document.getElementById('emaillink');
assert.ok(!emailBtn.classList.contains('hidden'), '#emaillink should be visible after showEmailButton');
const { getUrl, restore, win } = stubWinOpen($emailBtn);
const { getUrl, restore } = makeWindowOpenMock();
try {
$emailBtn.trigger('click');
emailBtn.click();
document.getElementById('emailconfirm-timezone-current').click();
const openedUrl = getUrl();
assert.ok(openedUrl, 'window.open should have been called');
const body = extractMailtoBody(openedUrl);
assert.match(body, new RegExp(win.location.href), 'email body should include the fallback page URL');
assert.match(body, new RegExp(window.location.href), 'email body should include the fallback page URL');
assert.doesNotMatch(body, /undefined/, 'email body must not contain "undefined"');
} finally {
restore();
cleanup();
}
});
});