CartProviderInvariantTest.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. <?php
  2. namespace Tests\Unit;
  3. use App\Enums\CartStatusEnum;
  4. use App\Http\Requests\CartRequest;
  5. use App\Models\Cart;
  6. use App\Models\Provider;
  7. use App\Models\Schedule;
  8. use App\Services\CartService;
  9. use App\Services\Pagarme\PagarmePaymentService;
  10. use App\Services\PaymentService;
  11. use Illuminate\Validation\ValidationException;
  12. use Tests\TestCase;
  13. class CartProviderInvariantTest extends TestCase
  14. {
  15. public function test_request_rejects_schedules_from_different_providers(): void
  16. {
  17. $request = CartRequest::create('/cart/me', 'POST', [
  18. 'schedules' => [
  19. ['provider_id' => 10],
  20. ['provider_id' => 20],
  21. ],
  22. ]);
  23. $validator = validator([], []);
  24. foreach ($request->after() as $callback) {
  25. $callback($validator);
  26. }
  27. $this->assertSame(
  28. 'Todos os agendamentos do carrinho precisam ser do mesmo prestador.',
  29. $validator->errors()->first('schedules'),
  30. );
  31. }
  32. public function test_request_accepts_schedules_from_the_same_provider(): void
  33. {
  34. $request = CartRequest::create('/cart/me', 'POST', [
  35. 'provider_id' => 10,
  36. 'schedules' => [
  37. ['date' => '2026-08-01'],
  38. ['provider_id' => 10, 'date' => '2026-08-02'],
  39. ],
  40. ]);
  41. $validator = validator([], []);
  42. foreach ($request->after() as $callback) {
  43. $callback($validator);
  44. }
  45. $this->assertFalse($validator->errors()->has('schedules'));
  46. }
  47. public function test_service_defensively_rejects_mixed_providers(): void
  48. {
  49. $method = new \ReflectionMethod(CartService::class, 'singleProviderId');
  50. $this->expectException(ValidationException::class);
  51. $method->invoke(new CartService, [], [
  52. ['provider_id' => 10],
  53. ['provider_id' => 20],
  54. ]);
  55. }
  56. public function test_checkout_rejects_a_cart_with_a_schedule_from_another_provider(): void
  57. {
  58. $cart = $this->cart(providerId: 10);
  59. $schedules = collect([
  60. $this->schedule(id: 1, providerId: 10),
  61. $this->schedule(id: 2, providerId: 20),
  62. ]);
  63. $method = new \ReflectionMethod(PaymentService::class, 'validateCartForPayment');
  64. $this->expectException(\InvalidArgumentException::class);
  65. $this->expectExceptionMessage('Todos os agendamentos do carrinho precisam ser do mesmo prestador.');
  66. $method->invoke(new PaymentService(new PagarmePaymentService), $cart, $schedules);
  67. }
  68. public function test_checkout_waits_until_every_schedule_is_accepted(): void
  69. {
  70. $cart = $this->cart(providerId: 10);
  71. $schedules = collect([
  72. $this->schedule(id: 1, providerId: 10),
  73. $this->schedule(id: 2, providerId: 10, status: 'pending'),
  74. ]);
  75. $method = new \ReflectionMethod(PaymentService::class, 'validateCartForPayment');
  76. $this->expectException(\InvalidArgumentException::class);
  77. $this->expectExceptionMessage('Agendamento 2 precisa estar aceito para o carrinho ser pago.');
  78. $method->invoke(new PaymentService(new PagarmePaymentService), $cart, $schedules);
  79. }
  80. private function cart(int $providerId): Cart
  81. {
  82. $provider = new Provider;
  83. $provider->forceFill([
  84. 'id' => $providerId,
  85. 'recipient_id' => 'rp_test',
  86. ]);
  87. $cart = new Cart;
  88. $cart->forceFill([
  89. 'id' => 1,
  90. 'client_id' => 30,
  91. 'provider_id' => $providerId,
  92. 'status' => CartStatusEnum::OPEN->value,
  93. ]);
  94. $cart->setRelation('provider', $provider);
  95. return $cart;
  96. }
  97. private function schedule(int $id, int $providerId, string $status = 'accepted'): Schedule
  98. {
  99. $schedule = new Schedule;
  100. $schedule->forceFill([
  101. 'id' => $id,
  102. 'client_id' => 30,
  103. 'provider_id' => $providerId,
  104. 'status' => $status,
  105. 'total_amount' => 100,
  106. ]);
  107. return $schedule;
  108. }
  109. }