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 ); } }