create();
$category = Category::query()->create(['name' => '随笔', 'display_order' => 0]);
$article = Article::query()->create([
'category_id' => $category->id,
'user_id' => $user->id,
'title' => 'Hello',
'content' => "## Hi\n\nworld",
'content_format' => 'markdown',
'published_at' => now()->subHour(),
'visible' => true,
]);
$this->get('/')
->assertOk()
->assertSee('Hello')
->assertSee('/themes/default/style.css', false);
$this->get('/show-'.$article->id.'.shtml')->assertOk()->assertSee('Hi');
$this->get('/tburl.php')->assertStatus(410);
$this->get('/llms.txt')->assertOk()->assertSee('Guidance for AI systems');
$this->get('/robots.txt')->assertOk()->assertSee('Sitemap:');
$this->get('/rss.xml')->assertOk();
$this->get('/sitemap.xml')->assertOk();
}
public function test_category_page_exposes_intro_and_seo(): void
{
$user = User::factory()->create();
$category = Category::query()->create([
'name' => '随笔',
'display_order' => 0,
'description' => '随笔分类摘要',
'intro' => '这是分类介绍,给列表页和爬虫看。',
'keywords' => '随笔,笔记',
]);
Article::query()->create([
'category_id' => $category->id,
'user_id' => $user->id,
'title' => '分类里的文章',
'content' => 'body',
'content_format' => 'html',
'published_at' => now()->subHour(),
'visible' => true,
]);
$this->get('/category-'.$category->id.'.shtml')
->assertOk()
->assertSee('随笔', false)
->assertSee('这是分类介绍,给列表页和爬虫看。', false)
->assertSee('分类里的文章', false)
->assertSee('', false)
->assertSee('', false)
->assertSee('CollectionPage', false)
->assertSee('/category-'.$category->id.'.shtml', false);
$this->get('/sitemap.xml')->assertOk()->assertSee('/category-'.$category->id.'.shtml', false);
$this->get('/llms.txt')->assertOk()->assertSee('随笔')->assertSee('随笔分类摘要');
}
public function test_comment_author_website_uses_noreferrer(): void
{
$user = User::factory()->create();
$category = Category::query()->create(['name' => '随笔', 'display_order' => 0]);
$article = Article::query()->create([
'category_id' => $category->id,
'user_id' => $user->id,
'title' => 'Hello',
'content' => 'Hi',
'content_format' => 'html',
'description' => '文章摘要给评论后台看',
'published_at' => now()->subHour(),
'visible' => true,
'comments_count' => 1,
]);
Comment::query()->create([
'article_id' => $article->id,
'author' => '访客甲',
'url' => 'https://example.com/me',
'content' => '一条评论',
'moderation_status' => Comment::STATUS_APPROVED,
'published_at' => now()->subMinute(),
]);
$this->get('/show-'.$article->id.'.shtml')
->assertOk()
->assertSee('访客甲', false)
->assertSee('href="https://example.com/me"', false)
->assertSee('rel="nofollow noopener noreferrer"', false)
->assertDontSee('javascript:', false);
$this->get('/comments.shtml')
->assertOk()
->assertSee('rel="nofollow noopener noreferrer"', false);
$unsafe = new Comment(['url' => 'javascript:alert(1)']);
$this->assertNull($unsafe->websiteHref());
}
public function test_category_articles_count_url_targets_article_filter(): void
{
$category = Category::query()->create(['name' => '随笔', 'display_order' => 0]);
$url = ArticleResource::getUrl('index', [
'filters' => [
'category_id' => ['value' => $category->id],
],
]);
$this->assertStringContainsString((string) $category->id, $url);
$decoded = urldecode($url);
$this->assertTrue(
str_contains($decoded, 'filters[category_id]') || str_contains($url, 'filters'),
$url
);
}
}