admin-settings.cy.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /**
  2. * @copyright Copyright (c) 2022 John Molakvoæ <skjnldsv@protonmail.com>
  3. *
  4. * @author John Molakvoæ <skjnldsv@protonmail.com>
  5. *
  6. * @license AGPL-3.0-or-later
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as
  10. * published by the Free Software Foundation, either version 3 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /* eslint-disable n/no-unpublished-import */
  23. import { User } from '@nextcloud/cypress'
  24. import { colord } from 'colord'
  25. import { defaultPrimary, defaultBackground, pickRandomColor, validateBodyThemingCss, validateUserThemingDefaultCss } from './themingUtils'
  26. const admin = new User('admin', 'admin')
  27. describe('Admin theming settings visibility check', function() {
  28. before(function() {
  29. // Just in case previous test failed
  30. cy.resetAdminTheming()
  31. cy.login(admin)
  32. })
  33. it('See the admin theming section', function() {
  34. cy.visit('/settings/admin/theming')
  35. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  36. cy.get('[data-admin-theming-settings]').should('be.visible')
  37. })
  38. it('See the default settings', function() {
  39. cy.get('[data-admin-theming-setting-primary-color-picker]').should('contain.text', defaultPrimary)
  40. cy.get('[data-admin-theming-setting-primary-color-reset]').should('not.exist')
  41. cy.get('[data-admin-theming-setting-file-reset]').should('not.exist')
  42. cy.get('[data-admin-theming-setting-file-remove]').should('be.visible')
  43. })
  44. })
  45. describe('Change the primary color and reset it', function() {
  46. let selectedColor = ''
  47. before(function() {
  48. // Just in case previous test failed
  49. cy.resetAdminTheming()
  50. cy.login(admin)
  51. })
  52. it('See the admin theming section', function() {
  53. cy.visit('/settings/admin/theming')
  54. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  55. cy.get('[data-admin-theming-settings]').should('be.visible')
  56. })
  57. it('Change the primary color', function() {
  58. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
  59. pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
  60. .then(color => { selectedColor = color })
  61. cy.wait('@setColor')
  62. cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
  63. })
  64. it('Screenshot the login page and validate login page', function() {
  65. cy.logout()
  66. cy.visit('/')
  67. cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
  68. cy.screenshot()
  69. })
  70. it('Undo theming settings and validate login page again', function() {
  71. cy.resetAdminTheming()
  72. cy.visit('/')
  73. cy.waitUntil(validateBodyThemingCss)
  74. cy.screenshot()
  75. })
  76. })
  77. describe('Remove the default background and restore it', function() {
  78. before(function() {
  79. // Just in case previous test failed
  80. cy.resetAdminTheming()
  81. cy.login(admin)
  82. })
  83. it('See the admin theming section', function() {
  84. cy.visit('/settings/admin/theming')
  85. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  86. cy.get('[data-admin-theming-settings]').should('be.visible')
  87. })
  88. it('Remove the default background', function() {
  89. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
  90. cy.get('[data-admin-theming-setting-file-remove]').click()
  91. cy.wait('@removeBackground')
  92. cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
  93. cy.waitUntil(() => cy.window().then((win) => {
  94. const backgroundPlain = getComputedStyle(win.document.body).getPropertyValue('--image-background-plain')
  95. return backgroundPlain !== ''
  96. }))
  97. })
  98. it('Screenshot the login page and validate login page', function() {
  99. cy.logout()
  100. cy.visit('/')
  101. cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
  102. cy.screenshot()
  103. })
  104. it('Undo theming settings and validate login page again', function() {
  105. cy.resetAdminTheming()
  106. cy.visit('/')
  107. cy.waitUntil(validateBodyThemingCss)
  108. cy.screenshot()
  109. })
  110. })
  111. describe('Remove the default background with a custom primary color', function() {
  112. let selectedColor = ''
  113. before(function() {
  114. // Just in case previous test failed
  115. cy.resetAdminTheming()
  116. cy.login(admin)
  117. })
  118. it('See the admin theming section', function() {
  119. cy.visit('/settings/admin/theming')
  120. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  121. cy.get('[data-admin-theming-settings]').should('be.visible')
  122. })
  123. it('Change the primary color', function() {
  124. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
  125. pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
  126. .then((color) => { selectedColor = color })
  127. cy.wait('@setColor')
  128. cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
  129. })
  130. it('Remove the default background', function() {
  131. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
  132. cy.get('[data-admin-theming-setting-file-remove]').click()
  133. cy.wait('@removeBackground')
  134. })
  135. it('Screenshot the login page and validate login page', function() {
  136. cy.logout()
  137. cy.visit('/')
  138. cy.waitUntil(() => validateBodyThemingCss(selectedColor, null))
  139. cy.screenshot()
  140. })
  141. it('Undo theming settings and validate login page again', function() {
  142. cy.resetAdminTheming()
  143. cy.visit('/')
  144. cy.waitUntil(validateBodyThemingCss)
  145. cy.screenshot()
  146. })
  147. })
  148. describe('Remove the default background with a bright color', function() {
  149. before(function() {
  150. // Just in case previous test failed
  151. cy.resetAdminTheming()
  152. cy.resetUserTheming(admin)
  153. cy.login(admin)
  154. })
  155. it('See the admin theming section', function() {
  156. cy.visit('/settings/admin/theming')
  157. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  158. cy.get('[data-admin-theming-settings]').should('be.visible')
  159. })
  160. it('Remove the default background', function() {
  161. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
  162. cy.get('[data-admin-theming-setting-file-remove]').click()
  163. cy.wait('@removeBackground')
  164. })
  165. it('Change the primary color', function() {
  166. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
  167. // Pick one of the bright color preset
  168. cy.get('[data-admin-theming-setting-primary-color-picker]').click()
  169. cy.get('.color-picker__simple-color-circle:eq(4)').click()
  170. cy.wait('@setColor')
  171. cy.waitUntil(() => validateBodyThemingCss('#ddcb55', null))
  172. })
  173. it('See the header being inverted', function() {
  174. cy.waitUntil(() => cy.window().then((win) => {
  175. const firstEntry = win.document.querySelector('.app-menu-main li img')
  176. if (!firstEntry) {
  177. return false
  178. }
  179. return getComputedStyle(firstEntry).filter === 'invert(1)'
  180. }))
  181. })
  182. })
  183. describe('Change the login fields then reset them', function() {
  184. const name = 'ABCdef123'
  185. const url = 'https://example.com'
  186. const slogan = 'Testing is fun'
  187. before(function() {
  188. // Just in case previous test failed
  189. cy.resetAdminTheming()
  190. cy.login(admin)
  191. })
  192. it('See the admin theming section', function() {
  193. cy.visit('/settings/admin/theming')
  194. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  195. cy.get('[data-admin-theming-settings]').should('be.visible')
  196. })
  197. it('Change the name field', function() {
  198. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('updateFields')
  199. // Name
  200. cy.get('[data-admin-theming-setting-field="name"] input[type="text"]')
  201. .scrollIntoView()
  202. cy.get('[data-admin-theming-setting-field="name"] input[type="text"]')
  203. .type(`{selectall}${name}{enter}`)
  204. cy.wait('@updateFields')
  205. // Url
  206. cy.get('[data-admin-theming-setting-field="url"] input[type="url"]')
  207. .scrollIntoView()
  208. cy.get('[data-admin-theming-setting-field="url"] input[type="url"]')
  209. .type(`{selectall}${url}{enter}`)
  210. cy.wait('@updateFields')
  211. // Slogan
  212. cy.get('[data-admin-theming-setting-field="slogan"] input[type="text"]')
  213. .scrollIntoView()
  214. cy.get('[data-admin-theming-setting-field="slogan"] input[type="text"]')
  215. .type(`{selectall}${slogan}{enter}`)
  216. cy.wait('@updateFields')
  217. })
  218. it('Ensure undo button presence', function() {
  219. cy.get('[data-admin-theming-setting-field="name"] .input-field__trailing-button')
  220. .scrollIntoView()
  221. cy.get('[data-admin-theming-setting-field="name"] .input-field__trailing-button')
  222. .should('be.visible')
  223. cy.get('[data-admin-theming-setting-field="url"] .input-field__trailing-button')
  224. .scrollIntoView()
  225. cy.get('[data-admin-theming-setting-field="url"] .input-field__trailing-button')
  226. .should('be.visible')
  227. cy.get('[data-admin-theming-setting-field="slogan"] .input-field__trailing-button')
  228. .scrollIntoView()
  229. cy.get('[data-admin-theming-setting-field="slogan"] .input-field__trailing-button')
  230. .should('be.visible')
  231. })
  232. it('Validate login screen changes', function() {
  233. cy.logout()
  234. cy.visit('/')
  235. cy.get('[data-login-form-headline]').should('contain.text', name)
  236. cy.get('footer p a').should('have.text', name)
  237. cy.get('footer p a').should('have.attr', 'href', url)
  238. cy.get('footer p').should('contain.text', `– ${slogan}`)
  239. })
  240. it('Undo theming settings', function() {
  241. cy.resetAdminTheming()
  242. })
  243. it('Validate login screen changes again', function() {
  244. cy.visit('/')
  245. cy.get('[data-login-form-headline]').should('not.contain.text', name)
  246. cy.get('footer p a').should('not.have.text', name)
  247. cy.get('footer p a').should('not.have.attr', 'href', url)
  248. cy.get('footer p').should('not.contain.text', `– ${slogan}`)
  249. })
  250. })
  251. describe('Disable user theming and enable it back', function() {
  252. before(function() {
  253. // Just in case previous test failed
  254. cy.resetAdminTheming()
  255. cy.login(admin)
  256. })
  257. it('See the admin theming section', function() {
  258. cy.visit('/settings/admin/theming')
  259. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  260. cy.get('[data-admin-theming-settings]').should('be.visible')
  261. })
  262. it('Disable user background theming', function() {
  263. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('disableUserTheming')
  264. cy.get('[data-admin-theming-setting-disable-user-theming]')
  265. .scrollIntoView()
  266. cy.get('[data-admin-theming-setting-disable-user-theming]')
  267. .should('be.visible')
  268. cy.get('[data-admin-theming-setting-disable-user-theming] input[type="checkbox"]').check({ force: true })
  269. cy.get('[data-admin-theming-setting-disable-user-theming] input[type="checkbox"]').should('be.checked')
  270. cy.wait('@disableUserTheming')
  271. })
  272. it('Login as user', function() {
  273. cy.logout()
  274. cy.createRandomUser().then((user) => {
  275. cy.login(user)
  276. })
  277. })
  278. it('User cannot not change background settings', function() {
  279. cy.visit('/settings/user/theming')
  280. cy.get('[data-user-theming-background-disabled]').scrollIntoView()
  281. cy.get('[data-user-theming-background-disabled]').should('be.visible')
  282. })
  283. })
  284. describe('The user default background settings reflect the admin theming settings', function() {
  285. let selectedColor = ''
  286. before(function() {
  287. // Just in case previous test failed
  288. cy.resetAdminTheming()
  289. cy.login(admin)
  290. })
  291. after(function() {
  292. cy.resetAdminTheming()
  293. })
  294. it('See the admin theming section', function() {
  295. cy.visit('/settings/admin/theming')
  296. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  297. cy.get('[data-admin-theming-settings]').should('be.visible')
  298. })
  299. it('Change the primary color', function() {
  300. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
  301. pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
  302. .then(color => { selectedColor = color })
  303. cy.wait('@setColor')
  304. cy.waitUntil(() => cy.window().then(($window) => {
  305. const primary = $window.getComputedStyle($window.document.body).getPropertyValue('--color-primary-default')
  306. return colord(primary).isEqual(selectedColor)
  307. }))
  308. })
  309. it('Change the default background', function() {
  310. cy.intercept('*/apps/theming/ajax/uploadImage').as('setBackground')
  311. cy.fixture('image.jpg', null).as('background')
  312. cy.get('[data-admin-theming-setting-file="background"] input[type="file"]').selectFile('@background', { force: true })
  313. cy.wait('@setBackground')
  314. cy.waitUntil(() => cy.window().then((win) => {
  315. const currentBackgroundDefault = getComputedStyle(win.document.body).getPropertyValue('--image-background-default')
  316. return currentBackgroundDefault.includes('/apps/theming/image/background?v=')
  317. }))
  318. })
  319. it('Login page should match admin theming settings', function() {
  320. cy.logout()
  321. cy.visit('/')
  322. cy.waitUntil(() => validateBodyThemingCss(selectedColor, '/apps/theming/image/background?v='))
  323. })
  324. it('Login as user', function() {
  325. cy.createRandomUser().then((user) => {
  326. cy.login(user)
  327. })
  328. })
  329. it('See the user background settings', function() {
  330. cy.visit('/settings/user/theming')
  331. cy.get('[data-user-theming-background-settings]').scrollIntoView()
  332. cy.get('[data-user-theming-background-settings]').should('be.visible')
  333. })
  334. it('Default user background settings should match admin theming settings', function() {
  335. cy.get('[data-user-theming-background-default]').should('be.visible')
  336. cy.get('[data-user-theming-background-default]').should('have.class', 'background--active')
  337. cy.waitUntil(() => validateUserThemingDefaultCss(selectedColor, '/apps/theming/image/background?v='))
  338. })
  339. })
  340. describe('The user default background settings reflect the admin theming settings with background removed', function() {
  341. before(function() {
  342. // Just in case previous test failed
  343. cy.resetAdminTheming()
  344. cy.login(admin)
  345. })
  346. after(function() {
  347. cy.resetAdminTheming()
  348. })
  349. it('See the admin theming section', function() {
  350. cy.visit('/settings/admin/theming')
  351. cy.get('[data-admin-theming-settings]').should('exist').scrollIntoView()
  352. cy.get('[data-admin-theming-settings]').should('be.visible')
  353. })
  354. it('Remove the default background', function() {
  355. cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
  356. cy.get('[data-admin-theming-setting-file-remove]').click()
  357. cy.wait('@removeBackground')
  358. cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
  359. })
  360. it('Login page should match admin theming settings', function() {
  361. cy.logout()
  362. cy.visit('/')
  363. cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
  364. })
  365. it('Login as user', function() {
  366. cy.createRandomUser().then((user) => {
  367. cy.login(user)
  368. })
  369. })
  370. it('See the user background settings', function() {
  371. cy.visit('/settings/user/theming')
  372. cy.get('[data-user-theming-background-settings]').scrollIntoView()
  373. cy.get('[data-user-theming-background-settings]').should('be.visible')
  374. })
  375. it('Default user background settings should match admin theming settings', function() {
  376. cy.get('[data-user-theming-background-default]').should('be.visible')
  377. cy.get('[data-user-theming-background-default]').should('have.class', 'background--active')
  378. cy.waitUntil(() => validateUserThemingDefaultCss(defaultPrimary, null))
  379. })
  380. })