test(theming): adjust cypress tests for Vue3

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen 2025-12-18 16:38:13 +01:00
parent 754422aa00
commit 32508c1f78
No known key found for this signature in database
GPG key ID: 45FAE7268762B400
9 changed files with 801 additions and 766 deletions

View file

@ -1,514 +0,0 @@
/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { User } from '@nextcloud/e2e-test-server/cypress'
import { NavigationHeader } from '../../pages/NavigationHeader.ts'
import {
defaultBackground,
defaultPrimary,
expectBackgroundColor,
pickRandomColor,
validateBodyThemingCss,
validateUserThemingDefaultCss,
} from './themingUtils.ts'
const admin = new User('admin', 'admin')
describe('Admin theming settings visibility check', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('See the default settings', function() {
cy.get('[data-admin-theming-setting-color-picker]').should('exist')
cy.get('[data-admin-theming-setting-file-reset]').should('not.exist')
cy.get('[data-admin-theming-setting-file-remove]').should('exist')
cy.get('[data-admin-theming-setting-primary-color] [data-admin-theming-setting-color]').then(($el) => expectBackgroundColor($el, defaultPrimary))
cy.get('[data-admin-theming-setting-background-color] [data-admin-theming-setting-color]').then(($el) => expectBackgroundColor($el, defaultPrimary))
})
})
describe('Change the primary color and reset it', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-primary-color]').then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(
selectedColor,
defaultBackground,
defaultPrimary,
))
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(
selectedColor,
defaultBackground,
defaultPrimary,
))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
})
describe('Remove the default background and restore it', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.get('[data-admin-theming-setting-file-remove]').click()
cy.wait('@removeBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
cy.waitUntil(() => cy.window().then((win) => {
const backgroundPlain = getComputedStyle(win.document.body).getPropertyValue('--image-background')
return backgroundPlain !== ''
}))
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
})
describe('Remove the default background with a custom background color', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-background-color]').then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(
defaultPrimary,
defaultBackground,
selectedColor,
))
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.get('[data-admin-theming-setting-file-remove]').scrollIntoView()
cy.get('[data-admin-theming-setting-file-remove]').click({
force: true,
})
cy.wait('@removeBackground')
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, selectedColor))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
})
describe('Remove the default background with a bright color', function() {
const navigationHeader = new NavigationHeader()
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.resetUserTheming(admin)
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.get('[data-admin-theming-setting-file-remove]').click()
cy.wait('@removeBackground')
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
// Pick one of the bright color preset
pickRandomColor(
'[data-admin-theming-setting-background-color]',
4,
).then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, selectedColor))
})
it('See the header being inverted', function() {
cy.waitUntil(() => navigationHeader
.getNavigationEntries()
.find('img')
.then((el) => {
let ret = true
el.each(function() {
ret = ret && window.getComputedStyle(this).filter === 'invert(1)'
})
return ret
}))
})
})
describe('Change the login fields then reset them', function() {
const name = 'ABCdef123'
const url = 'https://example.com'
const slogan = 'Testing is fun'
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Change the name field', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('updateFields')
// Name
cy.get('[data-admin-theming-setting-field="name"] input[type="text"]').scrollIntoView()
cy.get('[data-admin-theming-setting-field="name"] input[type="text"]').type(`{selectall}${name}{enter}`)
cy.wait('@updateFields')
// Url
cy.get('[data-admin-theming-setting-field="url"] input[type="url"]').scrollIntoView()
cy.get('[data-admin-theming-setting-field="url"] input[type="url"]').type(`{selectall}${url}{enter}`)
cy.wait('@updateFields')
// Slogan
cy.get('[data-admin-theming-setting-field="slogan"] input[type="text"]').scrollIntoView()
cy.get('[data-admin-theming-setting-field="slogan"] input[type="text"]').type(`{selectall}${slogan}{enter}`)
cy.wait('@updateFields')
})
it('Ensure undo button presence', function() {
cy.get('[data-admin-theming-setting-field="name"] .input-field__trailing-button').scrollIntoView()
cy.get('[data-admin-theming-setting-field="name"] .input-field__trailing-button').should('be.visible')
cy.get('[data-admin-theming-setting-field="url"] .input-field__trailing-button').scrollIntoView()
cy.get('[data-admin-theming-setting-field="url"] .input-field__trailing-button').should('be.visible')
cy.get('[data-admin-theming-setting-field="slogan"] .input-field__trailing-button').scrollIntoView()
cy.get('[data-admin-theming-setting-field="slogan"] .input-field__trailing-button').should('be.visible')
})
it('Validate login screen changes', function() {
cy.logout()
cy.visit('/')
cy.get('[data-login-form-headline]').should('contain.text', name)
cy.get('footer p a').should('have.text', name)
cy.get('footer p a').should('have.attr', 'href', url)
cy.get('footer p').should('contain.text', ` ${slogan}`)
})
it('Undo theming settings', function() {
cy.resetAdminTheming()
})
it('Validate login screen changes again', function() {
cy.visit('/')
cy.get('[data-login-form-headline]').should('not.contain.text', name)
cy.get('footer p a').should('not.have.text', name)
cy.get('footer p a').should('not.have.attr', 'href', url)
cy.get('footer p').should('not.contain.text', ` ${slogan}`)
})
})
describe('Disable user theming and enable it back', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Disable user background theming', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('disableUserTheming')
cy.get('[data-admin-theming-setting-disable-user-theming]').scrollIntoView()
cy.get('[data-admin-theming-setting-disable-user-theming]').should('be.visible')
cy.get('[data-admin-theming-setting-disable-user-theming] input[type="checkbox"]').check({ force: true })
cy.get('[data-admin-theming-setting-disable-user-theming] input[type="checkbox"]').should('be.checked')
cy.wait('@disableUserTheming')
})
it('Login as user', function() {
cy.logout()
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('User cannot not change background settings', function() {
cy.visit('/settings/user/theming')
cy.contains('Customization has been disabled by your administrator').should('exist')
})
})
describe('The user default background settings reflect the admin theming settings', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
after(function() {
cy.resetAdminTheming()
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Change the default background', function() {
cy.intercept('*/apps/theming/ajax/uploadImage').as('setBackground')
cy.fixture('image.jpg', null).as('background')
cy.get('[data-admin-theming-setting-file="background"] input[type="file"]').selectFile('@background', { force: true })
cy.wait('@setBackground')
cy.waitUntil(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
null,
))
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-background-color]').then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
selectedColor,
))
})
it('Login page should match admin theming settings', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
selectedColor,
))
})
it('Login as user', function() {
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
})
it('Default user background settings should match admin theming settings', function() {
cy.get('[data-user-theming-background-default]').should('be.visible')
cy.get('[data-user-theming-background-default]').should(
'have.class',
'background--active',
)
cy.waitUntil(() => validateUserThemingDefaultCss(
selectedColor,
'/apps/theming/image/background?v=',
))
})
})
describe('The user default background settings reflect the admin theming settings with background removed', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
after(function() {
cy.resetAdminTheming()
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.get('[data-admin-theming-settings]')
.should('exist')
.scrollIntoView()
cy.get('[data-admin-theming-settings]').should('be.visible')
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.get('[data-admin-theming-setting-file-remove]').click()
cy.wait('@removeBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
})
it('Login page should match admin theming settings', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
})
it('Login as user', function() {
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
})
it('Default user background settings should match admin theming settings', function() {
cy.get('[data-user-theming-background-default]').should('be.visible')
cy.get('[data-user-theming-background-default]').should(
'have.class',
'background--active',
)
cy.waitUntil(() => validateUserThemingDefaultCss(defaultPrimary, null))
})
})

View file

@ -0,0 +1,379 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { User } from '@nextcloud/e2e-test-server/cypress'
import { NavigationHeader } from '../../pages/NavigationHeader.ts'
import {
defaultBackground,
defaultPrimary,
pickColor,
validateBodyThemingCss,
validateUserThemingDefaultCss,
} from './themingUtils.ts'
const admin = new User('admin', 'admin')
describe('Remove the default background and restore it', { testIsolation: false }, function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.intercept('*/apps/theming/theme/default.css?*').as('cssLoaded')
cy.findByRole('checkbox', { name: /remove background image/i })
.should('exist')
.should('not.be.checked')
.check({ force: true })
cy.wait('@removeBackground')
cy.wait('@cssLoaded')
cy.window()
.should(() => validateBodyThemingCss(defaultPrimary, null))
cy.waitUntil(() => cy.window().then((win) => {
const backgroundPlain = getComputedStyle(win.document.body).getPropertyValue('--image-background')
return backgroundPlain !== ''
}))
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss(defaultPrimary, null))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss())
cy.screenshot()
})
})
describe('Remove the default background with a custom background color', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
cy.intercept('*/apps/theming/theme/default.css?*').as('cssLoaded')
pickColor(cy.findByRole('button', { name: /Background color/ }))
.then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.wait('@cssLoaded')
cy.window()
.should(() => validateBodyThemingCss(
defaultPrimary,
defaultBackground,
selectedColor,
))
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.findByRole('checkbox', { name: /remove background image/i })
.should('exist')
.should('not.be.checked')
.check({ force: true })
cy.wait('@removeBackground')
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss(defaultPrimary, null, selectedColor))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss())
cy.screenshot()
})
})
describe('Remove the default background with a bright color', function() {
const navigationHeader = new NavigationHeader()
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.resetUserTheming(admin)
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.findByRole('checkbox', { name: /remove background image/i })
.check({ force: true })
cy.wait('@removeBackground')
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
cy.intercept('*/apps/theming/theme/default.css?*').as('cssLoaded')
pickColor(cy.findByRole('button', { name: /Background color/ }), 4)
.then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.wait('@cssLoaded')
cy.window()
.should(() => validateBodyThemingCss(defaultPrimary, null, selectedColor))
})
it('See the header being inverted', function() {
cy.waitUntil(() => navigationHeader
.getNavigationEntries()
.find('img')
.then((el) => {
let ret = true
el.each(function() {
ret = ret && window.getComputedStyle(this).filter === 'invert(1)'
})
return ret
}))
})
})
describe('Disable user theming and enable it back', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Disable user background theming', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('disableUserTheming')
cy.findByRole('checkbox', { name: /Disable user theming/ })
.should('exist')
.and('not.be.checked')
.check({ force: true })
cy.wait('@disableUserTheming')
})
it('Login as user', function() {
cy.logout()
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('User cannot not change background settings', function() {
cy.visit('/settings/user/theming')
cy.contains('Customization has been disabled by your administrator').should('exist')
})
})
describe('The user default background settings reflect the admin theming settings', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
after(function() {
cy.resetAdminTheming()
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Change the default background', function() {
cy.intercept('*/apps/theming/ajax/uploadImage').as('setBackground')
cy.intercept('*/apps/theming/theme/default.css?*').as('cssLoaded')
cy.fixture('image.jpg', null).as('background')
cy.get('input[type="file"][name="background"]')
.should('exist')
.selectFile('@background', { force: true })
cy.wait('@setBackground')
cy.wait('@cssLoaded')
cy.window()
.should(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
null,
))
})
it('Change the background color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
cy.intercept('*/apps/theming/theme/default.css?*').as('cssLoaded')
pickColor(cy.findByRole('button', { name: /Background color/ }))
.then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.wait('@cssLoaded')
cy.window()
.should(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
selectedColor,
))
})
it('Login page should match admin theming settings', function() {
cy.logout()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss(
defaultPrimary,
'/apps/theming/image/background?v=',
selectedColor,
))
})
it('Login as user', function() {
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.findByRole('heading', { name: 'Background and color' })
.scrollIntoView()
})
it('Default user background settings should match admin theming settings', function() {
cy.findByRole('button', { name: 'Default background' })
.should('exist')
.and('have.attr', 'aria-pressed', 'true')
cy.window()
.should(() => validateUserThemingDefaultCss(
selectedColor,
'/apps/theming/image/background?v=',
))
})
})
describe('The user default background settings reflect the admin theming settings with background removed', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
after(function() {
cy.resetAdminTheming()
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Remove the default background', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground')
cy.findByRole('checkbox', { name: /remove background image/i })
.check({ force: true })
cy.wait('@removeBackground')
})
it('Login page should match admin theming settings', function() {
cy.logout()
cy.visit('/')
cy.window()
.should(() => validateBodyThemingCss(defaultPrimary, null))
})
it('Login as user', function() {
cy.createRandomUser().then((user) => {
cy.login(user)
})
})
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.findByRole('heading', { name: 'Background and color' })
.scrollIntoView()
})
it('Default user background settings should match admin theming settings', function() {
cy.findByRole('button', { name: 'Default background' })
.should('exist')
.and('have.attr', 'aria-pressed', 'true')
cy.window()
.should(() => validateUserThemingDefaultCss(defaultPrimary, null))
})
})

View file

@ -2,6 +2,7 @@
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { User } from '@nextcloud/e2e-test-server/cypress'
const admin = new User('admin', 'admin')
@ -139,3 +140,80 @@ describe('Admin theming: Web link corner cases', function() {
.and('have.attr', 'href', 'http://example.com/%22the%20path%22')
})
})
describe('Admin theming: Change the login fields then reset them', function() {
const name = 'ABCdef123'
const url = 'https://example.com'
const slogan = 'Testing is fun'
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: /^Theming/ })
.should('exist')
.scrollIntoView()
})
it('Change the name field', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('updateFields')
// Name
cy.findByRole('textbox', { name: 'Name' })
.should('be.visible')
.type(`{selectall}${name}{enter}`)
cy.wait('@updateFields')
// Url
cy.findByRole('textbox', { name: 'Web link' })
.should('be.visible')
.type(`{selectall}${url}{enter}`)
cy.wait('@updateFields')
// Slogan
cy.findByRole('textbox', { name: 'Slogan' })
.should('be.visible')
.type(`{selectall}${slogan}{enter}`)
cy.wait('@updateFields')
})
it('Ensure undo button presence', function() {
cy.findAllByRole('button', { name: /undo changes/i })
.should('have.length', 3)
})
it('Validate login screen changes', function() {
cy.logout()
cy.visit('/')
cy.get('[data-login-form-headline]').should('contain.text', name)
cy.get('footer p a').should('have.text', name)
cy.get('footer p a').should('have.attr', 'href', url)
cy.get('footer p').should('contain.text', ` ${slogan}`)
})
it('Undo theming settings', function() {
cy.login(admin)
cy.visit('/settings/admin/theming')
cy.findAllByRole('button', { name: /undo changes/i })
.each((button) => {
cy.intercept('*/apps/theming/ajax/undoChanges').as('undoField')
cy.wrap(button).click()
cy.wait('@undoField')
})
cy.logout()
})
it('Validate login screen changes again', function() {
cy.visit('/')
cy.get('[data-login-form-headline]').should('not.contain.text', name)
cy.get('footer p a').should('not.have.text', name)
cy.get('footer p a').should('not.have.attr', 'href', url)
cy.get('footer p').should('not.contain.text', ` ${slogan}`)
})
})

View file

@ -0,0 +1,67 @@
/*!
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { User } from '@nextcloud/e2e-test-server/cypress'
import {
defaultBackground,
defaultPrimary,
pickColor,
validateBodyThemingCss,
} from './themingUtils.ts'
const admin = new User('admin', 'admin')
describe('Change the primary color and reset it', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
cy.login(admin)
})
it('See the admin theming section', function() {
cy.visit('/settings/admin/theming')
cy.findByRole('heading', { name: 'Background and color' })
.should('exist')
.scrollIntoView()
})
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickColor(cy.findByRole('button', { name: /Primary color/ }))
.then((color) => {
selectedColor = color
})
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(
selectedColor,
defaultBackground,
defaultPrimary,
))
})
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(
selectedColor,
defaultBackground,
defaultPrimary,
))
cy.screenshot()
})
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
})

View file

@ -31,36 +31,73 @@ describe('Admin theming set default apps', () => {
cy.visit('/settings/admin/theming')
cy.get('.settings-section').contains('Navigation bar settings').should('exist')
cy.get('[data-cy-switch-default-app]').should('exist')
cy.get('[data-cy-switch-default-app]').scrollIntoView()
getDefaultAppSwitch().should('exist')
getDefaultAppSwitch().scrollIntoView()
})
it('Toggle the "use custom default app" switch', () => {
cy.get('[data-cy-switch-default-app] input').should('not.be.checked')
cy.get('[data-cy-switch-default-app] .checkbox-content').click()
cy.get('[data-cy-switch-default-app] input').should('be.checked')
getDefaultAppSwitch().should('not.be.checked')
cy.findByRole('region', { name: 'Global default app' })
.should('not.exist')
getDefaultAppSwitch().check({ force: true })
getDefaultAppSwitch().should('be.checked')
cy.findByRole('region', { name: 'Global default app' })
.should('exist')
})
it('See the default app combobox', () => {
cy.findByRole('region', { name: 'Global default app' })
.should('exist')
.findByRole('combobox')
.as('defaultAppSelect')
.scrollIntoView()
cy.get('@defaultAppSelect')
.findByText('Dashboard')
.should('be.visible')
cy.get('@defaultAppSelect')
.findByText('Files')
.should('be.visible')
})
it('See the default app order selector', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element]').then((elements) => {
const appIDs = elements.map((idx, el) => el.getAttribute('data-cy-app-order-element')).get()
expect(appIDs).to.deep.eq(['dashboard', 'files'])
})
cy.findByRole('region', { name: 'Global default app' })
.should('exist')
cy.findByRole('list', { name: 'Navigation bar app order' })
.should('exist')
.findAllByRole('listitem')
.should('have.length', 2)
.then((elements) => {
const appIDs = elements.map((idx, el) => el.innerText.trim()).get()
expect(appIDs).to.deep.eq(['Dashboard', 'Files'])
})
})
it('Change the default app', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"]').scrollIntoView()
cy.findByRole('list', { name: 'Navigation bar app order' })
.should('exist')
.as('appOrderSelector')
.scrollIntoView()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').click()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.be.visible')
cy.get('@appOrderSelector')
.findAllByRole('listitem')
.filter((_, e) => !!e.innerText.match(/Files/i))
.findByRole('button', { name: 'Move up' })
.as('moveFilesUpButton')
cy.get('@moveFilesUpButton').should('be.visible')
cy.get('@moveFilesUpButton').click()
cy.get('@moveFilesUpButton').should('not.exist')
})
it('See the default app is changed', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element]').then((elements) => {
const appIDs = elements.map((idx, el) => el.getAttribute('data-cy-app-order-element')).get()
expect(appIDs).to.deep.eq(['files', 'dashboard'])
})
cy.findByRole('list', { name: 'Navigation bar app order' })
.findAllByRole('listitem')
.then((elements) => {
const appIDs = elements.map((idx, el) => el.innerText.trim()).get()
expect(appIDs).to.deep.eq(['Files', 'Dashboard'])
})
// Check the redirect to the default app works
cy.request({ url: '/', followRedirect: false }).then((response) => {
@ -72,14 +109,12 @@ describe('Admin theming set default apps', () => {
it('Toggle the "use custom default app" switch back to reset the default apps', () => {
cy.visit('/settings/admin/theming')
cy.get('[data-cy-switch-default-app]').scrollIntoView()
getDefaultAppSwitch().scrollIntoView()
cy.get('[data-cy-switch-default-app] input').should('be.checked')
cy.get('[data-cy-switch-default-app] .checkbox-content').click()
cy.get('[data-cy-switch-default-app] input').should('be.not.checked')
})
getDefaultAppSwitch().should('be.checked')
getDefaultAppSwitch().uncheck({ force: true })
getDefaultAppSwitch().should('be.not.checked')
it('See the default app is changed back to default', () => {
// Check the redirect to the default app works
cy.request({ url: '/', followRedirect: false }).then((response) => {
expect(response.status).to.eq(302)
@ -88,3 +123,7 @@ describe('Admin theming set default apps', () => {
})
})
})
function getDefaultAppSwitch() {
return cy.findByRole('checkbox', { name: 'Use custom default app' })
}

View file

@ -63,13 +63,8 @@ export function expectBackgroundColor(element: JQuery<HTMLElement>, color: strin
* @param expectedBackground the expected background
*/
export function validateUserThemingDefaultCss(expectedColor = defaultPrimary, expectedBackground: string | null = defaultBackground) {
const defaultSelectButton = Cypress.$('[data-user-theming-background-default]')
if (defaultSelectButton.length === 0) {
return false
}
const backgroundImage = defaultSelectButton.css('background-image')
const backgroundColor = defaultSelectButton.css('background-color')
const backgroundImage = Cypress.$('body').css('background-image')
const backgroundColor = Cypress.$('body').css('background-color')
const isValidBackgroundImage = !expectedBackground
? (backgroundImage === 'none' || Cypress.$('body').css('background-image') === 'none')
@ -86,31 +81,30 @@ export function validateUserThemingDefaultCss(expectedColor = defaultPrimary, ex
}
/**
*
* @param context
* @param index
* @param trigger - The color picker trigger
* @param index - The color index to pick, if not provided a random one will be picked
*/
export function pickRandomColor(context: string, index?: number): Cypress.Chainable<string> {
export function pickColor(trigger: Cypress.Chainable<JQuery>, index?: number): Cypress.Chainable<string> {
// Pick one of the first 8 options
const randColour = index ?? Math.floor(Math.random() * 8)
const colorPreviewSelector = `${context} [data-admin-theming-setting-color]`
let oldColor = ''
cy.get(colorPreviewSelector).then(($el) => {
trigger.as('trigger').then(($el) => {
oldColor = $el.css('background-color')
})
// Open picker
cy.get(`${context} [data-admin-theming-setting-color-picker]`).scrollIntoView()
cy.get(`${context} [data-admin-theming-setting-color-picker]`).click({ force: true })
cy.get('@trigger').scrollIntoView()
cy.get('@trigger').click({ force: true })
// Click on random color
cy.get('.color-picker__simple-color-circle').eq(randColour).click()
// Wait for color change
cy.waitUntil(() => Cypress.$(colorPreviewSelector).css('background-color') !== oldColor)
cy.get('@trigger')
.should(($el) => $el.css('background-color') !== oldColor)
cy.findByRole('button', { name: /Choose/i }).click()
// Get the selected color from the color preview block
return cy.get(colorPreviewSelector).then(($el) => $el.css('background-color'))
return cy.get('@trigger').then(($el) => $el.css('background-color'))
}

View file

@ -6,19 +6,14 @@
import type { User } from '@nextcloud/e2e-test-server/cypress'
import { NavigationHeader } from '../../pages/NavigationHeader.ts'
import { SettingsAppOrderList } from '../../pages/SettingsAppOrderList.ts'
import { installTestApp, uninstallTestApp } from '../../support/commonUtils.ts'
/**
* Intercept setting the app order as `updateAppOrder`
*/
function interceptAppOrder() {
cy.intercept('POST', '/ocs/v2.php/apps/provisioning_api/api/v1/config/users/core/apporder').as('updateAppOrder')
}
before(() => uninstallTestApp())
describe('User theming set app order', () => {
const navigationHeader = new NavigationHeader()
const appOrderList = new SettingsAppOrderList()
let user: User
before(() => {
@ -33,49 +28,45 @@ describe('User theming set app order', () => {
after(() => cy.deleteUser(user))
it('See the app order settings', () => {
cy.visit('/settings/user/theming')
cy.get('.settings-section').contains('Navigation bar settings').should('exist')
cy.get('[data-cy-app-order]').scrollIntoView()
visitAppOrderSettings()
})
it('See that the dashboard app is the first one', () => {
const appOrder = ['Dashboard', 'Files']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(appOrder)
// Check the top app menu order
navigationHeader.getNavigationEntries()
.each((entry, index) => expect(entry).contain.text(appOrder[index]))
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
})
it('Change the app order', () => {
interceptAppOrder()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').click()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.be.visible')
cy.wait('@updateAppOrder')
appOrderList.interceptAppOrder()
appOrderList.getAppOrderList()
.scrollIntoView()
appOrderList.getUpButtonForApp('Files')
.should('be.visible')
.click()
appOrderList.waitForAppOrderUpdate()
const appOrder = ['Files', 'Dashboard']
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(['Files', 'Dashboard'])
})
it('See the app menu order is changed', () => {
cy.reload()
const appOrder = ['Files', 'Dashboard']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.getAppOrderList()
.scrollIntoView()
appOrderList.assertAppOrder(appOrder)
// Check the top app menu order
navigationHeader.getNavigationEntries()
.each((entry, index) => expect(entry).contain.text(appOrder[index]))
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
})
})
describe('User theming set app order with default app', () => {
const appOrderList = new SettingsAppOrderList()
const navigationHeader = new NavigationHeader()
let user: User
@ -108,43 +99,41 @@ describe('User theming set app order with default app', () => {
})
it('See the app order settings: files is the first one', () => {
cy.visit('/settings/user/theming')
cy.get('[data-cy-app-order]').scrollIntoView()
visitAppOrderSettings()
const appOrder = ['Files', 'Dashboard', 'Test App 2', 'Test App']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.getAppOrderList()
.scrollIntoView()
appOrderList.assertAppOrder(appOrder)
})
it('Can not change the default app', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="down"]').should('not.be.visible')
appOrderList.getUpButtonForApp('Files').should('not.exist')
appOrderList.getDownButtonForApp('Files').should('not.exist')
appOrderList.getUpButtonForApp('Dashboard').should('not.exist')
// but can move down
appOrderList.getDownButtonForApp('Dashboard').should('be.visible')
})
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="up"]').should('not.be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="down"]').should('be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="testapp"] [data-cy-app-order-button="up"]').should('be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="testapp"] [data-cy-app-order-button="down"]').should('not.be.visible')
it('Can see the correct buttons for other apps', () => {
appOrderList.getUpButtonForApp('Test App 2').should('be.visible')
appOrderList.getDownButtonForApp('Test App 2').should('be.visible')
appOrderList.getUpButtonForApp('Test App').should('be.visible')
appOrderList.getDownButtonForApp('Test App').should('not.exist')
})
it('Change the order of the other apps', () => {
interceptAppOrder()
// Move the testapp up twice, it should be the first one after files
cy.get('[data-cy-app-order] [data-cy-app-order-element="testapp"] [data-cy-app-order-button="up"]').click()
cy.wait('@updateAppOrder')
cy.get('[data-cy-app-order] [data-cy-app-order-element="testapp"] [data-cy-app-order-button="up"]').click()
cy.wait('@updateAppOrder')
appOrderList.interceptAppOrder()
appOrderList.getUpButtonForApp('Test App').click()
appOrderList.waitForAppOrderUpdate()
appOrderList.getUpButtonForApp('Test App').click()
appOrderList.waitForAppOrderUpdate()
// Can't get up anymore, files is enforced as default app
cy.get('[data-cy-app-order] [data-cy-app-order-element="testapp"] [data-cy-app-order-button="up"]').should('not.be.visible')
appOrderList.getUpButtonForApp('Test App').should('not.exist')
// Check the final list order
const appOrder = ['Files', 'Test App', 'Dashboard', 'Test App 2']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(['Files', 'Test App', 'Dashboard', 'Test App 2'])
})
it('See the app menu order is changed', () => {
@ -153,15 +142,17 @@ describe('User theming set app order with default app', () => {
const appOrder = ['Files', 'Test App', 'Dashboard', 'Test App 2']
// Check the top app menu order
navigationHeader.getNavigationEntries()
.each((entry, index) => expect(entry).contain.text(appOrder[index]))
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
})
})
describe('User theming app order list accessibility', () => {
const appOrderList = new SettingsAppOrderList()
let user: User
before(() => {
cy.resetAdminTheming()
installTestApp()
// Create random user for this test
cy.createRandomUser().then(($user) => {
user = $user
@ -170,45 +161,44 @@ describe('User theming app order list accessibility', () => {
})
after(() => {
uninstallTestApp()
cy.deleteUser(user)
})
it('See the app order settings', () => {
cy.visit('/settings/user/theming')
cy.get('[data-cy-app-order]').scrollIntoView()
cy.get('[data-cy-app-order] [data-cy-app-order-element]').should('have.length', 2)
})
it('click the first button', () => {
interceptAppOrder()
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="down"]').should('be.visible').focus()
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="down"]').click()
cy.wait('@updateAppOrder')
visitAppOrderSettings()
appOrderList.interceptAppOrder()
appOrderList.getDownButtonForApp('Dashboard')
.should('be.visible')
.scrollIntoView()
appOrderList.getDownButtonForApp('Dashboard')
.focus()
appOrderList.getDownButtonForApp('Dashboard')
.click()
appOrderList.waitForAppOrderUpdate()
})
it('see the same app kept the focus', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="down"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="down"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="up"]').should('have.focus')
appOrderList.getDownButtonForApp('Dashboard').should('have.focus')
})
it('click the last button', () => {
interceptAppOrder()
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="up"]').should('be.visible').focus()
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="up"]').click()
cy.wait('@updateAppOrder')
appOrderList.interceptAppOrder()
appOrderList.getUpButtonForApp('Dashboard')
.should('be.visible')
.focus()
appOrderList.getUpButtonForApp('Dashboard').click()
appOrderList.waitForAppOrderUpdate()
})
it('see the same app kept the focus', () => {
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="down"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="up"]').should('not.have.focus')
cy.get('[data-cy-app-order] [data-cy-app-order-element="dashboard"] [data-cy-app-order-button="down"]').should('have.focus')
appOrderList.getUpButtonForApp('Dashboard').should('not.exist')
appOrderList.getDownButtonForApp('Dashboard').should('have.focus')
})
})
describe('User theming reset app order', () => {
const appOrderList = new SettingsAppOrderList()
const navigationHeader = new NavigationHeader()
let user: User
@ -223,52 +213,46 @@ describe('User theming reset app order', () => {
after(() => cy.deleteUser(user))
it('See the app order settings', () => {
cy.visit('/settings/user/theming')
cy.get('.settings-section').contains('Navigation bar settings').should('exist')
cy.get('[data-cy-app-order]').scrollIntoView()
})
it('See that the dashboard app is the first one', () => {
visitAppOrderSettings()
const appOrder = ['Dashboard', 'Files']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(appOrder)
// Check the top app menu order
navigationHeader.getNavigationEntries()
.each((entry, index) => expect(entry).contain.text(appOrder[index]))
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
})
it('See the reset button is disabled', () => {
cy.get('[data-test-id="btn-apporder-reset"]').scrollIntoView()
cy.get('[data-test-id="btn-apporder-reset"]').should('be.visible').and('have.attr', 'disabled')
appOrderList.getResetButton()
.scrollIntoView()
appOrderList.getResetButton()
.should('be.disabled')
})
it('Change the app order', () => {
interceptAppOrder()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('be.visible')
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').click()
cy.get('[data-cy-app-order] [data-cy-app-order-element="files"] [data-cy-app-order-button="up"]').should('not.be.visible')
cy.wait('@updateAppOrder')
appOrderList.interceptAppOrder()
appOrderList.getUpButtonForApp('Files')
.should('be.visible')
.click()
appOrderList.waitForAppOrderUpdate()
// Check the app order settings UI
const appOrder = ['Files', 'Dashboard']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(['Files', 'Dashboard'])
})
it('See the reset button is no longer disabled', () => {
cy.get('[data-test-id="btn-apporder-reset"]').scrollIntoView()
cy.get('[data-test-id="btn-apporder-reset"]').should('be.visible').and('not.have.attr', 'disabled')
appOrderList.getResetButton()
.scrollIntoView()
appOrderList.getResetButton()
.should('be.visible')
.and('be.enabled')
})
it('Reset the app order', () => {
cy.intercept('GET', '/ocs/v2.php/core/navigation/apps').as('loadApps')
interceptAppOrder()
cy.get('[data-test-id="btn-apporder-reset"]').click({ force: true })
appOrderList.interceptAppOrder()
appOrderList.getResetButton().click({ force: true })
cy.wait('@updateAppOrder')
.its('request.body')
@ -278,16 +262,21 @@ describe('User theming reset app order', () => {
it('See the app order is restored', () => {
const appOrder = ['Dashboard', 'Files']
// Check the app order settings UI
cy.get('[data-cy-app-order] [data-cy-app-order-element]')
.each((element, index) => expect(element).to.contain.text(appOrder[index]))
appOrderList.assertAppOrder(appOrder)
// Check the top app menu order
navigationHeader.getNavigationEntries()
.each((entry, index) => expect(entry).contain.text(appOrder[index]))
.each((entry, index) => expect(entry).contain.text(appOrder[index]!))
})
it('See the reset button is disabled again', () => {
cy.get('[data-test-id="btn-apporder-reset"]').should('be.visible').and('have.attr', 'disabled')
appOrderList.getResetButton()
.should('be.disabled')
})
})
function visitAppOrderSettings() {
cy.visit('/settings/user/theming')
cy.findByRole('heading', { name: /Navigation bar settings/ })
.should('exist')
.scrollIntoView()
}

View file

@ -5,7 +5,7 @@
import { User } from '@nextcloud/e2e-test-server/cypress'
import { NavigationHeader } from '../../pages/NavigationHeader.ts'
import { defaultBackground, defaultPrimary, validateBodyThemingCss } from './themingUtils.ts'
import { defaultPrimary, pickColor, validateBodyThemingCss } from './themingUtils.ts'
const admin = new User('admin', 'admin')
@ -20,22 +20,14 @@ describe('User default background settings', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
})
// Default cloud background is not rendered if admin theming background remains unchanged
it('Default cloud background is not rendered', function() {
cy.get(`[data-user-theming-background-shipped="${defaultBackground}"]`).should('not.exist')
cy.findByRole('heading', { name: /Appearance and accessibility settings/ })
.should('be.visible')
})
it('Default is selected on new users', function() {
cy.get('[data-user-theming-background-default]').should('be.visible')
cy.get('[data-user-theming-background-default]').should('have.class', 'background--active')
})
it('Default background has accessibility attribute set', function() {
cy.get('[data-user-theming-background-default]').should('have.attr', 'aria-pressed', 'true')
cy.findByRole('button', { name: 'Default background', pressed: true })
.should('exist')
.scrollIntoView()
})
})
@ -48,19 +40,21 @@ describe('User select shipped backgrounds and remove background', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
cy.findByRole('heading', { name: /Background and color/ })
.should('exist')
.scrollIntoView()
})
it('Select a shipped background', function() {
const background = 'anatoly-mikhaltsov-butterfly-wing-scale.jpg'
const backgroundName = 'Background picture of a red-ish butterfly wing under microscope'
cy.intercept('*/apps/theming/background/shipped').as('setBackground')
// Select background
cy.get(`[data-user-theming-background-shipped="${background}"]`).click()
// Set the accessibility state
cy.get(`[data-user-theming-background-shipped="${background}"]`).should('have.attr', 'aria-pressed', 'true')
cy.findByRole('button', { name: backgroundName, pressed: false })
.click()
cy.findByRole('button', { name: backgroundName, pressed: true })
.should('be.visible')
// Validate changed background and primary
cy.wait('@setBackground')
@ -69,32 +63,18 @@ describe('User select shipped backgrounds and remove background', function() {
it('Select a bright shipped background', function() {
const background = 'bernie-cetonia-aurata-take-off-composition.jpg'
const backgroundName = 'Montage of a cetonia aurata bug that takes off with white background'
cy.intercept('*/apps/theming/background/shipped').as('setBackground')
// Select background
cy.get(`[data-user-theming-background-shipped="${background}"]`).click()
// Set the accessibility state
cy.get(`[data-user-theming-background-shipped="${background}"]`).should('have.attr', 'aria-pressed', 'true')
cy.findByRole('button', { name: backgroundName, pressed: false })
.click()
cy.findByRole('button', { name: backgroundName, pressed: true })
.should('be.visible')
// Validate changed background and primary
cy.wait('@setBackground')
cy.waitUntil(() => validateBodyThemingCss('#56633d', background, '#dee0d3'))
})
it('Remove background', function() {
cy.intercept('*/apps/theming/background/color').as('clearBackground')
// Clear background
cy.get('[data-user-theming-background-color]').click()
// Set the accessibility state
cy.get('[data-user-theming-background-color]').should('have.attr', 'aria-pressed', 'true')
// Validate clear background
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss('#56633d', null, '#dee0d3'))
})
})
describe('User select a custom color', function() {
@ -106,19 +86,20 @@ describe('User select a custom color', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
cy.findByRole('heading', { name: /Background and color/ })
.should('exist')
.scrollIntoView()
})
it('Select a custom color', function() {
cy.intercept('*/apps/theming/background/color').as('setColor')
cy.intercept('*/apps/theming/background/color').as('clearBackground')
cy.get('[data-user-theming-background-color]').click()
cy.get('.color-picker__simple-color-circle').eq(5).click()
// Clear background
pickColor(cy.findByRole('button', { name: 'Plain background' }), 7)
// Validate custom colour change
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, '#a5b872'))
// Validate clear background
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, '#3794ac'))
})
})
@ -133,32 +114,20 @@ describe('User select a bright custom color and remove background', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
cy.findByRole('heading', { name: /Background and color/ })
.should('exist')
.scrollIntoView()
})
it('Remove background', function() {
cy.intercept('*/apps/theming/background/color').as('clearBackground')
// Clear background
cy.get('[data-user-theming-background-color]').click()
cy.get('[data-user-theming-background-color]').click()
pickColor(cy.findByRole('button', { name: 'Plain background' }), 4)
// Validate clear background
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss(undefined, null))
})
it('Select a custom color', function() {
cy.intercept('*/apps/theming/background/color').as('setColor')
// Pick one of the bright color preset
cy.get('[data-user-theming-background-color]').scrollIntoView()
cy.get('[data-user-theming-background-color]').click()
cy.get('.color-picker__simple-color-circle:eq(4)').click()
// Validate custom colour change
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, '#ddcb55'))
})
it('See the header being inverted', function() {
@ -173,10 +142,14 @@ describe('User select a bright custom color and remove background', function() {
it('Select another but non-bright shipped background', function() {
const background = 'anatoly-mikhaltsov-butterfly-wing-scale.jpg'
const backgroundName = 'Background picture of a red-ish butterfly wing under microscope'
cy.intercept('*/apps/theming/background/shipped').as('setBackground')
// Select background
cy.get(`[data-user-theming-background-shipped="${background}"]`).click()
cy.findByRole('button', { name: backgroundName, pressed: false })
.click()
cy.findByRole('button', { name: backgroundName, pressed: true })
.should('be.visible')
// Validate changed background and primary
cy.wait('@setBackground')
@ -205,23 +178,21 @@ describe('User select a custom background', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
cy.findByRole('heading', { name: /Background and color/ })
.should('exist')
.scrollIntoView()
})
it('Select a custom background', function() {
cy.intercept('*/apps/theming/background/custom').as('setBackground')
cy.on('uncaught:exception', (err) => {
// This can happen because of blink engine & skeleton animation, its not a bug just engine related.
if (err.message.includes('ResizeObserver loop limit exceeded')) {
return false
}
})
// Pick background
cy.get('[data-user-theming-background-custom]').click()
cy.get('.file-picker__files tr').contains(image).click()
cy.findByRole('button', { name: 'Custom background' }).click()
cy.findByRole('dialog')
.should('be.visible')
.findAllByRole('row')
.contains(image)
.click()
cy.findByRole('button', { name: 'Select background' }).click()
// Wait for background to be set
@ -232,7 +203,6 @@ describe('User select a custom background', function() {
describe('User changes settings and reload the page', function() {
const image = 'image.jpg'
const colorFromImage = '#2f2221'
before(function() {
cy.createRandomUser().then((user: User) => {
@ -243,54 +213,44 @@ describe('User changes settings and reload the page', function() {
it('See the user background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-settings]').scrollIntoView()
cy.get('[data-user-theming-background-settings]').should('be.visible')
cy.findByRole('heading', { name: /Background and color/ })
.should('exist')
.scrollIntoView()
})
it('Select a custom background', function() {
cy.intercept('*/apps/theming/background/custom').as('setBackground')
cy.on('uncaught:exception', (err) => {
// This can happen because of blink engine & skeleton animation, its not a bug just engine related.
if (err.message.includes('ResizeObserver loop limit exceeded')) {
return false
}
})
// Pick background
cy.get('[data-user-theming-background-custom]').click()
cy.get('.file-picker__files tr').contains(image).click()
cy.findByRole('button', { name: 'Custom background' }).click()
cy.findByRole('dialog')
.should('be.visible')
.findAllByRole('row')
.contains(image)
.click()
cy.findByRole('button', { name: 'Select background' }).click()
// Wait for background to be set
cy.wait('@setBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, 'apps/theming/background?v=', colorFromImage))
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, 'apps/theming/background?v=', '#2f2221'))
})
it('Select a custom color', function() {
cy.intercept('*/apps/theming/background/color').as('setColor')
it('Select a custom background color', function() {
cy.intercept('*/apps/theming/background/color').as('clearBackground')
cy.get('[data-user-theming-background-color]').click()
cy.get('.color-picker__simple-color-circle:eq(5)').click()
cy.get('[data-user-theming-background-color]').click()
// Clear background
pickColor(cy.findByRole('button', { name: 'Plain background' }), 5)
// Validate clear background
cy.wait('@setColor')
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, '#a5b872'))
})
it('Select a custom primary color', function() {
cy.intercept('/ocs/v2.php/apps/provisioning_api/api/v1/config/users/theming/primary_color').as('setPrimaryColor')
cy.get('[data-user-theming-primary-color-trigger]').scrollIntoView()
cy.get('[data-user-theming-primary-color-trigger]').click()
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500)
cy.get('.color-picker__simple-color-circle').should('be.visible')
cy.get('.color-picker__simple-color-circle:eq(2)').click()
cy.get('[data-user-theming-primary-color-trigger]').click()
pickColor(cy.findByRole('button', { name: 'Primary color' }), 2)
// Validate clear background
cy.wait('@setPrimaryColor')
cy.waitUntil(() => validateBodyThemingCss('#c98879', null, '#a5b872'))
})

View file

@ -0,0 +1,43 @@
/*!
* SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
export class SettingsAppOrderList {
getAppOrderList() {
return cy.findByRole('list', { name: 'Navigation bar app order' })
}
assertAppOrder(expectedAppOrder: string[]) {
this.getAppOrderList()
.findAllByRole('listitem')
.should('have.length', expectedAppOrder.length)
.each((element, index) => expect(element).to.contain.text(expectedAppOrder[index]!))
}
getAppEntryByName(appName: string) {
return this.getAppOrderList()
.findAllByRole('listitem')
.filter((_, el) => el.textContent.trim() === appName)
}
getUpButtonForApp(appName: string) {
return this.getAppEntryByName(appName).findByRole('button', { name: 'Move up', hidden: true })
}
getDownButtonForApp(appName: string) {
return this.getAppEntryByName(appName).findByRole('button', { name: 'Move down', hidden: true })
}
getResetButton() {
return cy.findByRole('button', { name: 'Reset default app order', hidden: true })
}
interceptAppOrder() {
cy.intercept('POST', '/ocs/v2.php/apps/provisioning_api/api/v1/config/users/core/apporder').as('updateAppOrder')
}
waitForAppOrderUpdate() {
cy.wait('@updateAppOrder')
}
}