Pest.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. use App\Models\Channel;
  3. use App\Models\UserInfo;
  4. use App\Services\AuthService;
  5. use Firebase\JWT\JWT;
  6. use Firebase\JWT\Key;
  7. use Illuminate\Foundation\Testing\RefreshDatabase;
  8. use Illuminate\Http\Request;
  9. use Illuminate\Support\Str;
  10. use Tests\TestCase;
  11. /*
  12. |--------------------------------------------------------------------------
  13. | Test Case
  14. |--------------------------------------------------------------------------
  15. |
  16. | The closure you provide to your test functions is always bound to a specific PHPUnit test
  17. | case class. By default, that class is "PHPUnit\Framework\TestCase". Of course, you may
  18. | need to change it using the "pest()" function to bind different classes or traits.
  19. |
  20. */
  21. pest()->extend(TestCase::class)
  22. // ->use(RefreshDatabase::class)
  23. ->in('Feature');
  24. /*
  25. |--------------------------------------------------------------------------
  26. | Expectations
  27. |--------------------------------------------------------------------------
  28. |
  29. | When you're writing tests, you often need to check that values meet certain conditions. The
  30. | "expect()" function gives you access to a set of "expectations" methods that you can use
  31. | to assert different things. Of course, you may extend the Expectation API at any time.
  32. |
  33. */
  34. expect()->extend('toBeOne', function () {
  35. return $this->toBe(1);
  36. });
  37. /*
  38. |--------------------------------------------------------------------------
  39. | Functions
  40. |--------------------------------------------------------------------------
  41. |
  42. | While Pest is very powerful out-of-the-box, you may have some testing code specific to your
  43. | project that you don't want to repeat in every file. Here you can also expose helpers as
  44. | global functions to help you to reduce the number of lines of code in your test files.
  45. |
  46. */
  47. function something()
  48. {
  49. // ..
  50. }
  51. /**
  52. * 造一个用户 token。
  53. *
  54. * AuthService::current() 只解 JWT、不查库,所以测试里不必真的建用户;
  55. * payload 结构必须与 AuthService::getUserToken() 保持一致。
  56. */
  57. function userToken(string $userUid, int $userId = 1): string
  58. {
  59. return JWT::encode([
  60. 'nbf' => time(),
  61. 'exp' => time() + 3600,
  62. 'uid' => $userUid,
  63. 'id' => $userId,
  64. ], config('mint.app.jwt_secrets_key'), 'HS512');
  65. }
  66. /**
  67. * 解开一个 token 的 payload。
  68. */
  69. function decodeToken(string $token): object
  70. {
  71. return JWT::decode($token, new Key(config('mint.app.jwt_secrets_key'), 'HS512'));
  72. }
  73. /**
  74. * 把 token 交给 AuthService::current() 判定,返回 user_uid,无效则返回 false。
  75. *
  76. * 所有端点的鉴权都走这里,故用它来断言「token 是否还有效」。
  77. *
  78. * @return string|false
  79. */
  80. function currentUid(string $token)
  81. {
  82. $request = Request::create('/', 'GET');
  83. $request->headers->set('Authorization', 'Bearer '.$token);
  84. $user = AuthService::current($request);
  85. return $user ? $user['user_uid'] : false;
  86. }
  87. /**
  88. * 带用户 token 的请求头。
  89. */
  90. function authHeader(string $userUid): array
  91. {
  92. return ['Authorization' => 'Bearer '.userToken($userUid)];
  93. }
  94. /**
  95. * 建一个用户及其个人 studio,返回 user uid。
  96. *
  97. * StudioApi::getIdByName() 查的是 user_infos.username,所以 studio 名即用户名。
  98. */
  99. function makeStudio(string $username): string
  100. {
  101. $userId = (string) Str::uuid();
  102. (new UserInfo)->forceFill([
  103. 'userid' => $userId,
  104. 'username' => $username,
  105. 'nickname' => $username,
  106. 'password' => 'x',
  107. 'email' => $username.'@example.test',
  108. ])->save();
  109. return $userId;
  110. }
  111. /**
  112. * 建一个属于指定用户的 channel,返回 channel uid。
  113. *
  114. * channels.id 不是自增列,必须显式给值。
  115. */
  116. function makeChannel(string $ownerUid, string $name = 'test channel'): string
  117. {
  118. $uid = (string) Str::uuid();
  119. (new Channel)->forceFill([
  120. 'id' => random_int(1, PHP_INT_MAX),
  121. 'uid' => $uid,
  122. 'type' => 'translation',
  123. 'owner_uid' => $ownerUid,
  124. 'editor_id' => 0,
  125. 'name' => $name,
  126. 'lang' => 'zh-Hans',
  127. 'status' => 30,
  128. 'create_time' => time() * 1000,
  129. 'modify_time' => time() * 1000,
  130. ])->save();
  131. return $uid;
  132. }