wip: article AI polish, category SEO fields, cover generator, membership plan seeder
CI / PHPUnit (PHP 8.3) (push) Failing after 4s
CI / PHPUnit (PHP 8.2) (push) Failing after 1m9s
CI / Deploy (manual gate) (push) Skipped

This commit is contained in:
2026-09-07 18:48:37 +00:00
parent 263b98b218
commit 3cec4c5e18
121 changed files with 4701 additions and 313 deletions
+92
View File
@@ -2,8 +2,10 @@
namespace Tests\Feature;
use App\Filament\Resources\Articles\ArticleResource;
use App\Models\Article;
use App\Models\Category;
use App\Models\Comment;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
@@ -37,4 +39,94 @@ class BlogFrontendTest extends TestCase
$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('<meta name="description" content="随笔分类摘要">', false)
->assertSee('<meta name="keywords" content="随笔,笔记">', 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
);
}
}