Current state with latest updates

This commit is contained in:
2026-08-23 13:28:34 +02:00
parent 5af95f6533
commit f52879edbb
74 changed files with 5174 additions and 960 deletions
+150 -1
View File
@@ -3,6 +3,12 @@
declare(strict_types=1);
use App\Models\Artwork;
use App\Models\AcademyChallenge;
use App\Models\AcademyCourse;
use App\Models\AcademyCourseLesson;
use App\Models\AcademyLesson;
use App\Models\AcademyPromptPack;
use App\Models\AcademyPromptTemplate;
use App\Models\Category;
use App\Models\Collection;
use App\Models\ContentType;
@@ -46,12 +52,24 @@ it('renders the sitemap index and every child sitemap endpoint', function (): vo
expect($indexXml)->not->toBeFalse();
expect($indexResponse->getContent())
->toContain(url('/sitemaps/artworks.xml'))
->toContain(url('/sitemaps/academy-pages.xml'))
->toContain(url('/sitemaps/academy-courses.xml'))
->toContain(url('/sitemaps/academy-lessons.xml'))
->toContain(url('/sitemaps/academy-prompts.xml'))
->toContain(url('/sitemaps/academy-packs.xml'))
->toContain(url('/sitemaps/academy-challenges.xml'))
->toContain(url('/sitemaps/static-pages.xml'))
->toContain(url('/sitemaps/forum-threads.xml'))
->toContain(url('/sitemaps/news-google.xml'));
foreach ([
'artworks',
'academy-pages',
'academy-courses',
'academy-lessons',
'academy-prompts',
'academy-packs',
'academy-challenges',
'users',
'tags',
'categories',
@@ -139,8 +157,36 @@ it('includes only public canonical urls and exposes the sitemap in robots txt',
->toContain('http://skinbase26.test/')
->toContain('/about')
->toContain('/pages/community-handbook')
->not->toContain('/academy')
->not->toContain('/academy/pricing')
->not->toContain('/pages/about');
$academyPagesXml = $this->get('/sitemaps/academy-pages.xml')->assertOk()->getContent();
expect($academyPagesXml)
->toContain(route('academy.index'))
->toContain(route('academy.pricing'));
$academyCoursesXml = $this->get('/sitemaps/academy-courses.xml')->assertOk()->getContent();
expect($academyCoursesXml)
->toContain($fixtures['academy_course_url']);
$academyLessonsXml = $this->get('/sitemaps/academy-lessons.xml')->assertOk()->getContent();
expect($academyLessonsXml)
->toContain($fixtures['academy_lesson_url'])
->not->toContain($fixtures['academy_course_lesson_url']);
$academyPromptsXml = $this->get('/sitemaps/academy-prompts.xml')->assertOk()->getContent();
expect($academyPromptsXml)
->toContain(route('academy.prompts.popular'))
->toContain($fixtures['academy_prompt_url'])
->not->toContain(route('academy.prompts.popular', ['period' => '7d']));
$academyPacksXml = $this->get('/sitemaps/academy-packs.xml')->assertOk()->getContent();
expect($academyPacksXml)->toContain($fixtures['academy_pack_url']);
$academyChallengesXml = $this->get('/sitemaps/academy-challenges.xml')->assertOk()->getContent();
expect($academyChallengesXml)->toContain($fixtures['academy_challenge_url']);
$robots = $this->get('/robots.txt')
->assertOk()
->assertHeader('Content-Type', 'text/plain; charset=UTF-8')
@@ -149,6 +195,38 @@ it('includes only public canonical urls and exposes the sitemap in robots txt',
expect($robots)->toContain('Sitemap: http://skinbase26.test/sitemap.xml');
});
it('includes only canonical academy urls in academy sitemap families', function (): void {
$fixtures = seedSitemapFixtures();
$academyCoursesXml = $this->get('/sitemaps/academy-courses.xml')->assertOk()->getContent();
expect($academyCoursesXml)
->toContain(route('academy.courses.index'))
->toContain($fixtures['academy_course_url']);
$academyLessonsXml = $this->get('/sitemaps/academy-lessons.xml')->assertOk()->getContent();
expect($academyLessonsXml)
->toContain(route('academy.lessons.index'))
->toContain($fixtures['academy_lesson_url'])
->not->toContain($fixtures['academy_course_lesson_url']);
$academyPromptsXml = $this->get('/sitemaps/academy-prompts.xml')->assertOk()->getContent();
expect($academyPromptsXml)
->toContain(route('academy.prompts.index'))
->toContain(route('academy.prompts.popular'))
->toContain($fixtures['academy_prompt_url'])
->not->toContain(route('academy.prompts.popular', ['period' => '7d']));
$academyPacksXml = $this->get('/sitemaps/academy-packs.xml')->assertOk()->getContent();
expect($academyPacksXml)
->toContain(route('academy.packs.index'))
->toContain($fixtures['academy_pack_url']);
$academyChallengesXml = $this->get('/sitemaps/academy-challenges.xml')->assertOk()->getContent();
expect($academyChallengesXml)
->toContain(route('academy.challenges.index'))
->toContain($fixtures['academy_challenge_url']);
});
it('returns 404 for unknown sitemap names', function (): void {
$this->get('/sitemaps/not-a-real-sitemap.xml')->assertNotFound();
});
@@ -547,6 +625,71 @@ function seedSitemapFixtures(): array
'last_post_at' => now()->subHours(2),
]);
$academyCourse = AcademyCourse::query()->create([
'title' => 'Sitemap Academy Course',
'slug' => 'sitemap-academy-course',
'excerpt' => 'An academy course for sitemap coverage.',
'description' => 'Course sitemap description',
'access_level' => 'free',
'difficulty' => 'beginner',
'status' => 'published',
'published_at' => now()->subMinute(),
]);
$academyLesson = AcademyLesson::query()->create([
'title' => 'Sitemap Academy Lesson',
'slug' => 'sitemap-academy-lesson',
'excerpt' => 'An academy lesson for sitemap coverage.',
'content' => 'Lesson sitemap content',
'difficulty' => 'beginner',
'access_level' => 'free',
'lesson_type' => 'article',
'active' => true,
'published_at' => now()->subMinute(),
]);
AcademyCourseLesson::query()->create([
'course_id' => $academyCourse->id,
'lesson_id' => $academyLesson->id,
'order_num' => 0,
'is_required' => true,
]);
$academyPrompt = AcademyPromptTemplate::query()->create([
'title' => 'Sitemap Academy Prompt',
'slug' => 'sitemap-academy-prompt',
'excerpt' => 'An academy prompt for sitemap coverage.',
'prompt' => 'Create a cinematic moonlit portrait.',
'difficulty' => 'beginner',
'access_level' => 'free',
'active' => true,
'published_at' => now()->subMinute(),
]);
$academyPack = AcademyPromptPack::query()->create([
'title' => 'Sitemap Academy Pack',
'slug' => 'sitemap-academy-pack',
'excerpt' => 'An academy pack for sitemap coverage.',
'description' => 'Pack sitemap description',
'access_level' => 'free',
'active' => true,
'published_at' => now()->subMinute(),
]);
$academyChallenge = AcademyChallenge::query()->create([
'title' => 'Sitemap Academy Challenge',
'slug' => 'sitemap-academy-challenge',
'excerpt' => 'An academy challenge for sitemap coverage.',
'description' => 'Challenge sitemap description',
'brief' => 'Create a hero image.',
'rules' => 'Keep it public.',
'access_level' => 'free',
'status' => AcademyChallenge::STATUS_ACTIVE,
'starts_at' => now()->subDay(),
'ends_at' => now()->addDay(),
'active' => true,
]);
return [
'artwork_url' => route('art.show', [
'id' => $artwork->id,
@@ -556,6 +699,12 @@ function seedSitemapFixtures(): array
'profile_url' => route('profile.show', ['username' => 'sitemapuser']),
'collection_url' => route('profile.collections.show', ['username' => 'sitemapuser', 'slug' => 'showcase-set']),
'card_url' => route('cards.show', ['slug' => 'clarity-card', 'id' => $card->id]),
'academy_course_url' => route('academy.courses.show', ['course' => $academyCourse->slug]),
'academy_lesson_url' => route('academy.lessons.show', ['slug' => $academyLesson->slug]),
'academy_course_lesson_url' => route('academy.courses.lessons.show', ['course' => $academyCourse->slug, 'lesson' => $academyLesson->slug]),
'academy_prompt_url' => route('academy.prompts.show', ['slug' => $academyPrompt->slug]),
'academy_pack_url' => route('academy.packs.show', ['slug' => $academyPack->slug]),
'academy_challenge_url' => route('academy.challenges.show', ['slug' => $academyChallenge->slug]),
];
}
@@ -696,4 +845,4 @@ function extractUrlLocs(string $xml): array
static fn ($node): string => trim((string) $node),
$nodes,
)));
}
}