[ 'single_pages' => ['contact'], 'supported_locales' => ['fr', 'en'], 'cruds' => [], 'schedule' => false, 'cron' => '45 15 * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => $this->outputDisk, 'path' => $this->outputPath, ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); // THEN expect($sitemapConfig)->toBeInstanceOf(SitemapConfig::class) ->and($sitemapConfig->singlePages)->toBe(['contact']) ->and($sitemapConfig->supportedLocales)->toBe(['fr', 'en']) ->and($sitemapConfig->cruds)->toBe([]) ->and($sitemapConfig->schedule)->toBeFalse() ->and($sitemapConfig->localizer)->toBe('default') ->and($sitemapConfig->cron)->toBeInstanceOf(CronExpression::class) ->and($sitemapConfig->sitemapStorage)->toBeInstanceOf(SitemapStorage::class) ->and((string) $sitemapConfig->sitemapStorage)->toBe( "{$this->outputDisk}:" . ltrim($this->outputPath, '/') ); }); it('can be configured with a relative output path inside disk', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => ['contact'], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'public', 'path' => 'sitemaps/sitemap.xml', ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); // THEN expect((string) $sitemapConfig->sitemapStorage)->toBe('public:sitemaps/sitemap.xml'); }); it('throws exception when legacy singlePages config key is used', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'singlePages' => ['contact'], 'single_pages' => ['contact'], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action)->toThrow( SitemapException::class, "You may migrate your config to use the 'single_pages' key instead of 'singlePages'" ); }); it('throws exception when legacy output_path config key is used', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'output_path' => '/tmp/sitemap.xml', 'single_pages' => ['contact'], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action)->toThrow( SitemapException::class, "You may migrate your config to use the 'output.storage_disk' and 'output.path' keys instead of 'output_path'." ); }); it('throws exception when legacy relationFilters key is used in crud config', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [ [ 'model' => ModelClass::class, 'relationFilters' => ['posts' => fn () => true], ], ], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action)->toThrow( SitemapException::class, "CRUD config must use the 'relation_filters' key instead of 'relationFilters'." ); }); it('throws exception when legacy modelFilters key is used in crud config', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [ [ 'model' => ModelClass::class, 'modelFilters' => [['is_active', '=', true]], ], ], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action)->toThrow( SitemapException::class, "CRUD config must use the 'model_filters' key instead of 'modelFilters'." ); }); it('throws exception when legacy allowNullRelation key is used in crud config', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [ [ 'model' => ModelClass::class, 'allowNullRelation' => ['category'], ], ], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action)->toThrow( SitemapException::class, "CRUD config must use the 'allow_null_relation' key instead of 'allowNullRelation'." ); }); it('supports associative array for supported_locales and filters empty values', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => ['contact', '', ' ', 123, null], 'supported_locales' => [ 'fr' => 'Français', 'en' => 'English', '' => 'Vide', ' ' => 'Espaces', ], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); // THEN expect($sitemapConfig->supportedLocales)->toBe(['fr', 'en']) ->and($sitemapConfig->singlePages)->toBe(['contact']); }); it('throws exception when cron expression is invalid', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => 'invalid-cron', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action) ->toThrow(SitemapException::class, "Cron config is not a valid expression 'invalid-cron'"); }); it('throws exception when output path does not end with .xml', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => '/tmp/sitemap.txt', ], ], ]); // WHEN $action = fn () => new SitemapConfig($configRepository); // THEN expect($action) ->toThrow(SitemapException::class, 'The path must indicate a valid XML file location.'); }); it('can parse cruds configuration properly', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [ [ 'model' => ModelClass::class, 'relation_filters' => ['posts' => fn () => true], 'model_filters' => [['is_active', '=', true]], 'allow_null_relation' => ['category'], ], ], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'default', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); // THEN expect($sitemapConfig->cruds)->toHaveCount(1) ->and($sitemapConfig->cruds[0]->modelClass)->toBe(ModelClass::class) ->and($sitemapConfig->cruds[0]->allowNullRelations)->toBe(['category']); }); it('returns the configured localizer instance', function (string $strategy, string $expectedClass) { /** @var class-string $expectedClass */ // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => $strategy, 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); $localizer = $sitemapConfig->getConfiguredLocalizerFor(app()); // THEN expect($localizer)->toBeInstanceOf($expectedClass); })->with([ 'default alias' => ['default', DefaultRouteLocalizer::class], 'default class string' => [DefaultRouteLocalizer::class, DefaultRouteLocalizer::class], 'mcamara alias' => ['mcamara', McamaraRouteLocalizer::class], 'mcamara class string' => [McamaraRouteLocalizer::class, McamaraRouteLocalizer::class], ]); it('throws exception when localizer is unsupported', function () { // GIVEN $configRepository = new ConfigRepository([ SitemapConfig::CONFIG_KEY => [ 'single_pages' => [], 'supported_locales' => ['fr'], 'cruds' => [], 'schedule' => false, 'cron' => '* * * * *', 'localizer' => 'unsupported-localizer', 'output' => [ 'storage_disk' => 'local', 'path' => 'sitemap.xml', ], ], ]); // WHEN $sitemapConfig = new SitemapConfig($configRepository); $action = fn () => $sitemapConfig->getConfiguredLocalizerFor(app()); // THEN expect($action)->toThrow( SitemapException::class, "Unsupported localizer 'unsupported-localizer'" ); }); });