diff options
Diffstat (limited to 'apps/theming/tests/Controller/ThemingControllerTest.php')
-rw-r--r-- | apps/theming/tests/Controller/ThemingControllerTest.php | 370 |
1 files changed, 188 insertions, 182 deletions
diff --git a/apps/theming/tests/Controller/ThemingControllerTest.php b/apps/theming/tests/Controller/ThemingControllerTest.php index 511f7a6d528..fb461f03a28 100644 --- a/apps/theming/tests/Controller/ThemingControllerTest.php +++ b/apps/theming/tests/Controller/ThemingControllerTest.php @@ -1,93 +1,64 @@ <?php + +declare(strict_types=1); /** - * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> - * - * @author Bjoern Schiessle <bjoern@schiessle.org> - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Calviño Sánchez <danxuliu@gmail.com> - * @author Joas Schilling <coding@schilljs.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Haertl <jus@bitgrid.net> - * @author Julius Härtl <jus@bitgrid.net> - * @author Kyle Fazzari <kyrofa@ubuntu.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Michael Weimann <mail@michael-weimann.eu> - * @author rakekniven <mark.ziegler@rakekniven.de> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Theming\Tests\Controller; use OC\L10N\L10N; use OCA\Theming\Controller\ThemingController; -use OCA\Theming\Service\ThemesService; use OCA\Theming\ImageManager; +use OCA\Theming\Service\ThemesService; use OCA\Theming\ThemingDefaults; use OCP\App\IAppManager; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\AppFramework\Services\IAppConfig; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\IConfig; use OCP\IL10N; +use OCP\INavigationManager; use OCP\IRequest; use OCP\ITempManager; use OCP\IURLGenerator; +use OCP\Server; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ThemingControllerTest extends TestCase { - /** @var IRequest|MockObject */ - private $request; - /** @var IConfig|MockObject */ - private $config; - /** @var ThemingDefaults|MockObject */ - private $themingDefaults; - /** @var IL10N|MockObject */ - private $l10n; - /** @var ThemingController */ - private $themingController; - /** @var ITempManager */ - private $tempManager; - /** @var IAppManager|MockObject */ - private $appManager; - /** @var IAppData|MockObject */ - private $appData; - /** @var ImageManager|MockObject */ - private $imageManager; - /** @var IURLGenerator|MockObject */ - private $urlGenerator; - /** @var ThemeService|MockObject */ - private $themesService; + + private IRequest&MockObject $request; + private IConfig&MockObject $config; + private IAppConfig&MockObject $appConfig; + private ThemingDefaults&MockObject $themingDefaults; + private IL10N&MockObject $l10n; + private IAppManager&MockObject $appManager; + private ImageManager&MockObject $imageManager; + private IURLGenerator&MockObject $urlGenerator; + private ThemesService&MockObject $themesService; + private INavigationManager&MockObject $navigationManager; + + private ThemingController $themingController; protected function setUp(): void { $this->request = $this->createMock(IRequest::class); $this->config = $this->createMock(IConfig::class); + $this->appConfig = $this->createMock(IAppConfig::class); $this->themingDefaults = $this->createMock(ThemingDefaults::class); $this->l10n = $this->createMock(L10N::class); - $this->appData = $this->createMock(IAppData::class); $this->appManager = $this->createMock(IAppManager::class); - $this->tempManager = \OC::$server->getTempManager(); $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->imageManager = $this->createMock(ImageManager::class); $this->themesService = $this->createMock(ThemesService::class); + $this->navigationManager = $this->createMock(INavigationManager::class); $timeFactory = $this->createMock(ITimeFactory::class); $timeFactory->expects($this->any()) @@ -100,20 +71,20 @@ class ThemingControllerTest extends TestCase { 'theming', $this->request, $this->config, + $this->appConfig, $this->themingDefaults, $this->l10n, - $this->tempManager, - $this->appData, $this->urlGenerator, $this->appManager, $this->imageManager, $this->themesService, + $this->navigationManager, ); parent::setUp(); } - public function dataUpdateStylesheetSuccess() { + public static function dataUpdateStylesheetSuccess(): array { return [ ['name', str_repeat('a', 250), 'Saved'], ['url', 'https://nextcloud.com/' . str_repeat('a', 478), 'Saved'], @@ -126,14 +97,8 @@ class ThemingControllerTest extends TestCase { ]; } - /** - * @dataProvider dataUpdateStylesheetSuccess - * - * @param string $setting - * @param string $value - * @param string $message - */ - public function testUpdateStylesheetSuccess($setting, $value, $message) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetSuccess')] + public function testUpdateStylesheetSuccess(string $setting, string $value, string $message): void { $this->themingDefaults ->expects($this->once()) ->method('set') @@ -147,8 +112,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => $message, ], 'status' => 'success', @@ -157,31 +122,39 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value)); } - public function dataUpdateStylesheetError() { + public static function dataUpdateStylesheetError(): array { + $urls = [ + 'url' => 'web address', + 'imprintUrl' => 'legal notice address', + 'privacyUrl' => 'privacy policy address', + ]; + + $urlTests = []; + foreach ($urls as $urlKey => $urlName) { + // Check length limit + $urlTests[] = [$urlKey, 'http://example.com/' . str_repeat('a', 501), "The given {$urlName} is too long"]; + // Check potential evil javascript + $urlTests[] = [$urlKey, 'javascript:alert(1)', "The given {$urlName} is not a valid URL"]; + // Check XSS + $urlTests[] = [$urlKey, 'https://example.com/"><script/src="alert(\'1\')"><a/href/="', "The given {$urlName} is not a valid URL"]; + } + return [ ['name', str_repeat('a', 251), 'The given name is too long'], - ['url', 'http://example.com/' . str_repeat('a', 501), 'The given web address is too long'], - ['url', str_repeat('a', 501), 'The given web address is not a valid URL'], - ['url', 'javascript:alert(1)', 'The given web address is not a valid URL'], ['slogan', str_repeat('a', 501), 'The given slogan is too long'], - ['color', '0082C9', 'The given color is invalid'], - ['color', '#0082Z9', 'The given color is invalid'], - ['color', 'Nextcloud', 'The given color is invalid'], - ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'], - ['imprintUrl', '0082C9', 'The given legal notice address is not a valid URL'], - ['imprintUrl', 'javascript:foo', 'The given legal notice address is not a valid URL'], - ['privacyUrl', '#0082Z9', 'The given privacy policy address is not a valid URL'], + ['primary_color', '0082C9', 'The given color is invalid'], + ['primary_color', '#0082Z9', 'The given color is invalid'], + ['primary_color', 'Nextcloud', 'The given color is invalid'], + ['background_color', '0082C9', 'The given color is invalid'], + ['background_color', '#0082Z9', 'The given color is invalid'], + ['background_color', 'Nextcloud', 'The given color is invalid'], + + ...$urlTests, ]; } - /** - * @dataProvider dataUpdateStylesheetError - * - * @param string $setting - * @param string $value - * @param string $message - */ - public function testUpdateStylesheetError($setting, $value, $message) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateStylesheetError')] + public function testUpdateStylesheetError(string $setting, string $value, string $message): void { $this->themingDefaults ->expects($this->never()) ->method('set') @@ -195,8 +168,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => $message, ], 'status' => 'error', @@ -206,14 +179,14 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->updateStylesheet($setting, $value)); } - public function testUpdateLogoNoData() { + public function testUpdateLogoNoData(): void { $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('logo'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn(null); @@ -226,8 +199,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => 'No file uploaded', ], 'status' => 'failure', @@ -238,29 +211,56 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } + public function testUploadInvalidUploadKey(): void { + $this->request + ->expects($this->once()) + ->method('getParam') + ->with('key') + ->willReturn('invalid'); + $this->request + ->expects($this->never()) + ->method('getUploadedFile'); + $this->l10n + ->expects($this->any()) + ->method('t') + ->willReturnCallback(function ($str) { + return $str; + }); + + $expected = new DataResponse( + [ + 'data' + => [ + 'message' => 'Invalid key', + ], + 'status' => 'failure', + ], + Http::STATUS_BAD_REQUEST + ); + + $this->assertEquals($expected, $this->themingController->uploadImage()); + } + /** * Checks that trying to upload an SVG favicon without imagemagick * results in an unsupported media type response. - * - * @test - * @return void */ - public function testUploadSVGFaviconWithoutImagemagick() { + public function testUploadSVGFaviconWithoutImagemagick(): void { $this->imageManager ->method('shouldReplaceIcons') ->willReturn(false); $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('favicon'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ - 'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg', + 'tmp_name' => __DIR__ . '/../../../../tests/data/testimagelarge.svg', 'type' => 'image/svg', 'name' => 'testimagelarge.svg', 'error' => 0, @@ -278,8 +278,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => 'Unsupported image type', ], 'status' => 'failure' @@ -290,18 +290,18 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - public function testUpdateLogoInvalidMimeType() { + public function testUpdateLogoInvalidMimeType(): void { $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('logo'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ - 'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt', + 'tmp_name' => __DIR__ . '/../../../../tests/data/lorem.txt', 'type' => 'application/pdf', 'name' => 'logo.pdf', 'error' => 0, @@ -319,8 +319,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => 'Unsupported image type', ], 'status' => 'failure' @@ -331,7 +331,7 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - public function dataUpdateImages() { + public static function dataUpdateImages(): array { return [ ['image/jpeg', false], ['image/jpeg', true], @@ -342,20 +342,20 @@ class ThemingControllerTest extends TestCase { ]; } - /** @dataProvider dataUpdateImages */ - public function testUpdateLogoNormalLogoUpload($mimeType, $folderExists = true) { - $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg'; - $destination = \OC::$server->getTempManager()->getTemporaryFolder(); + #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdateImages')] + public function testUpdateLogoNormalLogoUpload(string $mimeType, bool $folderExists = true): void { + $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg'; + $destination = Server::get(ITempManager::class)->getTemporaryFolder(); touch($tmpLogo); copy(__DIR__ . '/../../../../tests/data/testimage.png', $tmpLogo); $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('logo'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ @@ -381,8 +381,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'name' => 'logo.svg', 'message' => 'Saved', 'url' => 'imageUrl', @@ -394,19 +394,18 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - /** @dataProvider dataUpdateImages */ - public function testUpdateLogoLoginScreenUpload($folderExists) { - $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . 'logo.png'; + public function testUpdateLogoLoginScreenUpload(): void { + $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . 'logo.png'; touch($tmpLogo); copy(__DIR__ . '/../../../../tests/data/desktopapp.png', $tmpLogo); $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('background'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ @@ -431,8 +430,8 @@ class ThemingControllerTest extends TestCase { ->willReturn('imageUrl'); $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'name' => 'logo.svg', 'message' => 'Saved', 'url' => 'imageUrl', @@ -443,18 +442,18 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - public function testUpdateLogoLoginScreenUploadWithInvalidImage() { - $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg'; + public function testUpdateLogoLoginScreenUploadWithInvalidImage(): void { + $tmpLogo = Server::get(ITempManager::class)->getTemporaryFolder() . '/logo.svg'; touch($tmpLogo); - file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip')); + file_put_contents($tmpLogo, file_get_contents(__DIR__ . '/../../../../tests/data/data.zip')); $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('logo'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ @@ -476,8 +475,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => 'Unsupported image type', ], 'status' => 'failure' @@ -487,7 +486,7 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - public function dataPhpUploadErrors() { + public static function dataPhpUploadErrors(): array { return [ [UPLOAD_ERR_INI_SIZE, 'The uploaded file exceeds the upload_max_filesize directive in php.ini'], [UPLOAD_ERR_FORM_SIZE, 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form'], @@ -499,17 +498,15 @@ class ThemingControllerTest extends TestCase { ]; } - /** - * @dataProvider dataPhpUploadErrors - */ - public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload($error, $expectedErrorMessage) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')] + public function testUpdateLogoLoginScreenUploadWithInvalidImageUpload(int $error, string $expectedErrorMessage): void { $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('background'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ @@ -527,8 +524,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => $expectedErrorMessage, ], 'status' => 'failure' @@ -538,17 +535,15 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - /** - * @dataProvider dataPhpUploadErrors - */ - public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataPhpUploadErrors')] + public function testUpdateLogoUploadWithInvalidImageUpload($error, $expectedErrorMessage): void { $this->request - ->expects($this->at(0)) + ->expects($this->once()) ->method('getParam') ->with('key') ->willReturn('background'); $this->request - ->expects($this->at(1)) + ->expects($this->once()) ->method('getUploadedFile') ->with('image') ->willReturn([ @@ -566,8 +561,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'message' => $expectedErrorMessage ], 'status' => 'failure' @@ -577,7 +572,7 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->uploadImage()); } - public function testUndo() { + public function testUndo(): void { $this->l10n ->expects($this->once()) ->method('t') @@ -591,8 +586,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'value' => 'MyValue', 'message' => 'Saved' ], @@ -602,15 +597,15 @@ class ThemingControllerTest extends TestCase { $this->assertEquals($expected, $this->themingController->undo('MySetting')); } - public function dataUndoDelete() { + public static function dataUndoDelete(): array { return [ [ 'backgroundMime', 'background' ], [ 'logoMime', 'logo' ] ]; } - /** @dataProvider dataUndoDelete */ - public function testUndoDelete($value, $filename) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUndoDelete')] + public function testUndoDelete(string $value, string $filename): void { $this->l10n ->expects($this->once()) ->method('t') @@ -624,8 +619,8 @@ class ThemingControllerTest extends TestCase { $expected = new DataResponse( [ - 'data' => - [ + 'data' + => [ 'value' => $value, 'message' => 'Saved', ], @@ -637,16 +632,16 @@ class ThemingControllerTest extends TestCase { - public function testGetLogoNotExistent() { + public function testGetLogoNotExistent(): void { $this->imageManager->method('getImage') ->with($this->equalTo('logo')) ->willThrowException(new NotFoundException()); - $expected = new Http\NotFoundResponse(); + $expected = new NotFoundResponse(); $this->assertEquals($expected, $this->themingController->getImage('logo')); } - public function testGetLogo() { + public function testGetLogo(): void { $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('logo.svg'); $file->method('getMTime')->willReturn(42); @@ -659,26 +654,26 @@ class ThemingControllerTest extends TestCase { ->with('theming', 'logoMime', '') ->willReturn('text/svg'); - @$expected = new Http\FileDisplayResponse($file); + @$expected = new FileDisplayResponse($file); $expected->cacheFor(3600); $expected->addHeader('Content-Type', 'text/svg'); $expected->addHeader('Content-Disposition', 'attachment; filename="logo"'); - $csp = new Http\ContentSecurityPolicy(); + $csp = new ContentSecurityPolicy(); $csp->allowInlineStyle(); $expected->setContentSecurityPolicy($csp); @$this->assertEquals($expected, $this->themingController->getImage('logo')); } - public function testGetLoginBackgroundNotExistent() { + public function testGetLoginBackgroundNotExistent(): void { $this->imageManager->method('getImage') ->with($this->equalTo('background')) ->willThrowException(new NotFoundException()); - $expected = new Http\NotFoundResponse(); + $expected = new NotFoundResponse(); $this->assertEquals($expected, $this->themingController->getImage('background')); } - public function testGetLoginBackground() { + public function testGetLoginBackground(): void { $file = $this->createMock(ISimpleFile::class); $file->method('getName')->willReturn('background.png'); $file->method('getMTime')->willReturn(42); @@ -692,17 +687,25 @@ class ThemingControllerTest extends TestCase { ->with('theming', 'backgroundMime', '') ->willReturn('image/png'); - @$expected = new Http\FileDisplayResponse($file); + @$expected = new FileDisplayResponse($file); $expected->cacheFor(3600); $expected->addHeader('Content-Type', 'image/png'); $expected->addHeader('Content-Disposition', 'attachment; filename="background"'); - $csp = new Http\ContentSecurityPolicy(); + $csp = new ContentSecurityPolicy(); $csp->allowInlineStyle(); $expected->setContentSecurityPolicy($csp); @$this->assertEquals($expected, $this->themingController->getImage('background')); } - public function testGetManifest() { + public static function dataGetManifest(): array { + return [ + [true], + [false], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetManifest')] + public function testGetManifest(bool $standalone): void { $this->config ->expects($this->once()) ->method('getAppValue') @@ -713,24 +716,26 @@ class ThemingControllerTest extends TestCase { ->method('getName') ->willReturn('Nextcloud'); $this->urlGenerator - ->expects($this->at(0)) + ->expects($this->once()) ->method('getBaseUrl') ->willReturn('localhost'); $this->urlGenerator - ->expects($this->at(1)) + ->expects($this->exactly(2)) ->method('linkToRoute') - ->with('theming.Icon.getTouchIcon', ['app' => 'core']) - ->willReturn('touchicon'); - $this->urlGenerator - ->expects($this->at(2)) - ->method('linkToRoute') - ->with('theming.Icon.getFavicon', ['app' => 'core']) - ->willReturn('favicon'); - $response = new Http\JSONResponse([ + ->willReturnMap([ + ['theming.Icon.getTouchIcon', ['app' => 'core'], 'touchicon'], + ['theming.Icon.getFavicon', ['app' => 'core'], 'favicon'], + ]); + $this->config + ->expects($this->exactly(2)) + ->method('getSystemValueBool') + ->with('theming.standalone_window.enabled', true) + ->willReturn($standalone); + $response = new JSONResponse([ 'name' => 'Nextcloud', 'start_url' => 'localhost', - 'icons' => - [ + 'icons' + => [ [ 'src' => 'touchicon?v=0', 'type' => 'image/png', @@ -742,7 +747,8 @@ class ThemingControllerTest extends TestCase { 'sizes' => '16x16' ] ], - 'display' => 'standalone', + 'display_override' => [$standalone ? 'minimal-ui' : ''], + 'display' => $standalone ? 'standalone' : 'browser', 'short_name' => 'Nextcloud', 'theme_color' => null, 'background_color' => null, |