ContactConfigurationTest.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. <?php
  2. namespace Tests\Integration;
  3. use App\Http\Controllers\admin\ContactConfiguration;
  4. use App\Services\ContactConfigurationService;
  5. use Illuminate\Config\Repository;
  6. use Illuminate\Database\Capsule\Manager;
  7. use Illuminate\Events\Dispatcher;
  8. use Illuminate\Foundation\Application;
  9. use Illuminate\Http\Request;
  10. use Illuminate\Routing\Router;
  11. use Illuminate\Support\Facades\DB;
  12. use Illuminate\Support\Facades\Facade;
  13. use Illuminate\Translation\ArrayLoader;
  14. use Illuminate\Translation\Translator;
  15. use Illuminate\Validation\Factory;
  16. use Illuminate\Validation\ValidationException;
  17. use PHPUnit\Framework\Attributes\DataProvider;
  18. use PHPUnit\Framework\TestCase;
  19. class ContactConfigurationTest extends TestCase
  20. {
  21. private Application $app;
  22. private ContactConfigurationService $service;
  23. protected function setUp(): void
  24. {
  25. Facade::clearResolvedInstances(); $this->app = new Application(dirname(__DIR__, 2));
  26. $this->app->instance('config', new Repository(['app' => ['locale' => 'zh', 'timezone' => 'Asia/Shanghai']]));
  27. Facade::setFacadeApplication($this->app);
  28. $db = new Manager($this->app); $db->addConnection(['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'bot_']);
  29. $db->setEventDispatcher(new Dispatcher($this->app)); $db->setAsGlobal(); $db->bootEloquent();
  30. $this->app->instance('db', $db->getDatabaseManager()); $this->app->bind('db.schema', fn () => $db->schema());
  31. $translator = new Translator(new ArrayLoader(), 'zh'); $this->app->instance('translator', $translator);
  32. $this->app->instance('validator', new Factory($translator, $this->app));
  33. $this->app->instance('log', new \Psr\Log\NullLogger());
  34. $this->app->instance(\Illuminate\Contracts\Routing\ResponseFactory::class, new \Tests\Support\JsonResponseFactory());
  35. $request = Request::create('/admin/contact/config'); $request->user = (object) ['id' => 1, 'username' => 'admin']; $this->app->instance('request', $request);
  36. DB::statement('CREATE TABLE bot_operation_audits (id INTEGER PRIMARY KEY AUTOINCREMENT,resource_type TEXT,resource_id INTEGER,action TEXT,changes TEXT,operator_id INTEGER,operator_name TEXT,created_at TEXT)');
  37. (require dirname(__DIR__, 2) . '/database/migrations/2026_11_04_130000_create_contact_settings.php')->up();
  38. $this->service = new ContactConfigurationService();
  39. }
  40. protected function tearDown(): void { DB::disconnect(); Facade::clearResolvedInstances(); parent::tearDown(); }
  41. public function test_empty_by_default(): void
  42. {
  43. $this->assertSame(['emails' => [], 'domains' => []], $this->service->get());
  44. }
  45. public function test_save_normalizes_dedupes_skips_blanks_and_keeps_order(): void
  46. {
  47. $result = $this->service->save([
  48. 'emails' => [' support@example.com ', '', null, 'Biz@Example.com', 'SUPPORT@example.com'],
  49. 'domains' => ['example.com', 'https://EXAMPLE.com/', ' ', 'HTTP://backup.example:8080'],
  50. ]);
  51. $this->assertSame(['emails' => ['support@example.com', 'Biz@Example.com'], 'domains' => ['https://example.com', 'http://backup.example:8080']], $result);
  52. $this->assertSame($result, $this->service->get());
  53. $this->assertSame(1, DB::table('operation_audits')->count());
  54. $this->service->save($result);
  55. $this->assertSame(1, DB::table('operation_audits')->count(), 'unchanged save is not audited');
  56. $this->assertSame(['emails' => [], 'domains' => []], $this->service->save(['emails' => [], 'domains' => []]));
  57. }
  58. #[DataProvider('invalidPayloads')]
  59. public function test_invalid_payload_does_not_save(array $payload): void
  60. {
  61. $before = $this->service->save(['emails' => ['a@example.com'], 'domains' => ['example.com']]);
  62. try { $this->service->save($payload); $this->fail('Expected validation failure'); }
  63. catch (ValidationException $e) { $this->assertNotEmpty($e->validator->errors()->first()); }
  64. $this->assertSame($before, $this->service->get());
  65. }
  66. public static function invalidPayloads(): array
  67. {
  68. return [
  69. [['domains' => []]], [['emails' => []]],
  70. [['emails' => 'a@example.com', 'domains' => []]],
  71. [['emails' => ['not-an-email'], 'domains' => []]],
  72. [['emails' => ['x' => 'a@example.com'], 'domains' => []]],
  73. [['emails' => [123], 'domains' => []]],
  74. [['emails' => array_fill(0, 51, 'a@example.com'), 'domains' => []]],
  75. [['emails' => [], 'domains' => ['ftp://example.com']]],
  76. [['emails' => [], 'domains' => ['https://example.com/path']]],
  77. [['emails' => [], 'domains' => array_fill(0, 51, 'example.com')]],
  78. ];
  79. }
  80. public function test_routes_and_controller(): void
  81. {
  82. $router = new Router(new Dispatcher($this->app), $this->app); $this->app->instance('router', $router);
  83. $router->group(['prefix' => 'admin'], function () { require dirname(__DIR__, 2) . '/routes/admin.php'; });
  84. $get = $router->getRoutes()->match(Request::create('/admin/contact/config', 'GET'));
  85. $post = $router->getRoutes()->match(Request::create('/admin/contact/config', 'POST'));
  86. foreach ([$get, $post] as $route) {
  87. $this->assertContains('admin.jwt', $route->middleware()); $this->assertContains('check.button.uri', $route->middleware());
  88. }
  89. $this->assertContains('operations.admin', $post->middleware());
  90. $this->assertSame('admin/contact/config/save', $post->defaults['permission_uri']);
  91. $this->app->instance('request', Request::create('/admin/contact/config', 'POST', ['emails' => ['bad'], 'domains' => []]));
  92. $response = (new ContactConfiguration())->save($this->service);
  93. $this->assertSame(-3, $response->getData(true)['code']);
  94. $this->assertStringContainsString('邮箱格式不正确', $response->getData(true)['msg']);
  95. $response = (new ContactConfiguration())->show($this->service);
  96. $this->assertSame(0, $response->getData(true)['code']);
  97. $this->assertSame(['emails' => [], 'domains' => []], $response->getData(true)['data']);
  98. }
  99. }