前端极简黑白重设计,并纳入客户端注册、站点设置与后台相关改动
- storefront 全站改为极简黑白配色:直角、细线分隔、卡片 hover 浅底、深色模式(跟随系统+手动切换) - 抽出 storefront/partials/card 复用卡片 - 一并提交此前暂存的客户端注册 API、站点设置、后台页面与测试 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Package;
|
||||
use App\Models\StoreClient;
|
||||
use App\Models\Version;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ClientRegistrationApiTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_client_can_register_and_sync_status(): void
|
||||
{
|
||||
$register = $this->postJson('/api/v1/client/register', [
|
||||
'site_url' => 'https://demo.example.com/',
|
||||
'site_name' => 'Demo Blog',
|
||||
'typecho_version' => '1.3.0',
|
||||
'php_version' => '8.2.16',
|
||||
'plugin_version' => '1.0.0',
|
||||
'user_count' => 3,
|
||||
]);
|
||||
|
||||
$register->assertOk()
|
||||
->assertJsonPath('code', 0)
|
||||
->assertJsonPath('data.site_url', 'https://demo.example.com')
|
||||
->assertJsonPath('data.user_count', 3);
|
||||
|
||||
$token = (string) $register->json('data.access_token');
|
||||
|
||||
$heartbeat = $this->withToken($token)->postJson('/api/v1/client/heartbeat', [
|
||||
'site_name' => 'Demo Blog',
|
||||
'user_count' => 5,
|
||||
'plugin_version' => '1.0.1',
|
||||
]);
|
||||
|
||||
$heartbeat->assertOk()
|
||||
->assertJsonPath('code', 0)
|
||||
->assertJsonPath('data.user_count', 5)
|
||||
->assertJsonPath('data.plugin_version', '1.0.1')
|
||||
->assertJsonPath('data.stats.registered_sites', 1)
|
||||
->assertJsonPath('data.stats.tracked_users', 5);
|
||||
|
||||
$this->withToken($token)->getJson('/api/v1/client/status')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', 0)
|
||||
->assertJsonPath('data.site_url', 'https://demo.example.com')
|
||||
->assertJsonMissingPath('data.access_token');
|
||||
|
||||
$client = StoreClient::query()->where('site_url', 'https://demo.example.com')->firstOrFail();
|
||||
$previousSeenAt = $client->last_seen_at;
|
||||
|
||||
sleep(1);
|
||||
|
||||
$this->withToken($token)->getJson('/api/v1/client/status')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', 0);
|
||||
|
||||
$client->refresh();
|
||||
|
||||
$this->assertNotNull($client->last_seen_at);
|
||||
$this->assertTrue($client->last_seen_at->gt($previousSeenAt));
|
||||
$this->assertSame('online', $client->status);
|
||||
}
|
||||
|
||||
public function test_download_endpoint_accepts_registered_client_token(): void
|
||||
{
|
||||
config(['app.url' => 'http://127.0.0.1:8000']);
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'DemoPlugin',
|
||||
'name' => 'Demo Plugin',
|
||||
'summary' => 'Summary',
|
||||
'description' => 'Description',
|
||||
'author' => 'Author',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '1.2.3',
|
||||
]);
|
||||
|
||||
Version::query()->create([
|
||||
'package_id' => $package->id,
|
||||
'version' => '1.2.3',
|
||||
'changelog' => 'Initial release',
|
||||
'typecho_min' => '1.2.0',
|
||||
'typecho_max' => '',
|
||||
'php_min' => '8.0',
|
||||
'php_max' => '',
|
||||
'php_extensions' => '[]',
|
||||
'package_url' => 'https://cdn.example.com/DemoPlugin-1.2.3.zip',
|
||||
'package_size' => 1234,
|
||||
'sha256' => str_repeat('a', 64),
|
||||
'is_stable' => true,
|
||||
'is_latest' => true,
|
||||
'download_count' => 0,
|
||||
'published_at' => now(),
|
||||
]);
|
||||
|
||||
$this->getJson('/api/v1/repo/download/plugin/DemoPlugin/latest')
|
||||
->assertStatus(403)
|
||||
->assertJsonPath('message', 'client token required');
|
||||
|
||||
$register = $this->postJson('/api/v1/client/register', [
|
||||
'site_url' => 'https://demo.example.com',
|
||||
'site_name' => 'Demo Blog',
|
||||
'user_count' => 2,
|
||||
]);
|
||||
|
||||
$token = (string) $register->json('data.access_token');
|
||||
|
||||
$this->withToken($token)
|
||||
->getJson('https://store.typecho.team/api/v1/repo/download/plugin/DemoPlugin/latest')
|
||||
->assertOk()
|
||||
->assertJsonPath('code', 0)
|
||||
->assertJsonPath('data.package.sha256', str_repeat('a', 64))
|
||||
->assertJsonPath('data.version', '1.2.3')
|
||||
->assertJsonPath('data.package.download_url', 'https://store.typecho.team/api/v1/repo/download/plugin/DemoPlugin/1.2.3?redirect=1');
|
||||
}
|
||||
|
||||
public function test_check_updates_returns_request_host_download_url_when_app_url_is_local(): void
|
||||
{
|
||||
config(['app.url' => 'http://127.0.0.1:8000']);
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'DemoPlugin',
|
||||
'name' => 'Demo Plugin',
|
||||
'summary' => 'Summary',
|
||||
'description' => 'Description',
|
||||
'author' => 'Author',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '1.2.3',
|
||||
]);
|
||||
|
||||
Version::query()->create([
|
||||
'package_id' => $package->id,
|
||||
'version' => '1.2.3',
|
||||
'changelog' => 'Initial release',
|
||||
'typecho_min' => '1.2.0',
|
||||
'typecho_max' => '',
|
||||
'php_min' => '8.0',
|
||||
'php_max' => '',
|
||||
'php_extensions' => '[]',
|
||||
'package_url' => 'http://127.0.0.1:8000/api/v1/repo/download/plugin/DemoPlugin/1.2.3?redirect=1',
|
||||
'package_size' => 1234,
|
||||
'sha256' => str_repeat('a', 64),
|
||||
'is_stable' => true,
|
||||
'is_latest' => true,
|
||||
'download_count' => 0,
|
||||
'published_at' => now(),
|
||||
]);
|
||||
|
||||
$response = $this->postJson('https://store.typecho.team/api/v1/repo/updates/check', [
|
||||
'installed' => [
|
||||
[
|
||||
'type' => 'plugin',
|
||||
'slug' => 'DemoPlugin',
|
||||
'version' => '1.0.0',
|
||||
],
|
||||
],
|
||||
'typecho_version' => '1.3.0',
|
||||
'php_version' => '8.2.16',
|
||||
]);
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonPath('code', 0)
|
||||
->assertJsonCount(1, 'data.updates')
|
||||
->assertJsonPath('data.updates.0.package.download_url', 'https://store.typecho.team/api/v1/repo/download/plugin/DemoPlugin/1.2.3?redirect=1');
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,52 @@ class VersionPublishServiceTest extends TestCase
|
||||
app(VersionPublishService::class)->publishFromZip($package, $uploadedFile, []);
|
||||
}
|
||||
|
||||
public function test_manifest_validation_allows_lowercase_theme_slug(): void
|
||||
{
|
||||
$package = Package::query()->create([
|
||||
'type' => 'theme',
|
||||
'slug' => 'clarity',
|
||||
'name' => 'Clarity',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'draft',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '',
|
||||
]);
|
||||
|
||||
$manifest = [
|
||||
'schema_version' => '1.0',
|
||||
'type' => 'theme',
|
||||
'slug' => 'clarity',
|
||||
'name' => 'Clarity',
|
||||
'author' => 'Author',
|
||||
'version' => '1.5.0',
|
||||
'compatibility' => [
|
||||
'typecho_min' => '1.2.0',
|
||||
'php_min' => '8.0',
|
||||
],
|
||||
'install' => [
|
||||
'root_dir' => 'clarity',
|
||||
'target_dir' => 'usr/themes/clarity',
|
||||
],
|
||||
'package' => [
|
||||
'sha256' => str_repeat('a', 64),
|
||||
],
|
||||
];
|
||||
|
||||
$method = new \ReflectionMethod(VersionPublishService::class, 'validateManifest');
|
||||
$method->setAccessible(true);
|
||||
$method->invoke(app(VersionPublishService::class), $manifest, $package, str_repeat('a', 64));
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
foreach ($this->temporaryZipPaths as $path) {
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminAccountPageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_authenticated_admin_can_view_account_page(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'name' => 'Security Admin',
|
||||
'email' => 'security@example.com',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/admin/account')
|
||||
->assertOk()
|
||||
->assertSee('账户安全')
|
||||
->assertSee('Security Admin')
|
||||
->assertSee('security@example.com')
|
||||
->assertSee('修改密码');
|
||||
}
|
||||
|
||||
public function test_authenticated_admin_can_update_password(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'email' => 'security@example.com',
|
||||
'password' => 'OldPassword123',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->put('/admin/account/password', [
|
||||
'current_password' => 'OldPassword123',
|
||||
'new_password' => 'NewPassword456',
|
||||
'new_password_confirmation' => 'NewPassword456',
|
||||
])
|
||||
->assertRedirect('/admin/account')
|
||||
->assertSessionHas('success', '密码已更新');
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertTrue(Hash::check('NewPassword456', $user->password));
|
||||
$this->assertFalse(Hash::check('OldPassword123', $user->password));
|
||||
}
|
||||
|
||||
public function test_password_update_requires_correct_current_password(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'password' => 'OldPassword123',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->from('/admin/account')
|
||||
->put('/admin/account/password', [
|
||||
'current_password' => 'WrongPassword999',
|
||||
'new_password' => 'NewPassword456',
|
||||
'new_password_confirmation' => 'NewPassword456',
|
||||
])
|
||||
->assertRedirect('/admin/account')
|
||||
->assertSessionHasErrors('current_password');
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertTrue(Hash::check('OldPassword123', $user->password));
|
||||
$this->assertFalse(Hash::check('NewPassword456', $user->password));
|
||||
}
|
||||
|
||||
public function test_authenticated_admin_can_update_profile(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'name' => 'Old Admin',
|
||||
'email' => 'old@example.com',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->put('/admin/account/profile', [
|
||||
'name' => 'New Admin',
|
||||
'email' => 'new@example.com',
|
||||
])
|
||||
->assertRedirect('/admin/account')
|
||||
->assertSessionHas('success', '账户资料已更新');
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertSame('New Admin', $user->name);
|
||||
$this->assertSame('new@example.com', $user->email);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\StoreClient;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminClientsPageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_authenticated_admin_can_view_clients_page(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
StoreClient::query()->create([
|
||||
'site_url' => 'https://demo.example.com',
|
||||
'site_name' => 'Demo Blog',
|
||||
'access_token' => str_repeat('a', 96),
|
||||
'status' => 'online',
|
||||
'user_count' => 12,
|
||||
'typecho_version' => '1.3.0',
|
||||
'php_version' => '8.2.16',
|
||||
'plugin_version' => '1.0.0',
|
||||
'registered_at' => now()->subDay(),
|
||||
'last_seen_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/admin/clients')
|
||||
->assertOk()
|
||||
->assertSee('站点接入')
|
||||
->assertSee('Demo Blog')
|
||||
->assertSee('https://demo.example.com')
|
||||
->assertSee('用户数')
|
||||
->assertSee('在线');
|
||||
}
|
||||
|
||||
public function test_clients_page_can_filter_offline_sites(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
StoreClient::query()->create([
|
||||
'site_url' => 'https://online.example.com',
|
||||
'site_name' => 'Online',
|
||||
'access_token' => str_repeat('b', 96),
|
||||
'status' => 'online',
|
||||
'user_count' => 3,
|
||||
'registered_at' => now()->subHours(2),
|
||||
'last_seen_at' => now(),
|
||||
]);
|
||||
|
||||
StoreClient::query()->create([
|
||||
'site_url' => 'https://offline.example.com',
|
||||
'site_name' => 'Offline',
|
||||
'access_token' => str_repeat('c', 96),
|
||||
'status' => 'online',
|
||||
'user_count' => 5,
|
||||
'registered_at' => now()->subHours(5),
|
||||
'last_seen_at' => now()->subHour(),
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/admin/clients?status=offline')
|
||||
->assertOk()
|
||||
->assertSee('Offline')
|
||||
->assertDontSee('Online');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Package;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminPackageCategoriesTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_admin_can_update_package_categories_and_missing_categories_are_created(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'HelloStore',
|
||||
'name' => 'Hello Store',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->put('/admin/packages/plugin/HelloStore', [
|
||||
'type' => 'plugin',
|
||||
'slug' => 'HelloStore',
|
||||
'name' => 'Hello Store',
|
||||
'status' => 'published',
|
||||
'categories_text' => 'SEO performance_cache',
|
||||
])
|
||||
->assertRedirect('/admin/packages/plugin/HelloStore')
|
||||
->assertSessionHas('success', '扩展已更新');
|
||||
|
||||
$package->refresh()->load('categories');
|
||||
|
||||
$this->assertSame(['performance-cache', 'seo'], $package->categories->pluck('slug')->sort()->values()->all());
|
||||
|
||||
$this->assertDatabaseHas('store_categories', [
|
||||
'type' => 'plugin',
|
||||
'slug' => 'seo',
|
||||
'name' => 'Seo',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('store_categories', [
|
||||
'type' => 'plugin',
|
||||
'slug' => 'performance-cache',
|
||||
'name' => 'Performance Cache',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_admin_can_update_package_categories_with_chinese_names(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'HelloWorld',
|
||||
'name' => 'Hello World',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->put('/admin/packages/plugin/HelloWorld', [
|
||||
'type' => 'plugin',
|
||||
'slug' => 'HelloWorld',
|
||||
'name' => 'Hello World',
|
||||
'status' => 'published',
|
||||
'categories_text' => '性能优化, 内容增强',
|
||||
])
|
||||
->assertRedirect('/admin/packages/plugin/HelloWorld')
|
||||
->assertSessionHas('success', '扩展已更新');
|
||||
|
||||
$package->refresh()->load('categories');
|
||||
|
||||
$this->assertSame(['内容增强', '性能优化'], $package->categories->pluck('name')->sort()->values()->all());
|
||||
|
||||
$this->assertDatabaseHas('store_categories', [
|
||||
'type' => 'plugin',
|
||||
'slug' => '性能优化',
|
||||
'name' => '性能优化',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('store_categories', [
|
||||
'type' => 'plugin',
|
||||
'slug' => '内容增强',
|
||||
'name' => '内容增强',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\Package;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminPackageDeletionTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_admin_can_delete_package_and_related_data(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'DeleteMe',
|
||||
'name' => 'Delete Me',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '1.0.0',
|
||||
]);
|
||||
|
||||
$category = Category::query()->create([
|
||||
'type' => 'plugin',
|
||||
'slug' => 'utility',
|
||||
'name' => 'Utility',
|
||||
'description' => '',
|
||||
'sort_order' => 0,
|
||||
]);
|
||||
|
||||
$package->categories()->attach($category->id);
|
||||
|
||||
$version = $package->versions()->create([
|
||||
'version' => '1.0.0',
|
||||
'changelog' => '',
|
||||
'typecho_min' => '1.2.0',
|
||||
'typecho_max' => '',
|
||||
'php_min' => '8.0',
|
||||
'php_max' => '',
|
||||
'php_extensions' => '[]',
|
||||
'package_url' => 'https://cdn.example.com/DeleteMe-1.0.0.zip',
|
||||
'package_size' => 1234,
|
||||
'sha256' => str_repeat('b', 64),
|
||||
'is_stable' => true,
|
||||
'is_latest' => true,
|
||||
'download_count' => 0,
|
||||
'published_at' => now(),
|
||||
]);
|
||||
|
||||
$screenshot = $package->screenshots()->create([
|
||||
'image_url' => 'https://cdn.example.com/DeleteMe-home.webp',
|
||||
'caption' => 'Home',
|
||||
'sort_order' => 1,
|
||||
]);
|
||||
|
||||
$packageDir = storage_path('app/packages/plugin/DeleteMe');
|
||||
File::ensureDirectoryExists($packageDir);
|
||||
File::put($packageDir . '/1.0.0.zip', 'demo');
|
||||
|
||||
$this->actingAs($user)
|
||||
->delete('/admin/packages/plugin/DeleteMe')
|
||||
->assertRedirect('/admin/packages?type=plugin')
|
||||
->assertSessionHas('success', '扩展已删除:Delete Me');
|
||||
|
||||
$this->assertDatabaseMissing('store_packages', [
|
||||
'id' => $package->id,
|
||||
]);
|
||||
$this->assertDatabaseMissing('store_versions', [
|
||||
'id' => $version->id,
|
||||
]);
|
||||
$this->assertDatabaseMissing('store_screenshots', [
|
||||
'id' => $screenshot->id,
|
||||
]);
|
||||
$this->assertDatabaseMissing('store_package_categories', [
|
||||
'package_id' => $package->id,
|
||||
'category_id' => $category->id,
|
||||
]);
|
||||
$this->assertFalse(File::isDirectory($packageDir));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Package;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminPackageScreenshotsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_admin_can_add_and_delete_package_screenshot(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$package = Package::query()->create([
|
||||
'type' => 'theme',
|
||||
'slug' => 'Mango',
|
||||
'name' => 'Mango',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post('/admin/packages/theme/Mango/screenshots', [
|
||||
'image_url' => 'https://cdn.example.com/mango/home.webp',
|
||||
'caption' => '首页预览',
|
||||
'sort_order' => 3,
|
||||
])
|
||||
->assertRedirect('/admin/packages/theme/Mango')
|
||||
->assertSessionHas('success', '截图已添加');
|
||||
|
||||
$this->assertDatabaseHas('store_screenshots', [
|
||||
'package_id' => $package->id,
|
||||
'image_url' => 'https://cdn.example.com/mango/home.webp',
|
||||
'caption' => '首页预览',
|
||||
'sort_order' => 3,
|
||||
]);
|
||||
|
||||
$shotId = (int) $package->screenshots()->value('id');
|
||||
|
||||
$this->actingAs($user)
|
||||
->delete('/admin/packages/theme/Mango/screenshots/' . $shotId)
|
||||
->assertRedirect('/admin/packages/theme/Mango')
|
||||
->assertSessionHas('success', '截图已删除');
|
||||
|
||||
$this->assertDatabaseMissing('store_screenshots', [
|
||||
'id' => $shotId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_storefront_detail_page_uses_screenshot_preview_section_instead_of_related_cards(): void
|
||||
{
|
||||
$package = Package::query()->create([
|
||||
'type' => 'theme',
|
||||
'slug' => 'Mango',
|
||||
'name' => 'Mango',
|
||||
'summary' => 'A clean theme.',
|
||||
'description' => 'Theme description.',
|
||||
'author' => 'Team Store',
|
||||
'homepage' => 'https://example.com/mango',
|
||||
'icon_url' => '',
|
||||
'license' => 'MIT',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 12,
|
||||
'latest_version' => '1.5.0',
|
||||
]);
|
||||
|
||||
$package->screenshots()->createMany([
|
||||
[
|
||||
'image_url' => 'https://cdn.example.com/mango/hero.webp',
|
||||
'caption' => '首页展示',
|
||||
'sort_order' => 1,
|
||||
],
|
||||
[
|
||||
'image_url' => 'https://cdn.example.com/mango/post.webp',
|
||||
'caption' => '文章页展示',
|
||||
'sort_order' => 2,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->get('/theme/Mango')
|
||||
->assertOk()
|
||||
->assertSee('预览截图')
|
||||
->assertSee('首页展示')
|
||||
->assertSee('文章页展示')
|
||||
->assertDontSee('主题继续浏览');
|
||||
}
|
||||
|
||||
public function test_legacy_package_detail_route_redirects_to_short_theme_route(): void
|
||||
{
|
||||
$package = Package::query()->create([
|
||||
'type' => 'theme',
|
||||
'slug' => 'Mango',
|
||||
'name' => 'Mango',
|
||||
'summary' => '',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'homepage' => '',
|
||||
'icon_url' => '',
|
||||
'license' => '',
|
||||
'status' => 'published',
|
||||
'is_featured' => false,
|
||||
'sort_order' => 0,
|
||||
'download_count' => 0,
|
||||
'latest_version' => '1.5.0',
|
||||
]);
|
||||
|
||||
$this->get('/packages/theme/' . $package->slug)
|
||||
->assertRedirect('/theme/' . $package->slug);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WebAdminSettingsPageTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_authenticated_admin_can_update_storefront_settings(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$payload = [
|
||||
'site_name' => 'Team Store',
|
||||
'site_tagline' => 'Custom Extension Catalog',
|
||||
'home_title_suffix' => '自定义副标题',
|
||||
'home_eyebrow' => 'Custom Eyebrow',
|
||||
'home_headline' => '自定义首页标题',
|
||||
'home_lede' => '这里是自定义首页说明。',
|
||||
'home_aside_kicker' => 'Custom Aside',
|
||||
'home_aside_title' => '自定义侧栏标题',
|
||||
'home_feature_one_title' => '卡片一',
|
||||
'home_feature_one_body' => '卡片一说明',
|
||||
'home_feature_two_title' => '卡片二',
|
||||
'home_feature_two_body' => '卡片二说明',
|
||||
'home_feature_three_title' => '卡片三',
|
||||
'home_feature_three_body' => '卡片三说明',
|
||||
'home_plugins_title' => '插件精选',
|
||||
'home_plugins_subtitle' => '插件区域说明',
|
||||
'home_themes_title' => '主题精选',
|
||||
'home_themes_subtitle' => '主题区域说明',
|
||||
];
|
||||
|
||||
$this->actingAs($user)
|
||||
->put('/admin/settings', $payload)
|
||||
->assertRedirect('/admin/settings')
|
||||
->assertSessionHas('success', '站点设置已更新');
|
||||
|
||||
$this->assertDatabaseHas('store_settings', [
|
||||
'key' => 'site_name',
|
||||
'value' => 'Team Store',
|
||||
]);
|
||||
|
||||
$this->get('/')
|
||||
->assertOk()
|
||||
->assertSee('Team Store')
|
||||
->assertSee('自定义首页标题')
|
||||
->assertSee('插件精选')
|
||||
->assertSee('主题精选')
|
||||
->assertSee('<title>Team Store · 自定义副标题</title>', false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user