diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-01-20 07:43:04 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-05-21 20:36:26 +0200 |
commit | 538a04968a24f645b12ca2647952a5b73ebc3eac (patch) | |
tree | fe6de92830c3cab15b8e2ea96e473566267726c7 | |
parent | 11dbfa636d746eac4a82460d0677dc6ffe98f068 (diff) | |
download | nextcloud-server-538a04968a24f645b12ca2647952a5b73ebc3eac.tar.gz nextcloud-server-538a04968a24f645b12ca2647952a5b73ebc3eac.zip |
fix(tests): Adjust theming test for new splitted background and primary colors
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r-- | apps/settings/src/components/AdminAI.vue | 6 | ||||
-rw-r--r-- | apps/theming/css/default.css | 2 | ||||
-rw-r--r-- | apps/theming/lib/Service/BackgroundService.php | 5 | ||||
-rw-r--r-- | apps/theming/lib/Themes/CommonThemeTrait.php | 3 | ||||
-rw-r--r-- | apps/theming/lib/Util.php | 2 | ||||
-rw-r--r-- | apps/theming/openapi.json | 4 | ||||
-rw-r--r-- | apps/theming/tests/Settings/PersonalTest.php | 14 | ||||
-rw-r--r-- | apps/theming/tests/ThemingDefaultsTest.php | 74 | ||||
-rw-r--r-- | cypress/e2e/theming/admin-settings.cy.ts | 336 | ||||
-rw-r--r-- | cypress/e2e/theming/themingUtils.ts | 70 | ||||
-rw-r--r-- | cypress/e2e/theming/user-background.cy.ts | 67 | ||||
-rw-r--r-- | lib/private/Server.php | 16 | ||||
-rw-r--r-- | lib/private/legacy/OC_Defaults.php | 4 |
13 files changed, 369 insertions, 234 deletions
diff --git a/apps/settings/src/components/AdminAI.vue b/apps/settings/src/components/AdminAI.vue index ea444fc25cf..5b71bb0dc04 100644 --- a/apps/settings/src/components/AdminAI.vue +++ b/apps/settings/src/components/AdminAI.vue @@ -190,9 +190,9 @@ export default { .draggable__number { border-radius: 20px; - border: 2px solid var(--color-primary-default); - color: var(--color-primary-default); - padding: 0px 7px; + border: 2px solid var(--color-primary-element); + color: var(--color-primary-element); + padding: 0px 7px; margin-right: 3px; } diff --git a/apps/theming/css/default.css b/apps/theming/css/default.css index c96e41d23fc..6a5f91af864 100644 --- a/apps/theming/css/default.css +++ b/apps/theming/css/default.css @@ -71,7 +71,6 @@ --primary-invert-if-bright: no; --primary-invert-if-dark: invert(100%); --color-primary: #00679e; - --color-primary-default: #0082c9; --color-primary-text: #ffffff; --color-primary-hover: #3285b1; --color-primary-light: #e5eff5; @@ -87,4 +86,5 @@ --gradient-primary-background: linear-gradient(40deg, var(--color-primary) 0%, var(--color-primary-hover) 100%); --color-background-plain: #00679e; --color-background-plain-text: #ffffff; + --image-background: url('/apps/theming/img/background/kamil-porembinski-clouds.jpg'); } diff --git a/apps/theming/lib/Service/BackgroundService.php b/apps/theming/lib/Service/BackgroundService.php index c323a721b60..cdaff2372a8 100644 --- a/apps/theming/lib/Service/BackgroundService.php +++ b/apps/theming/lib/Service/BackgroundService.php @@ -43,7 +43,7 @@ use OCP\Lock\LockedException; use OCP\PreConditionNotMetException; class BackgroundService { - public const DEFAULT_COLOR = '#0082c9'; + public const DEFAULT_COLOR = '#00679e'; public const DEFAULT_BACKGROUND_COLOR = '#00679e'; /** @@ -300,9 +300,10 @@ class BackgroundService { $meanColor = $this->calculateMeanColor($image); if ($meanColor !== false) { $this->config->setAppValue(Application::APP_ID, 'background_color', $meanColor); + return $meanColor; } - return $meanColor; } + return null; } /** diff --git a/apps/theming/lib/Themes/CommonThemeTrait.php b/apps/theming/lib/Themes/CommonThemeTrait.php index bdf95d98275..f2d86009cef 100644 --- a/apps/theming/lib/Themes/CommonThemeTrait.php +++ b/apps/theming/lib/Themes/CommonThemeTrait.php @@ -61,7 +61,6 @@ trait CommonThemeTrait { '--primary-invert-if-dark' => $this->util->invertTextColor($colorPrimaryElement) ? 'no' : 'invert(100%)', '--color-primary' => $this->primaryColor, - '--color-primary-default' => $this->defaultPrimaryColor, '--color-primary-text' => $this->util->invertTextColor($this->primaryColor) ? '#000000' : '#ffffff', '--color-primary-hover' => $this->util->mix($this->primaryColor, $colorMainBackground, 60), '--color-primary-light' => $colorPrimaryLight, @@ -105,7 +104,7 @@ trait CommonThemeTrait { if ($this->imageManager->hasImage($image)) { $imageUrl = $this->imageManager->getImageUrl($image); $variables["--image-$image"] = "url('" . $imageUrl . "')"; - } else if ($image === 'background') { + } elseif ($image === 'background') { // Apply default background if nothing is configured $variables['--image-background'] = "url('" . $this->themingDefaults->getBackground() . "')"; } diff --git a/apps/theming/lib/Util.php b/apps/theming/lib/Util.php index a2f8ee0abad..5dd71c1c1d3 100644 --- a/apps/theming/lib/Util.php +++ b/apps/theming/lib/Util.php @@ -93,7 +93,7 @@ class Util { $contrast = $this->colorContrast($color, $blurredBackground); // Min. element contrast is 3:1 but we need to keep hover states in mind -> min 3.2:1 - $minContrast = $highContrast ? 5.5 : 3.2; + $minContrast = $highContrast ? 5.6 : 3.2; while ($contrast < $minContrast && $iteration++ < 100) { $hsl = Color::hexToHsl($color); diff --git a/apps/theming/openapi.json b/apps/theming/openapi.json index 072b1897f69..fe0f342f993 100644 --- a/apps/theming/openapi.json +++ b/apps/theming/openapi.json @@ -63,6 +63,7 @@ "color-element-dark", "logo", "background", + "background-text", "background-plain", "background-default", "logoheader", @@ -99,6 +100,9 @@ "background": { "type": "string" }, + "background-text": { + "type": "string" + }, "background-plain": { "type": "boolean" }, diff --git a/apps/theming/tests/Settings/PersonalTest.php b/apps/theming/tests/Settings/PersonalTest.php index 0a9bf4b59c9..c2b08c72f30 100644 --- a/apps/theming/tests/Settings/PersonalTest.php +++ b/apps/theming/tests/Settings/PersonalTest.php @@ -30,6 +30,7 @@ namespace OCA\Theming\Tests\Settings; use OCA\Theming\AppInfo\Application; use OCA\Theming\ImageManager; use OCA\Theming\ITheme; +use OCA\Theming\Service\BackgroundService; use OCA\Theming\Service\ThemesService; use OCA\Theming\Settings\Personal; use OCA\Theming\Themes\DarkHighContrastTheme; @@ -116,18 +117,23 @@ class PersonalTest extends TestCase { ->with('enforce_theme', '') ->willReturn($enforcedTheme); - $this->config->expects($this->once()) + $this->config->expects($this->any()) ->method('getUserValue') - ->with('admin', 'core', 'apporder') - ->willReturn('[]'); + ->willReturnMap([ + ['admin', 'core', 'apporder', '[]', '[]'], + ['admin', 'theming', 'background_image', BackgroundService::BACKGROUND_DEFAULT], + ]); $this->appManager->expects($this->once()) ->method('getDefaultAppForUser') ->willReturn('forcedapp'); - $this->initialStateService->expects($this->exactly(4)) + $this->initialStateService->expects($this->exactly(7)) ->method('provideInitialState') ->withConsecutive( + ['shippedBackgrounds', BackgroundService::SHIPPED_BACKGROUNDS], + ['themingDefaults'], + ['userBackgroundImage'], ['themes', $themesState], ['enforceTheme', $enforcedTheme], ['isUserThemingDisabled', false], diff --git a/apps/theming/tests/ThemingDefaultsTest.php b/apps/theming/tests/ThemingDefaultsTest.php index 2011b62c3ea..0ea12f82563 100644 --- a/apps/theming/tests/ThemingDefaultsTest.php +++ b/apps/theming/tests/ThemingDefaultsTest.php @@ -455,82 +455,38 @@ class ThemingDefaultsTest extends TestCase { 'with fallback default' => [ 'disableTheming' => 'no', 'primaryColor' => '', - 'backgroundColor' => '', - 'userBackgroundColor' => '', - 'userPrimaryColor' => '', - 'expected' => BackgroundService::DEFAULT_COLOR, - ], - 'with custom admin background' => [ - 'disableTheming' => 'no', - 'primaryColor' => '', - 'backgroundColor' => '#123', - 'userBackgroundColor' => '', - 'userPrimaryColor' => '', - 'expected' => '#123', - ], - 'with custom invalid admin background' => [ - 'disableTheming' => 'no', - 'primaryColor' => '', - 'backgroundColor' => 'invalid-name', - 'userBackgroundColor' => '', 'userPrimaryColor' => '', 'expected' => BackgroundService::DEFAULT_COLOR, ], 'with custom admin primary' => [ 'disableTheming' => 'no', 'primaryColor' => '#aaa', - 'backgroundColor' => '', - 'userBackgroundColor' => '', 'userPrimaryColor' => '', 'expected' => '#aaa', ], 'with custom invalid admin primary' => [ 'disableTheming' => 'no', 'primaryColor' => 'invalid', - 'backgroundColor' => '', - 'userBackgroundColor' => '', 'userPrimaryColor' => '', 'expected' => BackgroundService::DEFAULT_COLOR, ], - 'with custom user background' => [ - 'disableTheming' => 'no', - 'primaryColor' => '', - 'backgroundColor' => '', - 'userBackgroundColor' => '#456', - 'userPrimaryColor' => '#456', - 'expected' => '#456', - ], 'with custom invalid user primary' => [ 'disableTheming' => 'no', 'primaryColor' => '', - 'backgroundColor' => '', - 'userBackgroundColor' => '', 'userPrimaryColor' => 'invalid-name', 'expected' => BackgroundService::DEFAULT_COLOR, ], 'with custom user primary' => [ 'disableTheming' => 'no', 'primaryColor' => '', - 'backgroundColor' => '', - 'userBackgroundColor' => '', 'userPrimaryColor' => '#bbb', 'expected' => '#bbb', ], - 'with custom invalid user background' => [ - 'disableTheming' => 'no', - 'primaryColor' => '', - 'backgroundColor' => '', - 'userBackgroundColor' => 'invalid-name', - 'userPrimaryColor' => '', - 'expected' => BackgroundService::DEFAULT_COLOR, - ], - 'with custom admin and user background' => [ - 'disableTheming' => 'no', - 'primaryColor' => '', - 'backgroundColor' => '#123', - 'userBackgroundColor' => '#456', - 'userPrimaryColor' => '#456', - 'expected' => '#456', + 'with disabled user theming primary' => [ + 'disableTheming' => 'yes', + 'primaryColor' => '#aaa', + 'userPrimaryColor' => '#bbb', + 'expected' => '#aaa', ], ]; } @@ -538,7 +494,7 @@ class ThemingDefaultsTest extends TestCase { /** * @dataProvider dataGetColorPrimary */ - public function testGetColorPrimary(string $disableTheming, string $primaryColor, string $backgroundColor, string $userBackgroundColor, $userPrimaryColor, $expected) { + public function testGetColorPrimary(string $disableTheming, string $primaryColor, string $userPrimaryColor, string $expected) { $user = $this->createMock(IUser::class); $this->userSession->expects($this->any()) ->method('getUser') @@ -552,15 +508,12 @@ class ThemingDefaultsTest extends TestCase { ->willReturnMap([ ['theming', 'disable-user-theming', 'no', $disableTheming], ['theming', 'primary_color', '', $primaryColor], - ['theming', 'background_color', '', $backgroundColor], ]); $this->config ->expects($this->any()) ->method('getUserValue') - ->willReturnMap([ - ['user', 'theming', 'background_color', '', $userBackgroundColor], - ['user', 'theming', 'primary_color', $userBackgroundColor, $userPrimaryColor], - ]); + ->with('user', 'theming', 'primary_color', '') + ->willReturn($userPrimaryColor); $this->assertEquals($expected, $this->template->getColorPrimary()); } @@ -668,15 +621,10 @@ class ThemingDefaultsTest extends TestCase { ->method('deleteAppValue') ->with('theming', 'primary_color'); $this->config - ->expects($this->exactly(2)) + ->expects($this->once()) ->method('getAppValue') - ->withConsecutive( - ['theming', 'cachebuster', '0'], - ['theming', 'primary_color', null], - )->willReturnOnConsecutiveCalls( - '15', - $this->defaults->getColorPrimary(), - ); + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); $this->config ->expects($this->once()) ->method('setAppValue') diff --git a/cypress/e2e/theming/admin-settings.cy.ts b/cypress/e2e/theming/admin-settings.cy.ts index 1c4e3458aae..e721ab4d332 100644 --- a/cypress/e2e/theming/admin-settings.cy.ts +++ b/cypress/e2e/theming/admin-settings.cy.ts @@ -21,9 +21,15 @@ */ /* eslint-disable n/no-unpublished-import */ import { User } from '@nextcloud/cypress' -import { colord } from 'colord' -import { defaultPrimary, defaultBackground, pickRandomColor, validateBodyThemingCss, validateUserThemingDefaultCss } from './themingUtils' +import { + defaultPrimary, + defaultBackground, + pickRandomColor, + validateBodyThemingCss, + validateUserThemingDefaultCss, + expectBackgroundColor, +} from './themingUtils' const admin = new User('admin', 'admin') @@ -36,15 +42,24 @@ describe('Admin theming settings visibility check', function() { 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('exist') + .scrollIntoView() cy.get('[data-admin-theming-settings]').should('be.visible') }) it('See the default settings', function() { - cy.get('[data-admin-theming-setting-primary-color-picker]').should('exist') - cy.get('[data-admin-theming-setting-primary-color-reset]').should('not.exist') + 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('be.visible') + 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)) }) }) @@ -59,24 +74,42 @@ describe('Change the primary color and reset it', function() { 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('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().then(color => { selectedColor = color }) + pickRandomColor('[data-admin-theming-setting-primary-color]').then( + (color) => { + selectedColor = color + }, + ) cy.wait('@setColor') - cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground)) + 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)) + cy.waitUntil(() => + validateBodyThemingCss( + selectedColor, + defaultBackground, + defaultPrimary, + ), + ) cy.screenshot() }) @@ -98,21 +131,29 @@ describe('Remove the default background and restore it', function() { 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('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.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-plain') - return backgroundPlain !== '' - })) + 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() { @@ -132,7 +173,7 @@ describe('Remove the default background and restore it', function() { }) }) -describe('Remove the default background with a custom primary color', function() { +describe('Remove the default background with a custom background color', function() { let selectedColor = '' before(function() { @@ -143,23 +184,40 @@ describe('Remove the default background with a custom primary color', function() 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('exist') + .scrollIntoView() cy.get('[data-admin-theming-settings]').should('be.visible') }) - it('Change the primary color', function() { + it('Change the background color', function() { cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor') - pickRandomColor().then(color => { selectedColor = color }) + pickRandomColor('[data-admin-theming-setting-background-color]').then( + (color) => { + selectedColor = color + }, + ) cy.wait('@setColor') - cy.waitUntil(() => validateBodyThemingCss(selectedColor, defaultBackground)) + cy.waitUntil(() => + validateBodyThemingCss( + defaultPrimary, + defaultBackground, + selectedColor, + ), + ) }) it('Remove the default background', function() { - cy.intercept('*/apps/theming/ajax/updateStylesheet').as('removeBackground') + cy.intercept('*/apps/theming/ajax/updateStylesheet').as( + 'removeBackground', + ) - cy.get('[data-admin-theming-setting-file-remove]').click() + cy.get('[data-admin-theming-setting-file-remove]').scrollIntoView() + cy.get('[data-admin-theming-setting-file-remove]').click({ + force: true, + }) cy.wait('@removeBackground') }) @@ -168,7 +226,9 @@ describe('Remove the default background with a custom primary color', function() cy.logout() cy.visit('/') - cy.waitUntil(() => validateBodyThemingCss(selectedColor, null)) + cy.waitUntil(() => + validateBodyThemingCss(defaultPrimary, null, selectedColor), + ) cy.screenshot() }) @@ -182,6 +242,8 @@ describe('Remove the default background with a custom primary color', function() }) describe('Remove the default background with a bright color', function() { + let selectedColor = '' + before(function() { // Just in case previous test failed cy.resetAdminTheming() @@ -191,37 +253,51 @@ describe('Remove the default background with a bright color', function() { 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('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.intercept('*/apps/theming/ajax/updateStylesheet').as( + 'removeBackground', + ) cy.get('[data-admin-theming-setting-file-remove]').click() cy.wait('@removeBackground') }) - it('Change the primary color', function() { + it('Change the background color', function() { cy.intercept('*/apps/theming/ajax/updateStylesheet').as('setColor') // Pick one of the bright color preset - cy.get('[data-admin-theming-setting-primary-color-picker]').click() - cy.get('.color-picker__simple-color-circle:eq(4)').click() + pickRandomColor( + '[data-admin-theming-setting-background-color]', + 4, + ).then((color) => { + selectedColor = color + }) cy.wait('@setColor') - cy.waitUntil(() => validateBodyThemingCss('#ddcb55', null)) + cy.waitUntil(() => + validateBodyThemingCss(defaultPrimary, null, selectedColor), + ) }) it('See the header being inverted', function() { - cy.waitUntil(() => cy.window().then((win) => { - const firstEntry = win.document.querySelector('.app-menu-main li img') - if (!firstEntry) { - return false - } - return getComputedStyle(firstEntry).filter === 'invert(1)' - })) + cy.waitUntil(() => + cy.window().then((win) => { + const firstEntry = win.document.querySelector( + '.app-menu-main li img', + ) + if (!firstEntry) { + return false + } + return getComputedStyle(firstEntry).filter === 'invert(1)' + }), + ) }) }) @@ -238,7 +314,9 @@ describe('Change the login fields then reset them', function() { 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('exist') + .scrollIntoView() cy.get('[data-admin-theming-settings]').should('be.visible') }) @@ -246,42 +324,54 @@ describe('Change the login fields then reset them', 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.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.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.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') + 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() { @@ -317,19 +407,29 @@ describe('Disable user theming and enable it back', function() { 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('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.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') }) @@ -343,8 +443,9 @@ describe('Disable user theming and enable it back', function() { it('User cannot not change background settings', function() { cy.visit('/settings/user/theming') - cy.get('[data-user-theming-background-disabled]').scrollIntoView() - cy.get('[data-user-theming-background-disabled]').should('be.visible') + cy.contains( + 'Customization has been disabled by your administrator', + ).should('exist') }) }) @@ -363,40 +464,60 @@ describe('The user default background settings reflect the admin theming setting 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('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().then(color => { selectedColor = color }) - - cy.wait('@setColor') - cy.waitUntil(() => cy.window().then(($window) => { - const primary = $window.getComputedStyle($window.document.body).getPropertyValue('--color-primary-default') - return colord(primary).isEqual(selectedColor) - })) - }) - 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.get( + '[data-admin-theming-setting-file="background"] input[type="file"]', + ).selectFile('@background', { force: true }) cy.wait('@setBackground') - cy.waitUntil(() => cy.window().then((win) => { - const currentBackgroundDefault = getComputedStyle(win.document.body).getPropertyValue('--image-background-default') - return currentBackgroundDefault.includes('/apps/theming/image/background?v=') - })) + 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(selectedColor, '/apps/theming/image/background?v=')) + cy.waitUntil(() => + validateBodyThemingCss( + defaultPrimary, + '/apps/theming/image/background?v=', + selectedColor, + ), + ) }) it('Login as user', function() { @@ -413,9 +534,17 @@ describe('The user default background settings reflect the admin theming setting 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=')) + cy.get('[data-user-theming-background-default]').should( + 'have.class', + 'background--active', + ) + + cy.waitUntil(() => + validateUserThemingDefaultCss( + selectedColor, + '/apps/theming/image/background?v=', + ), + ) }) }) @@ -432,12 +561,16 @@ describe('The user default background settings reflect the admin theming setting 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('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.intercept('*/apps/theming/ajax/updateStylesheet').as( + 'removeBackground', + ) cy.get('[data-admin-theming-setting-file-remove]').click() @@ -466,7 +599,10 @@ describe('The user default background settings reflect the admin theming setting 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.get('[data-user-theming-background-default]').should( + 'have.class', + 'background--active', + ) cy.waitUntil(() => validateUserThemingDefaultCss(defaultPrimary, null)) }) diff --git a/cypress/e2e/theming/themingUtils.ts b/cypress/e2e/theming/themingUtils.ts index 2965886c656..a3a0d509278 100644 --- a/cypress/e2e/theming/themingUtils.ts +++ b/cypress/e2e/theming/themingUtils.ts @@ -21,29 +21,54 @@ */ import { colord } from 'colord' -const defaultNextcloudBlue = '#0082c9' export const defaultPrimary = '#00679e' export const defaultBackground = 'kamil-porembinski-clouds.jpg' /** + * Check if a CSS variable is set to a specific color + * @param variable Variable to check + * @param expectedColor Color that is expected + */ +export function validateCSSVariable(variable: string, expectedColor: string) { + const value = window.getComputedStyle(Cypress.$('body').get(0)).getPropertyValue(variable) + console.debug(`${variable}, is: ${colord(value).toHex()} expected: ${expectedColor}`) + return colord(value).isEqual(expectedColor) +} + +/** * Validate the current page body css variables * - * @param {string} expectedColor the expected color + * @param {string} expectedColor the expected primary color * @param {string|null} expectedBackground the expected background + * @param {string|null} expectedBackgroundColor the expected background color (null to ignore) */ -export const validateBodyThemingCss = function(expectedColor = defaultPrimary, expectedBackground: string|null = defaultBackground) { +export function validateBodyThemingCss(expectedColor = defaultPrimary, expectedBackground: string|null = defaultBackground, expectedBackgroundColor: string|null = defaultPrimary) { // We must use `Cypress.$` here as any assertions (get is an assertion) is not allowed in wait-until's check function, see documentation const guestBackgroundColor = Cypress.$('body').css('background-color') const guestBackgroundImage = Cypress.$('body').css('background-image') - const isValidBackgroundColor = colord(guestBackgroundColor).isEqual(expectedColor) + const isValidBackgroundColor = expectedBackgroundColor === null || colord(guestBackgroundColor).isEqual(expectedBackgroundColor) const isValidBackgroundImage = !expectedBackground ? guestBackgroundImage === 'none' : guestBackgroundImage.includes(expectedBackground) - console.debug({ guestBackgroundColor: colord(guestBackgroundColor).toHex(), guestBackgroundImage, expectedColor, expectedBackground, isValidBackgroundColor, isValidBackgroundImage }) + console.debug({ + isValidBackgroundColor, + isValidBackgroundImage, + guestBackgroundColor: colord(guestBackgroundColor).toHex(), + guestBackgroundImage, + }) + + return isValidBackgroundColor && isValidBackgroundImage && validateCSSVariable('--color-primary', expectedColor) +} - return isValidBackgroundColor && isValidBackgroundImage +/** + * Check background color of element + * @param element JQuery element to check + * @param color expected color + */ +export function expectBackgroundColor(element: JQuery<HTMLElement>, color: string) { + expect(colord(element.css('background-color')).toHex()).equal(colord(color).toHex()) } /** @@ -58,28 +83,28 @@ export const validateUserThemingDefaultCss = function(expectedColor = defaultPri return false } - const defaultOptionBackground = defaultSelectButton.css('background-image') - const colorPickerOptionColor = defaultSelectButton.css('background-color') - const isNextcloudBlue = colord(colorPickerOptionColor).isEqual('#0082c9') + const backgroundImage = defaultSelectButton.css('background-image') + const backgroundColor = defaultSelectButton.css('background-color') const isValidBackgroundImage = !expectedBackground - ? defaultOptionBackground === 'none' - : defaultOptionBackground.includes(expectedBackground) - - console.debug({ colorPickerOptionColor: colord(colorPickerOptionColor).toHex(), expectedColor, isValidBackgroundImage, isNextcloudBlue }) + ? (backgroundImage === 'none' || Cypress.$('body').css('background-image') === 'none') + : backgroundImage.includes(expectedBackground) + + console.debug({ + colorPickerOptionColor: colord(backgroundColor).toHex(), + expectedColor, + isValidBackgroundImage, + backgroundImage, + }) - return isValidBackgroundImage && ( - colord(colorPickerOptionColor).isEqual(expectedColor) - // we replace nextcloud blue with the the default rpimary (apps/theming/lib/Themes/DefaultTheme.php line 76) - || (isNextcloudBlue && colord(expectedColor).isEqual(defaultPrimary)) - ) + return isValidBackgroundImage && colord(backgroundColor).isEqual(expectedColor) } -export const pickRandomColor = function(): Cypress.Chainable<string> { +export const pickRandomColor = function(context: string, index?: number): Cypress.Chainable<string> { // Pick one of the first 8 options - const randColour = Math.floor(Math.random() * 8) + const randColour = index ?? Math.floor(Math.random() * 8) - const colorPreviewSelector = '[data-user-theming-background-color],[data-admin-theming-setting-primary-color]' + const colorPreviewSelector = `${context} [data-admin-theming-setting-color]` let oldColor = '' cy.get(colorPreviewSelector).then(($el) => { @@ -87,7 +112,8 @@ export const pickRandomColor = function(): Cypress.Chainable<string> { }) // Open picker - cy.contains('button', 'Change color').click() + cy.get(`${context} [data-admin-theming-setting-color-picker]`).scrollIntoView() + cy.get(`${context} [data-admin-theming-setting-color-picker]`).click({ force: true }) // Click on random color cy.get('.color-picker__simple-color-circle').eq(randColour).click() diff --git a/cypress/e2e/theming/user-background.cy.ts b/cypress/e2e/theming/user-background.cy.ts index cdf3ef59f4d..2796247a654 100644 --- a/cypress/e2e/theming/user-background.cy.ts +++ b/cypress/e2e/theming/user-background.cy.ts @@ -80,7 +80,7 @@ describe('User select shipped backgrounds and remove background', function() { // Validate changed background and primary cy.wait('@setBackground') - cy.waitUntil(() => validateBodyThemingCss('#a53c17', background)) + cy.waitUntil(() => validateBodyThemingCss('#a53c17', background, '#652e11')) }) it('Select a bright shipped background', function() { @@ -95,21 +95,21 @@ describe('User select shipped backgrounds and remove background', function() { // Validate changed background and primary cy.wait('@setBackground') - cy.waitUntil(() => validateBodyThemingCss('#869171', background)) + cy.waitUntil(() => validateBodyThemingCss('#56633d', background, '#dee0d3')) }) it('Remove background', function() { - cy.intercept('*/apps/theming/background/custom').as('clearBackground') + cy.intercept('*/apps/theming/background/color').as('clearBackground') // Clear background - cy.get('[data-user-theming-background-clear]').click() + cy.get('[data-user-theming-background-color]').click() // Set the accessibility state - cy.get('[data-user-theming-background-clear]').should('have.attr', 'aria-pressed', 'true') + cy.get('[data-user-theming-background-color]').should('have.attr', 'aria-pressed', 'true') // Validate clear background cy.wait('@clearBackground') - cy.waitUntil(() => validateBodyThemingCss('#869171', null)) + cy.waitUntil(() => validateBodyThemingCss('#56633d', null, '#dee0d3')) }) }) @@ -129,14 +129,12 @@ describe('User select a custom color', function() { it('Select a custom color', function() { cy.intercept('*/apps/theming/background/color').as('setColor') - pickRandomColor() + cy.get('[data-user-theming-background-color]').click() + cy.get('.color-picker__simple-color-circle').eq(5).click() // Validate custom colour change cy.wait('@setColor') - cy.waitUntil(() => cy.window().then((win) => { - const primary = getComputedStyle(win.document.body).getPropertyValue('--color-primary') - return primary !== defaultPrimary && primary !== defaultPrimary - })) + cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, null, '#a5b872')) }) }) @@ -154,10 +152,11 @@ describe('User select a bright custom color and remove background', function() { }) it('Remove background', function() { - cy.intercept('*/apps/theming/background/custom').as('clearBackground') + cy.intercept('*/apps/theming/background/color').as('clearBackground') // Clear background - cy.get('[data-user-theming-background-clear]').click() + cy.get('[data-user-theming-background-color]').click() + cy.get('[data-user-theming-background-color]').click() // Validate clear background cy.wait('@clearBackground') @@ -168,7 +167,8 @@ describe('User select a bright custom color and remove background', function() { cy.intercept('*/apps/theming/background/color').as('setColor') // Pick one of the bright color preset - cy.contains('button', 'Change color').click() + 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 @@ -194,7 +194,7 @@ describe('User select a bright custom color and remove background', function() { // Validate changed background and primary cy.wait('@setBackground') - cy.waitUntil(() => validateBodyThemingCss('#a53c17', background)) + cy.waitUntil(() => validateBodyThemingCss('#a53c17', background, '#652e11')) }) it('See the header NOT being inverted this time', function() { @@ -240,15 +240,13 @@ describe('User select a custom background', function() { // Wait for background to be set cy.wait('@setBackground') - cy.waitUntil(() => validateBodyThemingCss('#4c0c04', 'apps/theming/background?v=')) + cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, 'apps/theming/background?v=', '#2f2221')) }) }) describe('User changes settings and reload the page', function() { const image = 'image.jpg' - const primaryFromImage = '#4c0c04' - - let selectedColor = '' + const colorFromImage = '#2f2221' before(function() { cy.createRandomUser().then((user: User) => { @@ -280,28 +278,39 @@ describe('User changes settings and reload the page', function() { // Wait for background to be set cy.wait('@setBackground') - cy.waitUntil(() => validateBodyThemingCss(primaryFromImage, 'apps/theming/background?v=')) + cy.waitUntil(() => validateBodyThemingCss(defaultPrimary, 'apps/theming/background?v=', colorFromImage)) }) it('Select a custom color', function() { cy.intercept('*/apps/theming/background/color').as('setColor') - cy.contains('button', 'Change color').click() + 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() // Validate clear background cy.wait('@setColor') - cy.waitUntil(() => cy.window().then((win) => { - selectedColor = getComputedStyle(win.document.body).getPropertyValue('--color-primary') - return selectedColor !== primaryFromImage - })) + 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() + + // Validate clear background + cy.wait('@setPrimaryColor') + cy.waitUntil(() => validateBodyThemingCss('#c98879', null, '#a5b872')) }) it('Reload the page and validate persistent changes', function() { cy.reload() - cy.waitUntil(() => validateBodyThemingCss(selectedColor, 'apps/theming/background?v=')) - - // validate accessibility state - cy.get('[data-user-theming-background-custom]').should('have.attr', 'aria-pressed', 'true') + cy.waitUntil(() => validateBodyThemingCss('#c98879', null, '#a5b872')) }) }) diff --git a/lib/private/Server.php b/lib/private/Server.php index f62b2426bba..8f2fb2b7383 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1185,14 +1185,20 @@ class Server extends ServerContainer implements IServerContainer { } if ($classExists && $c->get(\OCP\IConfig::class)->getSystemValueBool('installed', false) && $c->get(IAppManager::class)->isInstalled('theming') && $c->get(TrustedDomainHelper::class)->isTrustedDomain($c->getRequest()->getInsecureServerHost())) { + $backgroundService = new BackgroundService( + $c->get(IRootFolder::class), + $c->getAppDataDir('theming'), + $c->get(\OCP\IConfig::class), + $c->get(ISession::class)->get('user_id'), + ); $imageManager = new ImageManager( $c->get(\OCP\IConfig::class), $c->getAppDataDir('theming'), $c->get(IURLGenerator::class), - $this->get(ICacheFactory::class), - $this->get(LoggerInterface::class), - $this->get(ITempManager::class), - $this->get(BackgroundService::class), + $c->get(ICacheFactory::class), + $c->get(LoggerInterface::class), + $c->get(ITempManager::class), + $backgroundService, ); return new ThemingDefaults( $c->get(\OCP\IConfig::class), @@ -1204,7 +1210,7 @@ class Server extends ServerContainer implements IServerContainer { $imageManager, $c->get(IAppManager::class), $c->get(INavigationManager::class), - $c->get(BackgroundService::class), + $backgroundService, ); } return new \OC_Defaults(); diff --git a/lib/private/legacy/OC_Defaults.php b/lib/private/legacy/OC_Defaults.php index 01591af8611..97033d353dd 100644 --- a/lib/private/legacy/OC_Defaults.php +++ b/lib/private/legacy/OC_Defaults.php @@ -71,8 +71,8 @@ class OC_Defaults { $this->defaultFDroidClientUrl = $config->getSystemValue('customclient_fdroid', 'https://f-droid.org/packages/com.nextcloud.client/'); $this->defaultDocBaseUrl = 'https://docs.nextcloud.com'; $this->defaultDocVersion = \OC_Util::getVersion()[0]; // used to generate doc links - $this->defaultColorBackground = '#0069c3'; - $this->defaultColorPrimary = '#0082c9'; + $this->defaultColorBackground = '#00679e'; + $this->defaultColorPrimary = '#00679e'; $this->defaultTextColorPrimary = '#ffffff'; $this->defaultProductName = 'Nextcloud'; |