header-menu.cy.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*!
  2. * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: AGPL-3.0-or-later
  4. */
  5. import { haveValidity, zipFileContains } from '../../../support/utils/assertions.ts'
  6. import { getShareUrl, setupPublicShare } from './setup-public-share.ts'
  7. /**
  8. * This tests ensures that on public shares the header actions menu correctly works
  9. */
  10. describe('files_sharing: Public share - header actions menu', { testIsolation: true }, () => {
  11. before(() => setupPublicShare())
  12. beforeEach(() => {
  13. cy.logout()
  14. cy.visit(getShareUrl())
  15. })
  16. it('Can download all files', () => {
  17. cy.get('header')
  18. .findByRole('button', { name: 'Download' })
  19. .should('be.visible')
  20. cy.get('header')
  21. .findByRole('button', { name: 'Download' })
  22. .click()
  23. // check a file is downloaded
  24. const downloadsFolder = Cypress.config('downloadsFolder')
  25. cy.readFile(`${downloadsFolder}/shared.zip`, null, { timeout: 15000 })
  26. .should('exist')
  27. .and('have.length.gt', 30)
  28. // Check all files are included
  29. .and(zipFileContains([
  30. 'shared/',
  31. 'shared/foo.txt',
  32. 'shared/subfolder/',
  33. 'shared/subfolder/bar.txt',
  34. ]))
  35. })
  36. it('Can copy direct link', () => {
  37. // Check the button
  38. cy.get('header')
  39. .findByRole('button', { name: /More actions/i })
  40. .should('be.visible')
  41. cy.get('header')
  42. .findByRole('button', { name: /More actions/i })
  43. .click()
  44. // See the menu
  45. cy.findByRole('menu', { name: /More action/i })
  46. .should('be.visible')
  47. // see correct link in item
  48. cy.findByRole('menuitem', { name: 'Direct link' })
  49. .should('be.visible')
  50. .and('have.attr', 'href')
  51. .then((attribute) => expect(attribute).to.match(/^http:\/\/.+\/download$/))
  52. // see menu closes on click
  53. cy.findByRole('menuitem', { name: 'Direct link' })
  54. .click()
  55. cy.findByRole('menu', { name: /More actions/i })
  56. .should('not.exist')
  57. })
  58. it('Can create federated share', () => {
  59. // Check the button
  60. cy.get('header')
  61. .findByRole('button', { name: /More actions/i })
  62. .should('be.visible')
  63. cy.get('header')
  64. .findByRole('button', { name: /More actions/i })
  65. .click()
  66. // See the menu
  67. cy.findByRole('menu', { name: /More action/i })
  68. .should('be.visible')
  69. // see correct button
  70. cy.findByRole('menuitem', { name: /Add to your/i })
  71. .should('be.visible')
  72. .click()
  73. // see the dialog
  74. cy.findByRole('dialog', { name: /Add to your Nextcloud/i })
  75. .should('be.visible')
  76. cy.findByRole('dialog', { name: /Add to your Nextcloud/i }).within(() => {
  77. cy.findByRole('textbox')
  78. .type('user@nextcloud.local')
  79. // create share
  80. cy.intercept('POST', '**/apps/federatedfilesharing/createFederatedShare')
  81. .as('createFederatedShare')
  82. cy.findByRole('button', { name: 'Create share' })
  83. .click()
  84. cy.wait('@createFederatedShare')
  85. })
  86. })
  87. it('Has user feedback while creating federated share', () => {
  88. // Check the button
  89. cy.get('header')
  90. .findByRole('button', { name: /More actions/i })
  91. .should('be.visible')
  92. .click()
  93. // see correct button
  94. cy.findByRole('menuitem', { name: /Add to your/i })
  95. .should('be.visible')
  96. .click()
  97. // see the dialog
  98. cy.findByRole('dialog', { name: /Add to your Nextcloud/i }).should('be.visible').within(() => {
  99. cy.findByRole('textbox')
  100. .type('user@nextcloud.local')
  101. // intercept request, the request is continued when the promise is resolved
  102. const { promise, resolve } = Promise.withResolvers()
  103. cy.intercept('POST', '**/apps/federatedfilesharing/createFederatedShare', (request) => {
  104. // we need to wait in the onResponse handler as the intercept handler times out otherwise
  105. request.on('response', async (response) => { await promise; response.statusCode = 503 })
  106. }).as('createFederatedShare')
  107. // create the share
  108. cy.findByRole('button', { name: 'Create share' })
  109. .click()
  110. // see that while the share is created the button is disabled
  111. cy.findByRole('button', { name: 'Create share' })
  112. .should('be.disabled')
  113. .then(() => {
  114. // continue the request
  115. resolve(null)
  116. })
  117. cy.wait('@createFederatedShare')
  118. // see that the button is no longer disabled
  119. cy.findByRole('button', { name: 'Create share' })
  120. .should('not.be.disabled')
  121. })
  122. })
  123. it('Has input validation for federated share', () => {
  124. // Check the button
  125. cy.get('header')
  126. .findByRole('button', { name: /More actions/i })
  127. .should('be.visible')
  128. .click()
  129. // see correct button
  130. cy.findByRole('menuitem', { name: /Add to your/i })
  131. .should('be.visible')
  132. .click()
  133. // see the dialog
  134. cy.findByRole('dialog', { name: /Add to your Nextcloud/i }).should('be.visible').within(() => {
  135. // Check domain only
  136. cy.findByRole('textbox')
  137. .type('nextcloud.local')
  138. cy.findByRole('textbox')
  139. .should(haveValidity(/user/i))
  140. // Check no valid domain
  141. cy.findByRole('textbox')
  142. .type('{selectAll}user@invalid')
  143. cy.findByRole('textbox')
  144. .should(haveValidity(/invalid.+url/i))
  145. })
  146. })
  147. it('See primary action is moved to menu on small screens', () => {
  148. cy.viewport(490, 490)
  149. // Check the button does not exist
  150. cy.get('header').within(() => {
  151. cy.findByRole('button', { name: 'Direct link' })
  152. .should('not.exist')
  153. cy.findByRole('button', { name: 'Download' })
  154. .should('not.exist')
  155. cy.findByRole('button', { name: /Add to your/i })
  156. .should('not.exist')
  157. // Open the menu
  158. cy.findByRole('button', { name: /More actions/i })
  159. .should('be.visible')
  160. .click()
  161. })
  162. // See correct number of menu item
  163. cy.findByRole('menu', { name: 'More actions' })
  164. .findAllByRole('menuitem')
  165. .should('have.length', 3)
  166. cy.findByRole('menu', { name: 'More actions' })
  167. .within(() => {
  168. // See that download, federated share and direct link are moved to the menu
  169. cy.findByRole('menuitem', { name: /^Download/ })
  170. .should('be.visible')
  171. cy.findByRole('menuitem', { name: /Add to your/i })
  172. .should('be.visible')
  173. cy.findByRole('menuitem', { name: 'Direct link' })
  174. .should('be.visible')
  175. // See that direct link works
  176. cy.findByRole('menuitem', { name: 'Direct link' })
  177. .should('be.visible')
  178. .and('have.attr', 'href')
  179. .then((attribute) => expect(attribute).to.match(/^http:\/\/.+\/download$/))
  180. // See remote share works
  181. cy.findByRole('menuitem', { name: /Add to your/i })
  182. .should('be.visible')
  183. .click()
  184. })
  185. cy.findByRole('dialog', { name: /Add to your Nextcloud/i }).should('be.visible')
  186. })
  187. })