ranges.test.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import { expect, use } from 'chai'
  2. import { toggleRanges } from '../../../../../frontend/js/features/source-editor/commands/ranges'
  3. import { CodemirrorTestSession, viewHelpers } from '../helpers/codemirror'
  4. use(viewHelpers)
  5. const BOLD_COMMAND = toggleRanges('\\textbf')
  6. describe('toggleRanges', function () {
  7. describe('when text outside of a command is selected', function () {
  8. it('wraps the selection in a command', function () {
  9. const cm = new CodemirrorTestSession(['this <is my> range'])
  10. cm.applyCommand(BOLD_COMMAND)
  11. expect(cm).line(1).to.equal('this \\textbf{<is my>} range')
  12. })
  13. describe('when it is an empty selection', function () {
  14. it('inserts a wrapping command and keep cursor inside the argument', function () {
  15. const cm = new CodemirrorTestSession(['this is | my range'])
  16. cm.applyCommand(BOLD_COMMAND)
  17. expect(cm).line(1).to.equal('this is \\textbf{|} my range')
  18. })
  19. })
  20. describe('when it is an empty selection before a command', function () {
  21. it('inserts a wrapping command and keep cursor inside the argument', function () {
  22. const cm = new CodemirrorTestSession(['this is |\\textbf{my range}'])
  23. cm.applyCommand(BOLD_COMMAND)
  24. expect(cm).line(1).to.equal('this is \\textbf{|}\\textbf{my range}')
  25. })
  26. })
  27. })
  28. describe('when text inside a command is selected', function () {
  29. describe('if the whole command is selected', function () {
  30. it('removes the wrapping command', function () {
  31. const cm = new CodemirrorTestSession(['this \\textbf{<is my>} range'])
  32. cm.applyCommand(BOLD_COMMAND)
  33. expect(cm).line(1).to.equal('this <is my> range')
  34. })
  35. })
  36. describe('if the command is empty', function () {
  37. it('removes the command', function () {
  38. const cm = new CodemirrorTestSession(['\\textbf{|}'])
  39. cm.applyCommand(BOLD_COMMAND)
  40. expect(cm).line(1).to.equal('|')
  41. })
  42. })
  43. describe('if the selection is at the beginning of a wrapping command', function () {
  44. it('shifts the start of the command', function () {
  45. const cm = new CodemirrorTestSession(['\\textbf{<this is> my} range'])
  46. cm.applyCommand(BOLD_COMMAND)
  47. expect(cm).line(1).to.equal('this is\\textbf{ my} range')
  48. })
  49. })
  50. describe('if the selection is at the end of a wrapping command', function () {
  51. it('shifts the end of the command', function () {
  52. const cm = new CodemirrorTestSession(['\\textbf{this <is my>} range'])
  53. cm.applyCommand(BOLD_COMMAND)
  54. expect(cm).line(1).to.equal('\\textbf{this }<is my> range')
  55. })
  56. })
  57. describe('if the selection is in the middle of a wrapping command', function () {
  58. it('splits command in two with non-empty selection', function () {
  59. const cm = new CodemirrorTestSession(['\\textbf{this <is my> range}'])
  60. cm.applyCommand(BOLD_COMMAND)
  61. expect(cm).line(1).to.equal('\\textbf{this }<is my>\\textbf{ range}')
  62. })
  63. it('splits command in two with empty selection', function () {
  64. const cm = new CodemirrorTestSession(['\\textbf{this is | my range}'])
  65. cm.applyCommand(BOLD_COMMAND)
  66. expect(cm).line(1).to.equal('\\textbf{this is }|\\textbf{ my range}')
  67. })
  68. })
  69. })
  70. describe('when selection spans between two wrapping commands', function () {
  71. it('joins the two commands into one', function () {
  72. const cm = new CodemirrorTestSession([
  73. '\\textbf{this <is} my \\textbf{ran>ge}',
  74. ])
  75. cm.applyCommand(BOLD_COMMAND)
  76. expect(cm).line(1).to.equal('\\textbf{this <is my ran>ge}')
  77. })
  78. })
  79. describe('when selection spans across a wrapping command', function () {
  80. it('extends to the left', function () {
  81. const cm = new CodemirrorTestSession(['<this \\textbf{is my> range}'])
  82. cm.applyCommand(BOLD_COMMAND)
  83. expect(cm).line(1).to.equal('\\textbf{<this is my> range}')
  84. })
  85. it('extends to the right', function () {
  86. const cm = new CodemirrorTestSession(['\\textbf{this is <my} range>'])
  87. cm.applyCommand(BOLD_COMMAND)
  88. expect(cm).line(1).to.equal('\\textbf{this is <my range>}')
  89. })
  90. })
  91. describe('when selection includes more than content', function () {
  92. describe('when selection contains command', function () {
  93. it('still unbolds', function () {
  94. const cm = new CodemirrorTestSession(['<\\textbf{this is my range>}'])
  95. cm.applyCommand(BOLD_COMMAND)
  96. expect(cm).line(1).to.equal('<this is my range>')
  97. })
  98. })
  99. describe('when selection contains opening bracket', function () {
  100. it('still unbolds', function () {
  101. const cm = new CodemirrorTestSession(['\\textbf<{this is my range>}'])
  102. cm.applyCommand(BOLD_COMMAND)
  103. expect(cm).line(1).to.equal('<this is my range>')
  104. })
  105. })
  106. describe('when selection contains closing bracket', function () {
  107. it('still unbolds', function () {
  108. const cm = new CodemirrorTestSession(['\\textbf{<this is my range}>'])
  109. cm.applyCommand(BOLD_COMMAND)
  110. expect(cm).line(1).to.equal('<this is my range>')
  111. })
  112. })
  113. describe('when selection contains both brackets', function () {
  114. it('still unbolds', function () {
  115. const cm = new CodemirrorTestSession(['\\textbf<{this is my range}>'])
  116. cm.applyCommand(BOLD_COMMAND)
  117. expect(cm).line(1).to.equal('<this is my range>')
  118. })
  119. })
  120. describe('when selection contains entire command', function () {
  121. it('still unbolds', function () {
  122. const cm = new CodemirrorTestSession(['<\\textbf{this is my range}>'])
  123. cm.applyCommand(BOLD_COMMAND)
  124. expect(cm).line(1).to.equal('<this is my range>')
  125. })
  126. })
  127. describe('when toggling outer command', function () {
  128. it('it functions on the outer command', function () {
  129. const cm = new CodemirrorTestSession([
  130. '\\textbf{\\textit{<this is my range>}}',
  131. ])
  132. cm.applyCommand(BOLD_COMMAND)
  133. expect(cm).line(1).to.equal('<\\textit{this is my range}>')
  134. })
  135. it('prevents breaking commands', function () {
  136. const cm = new CodemirrorTestSession([
  137. '\\textbf{\\textit{this <is} my} range>',
  138. ])
  139. cm.applyCommand(BOLD_COMMAND)
  140. expect(cm).line(1).to.equal('\\textbf{\\textit{this <is} my} range>')
  141. })
  142. })
  143. describe('when range is after a command', function () {
  144. it('still formats list items', function () {
  145. const cm = new CodemirrorTestSession([
  146. '\\begin{itemize}',
  147. ' \\item <My item>',
  148. '\\end{itemize}',
  149. ])
  150. cm.applyCommand(BOLD_COMMAND)
  151. expect(cm).line(2).to.equal(' \\item \\textbf{<My item>}')
  152. })
  153. it('still formats after command', function () {
  154. const cm = new CodemirrorTestSession(['\\noindent <My paragraph>'])
  155. cm.applyCommand(BOLD_COMMAND)
  156. expect(cm).line(1).to.equal('\\noindent \\textbf{<My paragraph>}')
  157. })
  158. it('still formats after unknown command with arguments', function () {
  159. const cm = new CodemirrorTestSession(['\\foo{test}<My paragraph>'])
  160. cm.applyCommand(BOLD_COMMAND)
  161. expect(cm).line(1).to.equal('\\foo{test}\\textbf{<My paragraph>}')
  162. })
  163. it('still formats after known command with arguments', function () {
  164. const cm1 = new CodemirrorTestSession(['\\cite{foo}<text>'])
  165. cm1.applyCommand(BOLD_COMMAND)
  166. expect(cm1).line(1).to.equal('\\cite{foo}\\textbf{<text>}')
  167. const cm2 = new CodemirrorTestSession(['\\href{url}{title}<text>'])
  168. cm2.applyCommand(BOLD_COMMAND)
  169. expect(cm2).line(1).to.equal('\\href{url}{title}\\textbf{<text>}')
  170. })
  171. })
  172. })
  173. it('still formats text next to a command', function () {
  174. const cm = new CodemirrorTestSession(['<item>\\foo'])
  175. cm.applyCommand(BOLD_COMMAND)
  176. expect(cm).line(1).to.equal('\\textbf{item}\\foo')
  177. })
  178. it('still formats part of a text next to command', function () {
  179. const cm = new CodemirrorTestSession(['hello <world>\\foo'])
  180. cm.applyCommand(BOLD_COMMAND)
  181. expect(cm).line(1).to.equal('hello \\textbf{world}\\foo')
  182. })
  183. it('still formats command without arguments', function () {
  184. const cm = new CodemirrorTestSession(['\\item<\\foo>'])
  185. cm.applyCommand(BOLD_COMMAND)
  186. expect(cm).line(1).to.equal('\\item\\textbf{<\\foo>}')
  187. })
  188. it('skips formatting if in the middle of two commands', function () {
  189. const cm = new CodemirrorTestSession(['\\f<oo\\b>ar'])
  190. cm.applyCommand(BOLD_COMMAND)
  191. expect(cm).line(1).to.equal('\\foo\\bar')
  192. })
  193. })