UiHelper.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. 'use strict';
  2. const common = require('../common');
  3. const fc = require('fast-check');
  4. describe('UiHelper', function () {
  5. describe('historyChange', function () {
  6. this.timeout(30000);
  7. beforeEach(function () {
  8. PrivateBin.Helper.reset();
  9. cleanup();
  10. });
  11. /** @param {object?} state */
  12. function dispatchPopState(state = null) {
  13. let eventError = null;
  14. const captureError = event => {
  15. eventError = event.error;
  16. event.preventDefault();
  17. };
  18. window.addEventListener('error', captureError);
  19. PrivateBin.UiHelper.init();
  20. window.dispatchEvent(new window.PopStateEvent('popstate', {state: state}));
  21. window.removeEventListener('error', captureError);
  22. assert.strictEqual(eventError, null);
  23. }
  24. it('redirects to home, when the state is null', () => {
  25. fc.assert(fc.property(
  26. common.fcUrl(false, false),
  27. function (url) {
  28. const expected = common.urlToString(url),
  29. clean = globalThis.cleanup('', {url: expected});
  30. dispatchPopState();
  31. PrivateBin.Helper.reset();
  32. var result = window.location.href;
  33. clean();
  34. return expected === result;
  35. }
  36. ));
  37. });
  38. it('does not redirect to home, when a new document is created', () => {
  39. fc.assert(fc.property(
  40. common.fcUrl(false),
  41. fc.array(common.fcBase64String(), {minLength: 1}),
  42. function (url, fragment) {
  43. url.fragment = fragment.join('');
  44. const expected = common.urlToString(url),
  45. clean = globalThis.cleanup('', {url: expected});
  46. dispatchPopState([
  47. {type: 'newpaste'}, '', expected
  48. ]);
  49. PrivateBin.Helper.reset();
  50. var result = window.location.href;
  51. clean();
  52. return expected === result;
  53. }
  54. ));
  55. });
  56. });
  57. describe('reloadHome', function () {
  58. // TODO triggers error messages in jsDOM since version 11
  59. /*
  60. this.timeout(30000);
  61. before(function () {
  62. PrivateBin.Helper.reset();
  63. });
  64. it('redirects to home', () => {
  65. fc.assert(fc.property(
  66. common.fcUrl(),
  67. function (url) {
  68. const clean = globalThis.cleanup('', {url: common.urlToString(url)});
  69. delete(url.query);
  70. delete(url.fragment);
  71. const expected = common.urlToString(url);
  72. PrivateBin.UiHelper.reloadHome();
  73. PrivateBin.Helper.reset();
  74. var result = window.location.href;
  75. clean();
  76. return expected === result;
  77. }
  78. ));
  79. });
  80. */
  81. });
  82. describe('showModal & hideModal', function () {
  83. beforeEach(function () {
  84. cleanup();
  85. document.body.innerHTML =
  86. '<div id="testmodal" tabindex="-1" class="modal" role="dialog" aria-hidden="true">' +
  87. '<div class="modal-dialog" role="document"><div class="modal-content">' +
  88. '<div class="modal-body"><button type="button" data-bs-dismiss="modal">Close</button>' +
  89. '</div></div></div></div>';
  90. });
  91. /**
  92. * runs the given action, while collecting messages logged as errors
  93. *
  94. * @param {function} action
  95. * @returns {string[]} logged errors
  96. */
  97. function collectErrors(action) {
  98. const errors = [];
  99. const consoleError = console.error;
  100. console.error = function (...args) {
  101. errors.push(args.join(' '));
  102. };
  103. try {
  104. action();
  105. } finally {
  106. console.error = consoleError;
  107. }
  108. return errors;
  109. }
  110. it('shows and hides a modal repeatedly', function () {
  111. const modal = document.getElementById('testmodal');
  112. const errors = collectErrors(function () {
  113. for (let i = 0; i < 3; ++i) {
  114. PrivateBin.UiHelper.showModal(modal);
  115. assert.ok(modal.classList.contains('show'), 'modal is shown');
  116. assert.strictEqual(modal.getAttribute('aria-modal'), 'true');
  117. PrivateBin.UiHelper.hideModal(modal);
  118. assert.ok(!modal.classList.contains('show'), 'modal is hidden');
  119. assert.strictEqual(modal.style.display, 'none');
  120. }
  121. });
  122. assert.deepStrictEqual(errors, []);
  123. });
  124. it('ignores hiding a modal that was never shown', function () {
  125. const modal = document.getElementById('testmodal');
  126. assert.doesNotThrow(() => PrivateBin.UiHelper.hideModal(modal));
  127. assert.ok(!modal.classList.contains('show'));
  128. });
  129. it('keeps the options of the first showing of a modal', function () {
  130. const modal = document.getElementById('testmodal');
  131. PrivateBin.UiHelper.showModal(modal, {backdrop: 'static', keyboard: false});
  132. modal.dispatchEvent(new window.KeyboardEvent('keydown', {key: 'Escape', bubbles: true}));
  133. assert.ok(modal.classList.contains('show'), 'modal can not be closed with Escape');
  134. PrivateBin.UiHelper.hideModal(modal);
  135. PrivateBin.UiHelper.showModal(modal);
  136. modal.dispatchEvent(new window.KeyboardEvent('keydown', {key: 'Escape', bubbles: true}));
  137. assert.ok(modal.classList.contains('show'), 'modal still can not be closed with Escape');
  138. });
  139. it('lets a modal without options be closed with Escape', function () {
  140. const modal = document.getElementById('testmodal');
  141. PrivateBin.UiHelper.showModal(modal);
  142. modal.dispatchEvent(new window.KeyboardEvent('keydown', {key: 'Escape', bubbles: true}));
  143. assert.ok(!modal.classList.contains('show'), 'modal was closed with Escape');
  144. });
  145. });
  146. });