ldc-sitemap-generator/tests/Integration/McamaraSitemapGeneratorTest.php
Jérémy Munsch 58c9050ecc
feat(config): add SitemapStorage for managing sitemap files
- Introduced SitemapStorage class for reading, writing, and checking existence of sitemap files.
- Updated GenerateSitemapCommand to utilize SitemapStorage for file operations.
- Refactored tests to accommodate changes in sitemap file handling.
- Enhanced configuration to support output paths and storage disks.
2026-10-15 14:42:20 +02:00

389 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace Uwil\SitemapGenerator\Tests\Integration;
use Illuminate\Config\Repository as ConfigRepository;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Translation\Translator;
use Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
use Uwil\SitemapGenerator\Config\SitemapConfig;
use Uwil\SitemapGenerator\Localizers\McamaraRouteLocalizer;
use Uwil\SitemapGenerator\SitemapGenerator;
use Uwil\SitemapGenerator\SitemapHelper;
use Uwil\SitemapGenerator\Tests\Unit\Config\ModelClass;
use Webmozart\Assert\Assert;
covers([SitemapGenerator::class, SitemapHelper::class, McamaraRouteLocalizer::class]);
describe('SitemapGenerator with McamaraRouteLocalizer', function () {
beforeEach(function () {
app()->register(LaravelLocalizationServiceProvider::class);
config()->set('laravellocalization.supportedLocales', [
'fr' => ['name' => 'French', 'script' => 'Latn', 'native' => 'Français'],
'en' => ['name' => 'English', 'script' => 'Latn', 'native' => 'English'],
]);
config()->set('laravellocalization.hideDefaultLocaleInURL', false);
});
afterEach(function () {
Schema::dropIfExists('model_classes');
});
it('can be instantiated and resolved from container with mcamara localizer', function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
// GIVEN
config()->set('sitemap-generator.localizer', 'mcamara');
config()->set('sitemap-generator.output', [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
]);
config()->set('sitemap-generator.supported_locales', ['fr', 'en']);
// WHEN
$generator = app(SitemapGenerator::class);
// THEN
expect($generator)->toBeInstanceOf(SitemapGenerator::class);
});
it('generates an empty sitemap when no pages or cruds are configured', function () {
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
// GIVEN
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => [],
'supported_locales' => ['fr'],
'cruds' => [],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap)->toBeInstanceOf(Sitemap::class)
->and($sitemap->getTags())->toBeEmpty();
});
it('generates a sitemap with single pages in a single locale', function () {
// GIVEN
app('translator')->addLines([
'routes.about' => 'a-propos',
'routes.contact' => 'contactez-nous',
], 'fr');
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => ['about', 'contact'],
'supported_locales' => ['fr'],
'cruds' => [],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap)->toBeInstanceOf(Sitemap::class)
->and($sitemap->hasUrl('http://localhost/fr/a-propos'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/fr/contactez-nous'))->toBeTrue()
->and($sitemap->getTags())->toHaveCount(2);
});
it('generates a sitemap with single pages and alternates across multiple locales', function () {
// GIVEN
app('translator')->addLines([
'routes.about' => 'a-propos',
'routes.contact' => 'contactez-nous',
], 'fr');
app('translator')->addLines([
'routes.about' => 'about-us',
'routes.contact' => 'contact-us',
], 'en');
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => ['about', 'contact'],
'supported_locales' => ['fr', 'en'],
'cruds' => [],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap)->toBeInstanceOf(Sitemap::class)
->and($sitemap->hasUrl('http://localhost/fr/a-propos'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/en/about-us'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/fr/contactez-nous'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/en/contact-us'))->toBeTrue();
$aboutTagFr = collect($sitemap->getTags())
->first(fn (mixed $tag): bool => $tag instanceof Url && $tag->url === 'http://localhost/fr/a-propos');
Assert::isInstanceOf($aboutTagFr, Url::class);
expect($aboutTagFr->alternates)->toHaveCount(1)
->and($aboutTagFr->alternates[0]->url)->toBe('http://localhost/en/about-us')
->and($aboutTagFr->alternates[0]->locale)->toBe('en');
$aboutTagEn = collect($sitemap->getTags())
->first(fn (mixed $tag): bool => $tag instanceof Url && $tag->url === 'http://localhost/en/about-us');
Assert::isInstanceOf($aboutTagEn, Url::class);
expect($aboutTagEn->alternates)->toHaveCount(1)
->and($aboutTagEn->alternates[0]->url)->toBe('http://localhost/fr/a-propos')
->and($aboutTagEn->alternates[0]->locale)->toBe('fr');
});
it('ignores untranslated routes gracefully without producing bare locale root', function () {
// GIVEN
app('translator')->addLines([
'routes.contact' => 'contactez-nous',
], 'fr');
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => ['contact', 'missing_translation'],
'supported_locales' => ['fr'],
'cruds' => [],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap->hasUrl('http://localhost/fr/contactez-nous'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/fr'))->toBeFalse()
->and($sitemap->getTags())->toHaveCount(1);
});
it('handles partially translated routes across locales', function () {
// GIVEN
app('translator')->addLines([
'routes.contact' => 'contactez-nous',
'routes.french_only' => 'seulement-francais',
], 'fr');
app('translator')->addLines([
'routes.contact' => 'contact-us',
], 'en');
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => ['contact', 'french_only'],
'supported_locales' => ['fr', 'en'],
'cruds' => [],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap->hasUrl('http://localhost/fr/contactez-nous'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/en/contact-us'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/fr/seulement-francais'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/en'))->toBeFalse()
->and($sitemap->getTags())->toHaveCount(3);
$frenchOnlyTag = collect($sitemap->getTags())
->first(fn (mixed $tag): bool => $tag instanceof Url && $tag->url === 'http://localhost/fr/seulement-francais');
Assert::isInstanceOf($frenchOnlyTag, Url::class);
expect($frenchOnlyTag->alternates)->toBeEmpty();
});
it('generates a sitemap with cruds models and alternates', function () {
// GIVEN
Schema::create('model_classes', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
ModelClass::create();
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => [],
'supported_locales' => ['fr', 'en'],
'cruds' => [
[
'model' => ModelClass::class,
],
],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap)->toBeInstanceOf(Sitemap::class)
->and($sitemap->hasUrl('http://localhost/fr/posts'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/en/posts'))->toBeTrue();
$crudTagFr = collect($sitemap->getTags())
->first(fn (mixed $tag): bool => $tag instanceof Url && $tag->url === 'http://localhost/fr/posts');
Assert::isInstanceOf($crudTagFr, Url::class);
expect($crudTagFr->alternates)->toHaveCount(1)
->and($crudTagFr->alternates[0]->url)->toBe('http://localhost/en/posts')
->and($crudTagFr->alternates[0]->locale)->toBe('en');
});
it('generates a combined sitemap with single pages and cruds', function () {
// GIVEN
app('translator')->addLines([
'routes.home' => 'accueil',
], 'fr');
Schema::create('model_classes', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
ModelClass::create();
/** @var \Uwil\SitemapGenerator\Tests\TestCase $this */
$config = new SitemapConfig(new ConfigRepository([
SitemapConfig::CONFIG_KEY => [
'single_pages' => ['home'],
'supported_locales' => ['fr'],
'cruds' => [
[
'model' => ModelClass::class,
],
],
'schedule' => false,
'cron' => '* * * * *',
'localizer' => 'mcamara',
'output' => [
'storage_disk' => $this->outputDisk,
'path' => $this->outputPath,
],
],
]));
$translator = app()->make(Translator::class);
$generator = new SitemapGenerator(
$config,
new SitemapHelper(
$config,
new McamaraRouteLocalizer($translator)
)
);
// WHEN
$sitemap = $generator->generate();
// THEN
expect($sitemap->hasUrl('http://localhost/fr/accueil'))->toBeTrue()
->and($sitemap->hasUrl('http://localhost/fr/posts'))->toBeTrue()
->and($sitemap->getTags())->toHaveCount(2);
});
});