|
20 | 20 | use Symfony\Component\DependencyInjection\Alias; |
21 | 21 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
22 | 22 | use Symfony\Component\DependencyInjection\Reference; |
| 23 | +use Symfony\Component\HttpClient\Response\MockResponse; |
23 | 24 | use Symfony\Component\HttpFoundation\Request; |
24 | 25 | use Symfony\Component\HttpFoundation\Response; |
25 | 26 | use Symfony\Component\HttpKernel\HttpKernelInterface; |
26 | 27 | use Symfony\Component\HttpKernel\Kernel; |
27 | 28 | use Symfony\Component\HttpKernel\Log\Logger; |
28 | 29 | use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; |
| 30 | +use Symfony\Contracts\HttpClient\ResponseInterface; |
29 | 31 | use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupCollectionInterface; |
30 | 32 | use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface; |
31 | 33 | use Symfony\WebpackEncoreBundle\Asset\TagRenderer; |
@@ -71,6 +73,26 @@ public function testTwigIntegration() |
71 | 73 | '<script src="/build/other4.js"></script>', |
72 | 74 | $html2 |
73 | 75 | ); |
| 76 | + |
| 77 | + $html3 = $twig->render('@integration_test/template_remote.twig'); |
| 78 | + $this->assertStringContainsString( |
| 79 | + '<script src="https://cdn.example.com/app.js?v=abcde01" referrerpolicy="origin"></script>', |
| 80 | + $html3 |
| 81 | + ); |
| 82 | + $this->assertStringContainsString( |
| 83 | + '<link rel="stylesheet" href="https://cdn.example.com/app.css?v=abcde02">', |
| 84 | + $html3 |
| 85 | + ); |
| 86 | + |
| 87 | + $html4 = $twig->render('@integration_test/manual_template_remote.twig'); |
| 88 | + $this->assertStringContainsString( |
| 89 | + '<script src="https://cdn.example.com/backend.js?v=abcde01"></script>', |
| 90 | + $html4 |
| 91 | + ); |
| 92 | + $this->assertStringContainsString( |
| 93 | + '<link rel="stylesheet" href="https://cdn.example.com/backend.css?v=abcde02" />', |
| 94 | + $html4 |
| 95 | + ); |
74 | 96 | } |
75 | 97 |
|
76 | 98 | public function testEntriesAreNotRepeatedWhenAlreadyOutputIntegration() |
@@ -137,7 +159,7 @@ public function testCacheWarmer() |
137 | 159 | $this->assertFileExists($cachePath); |
138 | 160 | $data = require $cachePath; |
139 | 161 | // check for both build keys |
140 | | - $this->assertSame(['_default', 'different_build'], array_keys($data[0] ?? $data)); |
| 162 | + $this->assertSame(['_default', 'different_build', 'remote_build'], array_keys($data[0] ?? $data)); |
141 | 163 | } |
142 | 164 |
|
143 | 165 | public function testEnabledStrictModeThrowsExceptionIfBuildMissing() |
@@ -165,6 +187,31 @@ public function testDisabledStrictModeIgnoresMissingBuild() |
165 | 187 | self::assertSame('', trim($html)); |
166 | 188 | } |
167 | 189 |
|
| 190 | + public function testEnabledStrictModeThrowsExceptionIfRemoteBuildMissing() |
| 191 | + { |
| 192 | + $this->expectException(\Twig\Error\RuntimeError::class); |
| 193 | + $this->expectExceptionMessage('Could not find the entrypoints file from URL "https://example.com/missing_build/entrypoints.json": the HTTP request failed with status code 404.'); |
| 194 | + |
| 195 | + $kernel = new WebpackEncoreIntegrationTestKernel(true); |
| 196 | + $kernel->outputPath = 'remote_build'; |
| 197 | + $kernel->builds = ['remote_build' => 'https://example.com/missing_build']; |
| 198 | + $kernel->boot(); |
| 199 | + $twig = $this->getTwigEnvironmentFromBootedKernel($kernel); |
| 200 | + $twig->render('@integration_test/template_remote.twig'); |
| 201 | + } |
| 202 | + |
| 203 | + public function testDisabledStrictModeIgnoresMissingRemoteBuild() |
| 204 | + { |
| 205 | + $kernel = new WebpackEncoreIntegrationTestKernel(true); |
| 206 | + $kernel->outputPath = 'remote_build'; |
| 207 | + $kernel->strictMode = false; |
| 208 | + $kernel->builds = ['remote_build' => 'https://example.com/missing_build']; |
| 209 | + $kernel->boot(); |
| 210 | + $twig = $this->getTwigEnvironmentFromBootedKernel($kernel); |
| 211 | + $html = $twig->render('@integration_test/template_remote.twig'); |
| 212 | + self::assertSame('', trim($html)); |
| 213 | + } |
| 214 | + |
168 | 215 | public function testAutowireableInterfaces() |
169 | 216 | { |
170 | 217 | $kernel = new WebpackEncoreIntegrationTestKernel(true); |
@@ -228,6 +275,7 @@ class WebpackEncoreIntegrationTestKernel extends Kernel |
228 | 275 | public $outputPath = __DIR__.'/fixtures/build'; |
229 | 276 | public $builds = [ |
230 | 277 | 'different_build' => __DIR__.'/fixtures/different_build', |
| 278 | + 'remote_build' => 'https://example.com/build', |
231 | 279 | ]; |
232 | 280 | public $scriptAttributes = []; |
233 | 281 |
|
@@ -261,6 +309,9 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa |
261 | 309 | 'enabled' => $this->enableAssets, |
262 | 310 | ], |
263 | 311 | 'test' => true, |
| 312 | + 'http_client' => [ |
| 313 | + 'mock_response_factory' => WebpackEncoreHttpClientMockCallback::class, |
| 314 | + ], |
264 | 315 | ]; |
265 | 316 | if (self::VERSION_ID >= 50100) { |
266 | 317 | $frameworkConfig['router'] = [ |
@@ -310,6 +361,9 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa |
310 | 361 | // @legacy for 5.0 and earlier: did not have controller.service_arguments tag |
311 | 362 | $container->getDefinition('kernel') |
312 | 363 | ->addTag('controller.service_arguments'); |
| 364 | + |
| 365 | + $container->register(WebpackEncoreHttpClientMockCallback::class) |
| 366 | + ->setPublic(true); |
313 | 367 | } |
314 | 368 |
|
315 | 369 | public function getCacheDir(): string |
@@ -365,3 +419,46 @@ public function __construct(EntrypointLookupInterface $entrypointLookup, Entrypo |
365 | 419 | { |
366 | 420 | } |
367 | 421 | } |
| 422 | + |
| 423 | +class WebpackEncoreHttpClientMockCallback |
| 424 | +{ |
| 425 | + /** @var callable|null */ |
| 426 | + public $callback; |
| 427 | + |
| 428 | + public function __invoke(string $method, string $url, array $options = []): ResponseInterface |
| 429 | + { |
| 430 | + $callback = $this->callback ?? static function (string $method, string $url) { |
| 431 | + if ('GET' === $method && 'https://example.com/build/entrypoints.json' === $url) { |
| 432 | + return new MockResponse(json_encode([ |
| 433 | + 'entrypoints' => [ |
| 434 | + 'app' => [ |
| 435 | + 'js' => [ |
| 436 | + 'https://cdn.example.com/app.js?v=abcde01', |
| 437 | + ], |
| 438 | + 'css' => [ |
| 439 | + 'https://cdn.example.com/app.css?v=abcde02', |
| 440 | + ], |
| 441 | + ], |
| 442 | + 'backend' => [ |
| 443 | + 'js' => [ |
| 444 | + 'https://cdn.example.com/backend.js?v=abcde01', |
| 445 | + ], |
| 446 | + 'css' => [ |
| 447 | + 'https://cdn.example.com/backend.css?v=abcde02', |
| 448 | + ], |
| 449 | + ], |
| 450 | + ], |
| 451 | + ], flags: \JSON_THROW_ON_ERROR), [ |
| 452 | + 'http_code' => 200, |
| 453 | + 'response_headers' => ['Content-Type: application/json'], |
| 454 | + ]); |
| 455 | + } |
| 456 | + |
| 457 | + return new MockResponse('Not found.', [ |
| 458 | + 'http_code' => 404, |
| 459 | + ]); |
| 460 | + }; |
| 461 | + |
| 462 | + return ($callback)($method, $url, $options); |
| 463 | + } |
| 464 | +} |
0 commit comments