2
0

Pest.php 4.9 KB

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