layout-dropdown-button.test.jsx 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import sinon from 'sinon'
  2. import fetchMock from 'fetch-mock'
  3. import { expect } from 'chai'
  4. import { screen, waitFor } from '@testing-library/react'
  5. import LayoutDropdownButton from '../../../../../frontend/js/features/editor-navigation-toolbar/components/layout-dropdown-button'
  6. import { renderWithEditorContext } from '../../../helpers/render-with-context'
  7. import * as eventTracking from '@/infrastructure/event-tracking'
  8. describe('<LayoutDropdownButton />', function () {
  9. let openStub
  10. let sendMBSpy
  11. const defaultLayout = {
  12. pdfLayout: 'flat',
  13. view: 'pdf',
  14. chatIsOpen: false,
  15. }
  16. beforeEach(function () {
  17. openStub = sinon.stub(window, 'open')
  18. sendMBSpy = sinon.spy(eventTracking, 'sendMB')
  19. })
  20. afterEach(function () {
  21. openStub.restore()
  22. sendMBSpy.restore()
  23. fetchMock.removeRoutes().clearHistory()
  24. })
  25. it('should mark current layout option as selected', async function () {
  26. // Selected is aria-label, visually we show a checkmark
  27. renderWithEditorContext(<LayoutDropdownButton />, {
  28. layoutContext: defaultLayout,
  29. })
  30. screen.getByRole('button', { name: 'Layout' }).click()
  31. await waitFor(() =>
  32. expect(
  33. screen
  34. .getByRole('menuitem', {
  35. name: 'Editor & PDF',
  36. })
  37. .getAttribute('aria-selected')
  38. ).to.equal('false')
  39. )
  40. expect(
  41. screen
  42. .getByRole('menuitem', {
  43. name: 'PDF only (hide editor)',
  44. })
  45. .getAttribute('aria-selected')
  46. ).to.equal('true')
  47. expect(
  48. screen
  49. .getByRole('menuitem', {
  50. name: 'Editor only (hide PDF)',
  51. })
  52. .getAttribute('aria-selected')
  53. ).to.equal('false')
  54. expect(
  55. screen
  56. .getByRole('menuitem', {
  57. name: 'PDF in separate tab',
  58. })
  59. .getAttribute('aria-selected')
  60. ).to.equal('false')
  61. })
  62. it('should not select any option in history view', async function () {
  63. // Selected is aria-label, visually we show a checkmark
  64. renderWithEditorContext(<LayoutDropdownButton />, {
  65. layoutContext: { ...defaultLayout, view: 'history' },
  66. })
  67. screen.getByRole('button', { name: 'Layout' }).click()
  68. await waitFor(() =>
  69. expect(
  70. screen
  71. .getByRole('menuitem', {
  72. name: 'Editor & PDF',
  73. })
  74. .getAttribute('aria-selected')
  75. ).to.equal('false')
  76. )
  77. expect(
  78. screen
  79. .getByRole('menuitem', {
  80. name: 'PDF only (hide editor)',
  81. })
  82. .getAttribute('aria-selected')
  83. ).to.equal('false')
  84. expect(
  85. screen
  86. .getByRole('menuitem', {
  87. name: 'Editor only (hide PDF)',
  88. })
  89. .getAttribute('aria-selected')
  90. ).to.equal('false')
  91. expect(
  92. screen
  93. .getByRole('menuitem', {
  94. name: 'PDF in separate tab',
  95. })
  96. .getAttribute('aria-selected')
  97. ).to.equal('false')
  98. })
  99. it('should treat file and editor views the same way', async function () {
  100. // Selected is aria-label, visually we show a checkmark
  101. renderWithEditorContext(<LayoutDropdownButton />, {
  102. layoutContext: {
  103. pdfLayout: 'flat',
  104. view: 'file',
  105. chatIsOpen: false,
  106. },
  107. })
  108. screen.getByRole('button', { name: 'Layout' }).click()
  109. await waitFor(() =>
  110. expect(
  111. screen
  112. .getByRole('menuitem', {
  113. name: 'Editor & PDF',
  114. })
  115. .getAttribute('aria-selected')
  116. ).to.equal('false')
  117. )
  118. expect(
  119. screen
  120. .getByRole('menuitem', {
  121. name: 'PDF only (hide editor)',
  122. })
  123. .getAttribute('aria-selected')
  124. ).to.equal('false')
  125. expect(
  126. screen
  127. .getByRole('menuitem', {
  128. name: 'Editor only (hide PDF)',
  129. })
  130. .getAttribute('aria-selected')
  131. ).to.equal('true')
  132. expect(
  133. screen
  134. .getByRole('menuitem', {
  135. name: 'PDF in separate tab',
  136. })
  137. .getAttribute('aria-selected')
  138. ).to.equal('false')
  139. })
  140. describe('on detach', async function () {
  141. let originalBroadcastChannel
  142. beforeEach(async function () {
  143. window.BroadcastChannel = originalBroadcastChannel || true // ensure that window.BroadcastChannel is truthy
  144. renderWithEditorContext(<LayoutDropdownButton />, {
  145. layoutContext: { ...defaultLayout, view: 'editor' },
  146. })
  147. screen.getByRole('button', { name: 'Layout' }).click()
  148. await waitFor(() =>
  149. screen
  150. .getByRole('menuitem', {
  151. name: 'PDF in separate tab',
  152. })
  153. .click()
  154. )
  155. })
  156. afterEach(function () {
  157. window.BroadcastChannel = originalBroadcastChannel
  158. })
  159. it('should show processing', async function () {
  160. await screen.findByText('Layout processing')
  161. })
  162. it('should record event', function () {
  163. sinon.assert.calledWith(sendMBSpy, 'project-layout-detach')
  164. })
  165. })
  166. describe('on layout change / reattach', async function () {
  167. beforeEach(async function () {
  168. window.metaAttributesCache.set('ol-detachRole', 'detacher')
  169. renderWithEditorContext(<LayoutDropdownButton />, {
  170. layoutContext: { ...defaultLayout, view: 'editor' },
  171. })
  172. screen.getByRole('button', { name: 'Layout' }).click()
  173. await waitFor(() =>
  174. screen
  175. .getByRole('menuitem', {
  176. name: 'Editor only (hide PDF)',
  177. })
  178. .click()
  179. )
  180. })
  181. it('should not show processing', function () {
  182. const processingText = screen.queryByText('Layout processing')
  183. expect(processingText).to.not.exist
  184. })
  185. it('should record events', function () {
  186. sinon.assert.calledWith(sendMBSpy, 'project-layout-reattach')
  187. sinon.assert.calledWith(sendMBSpy, 'project-layout-change', {
  188. layout: 'flat',
  189. view: 'editor',
  190. page: '/detacher',
  191. })
  192. })
  193. it('should select new menu item', function () {
  194. screen.getByRole('menuitem', {
  195. name: 'Editor only (hide PDF)',
  196. })
  197. })
  198. })
  199. })