From ee6f2738d8740c32e2cebae5c9023391c4d2e17d Mon Sep 17 00:00:00 2001 From: Simon Praetorius <simon@praetorius.me> Date: Sat, 7 Sep 2024 22:20:50 +0200 Subject: [PATCH] [TASK] Refactor AssetCollector tests In preparation for changes on `AssetRenderer`, most of the unit tests are converted to functional tests. The test cases are preserved, but duplicated to cover both the new functional and the old unit tests. Resolves: #104854 Releases: main Change-Id: I3ab5bad81d7554061ca4d2ef61946e8282dc8f85 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/85921 Reviewed-by: Simon Praetorius <simon@praetorius.me> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: Benni Mack <benni@typo3.org> Reviewed-by: Simon Schaufelberger <simonschaufi+typo3@gmail.com> Tested-by: Simon Praetorius <simon@praetorius.me> --- .../Functional/Page/AssetRendererTest.php | 359 +++++++++++ .../Tests/Unit/Page/AssetCollectorTest.php | 558 +++++++++++++++--- .../Tests/Unit/Page/AssetDataProvider.php | 530 ----------------- .../Tests/Unit/Page/AssetRendererTest.php | 94 +-- 4 files changed, 846 insertions(+), 695 deletions(-) create mode 100644 typo3/sysext/core/Tests/Functional/Page/AssetRendererTest.php delete mode 100644 typo3/sysext/core/Tests/Unit/Page/AssetDataProvider.php diff --git a/typo3/sysext/core/Tests/Functional/Page/AssetRendererTest.php b/typo3/sysext/core/Tests/Functional/Page/AssetRendererTest.php new file mode 100644 index 000000000000..8d4e937482f9 --- /dev/null +++ b/typo3/sysext/core/Tests/Functional/Page/AssetRendererTest.php @@ -0,0 +1,359 @@ +<?php + +declare(strict_types=1); + +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +namespace TYPO3\CMS\Core\Tests\Functional\Page; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Page\AssetCollector; +use TYPO3\CMS\Core\Page\AssetRenderer; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; + +final class AssetRendererTest extends FunctionalTestCase +{ + protected bool $resetSingletonInstances = true; + + protected array $configurationToUseInTestInstance = [ + 'BE' => [ + 'versionNumberInFilename' => false, + ], + ]; + + public static function filesDataProvider(): array + { + return [ + '1 file from fileadmin' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file from extension' => [ + 'files' => [ + ['file1', 'EXT:core/Resource/Public/foo.ext', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file with suspicious source' => [ + 'files' => [ + ['file1', '"><script>alert(1)</script><x "', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href=""><script>alert(1)</script><x "" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src=""><script>alert(1)</script><x ""></script>', + 'js_prio' => '', + ], + ], + '1 file from external source' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="https://typo3.org/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="https://typo3.org/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file from external source with one parameter' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext?foo=bar', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="https://typo3.org/foo.ext?foo=bar" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="https://typo3.org/foo.ext?foo=bar"></script>', + 'js_prio' => '', + ], + ], + '1 file from external source with two parameters' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext?foo=bar&bar=baz', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="https://typo3.org/foo.ext?foo=bar&bar=baz" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="https://typo3.org/foo.ext?foo=bar&bar=baz"></script>', + 'js_prio' => '', + ], + ], + '2 files' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >' . PHP_EOL . '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>' . PHP_EOL . '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '2 files with override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], + ['file1', 'EXT:core/Resource/Public/bar.ext', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="typo3/sysext/core/Resource/Public/bar.ext" rel="stylesheet" >' . PHP_EOL . '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="typo3/sysext/core/Resource/Public/bar.ext"></script>' . PHP_EOL . '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file with attributes' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['rel' => 'foo'], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link rel="foo" href="fileadmin/foo.ext" >', + 'css_prio' => '', + 'js_no_prio' => '<script rel="foo" src="fileadmin/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file with controlled type' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['type' => 'module'], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link type="module" href="fileadmin/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script type="module" src="fileadmin/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file with attributes override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['rel' => 'foo', 'another' => 'keep on override'], []], + ['file1', 'fileadmin/foo.ext', ['rel' => 'bar'], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link rel="bar" another="keep on override" href="fileadmin/foo.ext" >', + 'css_prio' => '', + 'js_no_prio' => '<script rel="bar" another="keep on override" src="fileadmin/foo.ext"></script>', + 'js_prio' => '', + ], + ], + '1 file with options' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], ['priority' => true]], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '', + 'css_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', + 'js_no_prio' => '', + 'js_prio' => '<script src="fileadmin/foo.ext"></script>', + ], + ], + '1 file with options override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], ['priority' => true, 'another' => 'keep on override']], + ['file1', 'fileadmin/foo.ext', [], ['priority' => false]], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>', + 'js_prio' => '', + ], + ], + ]; + } + + #[DataProvider('filesDataProvider')] + #[Test] + public function styleSheets(array $files, array $expectedMarkup): void + { + $assetCollector = $this->get(AssetCollector::class); + $assetRenderer = $this->get(AssetRenderer::class); + foreach ($files as $file) { + [$identifier, $source, $attributes, $options] = $file; + $assetCollector->addStyleSheet($identifier, $source, $attributes, $options); + } + self::assertSame($expectedMarkup['css_no_prio'], $assetRenderer->renderStyleSheets()); + self::assertSame($expectedMarkup['css_prio'], $assetRenderer->renderStyleSheets(true)); + } + + #[DataProvider('filesDataProvider')] + #[Test] + public function javaScript(array $files, array $expectedMarkup): void + { + $assetCollector = $this->get(AssetCollector::class); + $assetRenderer = $this->get(AssetRenderer::class); + foreach ($files as $file) { + [$identifier, $source, $attributes, $options] = $file; + $assetCollector->addJavaScript($identifier, $source, $attributes, $options); + } + self::assertSame($expectedMarkup['js_no_prio'], $assetRenderer->renderJavaScript()); + self::assertSame($expectedMarkup['js_prio'], $assetRenderer->renderJavaScript(true)); + } + + public static function inlineDataProvider(): array + { + return [ + 'simple data' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style>foo bar baz</style>', + 'css_prio' => '', + 'js_no_prio' => '<script>foo bar baz</script>', + 'js_prio' => '', + ], + ], + '2 times simple data' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ['identifier_2', 'bar baz foo', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style>foo bar baz</style>' . PHP_EOL . '<style>bar baz foo</style>', + 'css_prio' => '', + 'js_no_prio' => '<script>foo bar baz</script>' . PHP_EOL . '<script>bar baz foo</script>', + 'js_prio' => '', + ], + ], + '2 times simple data with override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ['identifier_2', 'bar baz foo', [], []], + ['identifier_1', 'baz foo bar', [], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style>baz foo bar</style>' . PHP_EOL . '<style>bar baz foo</style>', + 'css_prio' => '', + 'js_no_prio' => '<script>baz foo bar</script>' . PHP_EOL . '<script>bar baz foo</script>', + 'js_prio' => '', + ], + ], + 'simple data with attributes' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', ['rel' => 'foo'], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style rel="foo">foo bar baz</style>', + 'css_prio' => '', + 'js_no_prio' => '<script rel="foo">foo bar baz</script>', + 'js_prio' => '', + ], + ], + 'simple data with attributes override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', ['rel' => 'foo', 'another' => 'keep on override'], []], + ['identifier_1', 'foo bar baz', ['rel' => 'bar'], []], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style rel="bar" another="keep on override">foo bar baz</style>', + 'css_prio' => '', + 'js_no_prio' => '<script rel="bar" another="keep on override">foo bar baz</script>', + 'js_prio' => '', + ], + ], + 'simple data with options' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], ['priority' => true]], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '', + 'css_prio' => '<style>foo bar baz</style>', + 'js_no_prio' => '', + 'js_prio' => '<script>foo bar baz</script>', + ], + ], + 'simple data with options override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], ['priority' => true, 'another' => 'keep on override']], + ['identifier_1', 'foo bar baz', [], ['priority' => false]], + ], + 'expectedMarkup' => [ + 'css_no_prio' => '<style>foo bar baz</style>', + 'css_prio' => '', + 'js_no_prio' => '<script>foo bar baz</script>', + 'js_prio' => '', + ], + ], + ]; + } + + #[DataProvider('inlineDataProvider')] + #[Test] + public function inlineJavaScript(array $sources, array $expectedMarkup): void + { + $assetCollector = $this->get(AssetCollector::class); + $assetRenderer = $this->get(AssetRenderer::class); + foreach ($sources as $source) { + [$identifier, $source, $attributes, $options] = $source; + $assetCollector->addInlineJavaScript($identifier, $source, $attributes, $options); + } + self::assertSame($expectedMarkup['js_no_prio'], $assetRenderer->renderInlineJavaScript()); + self::assertSame($expectedMarkup['js_prio'], $assetRenderer->renderInlineJavaScript(true)); + } + + #[DataProvider('inlineDataProvider')] + #[Test] + public function inlineStyleSheets(array $sources, array $expectedMarkup): void + { + $assetCollector = $this->get(AssetCollector::class); + $assetRenderer = $this->get(AssetRenderer::class); + foreach ($sources as $source) { + [$identifier, $source, $attributes, $options] = $source; + $assetCollector->addInlineStyleSheet($identifier, $source, $attributes, $options); + } + self::assertSame($expectedMarkup['css_no_prio'], $assetRenderer->renderInlineStyleSheets()); + self::assertSame($expectedMarkup['css_prio'], $assetRenderer->renderInlineStyleSheets(true)); + } + + public static function modifyAssetUriEventDataProvider(): array + { + return [ + 'no priority' => [ + 'source' => 'fileadmin/foo.ext', + 'options' => ['priority' => false, 'anotherOption' => true], + 'expectedMarkup' => [ + 'css_no_prio' => '<link href="fileadmin/foo.ext?someSuffix" rel="stylesheet" >', + 'css_prio' => '', + 'js_no_prio' => '<script src="fileadmin/foo.ext?someSuffix"></script>', + 'js_prio' => '', + ], + ], + 'priority' => [ + 'source' => 'fileadmin/foo.ext', + 'options' => ['priority' => true, 'anotherOption' => true], + 'expectedMarkup' => [ + 'css_no_prio' => '', + 'css_prio' => '<link href="fileadmin/foo.ext?someSuffix" rel="stylesheet" >', + 'js_no_prio' => '', + 'js_prio' => '<script src="fileadmin/foo.ext?someSuffix"></script>', + ], + ], + ]; + } +} diff --git a/typo3/sysext/core/Tests/Unit/Page/AssetCollectorTest.php b/typo3/sysext/core/Tests/Unit/Page/AssetCollectorTest.php index f59bce89a641..b3e6699a966c 100644 --- a/typo3/sysext/core/Tests/Unit/Page/AssetCollectorTest.php +++ b/typo3/sysext/core/Tests/Unit/Page/AssetCollectorTest.php @@ -17,164 +17,528 @@ declare(strict_types=1); namespace TYPO3\CMS\Core\Tests\Unit\Page; -use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use TYPO3\CMS\Core\Page\AssetCollector; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; final class AssetCollectorTest extends UnitTestCase { - protected bool $resetSingletonInstances = true; - protected ?AssetCollector $assetCollector; - - public function setUp(): void + public static function filesDataProvider(): array { - parent::setUp(); - $this->assetCollector = new AssetCollector(); + return [ + '1 file from fileadmin' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file from extension' => [ + 'files' => [ + ['file1', 'EXT:core/Resource/Public/foo.ext', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'EXT:core/Resource/Public/foo.ext', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file with suspicious source' => [ + 'files' => [ + ['file1', '"><script>alert(1)</script><x "', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => '"><script>alert(1)</script><x "', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file from external source' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'https://typo3.org/foo.ext', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file from external source with one parameter' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext?foo=bar', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'https://typo3.org/foo.ext?foo=bar', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file from external source with two parameters' => [ + 'files' => [ + ['file1', 'https://typo3.org/foo.ext?foo=bar&bar=baz', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'https://typo3.org/foo.ext?foo=bar&bar=baz', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '2 files' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [], + 'options' => [], + ], + 'file2' => [ + 'source' => 'EXT:core/Resource/Public/foo.ext', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '2 files with override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], []], + ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], + ['file1', 'EXT:core/Resource/Public/bar.ext', [], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'EXT:core/Resource/Public/bar.ext', + 'attributes' => [], + 'options' => [], + ], + 'file2' => [ + 'source' => 'EXT:core/Resource/Public/foo.ext', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '1 file with attributes' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['rel' => 'foo'], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [ + 'rel' => 'foo', + ], + 'options' => [], + ], + ], + ], + '1 file with controlled type' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['type' => 'module'], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [ + 'type' => 'module', + ], + 'options' => [], + ], + ], + ], + '1 file with attributes override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', ['rel' => 'foo', 'another' => 'keep on override'], []], + ['file1', 'fileadmin/foo.ext', ['rel' => 'bar'], []], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [ + 'rel' => 'bar', + 'another' => 'keep on override', + ], + 'options' => [], + ], + ], + ], + '1 file with options' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], ['priority' => true]], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [], + 'options' => [ + 'priority' => true, + ], + ], + ], + ], + '1 file with options override' => [ + 'files' => [ + ['file1', 'fileadmin/foo.ext', [], ['priority' => true, 'another' => 'keep on override']], + ['file1', 'fileadmin/foo.ext', [], ['priority' => false]], + ], + 'expectedResult' => [ + 'file1' => [ + 'source' => 'fileadmin/foo.ext', + 'attributes' => [], + 'options' => [ + 'priority' => false, + 'another' => 'keep on override', + ], + ], + ], + ], + ]; } - #[DataProviderExternal(\TYPO3\CMS\Core\Tests\Unit\Page\AssetDataProvider::class, 'filesDataProvider')] + #[DataProvider('filesDataProvider')] #[Test] public function styleSheets(array $files, array $expectedResult): void { + $assetCollector = new AssetCollector(); foreach ($files as $file) { [$identifier, $source, $attributes, $options] = $file; - $this->assetCollector->addStyleSheet($identifier, $source, $attributes, $options); - self::assertTrue($this->assetCollector->hasStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasInlineStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasInlineJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasMedia($identifier)); + $assetCollector->addStyleSheet($identifier, $source, $attributes, $options); + self::assertTrue($assetCollector->hasStyleSheet($identifier)); + self::assertFalse($assetCollector->hasInlineStyleSheet($identifier)); + self::assertFalse($assetCollector->hasInlineJavaScript($identifier)); + self::assertFalse($assetCollector->hasJavaScript($identifier)); + self::assertFalse($assetCollector->hasMedia($identifier)); } - self::assertSame($expectedResult, $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame($expectedResult, $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getMedia()); foreach ($files as $file) { [$identifier] = $file; - $this->assetCollector->removeStyleSheet($identifier); + $assetCollector->removeStyleSheet($identifier); } - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getMedia()); } - #[DataProviderExternal(\TYPO3\CMS\Core\Tests\Unit\Page\AssetDataProvider::class, 'filesDataProvider')] + #[DataProvider('filesDataProvider')] #[Test] public function javaScript(array $files, array $expectedResult): void { + $assetCollector = new AssetCollector(); foreach ($files as $file) { [$identifier, $source, $attributes, $options] = $file; - $this->assetCollector->addJavaScript($identifier, $source, $attributes, $options); - self::assertTrue($this->assetCollector->hasJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasInlineStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasInlineJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasMedia($identifier)); + $assetCollector->addJavaScript($identifier, $source, $attributes, $options); + self::assertTrue($assetCollector->hasJavaScript($identifier)); + self::assertFalse($assetCollector->hasInlineStyleSheet($identifier)); + self::assertFalse($assetCollector->hasInlineJavaScript($identifier)); + self::assertFalse($assetCollector->hasStyleSheet($identifier)); + self::assertFalse($assetCollector->hasMedia($identifier)); } - self::assertSame($expectedResult, $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame($expectedResult, $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); foreach ($files as $file) { [$identifier] = $file; - $this->assetCollector->removeJavaScript($identifier); + $assetCollector->removeJavaScript($identifier); } - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); + } + + public static function inlineDataProvider(): array + { + return [ + 'simple data' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '2 times simple data' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ['identifier_2', 'bar baz foo', [], []], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [], + 'options' => [], + ], + 'identifier_2' => [ + 'source' => 'bar baz foo', + 'attributes' => [], + 'options' => [], + ], + ], + ], + '2 times simple data with override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], []], + ['identifier_2', 'bar baz foo', [], []], + ['identifier_1', 'baz foo bar', [], []], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'baz foo bar', + 'attributes' => [], + 'options' => [], + ], + 'identifier_2' => [ + 'source' => 'bar baz foo', + 'attributes' => [], + 'options' => [], + ], + ], + ], + 'simple data with attributes' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', ['rel' => 'foo'], []], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [ + 'rel' => 'foo', + ], + 'options' => [], + ], + ], + ], + 'simple data with attributes override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', ['rel' => 'foo', 'another' => 'keep on override'], []], + ['identifier_1', 'foo bar baz', ['rel' => 'bar'], []], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [ + 'rel' => 'bar', + 'another' => 'keep on override', + ], + 'options' => [], + ], + ], + ], + 'simple data with options' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], ['priority' => true]], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [], + 'options' => [ + 'priority' => true, + ], + ], + ], + ], + 'simple data with options override' => [ + 'sources' => [ + ['identifier_1', 'foo bar baz', [], ['priority' => true, 'another' => 'keep on override']], + ['identifier_1', 'foo bar baz', [], ['priority' => false]], + ], + 'expectedResult' => [ + 'identifier_1' => [ + 'source' => 'foo bar baz', + 'attributes' => [], + 'options' => [ + 'priority' => false, + 'another' => 'keep on override', + ], + ], + ], + ], + ]; } - #[DataProviderExternal(\TYPO3\CMS\Core\Tests\Unit\Page\AssetDataProvider::class, 'inlineDataProvider')] + #[DataProvider('inlineDataProvider')] #[Test] public function inlineJavaScript(array $sources, array $expectedResult): void { + $assetCollector = new AssetCollector(); foreach ($sources as $source) { [$identifier, $source, $attributes, $options] = $source; - $this->assetCollector->addInlineJavaScript($identifier, $source, $attributes, $options); - self::assertTrue($this->assetCollector->hasInlineJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasInlineStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasMedia($identifier)); + $assetCollector->addInlineJavaScript($identifier, $source, $attributes, $options); + self::assertTrue($assetCollector->hasInlineJavaScript($identifier)); + self::assertFalse($assetCollector->hasInlineStyleSheet($identifier)); + self::assertFalse($assetCollector->hasJavaScript($identifier)); + self::assertFalse($assetCollector->hasStyleSheet($identifier)); + self::assertFalse($assetCollector->hasMedia($identifier)); } - self::assertSame($expectedResult, $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame($expectedResult, $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); foreach ($sources as $source) { [$identifier] = $source; - $this->assetCollector->removeInlineJavaScript($identifier); + $assetCollector->removeInlineJavaScript($identifier); } - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); } - #[DataProviderExternal(\TYPO3\CMS\Core\Tests\Unit\Page\AssetDataProvider::class, 'inlineDataProvider')] + #[DataProvider('inlineDataProvider')] #[Test] public function inlineStyles(array $sources, array $expectedResult): void { + $assetCollector = new AssetCollector(); foreach ($sources as $source) { [$identifier, $source, $attributes, $options] = $source; - $this->assetCollector->addInlineStyleSheet($identifier, $source, $attributes, $options); - self::assertTrue($this->assetCollector->hasInlineStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasInlineJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasJavaScript($identifier)); - self::assertFalse($this->assetCollector->hasStyleSheet($identifier)); - self::assertFalse($this->assetCollector->hasMedia($identifier)); + $assetCollector->addInlineStyleSheet($identifier, $source, $attributes, $options); + self::assertTrue($assetCollector->hasInlineStyleSheet($identifier)); + self::assertFalse($assetCollector->hasInlineJavaScript($identifier)); + self::assertFalse($assetCollector->hasJavaScript($identifier)); + self::assertFalse($assetCollector->hasStyleSheet($identifier)); + self::assertFalse($assetCollector->hasMedia($identifier)); } - self::assertSame($expectedResult, $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame($expectedResult, $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); foreach ($sources as $source) { [$identifier] = $source; - $this->assetCollector->removeInlineStyleSheet($identifier); + $assetCollector->removeInlineStyleSheet($identifier); } - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); - self::assertSame([], $this->assetCollector->getMedia()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); + } + + public static function mediaDataProvider(): array + { + return [ + '1 image no additional information' => [ + 'images' => [ + ['fileadmin/foo.png', []], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => [], + ], + ], + '2 images no additional information' => [ + 'images' => [ + ['fileadmin/foo.png', []], + ['fileadmin/bar.png', []], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => [], + 'fileadmin/bar.png' => [], + ], + ], + '1 image with additional information' => [ + 'images' => [ + ['fileadmin/foo.png', ['foo' => 'bar']], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => ['foo' => 'bar'], + ], + ], + '2 images with additional information' => [ + 'images' => [ + ['fileadmin/foo.png', ['foo' => 'bar']], + ['fileadmin/bar.png', ['foo' => 'baz']], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => ['foo' => 'bar'], + 'fileadmin/bar.png' => ['foo' => 'baz'], + ], + ], + '2 images with additional information override' => [ + 'images' => [ + ['fileadmin/foo.png', ['foo' => 'bar']], + ['fileadmin/bar.png', ['foo' => 'baz']], + ['fileadmin/foo.png', ['foo' => 'baz']], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => ['foo' => 'baz'], + 'fileadmin/bar.png' => ['foo' => 'baz'], + ], + ], + '2 images with additional information override keep existing' => [ + 'images' => [ + ['fileadmin/foo.png', ['foo' => 'bar', 'bar' => 'baz']], + ['fileadmin/bar.png', ['foo' => 'baz']], + ['fileadmin/foo.png', ['foo' => 'baz']], + ], + 'expectedResult' => [ + 'fileadmin/foo.png' => ['foo' => 'baz', 'bar' => 'baz'], + 'fileadmin/bar.png' => ['foo' => 'baz'], + ], + ], + ]; } - #[DataProviderExternal(\TYPO3\CMS\Core\Tests\Unit\Page\AssetDataProvider::class, 'mediaDataProvider')] + #[DataProvider('mediaDataProvider')] #[Test] public function media(array $images, array $expectedResult): void { + $assetCollector = new AssetCollector(); foreach ($images as $image) { [$fileName, $additionalInformation] = $image; - $this->assetCollector->addMedia($fileName, $additionalInformation); - self::assertTrue($this->assetCollector->hasMedia($fileName)); - self::assertFalse($this->assetCollector->hasInlineStyleSheet($fileName)); - self::assertFalse($this->assetCollector->hasInlineJavaScript($fileName)); - self::assertFalse($this->assetCollector->hasJavaScript($fileName)); - self::assertFalse($this->assetCollector->hasStyleSheet($fileName)); + $assetCollector->addMedia($fileName, $additionalInformation); + self::assertTrue($assetCollector->hasMedia($fileName)); + self::assertFalse($assetCollector->hasInlineStyleSheet($fileName)); + self::assertFalse($assetCollector->hasInlineJavaScript($fileName)); + self::assertFalse($assetCollector->hasJavaScript($fileName)); + self::assertFalse($assetCollector->hasStyleSheet($fileName)); } - self::assertSame($expectedResult, $this->assetCollector->getMedia()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); + self::assertSame($expectedResult, $assetCollector->getMedia()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); foreach ($images as $image) { [$fileName] = $image; - $this->assetCollector->removeMedia($fileName); + $assetCollector->removeMedia($fileName); } - self::assertSame([], $this->assetCollector->getMedia()); - self::assertSame([], $this->assetCollector->getInlineStyleSheets()); - self::assertSame([], $this->assetCollector->getInlineJavaScripts()); - self::assertSame([], $this->assetCollector->getJavaScripts()); - self::assertSame([], $this->assetCollector->getStyleSheets()); + self::assertSame([], $assetCollector->getMedia()); + self::assertSame([], $assetCollector->getInlineStyleSheets()); + self::assertSame([], $assetCollector->getInlineJavaScripts()); + self::assertSame([], $assetCollector->getJavaScripts()); + self::assertSame([], $assetCollector->getStyleSheets()); } } diff --git a/typo3/sysext/core/Tests/Unit/Page/AssetDataProvider.php b/typo3/sysext/core/Tests/Unit/Page/AssetDataProvider.php deleted file mode 100644 index cf9568411a4e..000000000000 --- a/typo3/sysext/core/Tests/Unit/Page/AssetDataProvider.php +++ /dev/null @@ -1,530 +0,0 @@ -<?php - -declare(strict_types=1); - -/* - * This file is part of the TYPO3 CMS project. - * - * It is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, either version 2 - * of the License, or any later version. - * - * For the full copyright and license information, please read the - * LICENSE.txt file that was distributed with this source code. - * - * The TYPO3 project - inspiring people to share! - */ - -namespace TYPO3\CMS\Core\Tests\Unit\Page; - -use TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent; -use TYPO3\CMS\Core\Page\Event\BeforeStylesheetsRenderingEvent; - -class AssetDataProvider -{ - public static function filesDataProvider(): array - { - return [ - '1 file from fileadmin' => [ - [ - ['file1', 'fileadmin/foo.ext', [], []], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file from extension' => [ - [ - ['file1', 'EXT:core/Resource/Public/foo.ext', [], []], - ], - [ - 'file1' => [ - 'source' => 'EXT:core/Resource/Public/foo.ext', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file with suspicious source' => [ - [ - ['file1', '"><script>alert(1)</script><x "', [], []], - ], - [ - 'file1' => [ - 'source' => '"><script>alert(1)</script><x "', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href=""><script>alert(1)</script><x "" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src=""><script>alert(1)</script><x ""></script>', - 'js_prio' => '', - ], - ], - '1 file from external source' => [ - [ - ['file1', 'https://typo3.org/foo.ext', [], []], - ], - [ - 'file1' => [ - 'source' => 'https://typo3.org/foo.ext', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="https://typo3.org/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="https://typo3.org/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file from external source with one parameter' => [ - [ - ['file1', 'https://typo3.org/foo.ext?foo=bar', [], []], - ], - [ - 'file1' => [ - 'source' => 'https://typo3.org/foo.ext?foo=bar', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="https://typo3.org/foo.ext?foo=bar" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="https://typo3.org/foo.ext?foo=bar"></script>', - 'js_prio' => '', - ], - ], - '1 file from external source with two parameters' => [ - [ - ['file1', 'https://typo3.org/foo.ext?foo=bar&bar=baz', [], []], - ], - [ - 'file1' => [ - 'source' => 'https://typo3.org/foo.ext?foo=bar&bar=baz', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="https://typo3.org/foo.ext?foo=bar&bar=baz" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="https://typo3.org/foo.ext?foo=bar&bar=baz"></script>', - 'js_prio' => '', - ], - ], - '2 files' => [ - [ - ['file1', 'fileadmin/foo.ext', [], []], - ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [], - 'options' => [], - ], - 'file2' => [ - 'source' => 'EXT:core/Resource/Public/foo.ext', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >' . LF . '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>' . LF . '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '2 files with override' => [ - [ - ['file1', 'fileadmin/foo.ext', [], []], - ['file2', 'EXT:core/Resource/Public/foo.ext', [], []], - ['file1', 'EXT:core/Resource/Public/bar.ext', [], []], - ], - [ - 'file1' => [ - 'source' => 'EXT:core/Resource/Public/bar.ext', - 'attributes' => [], - 'options' => [], - ], - 'file2' => [ - 'source' => 'EXT:core/Resource/Public/foo.ext', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link href="typo3/sysext/core/Resource/Public/bar.ext" rel="stylesheet" >' . LF . '<link href="typo3/sysext/core/Resource/Public/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="typo3/sysext/core/Resource/Public/bar.ext"></script>' . LF . '<script src="typo3/sysext/core/Resource/Public/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file with attributes' => [ - [ - ['file1', 'fileadmin/foo.ext', ['rel' => 'foo'], []], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [ - 'rel' => 'foo', - ], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link rel="foo" href="fileadmin/foo.ext" >', - 'css_prio' => '', - 'js_no_prio' => '<script rel="foo" src="fileadmin/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file with controlled type' => [ - [ - ['file1', 'fileadmin/foo.ext', ['type' => 'module'], []], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [ - 'type' => 'module', - ], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link type="module" href="fileadmin/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script type="module" src="fileadmin/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file with attributes override' => [ - [ - ['file1', 'fileadmin/foo.ext', ['rel' => 'foo', 'another' => 'keep on override'], []], - ['file1', 'fileadmin/foo.ext', ['rel' => 'bar'], []], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [ - 'rel' => 'bar', - 'another' => 'keep on override', - ], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<link rel="bar" another="keep on override" href="fileadmin/foo.ext" >', - 'css_prio' => '', - 'js_no_prio' => '<script rel="bar" another="keep on override" src="fileadmin/foo.ext"></script>', - 'js_prio' => '', - ], - ], - '1 file with options' => [ - [ - ['file1', 'fileadmin/foo.ext', [], ['priority' => true]], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [], - 'options' => [ - 'priority' => true, - ], - ], - ], - [ - 'css_no_prio' => '', - 'css_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', - 'js_no_prio' => '', - 'js_prio' => '<script src="fileadmin/foo.ext"></script>', - ], - ], - '1 file with options override' => [ - [ - ['file1', 'fileadmin/foo.ext', [], ['priority' => true, 'another' => 'keep on override']], - ['file1', 'fileadmin/foo.ext', [], ['priority' => false]], - ], - [ - 'file1' => [ - 'source' => 'fileadmin/foo.ext', - 'attributes' => [], - 'options' => [ - 'priority' => false, - 'another' => 'keep on override', - ], - ], - ], - [ - 'css_no_prio' => '<link href="fileadmin/foo.ext" rel="stylesheet" >', - 'css_prio' => '', - 'js_no_prio' => '<script src="fileadmin/foo.ext"></script>', - 'js_prio' => '', - ], - ], - ]; - } - - public static function inlineDataProvider(): array - { - return [ - 'simple data' => [ - [ - ['identifier_1', 'foo bar baz', [], []], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<style>foo bar baz</style>', - 'css_prio' => '', - 'js_no_prio' => '<script>foo bar baz</script>', - 'js_prio' => '', - ], - ], - '2 times simple data' => [ - [ - ['identifier_1', 'foo bar baz', [], []], - ['identifier_2', 'bar baz foo', [], []], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [], - 'options' => [], - ], - 'identifier_2' => [ - 'source' => 'bar baz foo', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<style>foo bar baz</style>' . LF . '<style>bar baz foo</style>', - 'css_prio' => '', - 'js_no_prio' => '<script>foo bar baz</script>' . LF . '<script>bar baz foo</script>', - 'js_prio' => '', - ], - ], - '2 times simple data with override' => [ - [ - ['identifier_1', 'foo bar baz', [], []], - ['identifier_2', 'bar baz foo', [], []], - ['identifier_1', 'baz foo bar', [], []], - ], - [ - 'identifier_1' => [ - 'source' => 'baz foo bar', - 'attributes' => [], - 'options' => [], - ], - 'identifier_2' => [ - 'source' => 'bar baz foo', - 'attributes' => [], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<style>baz foo bar</style>' . LF . '<style>bar baz foo</style>', - 'css_prio' => '', - 'js_no_prio' => '<script>baz foo bar</script>' . LF . '<script>bar baz foo</script>', - 'js_prio' => '', - ], - ], - 'simple data with attributes' => [ - [ - ['identifier_1', 'foo bar baz', ['rel' => 'foo'], []], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [ - 'rel' => 'foo', - ], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<style rel="foo">foo bar baz</style>', - 'css_prio' => '', - 'js_no_prio' => '<script rel="foo">foo bar baz</script>', - 'js_prio' => '', - ], - ], - 'simple data with attributes override' => [ - [ - ['identifier_1', 'foo bar baz', ['rel' => 'foo', 'another' => 'keep on override'], []], - ['identifier_1', 'foo bar baz', ['rel' => 'bar'], []], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [ - 'rel' => 'bar', - 'another' => 'keep on override', - ], - 'options' => [], - ], - ], - [ - 'css_no_prio' => '<style rel="bar" another="keep on override">foo bar baz</style>', - 'css_prio' => '', - 'js_no_prio' => '<script rel="bar" another="keep on override">foo bar baz</script>', - 'js_prio' => '', - ], - ], - 'simple data with options' => [ - [ - ['identifier_1', 'foo bar baz', [], ['priority' => true]], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [], - 'options' => [ - 'priority' => true, - ], - ], - ], - [ - 'css_no_prio' => '', - 'css_prio' => '<style>foo bar baz</style>', - 'js_no_prio' => '', - 'js_prio' => '<script>foo bar baz</script>', - ], - ], - 'simple data with options override' => [ - [ - ['identifier_1', 'foo bar baz', [], ['priority' => true, 'another' => 'keep on override']], - ['identifier_1', 'foo bar baz', [], ['priority' => false]], - ], - [ - 'identifier_1' => [ - 'source' => 'foo bar baz', - 'attributes' => [], - 'options' => [ - 'priority' => false, - 'another' => 'keep on override', - ], - ], - ], - [ - 'css_no_prio' => '<style>foo bar baz</style>', - 'css_prio' => '', - 'js_no_prio' => '<script>foo bar baz</script>', - 'js_prio' => '', - ], - ], - ]; - } - - public static function mediaDataProvider(): array - { - return [ - '1 image no additional information' => [ - [ - ['fileadmin/foo.png', []], - ], - [ - 'fileadmin/foo.png' => [], - ], - ], - '2 images no additional information' => [ - [ - ['fileadmin/foo.png', []], - ['fileadmin/bar.png', []], - ], - [ - 'fileadmin/foo.png' => [], - 'fileadmin/bar.png' => [], - ], - ], - '1 image with additional information' => [ - [ - ['fileadmin/foo.png', ['foo' => 'bar']], - ], - [ - 'fileadmin/foo.png' => ['foo' => 'bar'], - ], - ], - '2 images with additional information' => [ - [ - ['fileadmin/foo.png', ['foo' => 'bar']], - ['fileadmin/bar.png', ['foo' => 'baz']], - ], - [ - 'fileadmin/foo.png' => ['foo' => 'bar'], - 'fileadmin/bar.png' => ['foo' => 'baz'], - ], - ], - '2 images with additional information override' => [ - [ - ['fileadmin/foo.png', ['foo' => 'bar']], - ['fileadmin/bar.png', ['foo' => 'baz']], - ['fileadmin/foo.png', ['foo' => 'baz']], - ], - [ - 'fileadmin/foo.png' => ['foo' => 'baz'], - 'fileadmin/bar.png' => ['foo' => 'baz'], - ], - ], - '2 images with additional information override keep existing' => [ - [ - ['fileadmin/foo.png', ['foo' => 'bar', 'bar' => 'baz']], - ['fileadmin/bar.png', ['foo' => 'baz']], - ['fileadmin/foo.png', ['foo' => 'baz']], - ], - [ - 'fileadmin/foo.png' => ['foo' => 'baz', 'bar' => 'baz'], - 'fileadmin/bar.png' => ['foo' => 'baz'], - ], - ], - ]; - } - - /** - * cross-product of all combinations of AssetRenderer::render*() methods and priorities - * @return array[] [render method name, isInline, isPriority, event class] - */ - public static function renderMethodsAndEventsDataProvider(): array - { - return [ - ['renderInlineJavaScript', true, true, BeforeJavaScriptsRenderingEvent::class], - ['renderInlineJavaScript', true, false, BeforeJavaScriptsRenderingEvent::class], - ['renderJavaScript', false, true, BeforeJavaScriptsRenderingEvent::class], - ['renderJavaScript', false, false, BeforeJavaScriptsRenderingEvent::class], - ['renderInlineStylesheets', true, true, BeforeStylesheetsRenderingEvent::class], - ['renderInlineStylesheets', true, false, BeforeStylesheetsRenderingEvent::class], - ['renderStylesheets', false, true, BeforeStylesheetsRenderingEvent::class], - ['renderStylesheets', false, false, BeforeStylesheetsRenderingEvent::class], - ]; - } -} diff --git a/typo3/sysext/core/Tests/Unit/Page/AssetRendererTest.php b/typo3/sysext/core/Tests/Unit/Page/AssetRendererTest.php index c442712585fd..9f61bfe03b16 100644 --- a/typo3/sysext/core/Tests/Unit/Page/AssetRendererTest.php +++ b/typo3/sysext/core/Tests/Unit/Page/AssetRendererTest.php @@ -17,82 +17,36 @@ declare(strict_types=1); namespace TYPO3\CMS\Core\Tests\Unit\Page; -use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\MockObject\MockObject; use Psr\EventDispatcher\EventDispatcherInterface; use TYPO3\CMS\Core\Page\AssetCollector; use TYPO3\CMS\Core\Page\AssetRenderer; -use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Page\Event\BeforeJavaScriptsRenderingEvent; +use TYPO3\CMS\Core\Page\Event\BeforeStylesheetsRenderingEvent; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; final class AssetRendererTest extends UnitTestCase { - protected bool $resetSingletonInstances = true; - protected AssetRenderer $subject; - protected MockObject&EventDispatcherInterface $eventDispatcher; - - public function setUp(): void - { - parent::setUp(); - $eventDispatcher = $this->createMock(EventDispatcherInterface::class); - $this->subject = new AssetRenderer(null, $eventDispatcher); - $this->eventDispatcher = $eventDispatcher; - } - - #[DataProviderExternal(AssetDataProvider::class, 'filesDataProvider')] - #[Test] - public function styleSheets(array $files, array $expectedResult, array $expectedMarkup): void - { - $assetCollector = GeneralUtility::makeInstance(AssetCollector::class); - foreach ($files as $file) { - [$identifier, $source, $attributes, $options] = $file; - $assetCollector->addStyleSheet($identifier, $source, $attributes, $options); - } - self::assertSame($expectedMarkup['css_no_prio'], $this->subject->renderStyleSheets()); - self::assertSame($expectedMarkup['css_prio'], $this->subject->renderStyleSheets(true)); - } - - #[DataProviderExternal(AssetDataProvider::class, 'filesDataProvider')] - #[Test] - public function javaScript(array $files, array $expectedResult, array $expectedMarkup): void + /** + * cross-product of all combinations of AssetRenderer::render*() methods and priorities + * @return array[] [render method name, isInline, isPriority, event class] + */ + public static function renderMethodsAndEventsDataProvider(): array { - $assetCollector = GeneralUtility::makeInstance(AssetCollector::class); - foreach ($files as $file) { - [$identifier, $source, $attributes, $options] = $file; - $assetCollector->addJavaScript($identifier, $source, $attributes, $options); - } - self::assertSame($expectedMarkup['js_no_prio'], $this->subject->renderJavaScript()); - self::assertSame($expectedMarkup['js_prio'], $this->subject->renderJavaScript(true)); + return [ + ['renderInlineJavaScript', true, true, BeforeJavaScriptsRenderingEvent::class], + ['renderInlineJavaScript', true, false, BeforeJavaScriptsRenderingEvent::class], + ['renderJavaScript', false, true, BeforeJavaScriptsRenderingEvent::class], + ['renderJavaScript', false, false, BeforeJavaScriptsRenderingEvent::class], + ['renderInlineStylesheets', true, true, BeforeStylesheetsRenderingEvent::class], + ['renderInlineStylesheets', true, false, BeforeStylesheetsRenderingEvent::class], + ['renderStylesheets', false, true, BeforeStylesheetsRenderingEvent::class], + ['renderStylesheets', false, false, BeforeStylesheetsRenderingEvent::class], + ]; } - #[DataProviderExternal(AssetDataProvider::class, 'inlineDataProvider')] - #[Test] - public function inlineJavaScript(array $sources, array $expectedResult, array $expectedMarkup): void - { - $assetCollector = GeneralUtility::makeInstance(AssetCollector::class); - foreach ($sources as $source) { - [$identifier, $source, $attributes, $options] = $source; - $assetCollector->addInlineJavaScript($identifier, $source, $attributes, $options); - } - self::assertSame($expectedMarkup['js_no_prio'], $this->subject->renderInlineJavaScript()); - self::assertSame($expectedMarkup['js_prio'], $this->subject->renderInlineJavaScript(true)); - } - - #[DataProviderExternal(AssetDataProvider::class, 'inlineDataProvider')] - #[Test] - public function inlineStyleSheets(array $sources, array $expectedResult, array $expectedMarkup): void - { - $assetCollector = GeneralUtility::makeInstance(AssetCollector::class); - foreach ($sources as $source) { - [$identifier, $source, $attributes, $options] = $source; - $assetCollector->addInlineStyleSheet($identifier, $source, $attributes, $options); - } - self::assertSame($expectedMarkup['css_no_prio'], $this->subject->renderInlineStyleSheets()); - self::assertSame($expectedMarkup['css_prio'], $this->subject->renderInlineStyleSheets(true)); - } - - #[DataProviderExternal(AssetDataProvider::class, 'renderMethodsAndEventsDataProvider')] + #[DataProvider('renderMethodsAndEventsDataProvider')] #[Test] public function beforeRenderingEvent( string $renderMethodName, @@ -100,18 +54,22 @@ final class AssetRendererTest extends UnitTestCase bool $priority, string $eventClassName ): void { - $assetCollector = GeneralUtility::makeInstance(AssetCollector::class); + $eventDispatcher = $this->createMock(EventDispatcherInterface::class); + $eventDispatcher->method('dispatch')->willReturnArgument(0); + $assetCollector = new AssetCollector(); + $assetRenderer = new AssetRenderer($assetCollector, $eventDispatcher); + $event = new $eventClassName( $assetCollector, $isInline, $priority ); - $this->eventDispatcher + $eventDispatcher ->expects(self::once()) ->method('dispatch') ->with($event); - $this->subject->$renderMethodName($priority); + $assetRenderer->$renderMethodName($priority); } } -- GitLab