Merge pull request #35728 from nextcloud/fix/cypress

pull/40977/head
John Molakvoæ 8 months ago committed by GitHub
commit 049804d02f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -156,7 +156,7 @@ class ThemingController extends Controller {
}
break;
case 'disable-user-theming':
if ($value !== "yes" && $value !== "no") {
if ($value !== 'yes' && $value !== 'no') {
$error = $this->l10n->t('Disable-user-theming should be true or false');
}
break;

@ -97,10 +97,10 @@ class ImageManager {
* @throws NotPermittedException
*/
public function getImage(string $key, bool $useSvg = true): ISimpleFile {
$logo = $this->config->getAppValue('theming', $key . 'Mime', '');
$mime = $this->config->getAppValue('theming', $key . 'Mime', '');
$folder = $this->getRootFolder()->getFolder('images');
if ($logo === '' || !$folder->fileExists($key)) {
if ($mime === '' || !$folder->fileExists($key)) {
throw new NotFoundException();
}
@ -127,7 +127,8 @@ class ImageManager {
public function hasImage(string $key): bool {
$mimeSetting = $this->config->getAppValue('theming', $key . 'Mime', '');
return $mimeSetting !== '';
// Removing the background defines its mime as 'backgroundColor'
return $mimeSetting !== '' && $mimeSetting !== 'backgroundColor';
}
/**

@ -97,7 +97,7 @@ trait CommonThemeTrait {
foreach (ImageManager::SUPPORTED_IMAGE_KEYS as $image) {
if ($this->imageManager->hasImage($image)) {
$imageUrl = $this->imageManager->getImageUrl($image);
// --image-background is overridden by user theming
// --image-background is overridden by user theming if logged in
$variables["--image-$image"] = "url('" . $imageUrl . "')";
}
}
@ -127,15 +127,17 @@ trait CommonThemeTrait {
if ($user !== null
&& !$this->themingDefaults->isUserThemingDisabled()
&& $this->appManager->isEnabledForUser(Application::APP_ID)) {
$adminBackgroundDeleted = $this->config->getAppValue(Application::APP_ID, 'backgroundMime', '') === 'backgroundColor';
$backgroundImage = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'background_image', BackgroundService::BACKGROUND_DEFAULT);
$currentVersion = (int)$this->config->getUserValue($user->getUID(), Application::APP_ID, 'userCacheBuster', '0');
$isPrimaryBright = $this->util->invertTextColor($this->primaryColor);
$isPrimaryBright = $this->util->invertTextColor($this->themingDefaults->getColorPrimary());
// The user removed the background
if ($backgroundImage === BackgroundService::BACKGROUND_DISABLED) {
return [
'--image-background' => 'no',
'--color-background-plain' => $this->primaryColor,
// Might be defined already by admin theming, needs to be overridden
'--image-background' => 'none',
'--color-background-plain' => $this->themingDefaults->getColorPrimary(),
// If no background image is set, we need to check against the shown primary colour
'--background-image-invert-if-bright' => $isPrimaryBright ? 'invert(100%)' : 'no',
];
@ -150,6 +152,15 @@ trait CommonThemeTrait {
];
}
// The user is using the default background and admin removed the background image
if ($backgroundImage === BackgroundService::BACKGROUND_DEFAULT && $adminBackgroundDeleted) {
return [
// --image-background is not defined in this case
'--color-background-plain' => $this->themingDefaults->getColorPrimary(),
'--background-image-invert-if-bright' => $isPrimaryBright ? 'invert(100%)' : 'no',
];
}
// The user picked a shipped background
if (isset(BackgroundService::SHIPPED_BACKGROUNDS[$backgroundImage])) {
return [

@ -70,7 +70,7 @@ class DefaultTheme implements ITheme {
$this->defaultPrimaryColor = $this->themingDefaults->getDefaultColorPrimary();
$this->primaryColor = $this->themingDefaults->getColorPrimary();
// Override default defaultPrimaryColor if set to improve accessibility
// Override primary colors (if set) to improve accessibility
if ($this->primaryColor === BackgroundService::DEFAULT_COLOR) {
$this->primaryColor = BackgroundService::DEFAULT_ACCESSIBLE_COLOR;
}

@ -255,8 +255,9 @@ class ThemingDefaults extends \OC_Defaults {
public function getDefaultColorPrimary(): string {
$color = $this->config->getAppValue(Application::APP_ID, 'color', '');
if (!preg_match('/^\#([0-9a-f]{3}|[0-9a-f]{6})$/i', $color)) {
$color = '#0082c9';
return BackgroundService::DEFAULT_COLOR;
}
return $color;
}
@ -487,6 +488,7 @@ class ThemingDefaults extends \OC_Defaults {
case 'background':
case 'favicon':
$this->imageManager->delete($setting);
$this->config->deleteAppValue('theming', $setting . 'Mime');
break;
}

@ -297,12 +297,12 @@ export default {
/* This is basically https://github.com/nextcloud/server/blob/master/core/css/guest.css
But without the user variables. That way the admin can preview the render as guest*/
/* As guest, there is no user color color-background-plain */
background-color: var(--color-primary-element-default, #0082c9);
background-color: var(--color-primary-element-default);
/* As guest, there is no user background (--image-background)
1. Empty background if defined
2. Else default background
3. Finally default gradient (should not happened, the background is always defined anyway) */
background-image: var(--image-background-plain, var(--image-background-default, linear-gradient(40deg, #0082c9 0%, #30b6ff 100%)));
background-image: var(--image-background-plain, var(--image-background-default));
&-logo {
width: 20%;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -48,8 +48,8 @@ html {
body {
// color-background-plain should always be defined. It is the primary user colour
background-color: var(--color-background-plain, var(--color-main-background));
// image-background-plain means the admin has disabled the background image
background-image: var(--image-background, var(--image-background-default));
// user background, or plain colour and finally default admin background
background-image: var(--image-background, var(--image-background-plain, var(--image-background-default)));
background-size: cover;
background-position: center;
position: fixed;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -23,14 +23,11 @@
import { User } from '@nextcloud/cypress'
import { colord } from 'colord'
import { pickRandomColor, validateBodyThemingCss, validateUserThemingDefaultCss } from './themingUtils'
import { defaultPrimary, defaultBackground, pickRandomColor, validateBodyThemingCss, validateUserThemingDefaultCss } from './themingUtils'
const admin = new User('admin', 'admin')
const defaultPrimary = '#0082c9'
const defaultBackground = 'kamil-porembinski-clouds.jpg'
describe('Admin theming settings', function() {
describe('Admin theming settings visibility check', function() {
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
@ -50,8 +47,9 @@ describe('Admin theming settings', function() {
})
})
describe('Change the primary colour and reset it', function() {
describe('Change the primary color and reset it', function() {
let selectedColor = ''
before(function() {
// Just in case previous test failed
cy.resetAdminTheming()
@ -63,7 +61,7 @@ describe('Change the primary colour and reset it', function() {
cy.get('[data-admin-theming-settings]').scrollIntoView().should('be.visible')
})
it('Change the primary colour', function() {
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
@ -73,18 +71,18 @@ describe('Change the primary colour and reset it', function() {
cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
})
it('Screenshot the login page', function() {
it('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
cy.screenshot()
})
it('Undo theming settings', function() {
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
})
it('Screenshot the login page', function() {
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
@ -108,26 +106,74 @@ describe('Remove the default background and restore it', function() {
cy.get('[data-admin-theming-setting-file-remove]').click()
cy.wait('@removeBackground')
cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null))
cy.waitUntil(() => cy.window().then((win) => {
const currentBackgroundDefault = getComputedStyle(win.document.body).getPropertyValue('--image-background-default')
const backgroundPlain = getComputedStyle(win.document.body).getPropertyValue('--image-background-plain')
return !currentBackgroundDefault.includes(defaultBackground)
&& backgroundPlain !== ''
return backgroundPlain !== ''
}))
})
it('Screenshot the login page', function() {
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', function() {
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 primary 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]').scrollIntoView().should('be.visible')
})
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
.then(color => selectedColor = color)
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground))
})
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('Screenshot the login page and validate login page', function() {
cy.logout()
cy.visit('/')
cy.waitUntil(() => validateBodyThemingCss(selectedColor, null))
cy.screenshot()
})
it('Screenshot the login page', function() {
it('Undo theming settings and validate login page again', function() {
cy.resetAdminTheming()
cy.visit('/')
cy.waitUntil(validateBodyThemingCss)
cy.screenshot()
})
@ -154,7 +200,7 @@ describe('Remove the default background with a bright color', function() {
cy.wait('@removeBackground')
})
it('Change the primary colour', function() {
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
// Pick one of the bright color preset
@ -162,7 +208,7 @@ describe('Remove the default background with a bright color', function() {
cy.get('.color-picker__simple-color-circle:eq(4)').click()
cy.wait('@setColor')
cy.waitUntil(() => validateBodyThemingCss('#ddcb55', ''))
cy.waitUntil(() => validateBodyThemingCss('#ddcb55', null))
})
it('See the header being inverted', function() {
@ -229,7 +275,7 @@ describe('Change the login fields then reset them', function() {
.scrollIntoView().should('be.visible')
})
it('Check login screen changes', function() {
it('Validate login screen changes', function() {
cy.logout()
cy.visit('/')
@ -243,7 +289,7 @@ describe('Change the login fields then reset them', function() {
cy.resetAdminTheming()
})
it('Check login screen changes', function() {
it('Validate login screen changes again', function() {
cy.visit('/')
cy.get('[data-login-form-headline]').should('not.contain.text', name)
@ -265,7 +311,7 @@ describe('Disable user theming and enable it back', function() {
cy.get('[data-admin-theming-settings]').scrollIntoView().should('be.visible')
})
it('Disable user theming', function() {
it('Disable user background theming', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('disableUserTheming')
cy.get('[data-admin-theming-setting-disable-user-theming]')
@ -283,13 +329,13 @@ describe('Disable user theming and enable it back', function() {
})
})
it('See the user disabled background settings', function() {
it('User cannot not change background settings', function() {
cy.visit('/settings/user/theming')
cy.get('[data-user-theming-background-disabled]').scrollIntoView().should('be.visible')
})
})
describe('User default option matches admin theming', function() {
describe('The user default background settings reflect the admin theming settings', function() {
let selectedColor = ''
before(function() {
@ -307,7 +353,7 @@ describe('User default option matches admin theming', function() {
cy.get('[data-admin-theming-settings]').scrollIntoView().should('be.visible')
})
it('Change the primary colour', function() {
it('Change the primary color', function() {
cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor')
pickRandomColor('[data-admin-theming-setting-primary-color-picker]')
@ -333,7 +379,7 @@ describe('User default option matches admin theming', function() {
}))
})
it('Logout and check changes', function() {
it('Login page should match admin theming settings', function() {
cy.logout()
cy.visit('/')
@ -351,10 +397,61 @@ describe('User default option matches admin theming', function() {
cy.get('[data-user-theming-background-settings]').scrollIntoView().should('be.visible')
})
it('See the default background option selected', function() {
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]').scrollIntoView().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().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))
})
})

@ -21,18 +21,29 @@
*/
import { colord } from 'colord'
export const defaultPrimary = '#0082c9'
export const defaultAccessiblePrimary = '#006aa3'
export const defaultBackground = 'kamil-porembinski-clouds.jpg'
/**
* Validate the current page body css variables
*
* @param {string} expectedColor the expected color
* @param {string} expectedBackground the expected background
* @param {string|null} expectedBackground the expected background
*/
export const validateBodyThemingCss = function(expectedColor = '#0082c9', expectedBackground = 'kamil-porembinski-clouds.jpg') {
export const validateBodyThemingCss = function(expectedColor = defaultPrimary, expectedBackground: string|null = defaultBackground) {
return cy.window().then((win) => {
const guestBackgroundColor = getComputedStyle(win.document.body).backgroundColor
const guestBackgroundImage = getComputedStyle(win.document.body).backgroundImage
return colord(guestBackgroundColor).isEqual(expectedColor)
&& guestBackgroundImage.includes(expectedBackground)
const isValidBackgroundColor = colord(guestBackgroundColor).isEqual(expectedColor)
const isValidBackgroundImage = !expectedBackground
? guestBackgroundImage === 'none'
: guestBackgroundImage.includes(expectedBackground)
console.debug({ guestBackgroundColor: colord(guestBackgroundColor).toHex(), guestBackgroundImage, expectedColor, expectedBackground, isValidBackgroundColor, isValidBackgroundImage })
return isValidBackgroundColor && isValidBackgroundImage
})
}
@ -42,7 +53,7 @@ export const validateBodyThemingCss = function(expectedColor = '#0082c9', expect
* @param {string} expectedColor the expected color
* @param {string} expectedBackground the expected background
*/
export const validateUserThemingDefaultCss = function(expectedColor = '#0082c9', expectedBackground = 'kamil-porembinski-clouds.jpg') {
export const validateUserThemingDefaultCss = function(expectedColor = defaultPrimary, expectedBackground: string|null = defaultBackground) {
return cy.window().then((win) => {
const defaultSelectButton = win.document.querySelector('[data-user-theming-background-default]')
const customColorSelectButton = win.document.querySelector('[data-user-theming-background-color]')
@ -53,7 +64,14 @@ export const validateUserThemingDefaultCss = function(expectedColor = '#0082c9',
const defaultOptionBackground = getComputedStyle(defaultSelectButton).backgroundImage
const defaultOptionBorderColor = getComputedStyle(defaultSelectButton).borderColor
const colorPickerOptionColor = getComputedStyle(customColorSelectButton).backgroundColor
return defaultOptionBackground.includes(expectedBackground)
const isValidBackgroundImage = !expectedBackground
? defaultOptionBackground === 'none'
: defaultOptionBackground.includes(expectedBackground)
console.debug(colord(defaultOptionBorderColor).toHex(), colord(colorPickerOptionColor).toHex(), expectedColor, isValidBackgroundImage)
return isValidBackgroundImage
&& colord(defaultOptionBorderColor).isEqual(expectedColor)
&& colord(colorPickerOptionColor).isEqual(expectedColor)
})

@ -21,10 +21,8 @@
*/
import { User } from '@nextcloud/cypress'
import { pickRandomColor, validateBodyThemingCss } from './themingUtils'
import { defaultPrimary, defaultBackground, pickRandomColor, validateBodyThemingCss } from './themingUtils'
const defaultPrimary = '#006aa3'
const defaultBackground = 'kamil-porembinski-clouds.jpg'
const admin = new User('admin', 'admin')
describe('User default background settings', function() {
@ -111,7 +109,7 @@ describe('User select shipped backgrounds and remove background', function() {
// Validate clear background
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss('#56633d', ''))
cy.waitUntil(() => validateBodyThemingCss('#56633d', null))
})
})
@ -137,7 +135,7 @@ describe('User select a custom color', function() {
cy.wait('@setColor')
cy.waitUntil(() => cy.window().then((win) => {
const primary = getComputedStyle(win.document.body).getPropertyValue('--color-primary')
return primary !== defaultPrimary
return primary !== defaultPrimary && primary !== defaultPrimary
}))
})
})
@ -163,7 +161,7 @@ describe('User select a bright custom color and remove background', function() {
// Validate clear background
cy.wait('@clearBackground')
cy.waitUntil(() => validateBodyThemingCss(undefined, ''))
cy.waitUntil(() => validateBodyThemingCss(undefined, null))
})
it('Select a custom color', function() {
@ -187,7 +185,7 @@ describe('User select a bright custom color and remove background', function() {
}))
})
it('Select a shipped background', function() {
it('Select another but non-bright shipped background', function() {
const background = 'anatoly-mikhaltsov-butterfly-wing-scale.jpg'
cy.intercept('*/apps/theming/background/shipped').as('setBackground')
@ -199,7 +197,7 @@ describe('User select a bright custom color and remove background', function() {
cy.waitUntil(() => validateBodyThemingCss('#a53c17', background))
})
it('See the header NOT being inverted', function() {
it('See the header NOT being inverted this time', function() {
cy.waitUntil(() => cy.window().then((win) => {
const firstEntry = win.document.querySelector('.app-menu-main li')
if (!firstEntry) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save