From 53ef7f8745cb53afc29cd6b154e96e3d5bcbdb62 Mon Sep 17 00:00:00 2001 From: Florent Morselli Date: Thu, 21 Dec 2023 21:22:12 +0100 Subject: [PATCH] Added Router support for some routes --- composer.json | 5 +- src/Command/GenerateManifestCommand.php | 231 ++++++++---------- src/Command/WorkboxInitCommand.php | 30 +-- src/DependencyInjection/Configuration.php | 58 ++++- .../SpomkyLabsPwaExtension.php | 15 ++ tests/DummyImageProcessor.php | 30 +++ tests/Functional/CommandTest.php | 35 ++- tests/config.php | 14 +- 8 files changed, 247 insertions(+), 171 deletions(-) create mode 100644 tests/DummyImageProcessor.php diff --git a/composer.json b/composer.json index 41cddfb..d7e7a56 100644 --- a/composer.json +++ b/composer.json @@ -28,9 +28,10 @@ "php": ">=8.2", "symfony/config": "^6.4|^7.0", "symfony/dependency-injection": "^6.4|^7.0", - "symfony/filesystem": "6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "6.4|^7.0" + "symfony/mime": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0" }, "require-dev": { "infection/infection": "^0.27", diff --git a/src/Command/GenerateManifestCommand.php b/src/Command/GenerateManifestCommand.php index d8c3cea..dadcef0 100644 --- a/src/Command/GenerateManifestCommand.php +++ b/src/Command/GenerateManifestCommand.php @@ -11,15 +11,16 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Exception\IOExceptionInterface; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Filesystem\Path; use Symfony\Component\Mime\MimeTypes; +use Symfony\Component\Routing\RouterInterface; use function count; +use function dirname; +use function is_array; use function is_int; use const JSON_PRETTY_PRINT; use const JSON_THROW_ON_ERROR; @@ -34,29 +35,16 @@ final class GenerateManifestCommand extends Command public function __construct( private readonly null|ImageProcessor $imageProcessor, #[Autowire('%spomky_labs_pwa.config%')] - private readonly array $config, - #[Autowire('%kernel.project_dir%')] - private readonly string $rootDir, - private readonly Filesystem $filesystem, + private readonly array $config, + #[Autowire('%spomky_labs_pwa.dest%')] + private readonly array $dest, + private readonly Filesystem $filesystem, + private readonly ?RouterInterface $router = null, ) { $this->mime = MimeTypes::getDefault(); parent::__construct(); } - protected function configure(): void - { - $this->addOption('url_prefix', 'u', InputOption::VALUE_OPTIONAL, 'Public URL prefix', ''); - $this->addOption( - 'public_folder', - 'p', - InputOption::VALUE_OPTIONAL, - 'Public folder', - $this->rootDir . '/public' - ); - $this->addOption('asset_folder', 'a', InputOption::VALUE_OPTIONAL, 'Asset folder', '/pwa'); - $this->addOption('output', 'o', InputOption::VALUE_OPTIONAL, 'Output file', 'pwa.json'); - } - protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); @@ -64,31 +52,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int $manifest = $this->config; $manifest = array_filter($manifest, static fn ($value) => ($value !== null && $value !== [])); - $publicUrl = $input->getOption('url_prefix'); - $publicFolder = Path::canonicalize($input->getOption('public_folder')); - $assetFolder = '/' . trim((string) $input->getOption('asset_folder'), '/'); - $outputFile = '/' . trim((string) $input->getOption('output'), '/'); - - if (! $this->filesystem->exists($publicFolder)) { - $this->filesystem->mkdir($publicFolder); + $manifest = $this->processIcons($io, $manifest); + if (! is_array($manifest)) { + return self::FAILURE; } - - $manifest = $this->processIcons($io, $manifest, $publicUrl, $publicFolder, $assetFolder); - if ($manifest === self::FAILURE) { + $manifest = $this->processScreenshots($io, $manifest); + if (! is_array($manifest)) { return self::FAILURE; } - $manifest = $this->processScreenshots($io, $manifest, $publicUrl, $publicFolder, $assetFolder); - if ($manifest === self::FAILURE) { + $manifest = $this->processShortcutIcons($io, $manifest); + if (! is_array($manifest)) { return self::FAILURE; } - $manifest = $this->processShortcutIcons($io, $manifest, $publicUrl, $publicFolder, $assetFolder); - if ($manifest === self::FAILURE) { + $manifest = $this->processActions($io, $manifest); + if (! is_array($manifest)) { return self::FAILURE; } try { + $this->createDirectoryIfNotExists(dirname((string) $this->dest['manifest_filepath'])); + if (! $this->filesystem->exists($this->dest['manifest_filepath'])) { + $this->filesystem->remove($this->dest['manifest_filepath']); + } file_put_contents( - sprintf('%s%s', $publicFolder, $outputFile), + (string) $this->dest['manifest_filepath'], json_encode( $manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR @@ -106,15 +93,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @param array $components * @return array{src: string, type: string} */ - private function storeFile( - string $data, - string $publicUrl, - string $publicFolder, - string $assetFolder, - string $type, - array $components - ): array { - $tempFilename = $this->filesystem->tempnam($publicFolder, $type . '-'); + private function storeFile(string $data, string $prefixUrl, string $storageFolder, array $components): array + { + $tempFilename = $this->filesystem->tempnam($storageFolder, 'pwa-'); $hash = mb_substr(hash('sha256', $data), 0, 8); file_put_contents($tempFilename, $data); $mime = $this->mime->guessMimeType($tempFilename); @@ -125,14 +106,14 @@ private function storeFile( } $components[] = $hash; - $filename = sprintf('%s/%s.%s', $assetFolder, implode('-', $components), $extension[0]); - $localFilename = sprintf('%s%s', $publicFolder, $filename); + $filename = sprintf('%s.%s', implode('-', $components), $extension[0]); + $localFilename = sprintf('%s/%s', rtrim($storageFolder, '/'), $filename); file_put_contents($localFilename, $data); $this->filesystem->remove($tempFilename); return [ - 'src' => sprintf('%s%s', $publicUrl, $filename), + 'src' => sprintf('%s%s', $prefixUrl, $filename), 'type' => $mime, ]; } @@ -140,34 +121,29 @@ private function storeFile( /** * @return array{src: string, type: string, sizes: string, form_factor: ?string} */ - private function storeScreenshot( - string $data, - string $publicUrl, - string $publicFolder, - string $assetFolder, - ?string $format, - ?string $formFactor - ): array { + private function storeScreenshot(string $data, ?string $format, ?string $formFactor): array + { if ($format !== null) { $data = $this->imageProcessor->process($data, null, null, $format); } ['width' => $width, 'height' => $height] = $this->imageProcessor->getSizes($data); $size = sprintf('%sx%s', $width, $height); - $formFactor ??= $width > $height ? 'wide' : 'narrow'; $fileData = $this->storeFile( $data, - $publicUrl, - $publicFolder, - $assetFolder, - 'screenshot', + $this->dest['screenshot_prefix_url'], + $this->dest['screenshot_folder'], ['screenshot', $formFactor, $size] ); + if ($formFactor !== null) { + $fileData += [ + 'form_factor' => $formFactor, + ]; + } return $fileData + [ 'sizes' => $size, - 'form_factor' => $formFactor, ]; } @@ -190,20 +166,12 @@ private function handleSizeAndPurpose(?string $purpose, int $size, array $fileDa /** * @return array{src: string, sizes: string, type: string, purpose: ?string} */ - private function storeShortcutIcon( - string $data, - string $publicUrl, - string $publicFolder, - string $assetFolder, - int $size, - ?string $purpose - ): array { + private function storeShortcutIcon(string $data, int $size, ?string $purpose): array + { $fileData = $this->storeFile( $data, - $publicUrl, - $publicFolder, - $assetFolder, - 'shortcut-icon', + $this->dest['shortcut_icon_prefix_url'], + $this->dest['shortcut_icon_folder'], ['shortcut-icon', $purpose, $size === 0 ? 'any' : $size . 'x' . $size] ); @@ -213,37 +181,24 @@ private function storeShortcutIcon( /** * @return array{src: string, sizes: string, type: string, purpose: ?string} */ - private function storeIcon( - string $data, - string $publicUrl, - string $publicFolder, - string $assetFolder, - int $size, - ?string $purpose - ): array { + private function storeIcon(string $data, int $size, ?string $purpose): array + { $fileData = $this->storeFile( $data, - $publicUrl, - $publicFolder, - $assetFolder, - 'icon', + $this->dest['icon_prefix_url'], + $this->dest['icon_folder'], ['icon', $purpose, $size === 0 ? 'any' : $size . 'x' . $size] ); return $this->handleSizeAndPurpose($purpose, $size, $fileData); } - private function processIcons( - SymfonyStyle $io, - array $manifest, - mixed $publicUrl, - string $publicFolder, - string $assetFolder - ): array|int { + private function processIcons(SymfonyStyle $io, array $manifest): array|int + { if ($this->config['icons'] === []) { return $manifest; } - if (! $this->createDirectoryIfNotExists($publicFolder, $assetFolder) || ! $this->checkImageProcessor($io)) { + if (! $this->createDirectoryIfNotExists($this->dest['icon_folder']) || ! $this->checkImageProcessor($io)) { return self::FAILURE; } $manifest['icons'] = []; @@ -258,20 +213,13 @@ private function processIcons( $io->error('The icon size must be a positive integer'); return self::FAILURE; } - $data = $this->loadFile($icon['src'], $size, $icon['format'] ?? null); + $data = $this->loadFileAndConvert($icon['src'], $size, $icon['format'] ?? null); if ($data === null) { $io->error(sprintf('Unable to read the icon "%s"', $icon['src'])); return self::FAILURE; } - $iconManifest = $this->storeIcon( - $data, - $publicUrl, - $publicFolder, - $assetFolder, - $size, - $icon['purpose'] ?? null - ); + $iconManifest = $this->storeIcon($data, $size, $icon['purpose'] ?? null); $manifest['icons'][] = $iconManifest; } } @@ -281,17 +229,14 @@ private function processIcons( return $manifest; } - private function processScreenshots( - SymfonyStyle $io, - array $manifest, - mixed $publicUrl, - string $publicFolder, - string $assetFolder - ): array|int { + private function processScreenshots(SymfonyStyle $io, array $manifest): array|int + { if ($this->config['screenshots'] === []) { return $manifest; } - if (! $this->createDirectoryIfNotExists($publicFolder, $assetFolder) || ! $this->checkImageProcessor($io)) { + if (! $this->createDirectoryIfNotExists($this->dest['screenshot_folder']) || ! $this->checkImageProcessor( + $io + )) { return self::FAILURE; } $manifest['screenshots'] = []; @@ -300,16 +245,13 @@ private function processScreenshots( $io->info('Processing screenshots'); foreach ($this->config['screenshots'] as $screenshot) { $this->processProgressBar($progressBar, 'screenshot', $screenshot['src']); - $data = $this->loadFile($screenshot['src'], null, $screenshot['format'] ?? null); + $data = $this->loadFileAndConvert($screenshot['src'], null, $screenshot['format'] ?? null); if ($data === null) { $io->error(sprintf('Unable to read the icon "%s"', $screenshot['src'])); return self::FAILURE; } $screenshotManifest = $this->storeScreenshot( $data, - $publicUrl, - $publicFolder, - $assetFolder, $screenshot['format'] ?? null, $screenshot['form_factor'] ?? null ); @@ -326,17 +268,14 @@ private function processScreenshots( return $manifest; } - private function processShortcutIcons( - SymfonyStyle $io, - array|int $manifest, - mixed $publicUrl, - string $publicFolder, - string $assetFolder - ): array|int { + private function processShortcutIcons(SymfonyStyle $io, array|int $manifest): array|int + { if ($this->config['shortcuts'] === []) { return $manifest; } - if (! $this->createDirectoryIfNotExists($publicFolder, $assetFolder) || ! $this->checkImageProcessor($io)) { + if (! $this->createDirectoryIfNotExists($this->dest['shortcut_icon_folder']) || ! $this->checkImageProcessor( + $io + )) { return self::FAILURE; } $manifest['shortcuts'] = []; @@ -349,6 +288,14 @@ private function processShortcutIcons( if (isset($shortcut['icons'])) { unset($shortcut['icons']); } + if (! str_starts_with((string) $shortcut['url'], '/')) { + if ($this->router === null) { + $io->error('The router is not available'); + return self::FAILURE; + } + $shortcut['url'] = $this->router->generate($shortcut['url'], [], RouterInterface::RELATIVE_PATH); + } + if (isset($shortcutConfig['icons'])) { if (! $this->checkImageProcessor($io)) { return self::FAILURE; @@ -360,20 +307,13 @@ private function processShortcutIcons( return self::FAILURE; } - $data = $this->loadFile($icon['src'], $size, $icon['format'] ?? null); + $data = $this->loadFileAndConvert($icon['src'], $size, $icon['format'] ?? null); if ($data === null) { $io->error(sprintf('Unable to read the icon "%s"', $icon['src'])); return self::FAILURE; } - $iconManifest = $this->storeShortcutIcon( - $data, - $publicUrl, - $publicFolder, - $assetFolder, - $size, - $icon['purpose'] ?? null - ); + $iconManifest = $this->storeShortcutIcon($data, $size, $icon['purpose'] ?? null); $shortcut['icons'][] = $iconManifest; } } @@ -386,7 +326,7 @@ private function processShortcutIcons( return $manifest; } - private function loadFile(string $src, ?int $size, ?string $format): ?string + private function loadFileAndConvert(string $src, ?int $size, ?string $format): ?string { $data = file_get_contents($src); if ($data === false) { @@ -409,10 +349,12 @@ private function checkImageProcessor(SymfonyStyle $io): bool return true; } - private function createDirectoryIfNotExists(string $publicFolder, string $assetFolder): bool + private function createDirectoryIfNotExists(string $folder): bool { try { - $this->filesystem->mkdir(sprintf('%s%s', $publicFolder, $assetFolder)); + if (! $this->filesystem->exists($folder)) { + $this->filesystem->mkdir($folder); + } } catch (IOExceptionInterface) { return false; } @@ -425,4 +367,25 @@ private function processProgressBar(ProgressBar $progressBar, string $type, stri $progressBar->advance(); $progressBar->setMessage(sprintf('Processing %s %s', $type, $src)); } + + private function processActions(SymfonyStyle $io, array $manifest): array|int + { + $io->info('Processing file handlers'); + foreach ($manifest['file_handlers'] as $id => $handler) { + if (str_starts_with((string) $handler['action'], '/')) { + continue; + } + if ($this->router === null) { + $io->error('The router is not available'); + return self::FAILURE; + } + $manifest['file_handlers'][$id]['action'] = $this->router->generate( + $handler['action'], + [], + RouterInterface::RELATIVE_PATH + ); + } + + return $manifest; + } } diff --git a/src/Command/WorkboxInitCommand.php b/src/Command/WorkboxInitCommand.php index 9607199..5425402 100644 --- a/src/Command/WorkboxInitCommand.php +++ b/src/Command/WorkboxInitCommand.php @@ -7,51 +7,33 @@ use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Filesystem\Path; use Symfony\Component\HttpKernel\Config\FileLocator; use function count; +use function dirname; #[AsCommand(name: 'pwa:sw', description: 'Initializes the Workbox-based Service Worker.',)] class WorkboxInitCommand extends Command { public function __construct( - #[Autowire('%kernel.project_dir%')] - private readonly string $rootDir, + #[Autowire('%spomky_labs_pwa.dest%')] + private readonly array $dest, private readonly Filesystem $filesystem, private readonly FileLocator $fileLocator, ) { parent::__construct(); } - protected function configure(): void - { - $this - ->addOption( - 'public_folder', - 'p', - InputOption::VALUE_OPTIONAL, - 'Public folder', - $this->rootDir . '/public' - ) - ->addOption('output', 'o', InputOption::VALUE_OPTIONAL, 'Output file', 'sw.js') - ; - } - protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $io->title('Workbox Service Worker'); - $publicFolder = Path::canonicalize($input->getOption('public_folder')); - $outputFile = '/' . trim((string) $input->getOption('output'), '/'); - - if (! $this->filesystem->exists($publicFolder)) { - $this->filesystem->mkdir($publicFolder); + if (! $this->filesystem->exists(dirname((string) $this->dest['serviceworker_filepath']))) { + $this->filesystem->mkdir(dirname((string) $this->dest['serviceworker_filepath'])); } $resourcePath = $this->fileLocator->locate('@SpomkyLabsPwaBundle/Resources/workbox.js', null, false); @@ -60,7 +42,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return self::FAILURE; } $resourcePath = $resourcePath[0]; - $this->filesystem->copy($resourcePath, $publicFolder . $outputFile); + $this->filesystem->copy($resourcePath, $this->dest['serviceworker_filepath']); $io->success('Workbox is ready to use!'); diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 0b797af..8ca62b0 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -33,6 +33,7 @@ public function getConfigTreeBuilder(): TreeBuilder $this->setupRelatedApplications($rootNode); $this->setupShortcuts($rootNode); $this->setupSharedTarget($rootNode); + $this->setupServiceWorker($rootNode); return $treeBuilder; } @@ -271,6 +272,38 @@ private function setupSimpleOptions(ArrayNodeDefinition $node): void ->info('The image processor to use to generate the icons of different sizes.') ->example(GDImageProcessor::class) ->end() + ->scalarNode('icon_folder') + ->defaultValue('%kernel.project_dir%/public/pwa') + ->info('The folder where the icons will be generated.') + ->end() + ->scalarNode('icon_prefix_url') + ->defaultValue('/pwa') + ->info('The URL prefix to use to generate the icons.') + ->end() + ->scalarNode('shortcut_icon_folder') + ->defaultValue('%kernel.project_dir%/public/pwa') + ->info('The folder where the shortcut icons will be generated.') + ->end() + ->scalarNode('shortcut_icon_prefix_url') + ->defaultValue('/pwa') + ->info('The URL prefix to use to generate the icons.') + ->end() + ->scalarNode('screenshot_folder') + ->defaultValue('%kernel.project_dir%/public/pwa') + ->info('The folder where the screenshots will be generated.') + ->end() + ->scalarNode('screenshot_prefix_url') + ->defaultValue('/pwa') + ->info('The URL prefix to use to generate the icons.') + ->end() + ->scalarNode('manifest_filepath') + ->defaultValue('%kernel.project_dir%/public/pwa.json') + ->info('The filename where the manifest will be generated.') + ->end() + ->scalarNode('serviceworker_filepath') + ->defaultValue('%kernel.project_dir%/public/sw.js') + ->info('The filename where the service worker will be generated.') + ->end() ->scalarNode('background_color') ->info( 'The background color of the application. It should match the background-color CSS property in the sites stylesheet for a smooth transition between launching the web application and loading the site\'s content.' @@ -341,7 +374,6 @@ private function getIconsNode(): ArrayNodeDefinition $node = $treeBuilder->getRootNode(); assert($node instanceof ArrayNodeDefinition); $node - ->info('The icons of the application.') ->arrayPrototype() ->children() ->scalarNode('src') @@ -370,4 +402,28 @@ private function getIconsNode(): ArrayNodeDefinition return $node; } + + private function setupServiceWorker(ArrayNodeDefinition $node): void + { + $node->children() + ->arrayNode('serviceworker') + ->info( + 'EXPERIMENTAL. Specifies a serviceworker that is Just-In-Time (JIT)-installed and registered to run a web-based payment app providing a payment mechanism for a specified payment method in a merchant website.' + ) + ->children() + ->scalarNode('src') + ->info('The path to the service worker.') + ->example('sw.js') + ->end() + ->scalarNode('scope') + ->info('The scope of the service worker.') + ->example('/app/') + ->end() + ->booleanNode('use_cache') + ->info('Whether the service worker should use the cache.') + ->end() + ->end() + ->end() + ->end(); + } } diff --git a/src/DependencyInjection/SpomkyLabsPwaExtension.php b/src/DependencyInjection/SpomkyLabsPwaExtension.php index 264415a..e4cbefd 100644 --- a/src/DependencyInjection/SpomkyLabsPwaExtension.php +++ b/src/DependencyInjection/SpomkyLabsPwaExtension.php @@ -32,6 +32,21 @@ public function load(array $configs, ContainerBuilder $container): void $container->setAlias(ImageProcessor::class, $config['image_processor']); } unset($config['image_processor']); + $params = [ + 'icon_folder', + 'icon_prefix_url', + 'shortcut_icon_folder', + 'shortcut_icon_prefix_url', + 'screenshot_folder', + 'screenshot_prefix_url', + 'manifest_filepath', + 'serviceworker_filepath', + ]; + $container->setParameter('spomky_labs_pwa.dest', array_intersect_key($config, array_flip($params))); + foreach ($params as $param) { + unset($config[$param]); + } + $container->setParameter('spomky_labs_pwa.config', $config); } diff --git a/tests/DummyImageProcessor.php b/tests/DummyImageProcessor.php new file mode 100644 index 0000000..58ed59c --- /dev/null +++ b/tests/DummyImageProcessor.php @@ -0,0 +1,30 @@ + $width, + 'height' => $height, + 'format' => $format, + ]); + } + + /** + * @return array{width: int, height: int} + */ + public function getSizes(string $image): array + { + return [ + 'width' => 1024, + 'height' => 1920, + ]; + } +} diff --git a/tests/Functional/CommandTest.php b/tests/Functional/CommandTest.php index 5ec6a29..4d6873b 100644 --- a/tests/Functional/CommandTest.php +++ b/tests/Functional/CommandTest.php @@ -35,18 +35,37 @@ public static function theCommandCanGenerateTheManifestAndIcons(): void $commandTester = new CommandTester($command); // When - $commandTester->execute([ - '--url_prefix' => '/foo/bar', - '--public_folder' => sprintf('%s/samples', $kernel->getCacheDir()), - '--asset_folder' => '/data', - '--output' => 'my-pwa.json', - ]); + $commandTester->execute([]); // Then $commandTester->assertCommandIsSuccessful(); $output = $commandTester->getDisplay(); static::assertStringContainsString('PWA Manifest Generator', $output); - static::assertFileExists(sprintf('%s/samples/my-pwa.json', $kernel->getCacheDir())); - static::assertDirectoryExists(sprintf('%s/samples/data', $kernel->getCacheDir())); + static::assertFileExists(sprintf('%s/samples/manifest/my-pwa.json', $kernel->getCacheDir())); + static::assertDirectoryExists(sprintf('%s/samples/icons', $kernel->getCacheDir())); + static::assertDirectoryExists(sprintf('%s/samples/screenshots', $kernel->getCacheDir())); + static::assertDirectoryExists(sprintf('%s/samples/shortcut_icons', $kernel->getCacheDir())); + } + + #[Test] + public static function theCommandCanCreateTheServiceWorker(): void + { + // Given + $kernel = self::bootKernel(); + $application = new Application($kernel); + $filesystem = self::getContainer()->get('filesystem'); + $filesystem->remove(sprintf('%s/samples', $kernel->getCacheDir())); + + $command = $application->find('pwa:sw'); + $commandTester = new CommandTester($command); + + // When + $commandTester->execute([]); + + // Then + $commandTester->assertCommandIsSuccessful(); + $output = $commandTester->getDisplay(); + static::assertStringContainsString('Workbox Service Worker', $output); + static::assertFileExists(sprintf('%s/samples/sw/my-sw.js', $kernel->getCacheDir())); } } diff --git a/tests/config.php b/tests/config.php index 508dc7d..8c68ea1 100644 --- a/tests/config.php +++ b/tests/config.php @@ -4,9 +4,11 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; -use SpomkyLabs\PwaBundle\ImageProcessor\ImagickImageProcessor; +use SpomkyLabs\PwaBundle\Tests\DummyImageProcessor; return static function (ContainerConfigurator $container) { + $container->services() + ->set(DummyImageProcessor::class); $container->extension('framework', [ 'test' => true, 'secret' => 'test', @@ -16,7 +18,15 @@ ], ]); $container->extension('pwa', [ - 'image_processor' => ImagickImageProcessor::class, + 'image_processor' => DummyImageProcessor::class, + 'icon_folder' => '%kernel.cache_dir%/samples/icons', + 'icon_prefix_url' => '/icons', + 'shortcut_icon_folder' => '%kernel.cache_dir%/samples/shortcut_icons', + 'shortcut_icon_prefix_url' => '/shortcut_icons', + 'screenshot_folder' => '%kernel.cache_dir%/samples/screenshots', + 'screenshot_prefix_url' => '/screenshots', + 'manifest_filepath' => '%kernel.cache_dir%/samples/manifest/my-pwa.json', + 'serviceworker_filepath' => '%kernel.cache_dir%/samples/sw/my-sw.js', 'background_color' => 'red', 'categories' => ['books', 'education', 'medical'], 'description' => 'Awesome application that will help you achieve your dreams.',