|
|
@@ -1,5 +1,6 @@
|
|
|
'use strict';
|
|
|
require('../common');
|
|
|
+const fc = require('fast-check');
|
|
|
|
|
|
// DOM builder that mirrors bootstrap5.php navbar
|
|
|
function buildEmailDomNoShortUrl() {
|
|
|
@@ -54,17 +55,20 @@ function buildEmailDomWithShortUrl() {
|
|
|
function makeWindowOpenMock() {
|
|
|
const originalOpen = window.open;
|
|
|
let openedUrl = null;
|
|
|
+ let openedCount = 0;
|
|
|
let mockRestoreFn = null;
|
|
|
|
|
|
if (typeof jest !== 'undefined' && typeof jest.spyOn === 'function') {
|
|
|
const spy = jest.spyOn(window, 'open').mockImplementation((url) => {
|
|
|
openedUrl = url;
|
|
|
+ openedCount++;
|
|
|
return {};
|
|
|
});
|
|
|
mockRestoreFn = () => spy.mockRestore();
|
|
|
} else {
|
|
|
window.open = function (url) {
|
|
|
openedUrl = url;
|
|
|
+ openedCount++;
|
|
|
return {};
|
|
|
};
|
|
|
mockRestoreFn = () => { window.open = originalOpen; };
|
|
|
@@ -72,6 +76,7 @@ function makeWindowOpenMock() {
|
|
|
|
|
|
return {
|
|
|
getUrl: () => openedUrl,
|
|
|
+ getCount: () => openedCount,
|
|
|
restore: () => {
|
|
|
if (mockRestoreFn) {
|
|
|
mockRestoreFn();
|
|
|
@@ -252,3 +257,132 @@ describe('Email - mail subject', function () {
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
+
|
|
|
+describe('Email - click handlers', function () {
|
|
|
+ beforeEach(function () {
|
|
|
+ cleanup(); // provided by common
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Sends a single e-mail after the confirmation dialog was dismissed', function () {
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ PrivateBin.TopNav.showEmailButton(3600);
|
|
|
+
|
|
|
+ const { getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ // open the dialog and dismiss it without choosing a timezone
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ assert.strictEqual(getCount(), 0, 'no e-mail before choosing a timezone');
|
|
|
+
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ document.getElementById('emailconfirm-timezone-current').click();
|
|
|
+ assert.strictEqual(getCount(), 1, 'exactly one e-mail with the current timezone');
|
|
|
+
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ document.getElementById('emailconfirm-timezone-utc').click();
|
|
|
+ assert.strictEqual(getCount(), 2, 'exactly one more e-mail with UTC');
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Sends a single e-mail per click after the button was shown again', function () {
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ // i.e. sending a second document without reloading the page
|
|
|
+ PrivateBin.TopNav.showEmailButton(0);
|
|
|
+ PrivateBin.TopNav.showEmailButton(0);
|
|
|
+
|
|
|
+ const { getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ assert.strictEqual(getCount(), 1, 'exactly one e-mail per click');
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Uses the expiration of the document the button was last shown for', function () {
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ // first document expires, the second never does
|
|
|
+ PrivateBin.TopNav.showEmailButton(3600);
|
|
|
+ PrivateBin.TopNav.showEmailButton(0);
|
|
|
+
|
|
|
+ const { getUrl, getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ assert.strictEqual(getCount(), 1, 'sent directly, without confirmation dialog');
|
|
|
+ assert.doesNotMatch(extractMailtoBody(getUrl()), /expire/i, 'body has no expiration');
|
|
|
+
|
|
|
+ document.getElementById('emailconfirm-timezone-current').click();
|
|
|
+ assert.strictEqual(getCount(), 1, 'no e-mail from a stale confirmation dialog');
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Sends no e-mail from a confirmation dialog opened for an earlier document', function () {
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ PrivateBin.TopNav.showEmailButton(3600);
|
|
|
+
|
|
|
+ const { getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ // open the dialog, but start a new document instead of choosing
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ PrivateBin.TopNav.hideEmailButton();
|
|
|
+ PrivateBin.TopNav.showEmailButton(0);
|
|
|
+
|
|
|
+ document.getElementById('emailconfirm-timezone-current').click();
|
|
|
+ document.getElementById('emailconfirm-timezone-utc').click();
|
|
|
+ assert.strictEqual(getCount(), 0, 'no e-mail from a stale confirmation dialog');
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Sends no e-mail after the button was hidden', function () {
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ PrivateBin.TopNav.showEmailButton(0);
|
|
|
+ PrivateBin.TopNav.hideEmailButton();
|
|
|
+
|
|
|
+ const { getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ // i.e. a keyboard shortcut or assistive technology activating it
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ assert.strictEqual(getCount(), 0, 'no e-mail from a hidden button');
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ it('Sends exactly one e-mail, regardless of how often the button was shown or the dialog dismissed', function () {
|
|
|
+ fc.assert(fc.property(
|
|
|
+ fc.integer({min: 1, max: 5}),
|
|
|
+ fc.integer({min: 0, max: 5}),
|
|
|
+ fc.constantFrom('current', 'utc'),
|
|
|
+ function (shown, dismissed, timezone) {
|
|
|
+ cleanup();
|
|
|
+ buildEmailDomNoShortUrl();
|
|
|
+ PrivateBin.TopNav.init();
|
|
|
+ for (let i = 0; i < shown; ++i) {
|
|
|
+ PrivateBin.TopNav.showEmailButton(3600);
|
|
|
+ }
|
|
|
+
|
|
|
+ const { getCount, restore } = makeWindowOpenMock();
|
|
|
+ try {
|
|
|
+ for (let i = 0; i < dismissed; ++i) {
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ }
|
|
|
+ document.getElementById('emaillink').click();
|
|
|
+ document.getElementById('emailconfirm-timezone-' + timezone).click();
|
|
|
+ assert.strictEqual(getCount(), 1);
|
|
|
+ } finally {
|
|
|
+ restore();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ));
|
|
|
+ });
|
|
|
+});
|