CartCreateTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Feature;
  3. use Illuminate\Foundation\Testing\RefreshDatabase;
  4. use Tests\TestCase;
  5. use Webkul\Checkout\Models\Cart;
  6. use Webkul\Checkout\Models\CartItem;
  7. use Webkul\Customer\Models\Customer;
  8. use Webkul\Product\Models\Product;
  9. class CartCreateTest extends TestCase
  10. {
  11. use RefreshDatabase;
  12. private string $graphqlUrl = '/api/graphql';
  13. /**
  14. * Create customer with Sanctum token
  15. */
  16. private function createCustomerWithToken(): array
  17. {
  18. $customer = Customer::factory()->create([
  19. 'email' => 'test@example.com',
  20. 'password' => bcrypt('password123'),
  21. ]);
  22. $token = $customer->createToken('api-token')->plainTextToken;
  23. return compact('customer', 'token');
  24. }
  25. /**
  26. * Add product to cart mutation
  27. */
  28. private function addProductToCart(string $token, int $productId, int $quantity, ?array $options = null): array
  29. {
  30. $mutation = <<<'GQL'
  31. mutation addProductToCart($token: String!, $productId: Int!, $quantity: Int!, $options: Object) {
  32. addProductToCartCartToken(input: {
  33. token: $token
  34. productId: $productId
  35. quantity: $quantity
  36. options: $options
  37. }) {
  38. success
  39. message
  40. cart {
  41. id
  42. cartToken
  43. customerId
  44. itemsCount
  45. items {
  46. id
  47. productId
  48. name
  49. quantity
  50. formattedPrice
  51. formattedTotal
  52. options
  53. }
  54. formattedGrandTotal
  55. }
  56. }
  57. }
  58. GQL;
  59. $variables = compact('token', 'productId', 'quantity');
  60. if ($options !== null) {
  61. $variables['options'] = $options;
  62. }
  63. return $this->postJson($this->graphqlUrl, [
  64. 'query' => $mutation,
  65. 'variables' => $variables,
  66. ])->json();
  67. }
  68. /**
  69. * Test: Add product to cart successfully
  70. */
  71. public function test_add_product_to_cart_successfully(): void
  72. {
  73. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  74. $product = Product::factory()->create();
  75. $response = $this->addProductToCart($token, $product->id, 2);
  76. $this->assertArrayHasKey('data', $response);
  77. $this->assertTrue($response['data']['addProductToCartCartToken']['success']);
  78. $this->assertCount(1, $response['data']['addProductToCartCartToken']['cart']['items']);
  79. $this->assertEquals(2, $response['data']['addProductToCartCartToken']['cart']['items'][0]['quantity']);
  80. $this->assertDatabaseHas('cart_items', [
  81. 'product_id' => $product->id,
  82. 'quantity' => 2,
  83. ]);
  84. }
  85. /**
  86. * Test: Creates new cart on first product add
  87. */
  88. public function test_creates_new_cart_on_first_product_add(): void
  89. {
  90. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  91. $product = Product::factory()->create();
  92. $cartsCountBefore = Cart::where('customer_id', $customer->id)->count();
  93. $response = $this->addProductToCart($token, $product->id, 1);
  94. $this->assertTrue($response['data']['addProductToCartCartToken']['success']);
  95. $cartsCountAfter = Cart::where('customer_id', $customer->id)->count();
  96. $this->assertEquals($cartsCountBefore + 1, $cartsCountAfter);
  97. }
  98. /**
  99. * Test: Increases quantity when adding same product
  100. */
  101. public function test_increases_quantity_when_adding_same_product(): void
  102. {
  103. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  104. $product = Product::factory()->create();
  105. // Add product first time
  106. $this->addProductToCart($token, $product->id, 2);
  107. // Add same product again
  108. $response = $this->addProductToCart($token, $product->id, 3);
  109. $this->assertCount(1, $response['data']['addProductToCartCartToken']['cart']['items']);
  110. $this->assertEquals(5, $response['data']['addProductToCartCartToken']['cart']['items'][0]['quantity']);
  111. $this->assertDatabaseHas('cart_items', [
  112. 'product_id' => $product->id,
  113. 'quantity' => 5,
  114. ]);
  115. }
  116. /**
  117. * Test: Can add product with options
  118. */
  119. public function test_can_add_product_with_options(): void
  120. {
  121. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  122. $product = Product::factory()->create();
  123. $options = ['size' => 'M', 'color' => 'red'];
  124. $response = $this->addProductToCart($token, $product->id, 1, $options);
  125. $this->assertTrue($response['data']['addProductToCartCartToken']['success']);
  126. $this->assertEquals($options, $response['data']['addProductToCartCartToken']['cart']['items'][0]['options']);
  127. $cartItem = CartItem::where('product_id', $product->id)->first();
  128. $this->assertEquals($options, $cartItem->options);
  129. }
  130. /**
  131. * Test: Correctly updates items count
  132. */
  133. public function test_correctly_updates_items_count(): void
  134. {
  135. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  136. $product = Product::factory()->create();
  137. $response = $this->addProductToCart($token, $product->id, 5);
  138. $this->assertEquals(5, $response['data']['addProductToCartCartToken']['cart']['itemsCount']);
  139. }
  140. /**
  141. * Test: Calculates formatted total correctly
  142. */
  143. public function test_calculates_formatted_total_correctly(): void
  144. {
  145. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  146. $product = Product::factory()->create();
  147. $response = $this->addProductToCart($token, $product->id, 2);
  148. $formattedTotal = $response['data']['addProductToCartCartToken']['cart']['items'][0]['formattedTotal'];
  149. $this->assertIsString($formattedTotal);
  150. $this->assertMatchesRegularExpression('/^\$[\d,.]+$/', $formattedTotal);
  151. }
  152. /**
  153. * Test: Fails when token is missing
  154. */
  155. public function test_fails_when_token_is_missing(): void
  156. {
  157. $product = Product::factory()->create();
  158. $mutation = <<<'GQL'
  159. mutation addProductToCart($productId: Int!, $quantity: Int!) {
  160. addProductToCartCartToken(input: {
  161. productId: $productId
  162. quantity: $quantity
  163. }) {
  164. success
  165. }
  166. }
  167. GQL;
  168. $response = $this->postJson($this->graphqlUrl, [
  169. 'query' => $mutation,
  170. 'variables' => ['productId' => $product->id, 'quantity' => 1],
  171. ])->json();
  172. $this->assertArrayHasKey('errors', $response);
  173. }
  174. /**
  175. * Test: Fails when product id is missing
  176. */
  177. public function test_fails_when_product_id_is_missing(): void
  178. {
  179. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  180. $mutation = <<<'GQL'
  181. mutation addProductToCart($token: String!, $quantity: Int!) {
  182. addProductToCartCartToken(input: {
  183. token: $token
  184. quantity: $quantity
  185. }) {
  186. success
  187. }
  188. }
  189. GQL;
  190. $response = $this->postJson($this->graphqlUrl, [
  191. 'query' => $mutation,
  192. 'variables' => ['token' => $token, 'quantity' => 1],
  193. ])->json();
  194. $this->assertArrayHasKey('errors', $response);
  195. }
  196. /**
  197. * Test: Fails with invalid token
  198. */
  199. public function test_fails_with_invalid_token(): void
  200. {
  201. $product = Product::factory()->create();
  202. $response = $this->addProductToCart('invalid-token-xyz', $product->id, 1);
  203. $this->assertArrayHasKey('errors', $response);
  204. }
  205. /**
  206. * Test: Fails with non-existent product
  207. */
  208. public function test_fails_with_non_existent_product(): void
  209. {
  210. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  211. $response = $this->addProductToCart($token, 99999, 1);
  212. $this->assertArrayHasKey('errors', $response);
  213. }
  214. /**
  215. * Test: Can add product for guest using cart id as token
  216. */
  217. public function test_can_add_product_for_guest_using_cart_id_as_token(): void
  218. {
  219. $guestCart = Cart::factory()->create(['customer_id' => null]);
  220. $product = Product::factory()->create();
  221. $response = $this->addProductToCart((string) $guestCart->id, $product->id, 1);
  222. $this->assertTrue($response['data']['addProductToCartCartToken']['success']);
  223. $this->assertDatabaseHas('cart_items', [
  224. 'cart_id' => $guestCart->id,
  225. 'product_id' => $product->id,
  226. ]);
  227. }
  228. /**
  229. * Test: Adds multiple different products to cart
  230. */
  231. public function test_adds_multiple_different_products_to_cart(): void
  232. {
  233. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  234. $product1 = Product::factory()->create();
  235. $product2 = Product::factory()->create();
  236. // Add first product
  237. $this->addProductToCart($token, $product1->id, 1);
  238. // Add second product
  239. $response = $this->addProductToCart($token, $product2->id, 2);
  240. $this->assertCount(2, $response['data']['addProductToCartCartToken']['cart']['items']);
  241. $this->assertEquals(3, $response['data']['addProductToCartCartToken']['cart']['itemsCount']);
  242. }
  243. /**
  244. * Test: Handles zero quantity
  245. */
  246. public function test_handles_zero_quantity(): void
  247. {
  248. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  249. $product = Product::factory()->create();
  250. $response = $this->addProductToCart($token, $product->id, 0);
  251. // Should either fail or handle gracefully
  252. $this->assertTrue(
  253. isset($response['errors']) || isset($response['data']['addProductToCartCartToken']['success'])
  254. );
  255. }
  256. /**
  257. * Test: Handles negative quantity
  258. */
  259. public function test_handles_negative_quantity(): void
  260. {
  261. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  262. $product = Product::factory()->create();
  263. $response = $this->addProductToCart($token, $product->id, -5);
  264. // Should fail
  265. $this->assertArrayHasKey('errors', $response);
  266. }
  267. /**
  268. * Test: Returns cart token in response
  269. */
  270. public function test_returns_cart_token_in_response(): void
  271. {
  272. ['customer' => $customer, 'token' => $token] = $this->createCustomerWithToken();
  273. $product = Product::factory()->create();
  274. $response = $this->addProductToCart($token, $product->id, 1);
  275. $this->assertNotEmpty($response['data']['addProductToCartCartToken']['cart']['cartToken']);
  276. }
  277. }