SafeHTMLSubstituteTests.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const { expect } = require('chai')
  2. const SandboxedModule = require('sandboxed-module')
  3. const MODULE_PATH = require('path').join(
  4. __dirname,
  5. '../../../../app/src/Features/Helpers/SafeHTMLSubstitution.js'
  6. )
  7. describe('SafeHTMLSubstitution', function () {
  8. let SafeHTMLSubstitution
  9. before(function () {
  10. SafeHTMLSubstitution = SandboxedModule.require(MODULE_PATH)
  11. })
  12. describe('SPLIT_REGEX', function () {
  13. const CASES = {
  14. 'PRE<0>INNER</0>POST': ['PRE', '0', 'INNER', 'POST'],
  15. '<0>INNER</0>': ['', '0', 'INNER', ''],
  16. '<0></0>': ['', '0', '', ''],
  17. '<0>INNER</0><0>INNER2</0>': ['', '0', 'INNER', '', '0', 'INNER2', ''],
  18. '<0><1>INNER</1></0>': ['', '0', '<1>INNER</1>', ''],
  19. 'PLAIN TEXT': ['PLAIN TEXT'],
  20. }
  21. Object.entries(CASES).forEach(([input, output]) => {
  22. it(`should parse "${input}" as expected`, function () {
  23. expect(input.split(SafeHTMLSubstitution.SPLIT_REGEX)).to.deep.equal(
  24. output
  25. )
  26. })
  27. })
  28. })
  29. describe('render', function () {
  30. describe('substitution', function () {
  31. it('should substitute a single component', function () {
  32. expect(
  33. SafeHTMLSubstitution.render('<0>good</0>', [{ name: 'b' }])
  34. ).to.equal('<b>good</b>')
  35. })
  36. it('should substitute a single component as string', function () {
  37. expect(SafeHTMLSubstitution.render('<0>good</0>', ['b'])).to.equal(
  38. '<b>good</b>'
  39. )
  40. })
  41. it('should substitute a single component twice', function () {
  42. expect(
  43. SafeHTMLSubstitution.render('<0>one</0><0>two</0>', [{ name: 'b' }])
  44. ).to.equal('<b>one</b><b>two</b>')
  45. })
  46. it('should substitute two components', function () {
  47. expect(
  48. SafeHTMLSubstitution.render('<0>one</0><1>two</1>', [
  49. { name: 'b' },
  50. { name: 'i' },
  51. ])
  52. ).to.equal('<b>one</b><i>two</i>')
  53. })
  54. it('should substitute a single component with a class', function () {
  55. expect(
  56. SafeHTMLSubstitution.render('<0>text</0>', [
  57. {
  58. name: 'b',
  59. attrs: {
  60. class: 'magic',
  61. },
  62. },
  63. ])
  64. ).to.equal('<b class="magic">text</b>')
  65. })
  66. it('should substitute two nested components', function () {
  67. expect(
  68. SafeHTMLSubstitution.render('<0><1>nested</1></0>', [
  69. { name: 'b' },
  70. { name: 'i' },
  71. ])
  72. ).to.equal('<b><i>nested</i></b>')
  73. })
  74. it('should handle links', function () {
  75. expect(
  76. SafeHTMLSubstitution.render('<0>Go to Login</0>', [
  77. { name: 'a', attrs: { href: 'https://www.overleaf.com/login' } },
  78. ])
  79. ).to.equal('<a href="https://www.overleaf.com/login">Go to Login</a>')
  80. })
  81. it('should not complain about too many components', function () {
  82. expect(
  83. SafeHTMLSubstitution.render('<0>good</0>', [
  84. { name: 'b' },
  85. { name: 'i' },
  86. { name: 'u' },
  87. ])
  88. ).to.equal('<b>good</b>')
  89. })
  90. })
  91. describe('pug.escape', function () {
  92. it('should handle plain text', function () {
  93. expect(SafeHTMLSubstitution.render('plain text')).to.equal('plain text')
  94. })
  95. it('should keep a simple string delimiter', function () {
  96. expect(SafeHTMLSubstitution.render("'")).to.equal(`'`)
  97. })
  98. it('should escape double quotes', function () {
  99. expect(SafeHTMLSubstitution.render('"')).to.equal(`&quot;`)
  100. })
  101. it('should escape &', function () {
  102. expect(SafeHTMLSubstitution.render('&')).to.equal(`&amp;`)
  103. })
  104. it('should escape <', function () {
  105. expect(SafeHTMLSubstitution.render('<')).to.equal(`&lt;`)
  106. })
  107. it('should escape >', function () {
  108. expect(SafeHTMLSubstitution.render('>')).to.equal(`&gt;`)
  109. })
  110. it('should escape html', function () {
  111. expect(SafeHTMLSubstitution.render('<b>bad</b>')).to.equal(
  112. '&lt;b&gt;bad&lt;/b&gt;'
  113. )
  114. })
  115. })
  116. describe('escape around substitutions', function () {
  117. it('should escape text inside a component', function () {
  118. expect(
  119. SafeHTMLSubstitution.render('<0><i>inner</i></0>', [{ name: 'b' }])
  120. ).to.equal('<b>&lt;i&gt;inner&lt;/i&gt;</b>')
  121. })
  122. it('should escape text in front of a component', function () {
  123. expect(
  124. SafeHTMLSubstitution.render('<i>PRE</i><0>inner</0>', [{ name: 'b' }])
  125. ).to.equal('&lt;i&gt;PRE&lt;/i&gt;<b>inner</b>')
  126. })
  127. it('should escape text after of a component', function () {
  128. expect(
  129. SafeHTMLSubstitution.render('<0>inner</0><i>POST</i>', [
  130. { name: 'b' },
  131. ])
  132. ).to.equal('<b>inner</b>&lt;i&gt;POST&lt;/i&gt;')
  133. })
  134. })
  135. })
  136. })