FirstTimeUserCartScenarioTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. <?php
  2. namespace Webkul\BagistoApi\Tests\Feature;
  3. use Illuminate\Foundation\Testing\RefreshDatabase;
  4. use Tests\TestCase;
  5. use Webkul\Customer\Models\Customer;
  6. use Webkul\Product\Models\Product;
  7. class FirstTimeUserCartScenarioTest extends TestCase
  8. {
  9. use RefreshDatabase;
  10. private string $graphqlUrl = '/graphql';
  11. /**
  12. * GraphQL query to add product to cart (for first-time users)
  13. */
  14. private function addProductToCart(string $token, int $productId, int $quantity): array
  15. {
  16. $mutation = <<<'GQL'
  17. mutation addProductToCart($token: String!, $productId: Int!, $quantity: Int!) {
  18. addProductToCartCartToken(input: {
  19. token: $token
  20. productId: $productId
  21. quantity: $quantity
  22. }) {
  23. success
  24. message
  25. cart {
  26. id
  27. cartToken
  28. itemsCount
  29. items {
  30. id
  31. productId
  32. name
  33. quantity
  34. formattedPrice
  35. formattedTotal
  36. }
  37. formattedGrandTotal
  38. }
  39. }
  40. }
  41. GQL;
  42. return $this->postJson($this->graphqlUrl, [
  43. 'query' => $mutation,
  44. 'variables' => compact('token', 'productId', 'quantity'),
  45. ])->json();
  46. }
  47. /**
  48. * GraphQL query to read cart (for first-time users)
  49. */
  50. private function readCart(string $token, int $cartId): array
  51. {
  52. $query = <<<'GQL'
  53. query readCart($token: String!, $cartId: Int!) {
  54. readCartToken(input: {
  55. token: $token
  56. cartId: $cartId
  57. }) {
  58. cart {
  59. id
  60. cartToken
  61. itemsCount
  62. items {
  63. id
  64. name
  65. quantity
  66. formattedPrice
  67. formattedTotal
  68. }
  69. formattedSubtotal
  70. formattedTaxAmount
  71. formattedShippingAmount
  72. formattedGrandTotal
  73. }
  74. }
  75. }
  76. GQL;
  77. return $this->postJson($this->graphqlUrl, [
  78. 'query' => $query,
  79. 'variables' => compact('token', 'cartId'),
  80. ])->json();
  81. }
  82. /**
  83. * GraphQL mutation to update item quantity (for first-time users)
  84. */
  85. private function updateCartItem(string $token, int $cartItemId, int $quantity): array
  86. {
  87. $mutation = <<<'GQL'
  88. mutation updateCartItem($token: String!, $cartItemId: Int!, $quantity: Int!) {
  89. updateItemCartToken(input: {
  90. token: $token
  91. cartItemId: $cartItemId
  92. quantity: $quantity
  93. }) {
  94. success
  95. message
  96. cart {
  97. itemsCount
  98. items {
  99. id
  100. quantity
  101. formattedTotal
  102. }
  103. formattedGrandTotal
  104. }
  105. }
  106. }
  107. GQL;
  108. return $this->postJson($this->graphqlUrl, [
  109. 'query' => $mutation,
  110. 'variables' => compact('token', 'cartItemId', 'quantity'),
  111. ])->json();
  112. }
  113. /**
  114. * SCENARIO 1: First-time guest user creates and manages cart
  115. *
  116. * User Steps:
  117. * 1. Browse products
  118. * 2. Add first product to cart
  119. * 3. View cart
  120. * 4. Add another product
  121. * 5. Update quantity
  122. * 6. View final cart
  123. */
  124. public function test_first_time_guest_user_creates_cart(): void
  125. {
  126. echo "\n\n🛒 SCENARIO 1: First-Time Guest User Creates Cart\n";
  127. echo "═════════════════════════════════════════════════\n";
  128. // Step 1: Create some products (simulating browsing)
  129. $product1 = Product::factory()->create(['name' => 'Laptop']);
  130. $product2 = Product::factory()->create(['name' => 'Mouse']);
  131. echo "📦 Products available:\n";
  132. echo " - Product 1: {$product1->name} (ID: {$product1->id})\n";
  133. echo " - Product 2: {$product2->name} (ID: {$product2->id})\n\n";
  134. // Step 2: Guest user adds first product to cart
  135. // For guests, we use a simple cart token (cart ID)
  136. $guestToken = '1'; // This will be the cart ID for guests
  137. echo "👤 Guest User Action: Add first product\n";
  138. echo " Input: token='$guestToken', productId={$product1->id}, quantity=1\n";
  139. $addResponse1 = $this->addProductToCart($guestToken, $product1->id, 1);
  140. $this->assertTrue($addResponse1['data']['addProductToCartCartToken']['success']);
  141. $cartId = $addResponse1['data']['addProductToCartCartToken']['cart']['id'];
  142. echo " ✅ Success! Cart created\n";
  143. echo " Response:\n";
  144. echo " - Cart ID: {$cartId}\n";
  145. echo " - Items in cart: {$addResponse1['data']['addProductToCartCartToken']['cart']['itemsCount']}\n";
  146. echo " - Total: {$addResponse1['data']['addProductToCartCartToken']['cart']['formattedGrandTotal']}\n\n";
  147. // Step 3: Guest views their cart
  148. echo "👤 Guest User Action: View cart\n";
  149. echo " Input: token='$guestToken', cartId={$cartId}\n";
  150. $readResponse = $this->readCart($guestToken, $cartId);
  151. $this->assertTrue(isset($readResponse['data']['readCartToken']['cart']));
  152. $cart = $readResponse['data']['readCartToken']['cart'];
  153. echo " ✅ Cart retrieved\n";
  154. echo " Response:\n";
  155. echo " - Items: {$cart['itemsCount']}\n";
  156. echo " - Items in cart:\n";
  157. foreach ($cart['items'] as $item) {
  158. echo " • {$item['name']} x {$item['quantity']} = {$item['formattedTotal']}\n";
  159. }
  160. echo " - Subtotal: {$cart['formattedSubtotal']}\n";
  161. echo " - Grand Total: {$cart['formattedGrandTotal']}\n\n";
  162. // Step 4: Guest adds another product
  163. echo "👤 Guest User Action: Add second product\n";
  164. echo " Input: token='$guestToken', productId={$product2->id}, quantity=2\n";
  165. $addResponse2 = $this->addProductToCart($guestToken, $product2->id, 2);
  166. $this->assertTrue($addResponse2['data']['addProductToCartCartToken']['success']);
  167. echo " ✅ Second product added\n";
  168. echo " Response:\n";
  169. echo " - Items in cart: {$addResponse2['data']['addProductToCartCartToken']['cart']['itemsCount']}\n";
  170. echo " - Total: {$addResponse2['data']['addProductToCartCartToken']['cart']['formattedGrandTotal']}\n\n";
  171. // Step 5: Guest updates quantity of first product
  172. $firstItemId = $addResponse2['data']['addProductToCartCartToken']['cart']['items'][0]['id'];
  173. echo "👤 Guest User Action: Update first product quantity\n";
  174. echo " Input: token='$guestToken', cartItemId={$firstItemId}, quantity=3\n";
  175. $updateResponse = $this->updateCartItem($guestToken, $firstItemId, 3);
  176. $this->assertTrue($updateResponse['data']['updateItemCartToken']['success']);
  177. echo " ✅ Quantity updated\n";
  178. echo " Response:\n";
  179. echo " - New quantity: {$updateResponse['data']['updateItemCartToken']['cart']['items'][0]['quantity']}\n";
  180. echo " - New total: {$updateResponse['data']['updateItemCartToken']['cart']['formattedGrandTotal']}\n\n";
  181. // Step 6: Guest views final cart
  182. echo "👤 Guest User Action: View final cart\n";
  183. $finalCart = $this->readCart($guestToken, $cartId);
  184. $finalData = $finalCart['data']['readCartToken']['cart'];
  185. echo " ✅ Final cart:\n";
  186. echo " - Total items: {$finalData['itemsCount']}\n";
  187. echo " - Items:\n";
  188. foreach ($finalData['items'] as $item) {
  189. echo " • {$item['name']} x {$item['quantity']} = {$item['formattedTotal']}\n";
  190. }
  191. echo " - Subtotal: {$finalData['formattedSubtotal']}\n";
  192. echo " - Tax: {$finalData['formattedTaxAmount']}\n";
  193. echo " - Shipping: {$finalData['formattedShippingAmount']}\n";
  194. echo " - GRAND TOTAL: {$finalData['formattedGrandTotal']}\n";
  195. echo " ✨ Ready for checkout!\n\n";
  196. }
  197. /**
  198. * SCENARIO 2: First-time authenticated user creates cart
  199. *
  200. * User Steps:
  201. * 1. User logs in/registers
  202. * 2. Browses and adds product to cart
  203. * 3. Views cart
  204. * 4. Continues shopping - adds more items
  205. * 5. Checks cart details
  206. */
  207. public function test_first_time_authenticated_user_creates_cart(): void
  208. {
  209. echo "\n\n🛒 SCENARIO 2: First-Time Authenticated User Creates Cart\n";
  210. echo "═════════════════════════════════════════════════════════\n";
  211. // Step 1: Create customer and get token (simulating login/register)
  212. $customer = Customer::factory()->create([
  213. 'email' => 'newuser@example.com',
  214. 'first_name' => 'John',
  215. 'last_name' => 'Doe',
  216. ]);
  217. $token = $customer->createToken('api-token')->plainTextToken;
  218. echo "👤 New User Registration/Login\n";
  219. echo " User: {$customer->first_name} {$customer->last_name}\n";
  220. echo " Email: {$customer->email}\n";
  221. echo ' Token generated: '.substr($token, 0, 20)."...\n\n";
  222. // Step 2: Browse products and add to cart
  223. $product1 = Product::factory()->create(['name' => 'Wireless Headphones']);
  224. $product2 = Product::factory()->create(['name' => 'Phone Case']);
  225. $product3 = Product::factory()->create(['name' => 'USB Cable']);
  226. echo "📦 Products available:\n";
  227. echo " 1. {$product1->name} (ID: {$product1->id})\n";
  228. echo " 2. {$product2->name} (ID: {$product2->id})\n";
  229. echo " 3. {$product3->name} (ID: {$product3->id})\n\n";
  230. // Step 3: Add first product
  231. echo "🛍️ Step 1: Browse and add first product\n";
  232. echo " Action: Add {$product1->name}\n";
  233. $addResponse1 = $this->addProductToCart($token, $product1->id, 1);
  234. $this->assertTrue($addResponse1['data']['addProductToCartCartToken']['success']);
  235. $cartId = $addResponse1['data']['addProductToCartCartToken']['cart']['id'];
  236. echo " ✅ Added to cart!\n";
  237. echo " - Cart created with ID: {$cartId}\n";
  238. echo " - Items: {$addResponse1['data']['addProductToCartCartToken']['cart']['itemsCount']}\n\n";
  239. // Step 4: Continue shopping - add more items
  240. echo "🛍️ Step 2: Continue shopping - add more items\n";
  241. echo " Action: Add {$product2->name}\n";
  242. $addResponse2 = $this->addProductToCart($token, $product2->id, 2);
  243. echo " ✅ Added {$addResponse2['data']['addProductToCartCartToken']['cart']['items'][count($addResponse2['data']['addProductToCartCartToken']['cart']['items']) - 1]['name']}\n";
  244. echo " Action: Add {$product3->name}\n";
  245. $addResponse3 = $this->addProductToCart($token, $product3->id, 3);
  246. echo " ✅ Added {$addResponse3['data']['addProductToCartCartToken']['cart']['items'][count($addResponse3['data']['addProductToCartCartToken']['cart']['items']) - 1]['name']}\n\n";
  247. // Step 5: Check cart details
  248. echo "🛍️ Step 3: Review shopping cart\n";
  249. $cartDetails = $this->readCart($token, $cartId);
  250. $finalCart = $cartDetails['data']['readCartToken']['cart'];
  251. echo " 📋 Cart Summary:\n";
  252. echo " Total Items: {$finalCart['itemsCount']}\n";
  253. echo " Items in cart:\n";
  254. foreach ($finalCart['items'] as $index => $item) {
  255. echo ' '.($index + 1).". {$item['name']}\n";
  256. echo " Qty: {$item['quantity']}\n";
  257. echo " Price: {$item['formattedPrice']}\n";
  258. echo " Total: {$item['formattedTotal']}\n";
  259. }
  260. echo "\n 💰 Pricing Breakdown:\n";
  261. echo " Subtotal: {$finalCart['formattedSubtotal']}\n";
  262. echo " Tax: {$finalCart['formattedTaxAmount']}\n";
  263. echo " Shipping: {$finalCart['formattedShippingAmount']}\n";
  264. echo " ─────────────────────────\n";
  265. echo " GRAND TOTAL: {$finalCart['formattedGrandTotal']}\n\n";
  266. echo " ✨ Ready to proceed to checkout!\n\n";
  267. }
  268. /**
  269. * SCENARIO 3: First-time user makes mistakes and corrects them
  270. *
  271. * User Steps:
  272. * 1. Adds wrong quantity
  273. * 2. Updates quantity
  274. * 3. Realizes wrong product
  275. * 4. Still learning but cart works!
  276. */
  277. public function test_first_time_user_makes_mistakes_and_learns(): void
  278. {
  279. echo "\n\n🛒 SCENARIO 3: First-Time User Makes Mistakes\n";
  280. echo "══════════════════════════════════════════════\n";
  281. $token = 'guest-token-1';
  282. $product1 = Product::factory()->create(['name' => 'Item A']);
  283. $product2 = Product::factory()->create(['name' => 'Item B']);
  284. echo "👤 New Guest User\n\n";
  285. // Mistake 1: Adds too many items
  286. echo "❌ MISTAKE 1: Adds too many of first product\n";
  287. echo " Action: Add 10 units of {$product1->name}\n";
  288. $response1 = $this->addProductToCart($token, $product1->id, 10);
  289. $cartId = $response1['data']['addProductToCartCartToken']['cart']['id'];
  290. echo ' Added: '.$response1['data']['addProductToCartCartToken']['cart']['items'][0]['quantity']." items\n";
  291. echo ' Total: '.$response1['data']['addProductToCartCartToken']['cart']['formattedGrandTotal']."\n\n";
  292. // Correction 1: Updates to correct quantity
  293. echo "✅ CORRECTION 1: User reduces quantity to 2\n";
  294. $itemId = $response1['data']['addProductToCartCartToken']['cart']['items'][0]['id'];
  295. echo " Action: Update quantity to 2\n";
  296. $updateResponse = $this->updateCartItem($token, $itemId, 2);
  297. echo ' Updated: '.$updateResponse['data']['updateItemCartToken']['cart']['items'][0]['quantity']." items\n";
  298. echo ' New Total: '.$updateResponse['data']['updateItemCartToken']['cart']['formattedGrandTotal']."\n\n";
  299. // Mistake 2: Adds wrong product
  300. echo "❌ MISTAKE 2: Adds wrong product\n";
  301. echo " Action: Accidentally adds {$product2->name}\n";
  302. $response2 = $this->addProductToCart($token, $product2->id, 1);
  303. $itemCount = count($response2['data']['addProductToCartCartToken']['cart']['items']);
  304. echo " Now has {$itemCount} different items in cart\n";
  305. echo " Items:\n";
  306. foreach ($response2['data']['addProductToCartCartToken']['cart']['items'] as $item) {
  307. echo " - {$item['name']} x {$item['quantity']}\n";
  308. }
  309. echo ' Total: '.$response2['data']['addProductToCartCartToken']['cart']['formattedGrandTotal']."\n\n";
  310. // Recovery: User accepts it or can learn to remove items
  311. echo "✨ USER LEARNING:\n";
  312. echo " ✅ Successfully created cart\n";
  313. echo " ✅ Successfully added items\n";
  314. echo " ✅ Successfully updated quantities\n";
  315. echo " 📌 Note: Can also remove items using removeItemCartToken mutation\n";
  316. echo " 📌 Cart persists with token, can view anytime\n\n";
  317. }
  318. }