GuestCartTest.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Feature\GraphQL;
  3. use Webkul\BagistoApi\Tests\GraphQLTestCase;
  4. class GuestCartTest extends GraphQLTestCase
  5. {
  6. /**
  7. * Get guest cart token from the createCart mutation response
  8. * This token is used as Bearer token for subsequent operations
  9. */
  10. private function getGuestCartToken(): string
  11. {
  12. $mutation = <<<'GQL'
  13. mutation createCart {
  14. createCartToken(input: {}) {
  15. cartToken {
  16. id
  17. _id
  18. cartToken
  19. customerId
  20. channelId
  21. itemsCount
  22. subtotal
  23. baseSubtotal
  24. discountAmount
  25. baseDiscountAmount
  26. taxAmount
  27. baseTaxAmount
  28. shippingAmount
  29. baseShippingAmount
  30. grandTotal
  31. baseGrandTotal
  32. formattedSubtotal
  33. formattedDiscountAmount
  34. formattedTaxAmount
  35. formattedShippingAmount
  36. formattedGrandTotal
  37. couponCode
  38. success
  39. message
  40. sessionToken
  41. isGuest
  42. }
  43. }
  44. }
  45. GQL;
  46. $response = $this->graphQL($mutation);
  47. $response->assertSuccessful();
  48. $data = $response->json('data.createCartToken.cartToken');
  49. $this->assertNotNull($data, 'cartToken response is null');
  50. $this->assertTrue((bool) ($data['success'] ?? false));
  51. // Use cartToken as the bearer token
  52. $token = $data['cartToken'] ?? null;
  53. $this->assertNotEmpty($token, 'guest cart token is missing');
  54. return $token;
  55. }
  56. /**
  57. * Helper method to get authorization headers with guest cart token
  58. */
  59. private function guestHeaders(string $token): array
  60. {
  61. return [
  62. 'Authorization' => 'Bearer ' . $token,
  63. ];
  64. }
  65. /**
  66. * Create Simple Cart (Guest)
  67. */
  68. public function test_create_simple_cart(): void
  69. {
  70. $token = $this->getGuestCartToken();
  71. $this->assertNotEmpty($token);
  72. }
  73. /**
  74. * Add Product In Cart (Guest)
  75. */
  76. public function test_create_add_product_in_cart_as_guest(): void
  77. {
  78. $token = $this->getGuestCartToken();
  79. $headers = $this->guestHeaders($token);
  80. // Use test product helper to get a product with inventory
  81. $productData = $this->createTestProduct();
  82. $product = $productData['product'];
  83. $mutation = <<<'GQL'
  84. mutation createAddProductInCart($productId: Int!, $quantity: Int!) {
  85. createAddProductInCart(input: {productId: $productId, quantity: $quantity}) {
  86. addProductInCart {
  87. id
  88. _id
  89. cartToken
  90. customerId
  91. channelId
  92. subtotal
  93. baseSubtotal
  94. discountAmount
  95. baseDiscountAmount
  96. taxAmount
  97. baseTaxAmount
  98. shippingAmount
  99. baseShippingAmount
  100. grandTotal
  101. baseGrandTotal
  102. formattedSubtotal
  103. formattedDiscountAmount
  104. formattedTaxAmount
  105. formattedShippingAmount
  106. formattedGrandTotal
  107. couponCode
  108. success
  109. message
  110. sessionToken
  111. isGuest
  112. itemsQty
  113. itemsCount
  114. haveStockableItems
  115. items {
  116. totalCount
  117. pageInfo {
  118. startCursor
  119. endCursor
  120. hasNextPage
  121. hasPreviousPage
  122. }
  123. edges {
  124. cursor
  125. node {
  126. id
  127. cartId
  128. productId
  129. name
  130. sku
  131. quantity
  132. price
  133. basePrice
  134. total
  135. baseTotal
  136. discountAmount
  137. baseDiscountAmount
  138. taxAmount
  139. baseTaxAmount
  140. type
  141. formattedPrice
  142. formattedTotal
  143. priceInclTax
  144. basePriceInclTax
  145. formattedPriceInclTax
  146. totalInclTax
  147. baseTotalInclTax
  148. formattedTotalInclTax
  149. productUrlKey
  150. canChangeQty
  151. }
  152. }
  153. }
  154. }
  155. }
  156. }
  157. GQL;
  158. $response = $this->graphQL($mutation, [
  159. 'productId' => $product->id,
  160. 'quantity' => 1,
  161. ], $headers);
  162. $response->assertSuccessful();
  163. $data = $response->json('data.createAddProductInCart.addProductInCart');
  164. $this->assertNotNull($data);
  165. $this->assertGreaterThan(0, (int) ($data['itemsCount'] ?? 0));
  166. $this->assertSame($product->id, $data['items']['edges'][0]['node']['productId'] ?? null);
  167. $this->assertSame(1, $data['items']['edges'][0]['node']['quantity'] ?? null);
  168. }
  169. /**
  170. * Update Cart Item Quantity (Guest)
  171. */
  172. public function test_update_cart_item_quantity_as_guest(): void
  173. {
  174. $token = $this->getGuestCartToken();
  175. $headers = $this->guestHeaders($token);
  176. // Use test product helper to get a product with inventory
  177. $productData = $this->createTestProduct();
  178. $product = $productData['product'];
  179. $addMutation = <<<'GQL'
  180. mutation createAddProductInCart($productId: Int!, $quantity: Int!) {
  181. createAddProductInCart(input: {productId: $productId, quantity: $quantity}) {
  182. addProductInCart {
  183. items {
  184. edges {
  185. node {
  186. id
  187. productId
  188. quantity
  189. }
  190. }
  191. }
  192. }
  193. }
  194. }
  195. GQL;
  196. $addResponse = $this->graphQL($addMutation, [
  197. 'productId' => $product->id,
  198. 'quantity' => 9,
  199. ], $headers);
  200. $addResponse->assertSuccessful();
  201. $cartItemId = $addResponse->json('data.createAddProductInCart.addProductInCart.items.edges.0.node.id');
  202. $this->assertNotNull($cartItemId, 'cart item id is missing for update test');
  203. $updateMutation = <<<'GQL'
  204. mutation createUpdateCartItem($cartItemId: Int!, $quantity: Int!) {
  205. createUpdateCartItem(input: {cartItemId: $cartItemId, quantity: $quantity}) {
  206. updateCartItem {
  207. id
  208. _id
  209. cartToken
  210. customerId
  211. channelId
  212. subtotal
  213. baseSubtotal
  214. discountAmount
  215. baseDiscountAmount
  216. taxAmount
  217. baseTaxAmount
  218. shippingAmount
  219. baseShippingAmount
  220. grandTotal
  221. baseGrandTotal
  222. formattedSubtotal
  223. formattedDiscountAmount
  224. formattedTaxAmount
  225. formattedShippingAmount
  226. formattedGrandTotal
  227. couponCode
  228. items {
  229. totalCount
  230. pageInfo {
  231. startCursor
  232. endCursor
  233. hasNextPage
  234. hasPreviousPage
  235. }
  236. edges {
  237. cursor
  238. node {
  239. id
  240. cartId
  241. productId
  242. name
  243. sku
  244. quantity
  245. price
  246. basePrice
  247. total
  248. baseTotal
  249. discountAmount
  250. baseDiscountAmount
  251. taxAmount
  252. baseTaxAmount
  253. type
  254. formattedPrice
  255. formattedTotal
  256. priceInclTax
  257. basePriceInclTax
  258. formattedPriceInclTax
  259. totalInclTax
  260. baseTotalInclTax
  261. formattedTotalInclTax
  262. productUrlKey
  263. canChangeQty
  264. }
  265. }
  266. }
  267. success
  268. message
  269. sessionToken
  270. isGuest
  271. itemsQty
  272. itemsCount
  273. haveStockableItems
  274. paymentMethod
  275. paymentMethodTitle
  276. subTotalInclTax
  277. baseSubTotalInclTax
  278. formattedSubTotalInclTax
  279. taxTotal
  280. formattedTaxTotal
  281. shippingAmountInclTax
  282. baseShippingAmountInclTax
  283. formattedShippingAmountInclTax
  284. }
  285. }
  286. }
  287. GQL;
  288. $updateResponse = $this->graphQL($updateMutation, [
  289. 'cartItemId' => (int) $cartItemId,
  290. 'quantity' => 1,
  291. ], $headers);
  292. $updateResponse->assertSuccessful();
  293. $data = $updateResponse->json('data.createUpdateCartItem.updateCartItem');
  294. $this->assertNotNull($data);
  295. $this->assertGreaterThan(0, (int) ($data['itemsCount'] ?? 0));
  296. $this->assertSame($product->id, $data['items']['edges'][0]['node']['productId'] ?? null);
  297. $this->assertSame(1, $data['items']['edges'][0]['node']['quantity'] ?? null);
  298. }
  299. /**
  300. * Remove Cart Item (Guest)
  301. */
  302. public function test_remove_cart_item_as_guest(): void
  303. {
  304. $token = $this->getGuestCartToken();
  305. $headers = $this->guestHeaders($token);
  306. // Use test product helper to get a product with inventory
  307. $productData = $this->createTestProduct();
  308. $product = $productData['product'];
  309. // First add product to cart
  310. $addMutation = <<<'GQL'
  311. mutation createAddProductInCart($productId: Int!, $quantity: Int!) {
  312. createAddProductInCart(input: {productId: $productId, quantity: $quantity}) {
  313. addProductInCart {
  314. id
  315. itemsCount
  316. items {
  317. edges {
  318. node {
  319. id
  320. productId
  321. quantity
  322. }
  323. }
  324. }
  325. }
  326. }
  327. }
  328. GQL;
  329. $addResponse = $this->graphQL($addMutation, [
  330. 'productId' => $product->id,
  331. 'quantity' => 2,
  332. ], $headers);
  333. $addResponse->assertSuccessful();
  334. $cartItemId = $addResponse->json('data.createAddProductInCart.addProductInCart.items.edges.0.node.id');
  335. $this->assertNotNull($cartItemId);
  336. // Now remove the item
  337. $removeMutation = <<<'GQL'
  338. mutation createRemoveCartItem($cartItemId: Int!) {
  339. createRemoveCartItem(input: {cartItemId: $cartItemId}) {
  340. removeCartItem {
  341. id
  342. _id
  343. cartToken
  344. items {
  345. totalCount
  346. edges {
  347. node {
  348. id
  349. cartId
  350. productId
  351. name
  352. sku
  353. quantity
  354. price
  355. basePrice
  356. total
  357. baseTotal
  358. productUrlKey
  359. canChangeQty
  360. }
  361. }
  362. }
  363. }
  364. }
  365. }
  366. GQL;
  367. $response = $this->graphQL($removeMutation, [
  368. 'cartItemId' => (int) $cartItemId,
  369. ], $headers);
  370. $response->assertSuccessful();
  371. $data = $response->json('data.createRemoveCartItem.removeCartItem');
  372. $this->assertNotNull($data);
  373. $this->assertLessThanOrEqual(0, (int) ($data['itemsCount'] ?? 0));
  374. }
  375. /**
  376. * Apply Coupon (Guest)
  377. */
  378. public function test_apply_coupon_as_guest(): void
  379. {
  380. $token = $this->getGuestCartToken();
  381. $headers = $this->guestHeaders($token);
  382. // Use test product helper to get a product with inventory
  383. $productData = $this->createTestProduct();
  384. $product = $productData['product'];
  385. // First add product to cart
  386. $addMutation = <<<'GQL'
  387. mutation createAddProductInCart($productId: Int!, $quantity: Int!) {
  388. createAddProductInCart(input: {productId: $productId, quantity: $quantity}) {
  389. addProductInCart {
  390. itemsCount
  391. }
  392. }
  393. }
  394. GQL;
  395. $this->graphQL($addMutation, [
  396. 'productId' => $product->id,
  397. 'quantity' => 1,
  398. ], $headers);
  399. // Apply coupon
  400. $couponMutation = <<<'GQL'
  401. mutation createApplyCoupon($couponCode: String!) {
  402. createApplyCoupon(input: {couponCode: $couponCode}) {
  403. applyCoupon {
  404. id
  405. discountAmount
  406. grandTotal
  407. }
  408. }
  409. }
  410. GQL;
  411. $response = $this->graphQL($couponMutation, [
  412. 'couponCode' => 'SAVE10',
  413. ], $headers);
  414. $response->assertSuccessful();
  415. $data = $response->json('data.createApplyCoupon.applyCoupon');
  416. $this->assertNotNull($data);
  417. }
  418. /**
  419. * Remove Coupon (Guest)
  420. */
  421. public function test_remove_coupon_as_guest(): void
  422. {
  423. $token = $this->getGuestCartToken();
  424. $headers = $this->guestHeaders($token);
  425. // Use test product helper to get a product with inventory
  426. $productData = $this->createTestProduct();
  427. $product = $productData['product'];
  428. // First add product to cart
  429. $addMutation = <<<'GQL'
  430. mutation createAddProductInCart($productId: Int!, $quantity: Int!) {
  431. createAddProductInCart(input: {productId: $productId, quantity: $quantity}) {
  432. addProductInCart {
  433. itemsCount
  434. }
  435. }
  436. }
  437. GQL;
  438. $this->graphQL($addMutation, [
  439. 'productId' => $product->id,
  440. 'quantity' => 1,
  441. ], $headers);
  442. // Remove coupon
  443. $removeCouponMutation = <<<'GQL'
  444. mutation createRemoveCoupon {
  445. createRemoveCoupon(input: {}) {
  446. removeCoupon {
  447. id
  448. discountAmount
  449. grandTotal
  450. }
  451. }
  452. }
  453. GQL;
  454. $response = $this->graphQL($removeCouponMutation, [], $headers);
  455. $response->assertSuccessful();
  456. $data = $response->json('data.createRemoveCoupon.removeCoupon');
  457. $this->assertNotNull($data);
  458. }
  459. }