From fda4e8c069af27106c1761ea2da364c1e4a7bffb Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Mon, 9 Oct 2023 16:35:08 +0530 Subject: [PATCH 01/11] LYNX-259: Created new mutation with test coverage and deprecated mutation --- .../Model/Resolver/CreateGuestCart.php | 126 ++++++++++++ .../Magento/QuoteGraphQl/etc/schema.graphqls | 11 +- .../Quote/Customer/CreateGuestCartTest.php | 105 ++++++++++ .../Quote/Guest/CreateGuestCartTest.php | 192 ++++++++++++++++++ 4 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php new file mode 100644 index 0000000000000..f8baeb02f1e5b --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -0,0 +1,126 @@ +createEmptyCartForGuest = $createEmptyCartForGuest; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->cartRepository = $cartRepository; + } + + /** + * Creates an empty cart for guest and returns a cart object + * + * @param Field $field + * @param $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @return array[] + * @throws GraphQlAlreadyExistsException + * @throws GraphQlInputException + * @throws NoSuchEntityException + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + $customerId = $context->getUserId(); + + $predefinedMaskedQuoteId = null; + if (isset($args['input']['cart_uid'])) { + $predefinedMaskedQuoteId = $args['input']['cart_uid']; + $this->validateMaskedId($predefinedMaskedQuoteId); + } + + if (0 === $customerId || null === $customerId) { + $maskedQuoteId = $this->createEmptyCartForGuest->execute($predefinedMaskedQuoteId); + $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedQuoteId); + $cart = $this->cartRepository->get($cartId); + } else { + throw new GraphQlAlreadyExistsException(__('Use `Query.customerCart` for logged in customer.')); + } + + return [ + 'cart' => [ + 'model' => $cart, + ], + ]; + } + + /** + * Validate masked id + * + * @param string $maskedId + * @throws GraphQlAlreadyExistsException + * @throws GraphQlInputException + */ + private function validateMaskedId(string $maskedId): void + { + if (mb_strlen($maskedId) != 32) { + throw new GraphQlInputException(__('Cart ID length should be 32 characters.')); + } + + if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) { + throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId)); + } + } + + /** + * Check is quote with such maskedId already exists + * + * @param string $maskedId + * @return bool + */ + private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool + { + try { + $this->maskedQuoteIdToQuoteId->execute($maskedId); + return true; + } catch (NoSuchEntityException $e) { + return false; + } + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 1b65bdcf4564c..afbfd20be1d7b 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -8,7 +8,8 @@ type Query { } type Mutation { - createEmptyCart(input: createEmptyCartInput @doc(description: "An optional input object that assigns the specified ID to the cart.")): String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user") + createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart`, or `Query.customerCart` for logged in customer") + createGuestCart(input: CreateGuestCartInput): CreateGuestCartOutput @doc(description: "Create a new shopping cart") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateGuestCart") addSimpleProductsToCart(input: AddSimpleProductsToCartInput @doc(description: "An input object that defines which simple products to add to the cart.")): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more simple products to the specified cart. We recommend using `addProductsToCart` instead.") addVirtualProductsToCart(input: AddVirtualProductsToCartInput @doc(description: "An input object that defines which virtual products to add to the cart.")): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more virtual products to the specified cart. We recommend using `addProductsToCart` instead.") applyCouponToCart(input: ApplyCouponToCartInput @doc(description: "An input object that defines the coupon code to apply to the cart.")): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") @doc(description:"Apply a pre-defined coupon code to the specified cart.") @@ -29,6 +30,14 @@ type Mutation { addProductsToCart(cartId: String! @doc(description: "The cart ID of the shopper."), cartItems: [CartItemInput!]! @doc(description: "An array that defines the products to add to the cart.")): AddProductsToCartOutput @doc(description:"Add any type of product to the cart.") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddProductsToCart") } +input CreateGuestCartInput { + cart_uid: ID @doc(description: "Optional client-generated ID") +} + +type CreateGuestCartOutput { + cart: Cart +} + input createEmptyCartInput @doc(description: "Assigns a specific `cart_id` to the empty cart.") { cart_id: String @doc(description: "The ID to assign to the cart.") } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php new file mode 100644 index 0000000000000..b4b92d1452d52 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php @@ -0,0 +1,105 @@ +customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class); + $this->quoteResource = $objectManager->get(QuoteResource::class); + $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testFailForLoggedInUser() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("Use `Query.customerCart` for logged in customer."); + + $query = $this->getQuery(); + $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + } + + /** + * @return string + */ + private function getQuery(): string + { + return <<customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } + + protected function tearDown(): void + { + $quoteCollection = $this->quoteCollectionFactory->create(); + foreach ($quoteCollection as $quote) { + $this->quoteResource->delete($quote); + + $quoteIdMask = $this->quoteIdMaskFactory->create(); + $quoteIdMask->setQuoteId($quote->getId()) + ->delete(); + } + parent::tearDown(); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php new file mode 100644 index 0000000000000..437efa7b928b9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php @@ -0,0 +1,192 @@ +guestCartRepository = $objectManager->get(GuestCartRepositoryInterface::class); + $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class); + $this->quoteResource = $objectManager->get(QuoteResource::class); + $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class); + } + + public function testSuccessfulCreateGuestCart() + { + $query = $this->getQuery(); + $response = $this->graphQlMutation($query); + + self::assertArrayHasKey('createGuestCart', $response); + self::assertNotEmpty($response['createGuestCart']); + self::assertArrayHasKey('cart', $response['createGuestCart']); + self::assertNotEmpty($response['createGuestCart']['cart']); + self::assertArrayHasKey('id', $response['createGuestCart']['cart']); + self::assertNotEmpty($response['createGuestCart']['cart']['id']); + + $guestCart = $this->guestCartRepository->get($response['createGuestCart']['cart']['id']); + + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + self::assertEquals('default', $guestCart->getStore()->getCode()); + self::assertEquals('1', $guestCart->getCustomerIsGuest()); + } + + /** + * @magentoApiDataFixture Magento/Store/_files/second_store.php + */ + public function testSuccessfulWithNotDefaultStore() + { + $query = $this->getQuery(); + $headerMap = ['Store' => 'fixture_second_store']; + $response = $this->graphQlMutation($query, [], '', $headerMap); + + self::assertArrayHasKey('createGuestCart', $response); + self::assertNotEmpty($response['createGuestCart']); + self::assertArrayHasKey('cart', $response['createGuestCart']); + self::assertNotEmpty($response['createGuestCart']['cart']); + self::assertArrayHasKey('id', $response['createGuestCart']['cart']); + self::assertNotEmpty($response['createGuestCart']['cart']['id']); + + $guestCart = $this->guestCartRepository->get($response['createGuestCart']['cart']['id']); + + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + self::assertSame('fixture_second_store', $guestCart->getStore()->getCode()); + self::assertEquals('1', $guestCart->getCustomerIsGuest()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testSuccessfulWithPredefinedCartId() + { + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = $this->getQueryWithCartId($predefinedCartId); + $response = $this->graphQlMutation($query); + + self::assertArrayHasKey('createGuestCart', $response); + self::assertNotEmpty($response['createGuestCart']); + self::assertArrayHasKey('cart', $response['createGuestCart']); + self::assertNotEmpty($response['createGuestCart']['cart']); + self::assertArrayHasKey('id', $response['createGuestCart']['cart']); + self::assertNotEmpty($response['createGuestCart']['cart']['id']); + + $guestCart = $this->guestCartRepository->get($response['createGuestCart']['cart']['id']); + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testFailIfPredefinedCartIdAlreadyExists() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("Cart with ID \"572cda51902b5b517c0e1a2b2fd004b4\" already exists."); + + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = $this->getQueryWithCartId($predefinedCartId); + $this->graphQlMutation($query); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testFailWithWrongPredefinedCartId() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage("Cart ID length should be 32 characters."); + + $predefinedCartId = '1234567890'; + + $query = $this->getQueryWithCartId($predefinedCartId); + $this->graphQlMutation($query); + } + + /** + * @return string + */ + private function getQuery(): string + { + return <<quoteCollectionFactory->create(); + foreach ($quoteCollection as $quote) { + $this->quoteResource->delete($quote); + + $quoteIdMask = $this->quoteIdMaskFactory->create(); + $quoteIdMask->setQuoteId($quote->getId()) + ->delete(); + } + parent::tearDown(); + } +} From 760bc1f0a579aa0be25ea041471f3e207ee2ce6b Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Tue, 10 Oct 2023 12:25:50 +0530 Subject: [PATCH 02/11] LYNX-259: Updated the deprecated tests --- .../Model/Resolver/CreateGuestCart.php | 16 +-- .../Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- .../Quote/Customer/CreateEmptyCartTest.php | 113 +----------------- .../Quote/Customer/CreateGuestCartTest.php | 2 +- .../Quote/Guest/CreateEmptyCartTest.php | 93 +------------- 5 files changed, 10 insertions(+), 216 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index f8baeb02f1e5b..943415646d526 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -53,17 +53,7 @@ public function __construct( } /** - * Creates an empty cart for guest and returns a cart object - * - * @param Field $field - * @param $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * @return array[] - * @throws GraphQlAlreadyExistsException - * @throws GraphQlInputException - * @throws NoSuchEntityException + * @inheritdoc */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { @@ -80,7 +70,9 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedQuoteId); $cart = $this->cartRepository->get($cartId); } else { - throw new GraphQlAlreadyExistsException(__('Use `Query.customerCart` for logged in customer.')); + throw new GraphQlAlreadyExistsException( + __('Use `Query.cart` or `Query.customerCart` for logged in customer.') + ); } return [ diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index afbfd20be1d7b..802909f3d5395 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -8,7 +8,7 @@ type Query { } type Mutation { - createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart`, or `Query.customerCart` for logged in customer") + createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart` for guest and `Query.cart` or `Query.customerCart` for logged in customer") createGuestCart(input: CreateGuestCartInput): CreateGuestCartOutput @doc(description: "Create a new shopping cart") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateGuestCart") addSimpleProductsToCart(input: AddSimpleProductsToCartInput @doc(description: "An input object that defines which simple products to add to the cart.")): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more simple products to the specified cart. We recommend using `addProductsToCart` instead.") addVirtualProductsToCart(input: AddVirtualProductsToCartInput @doc(description: "An input object that defines which virtual products to add to the cart.")): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more virtual products to the specified cart. We recommend using `addProductsToCart` instead.") diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php index 360e405cab139..9258451b15185 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php @@ -58,122 +58,13 @@ protected function setUp(): void /** * @magentoApiDataFixture Magento/Customer/_files/customer.php */ - public function testCreateEmptyCart() + public function testDeprecatedCreateEmptyCart() { $query = $this->getQuery(); $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - - self::assertNotNull($guestCart->getId()); - self::assertEquals(1, $guestCart->getCustomer()->getId()); - self::assertEquals('default', $guestCart->getStore()->getCode()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ - public function testCreateEmptyMultipleRequestsCart() - { - $query = $this->getQuery(); - $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); - - self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - $maskedCartId = $response['createEmptyCart']; - - $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); - self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - - self::assertEquals($maskedCartId, $response['createEmptyCart']); - } - - /** - * @magentoApiDataFixture Magento/Store/_files/second_store.php - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ - public function testCreateEmptyCartWithNotDefaultStore() - { - $query = $this->getQuery(); - - $headerMap = $this->getHeaderMapWithCustomerToken(); - $headerMap['Store'] = 'fixture_second_store'; - $response = $this->graphQlMutation($query, [], '', $headerMap); - - self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - - /* guestCartRepository is used for registered customer to get the cart hash */ - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - - self::assertNotNull($guestCart->getId()); - self::assertEquals(1, $guestCart->getCustomer()->getId()); - self::assertEquals('fixture_second_store', $guestCart->getStore()->getCode()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ - public function testCreateEmptyCartWithPredefinedCartId() - { - $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; - - $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); - - self::assertArrayHasKey('createEmptyCart', $response); - self::assertEquals($predefinedCartId, $response['createEmptyCart']); - - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - self::assertNotNull($guestCart->getId()); - self::assertEquals(1, $guestCart->getCustomer()->getId()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ - public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.'); - - $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; - - $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); - $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ - public function testCreateEmptyCartWithWrongPredefinedCartId() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cart ID length should to be 32 symbols.'); - - $predefinedCartId = '572'; - - $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + self::assertEmpty($response['createEmptyCart']); } /** diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php index b4b92d1452d52..1d3861d7c942d 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php @@ -54,7 +54,7 @@ protected function setUp(): void public function testFailForLoggedInUser() { $this->expectException(\Exception::class); - $this->expectExceptionMessage("Use `Query.customerCart` for logged in customer."); + $this->expectExceptionMessage("Use `Query.cart` or `Query.customerCart` for logged in customer."); $query = $this->getQuery(); $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php index 67012e75bf272..297c7facdadcd 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php @@ -53,102 +53,13 @@ protected function setUp(): void $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class); } - public function testCreateEmptyCart() + public function testDeprecatedCreateEmptyCart() { $query = $this->getQuery(); $response = $this->graphQlMutation($query); self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - - self::assertNotNull($guestCart->getId()); - self::assertNull($guestCart->getCustomer()->getId()); - self::assertEquals('default', $guestCart->getStore()->getCode()); - self::assertEquals('1', $guestCart->getCustomerIsGuest()); - } - - /** - * @magentoApiDataFixture Magento/Store/_files/second_store.php - */ - public function testCreateEmptyCartWithNotDefaultStore() - { - $query = $this->getQuery(); - $headerMap = ['Store' => 'fixture_second_store']; - $response = $this->graphQlMutation($query, [], '', $headerMap); - - self::assertArrayHasKey('createEmptyCart', $response); - self::assertNotEmpty($response['createEmptyCart']); - - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - $this->maskedQuoteId = $response['createEmptyCart']; - - self::assertNotNull($guestCart->getId()); - self::assertNull($guestCart->getCustomer()->getId()); - self::assertSame('fixture_second_store', $guestCart->getStore()->getCode()); - self::assertEquals('1', $guestCart->getCustomerIsGuest()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ - public function testCreateEmptyCartWithPredefinedCartId() - { - $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; - - $query = <<graphQlMutation($query); - - self::assertArrayHasKey('createEmptyCart', $response); - self::assertEquals($predefinedCartId, $response['createEmptyCart']); - - $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); - self::assertNotNull($guestCart->getId()); - self::assertNull($guestCart->getCustomer()->getId()); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ - public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.'); - - $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; - - $query = <<graphQlMutation($query); - $this->graphQlMutation($query); - } - - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ - public function testCreateEmptyCartWithWrongPredefinedCartId() - { - $this->expectException(\Exception::class); - $this->expectExceptionMessage('Cart ID length should to be 32 symbols.'); - - $predefinedCartId = '572'; - - $query = <<graphQlMutation($query); + self::assertEmpty($response['createEmptyCart']); } /** From fbc20cf65684a77ab876777fafbc21808e58b1f6 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Wed, 11 Oct 2023 16:46:59 +0530 Subject: [PATCH 03/11] LYNX-259: parametrized fixtures for tests --- .../Quote/Guest/CreateEmptyCartTest.php | 5 --- .../Quote/Guest/CreateGuestCartTest.php | 34 +++++++------------ 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php index 297c7facdadcd..ca05e548463bf 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php @@ -39,11 +39,6 @@ class CreateEmptyCartTest extends GraphQlAbstract */ private $quoteIdMaskFactory; - /** - * @var string - */ - private $maskedQuoteId; - protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php index 437efa7b928b9..338187c56e5de 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php @@ -7,12 +7,15 @@ namespace Magento\GraphQl\Quote\Guest; +use Magento\Quote\Api\GuestCartRepositoryInterface; use Magento\Quote\Model\QuoteIdMaskFactory; use Magento\Quote\Model\ResourceModel\Quote\CollectionFactory as QuoteCollectionFactory; use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; +use Magento\Store\Test\Fixture\Store; +use Magento\TestFramework\Fixture\DataFixture; +use Magento\TestFramework\Fixture\DataFixtureStorageManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; -use Magento\Quote\Api\GuestCartRepositoryInterface; /** * Test for guest cart creation mutation @@ -68,13 +71,16 @@ public function testSuccessfulCreateGuestCart() self::assertEquals('1', $guestCart->getCustomerIsGuest()); } - /** - * @magentoApiDataFixture Magento/Store/_files/second_store.php - */ + #[ + DataFixture(Store::class, as: 'store') + ] public function testSuccessfulWithNotDefaultStore() { + $store = DataFixtureStorageManager::getStorage()->get('store'); + $storeCode = $store->getCode(); + $query = $this->getQuery(); - $headerMap = ['Store' => 'fixture_second_store']; + $headerMap = ['Store' => $storeCode]; $response = $this->graphQlMutation($query, [], '', $headerMap); self::assertArrayHasKey('createGuestCart', $response); @@ -88,13 +94,10 @@ public function testSuccessfulWithNotDefaultStore() self::assertNotNull($guestCart->getId()); self::assertNull($guestCart->getCustomer()->getId()); - self::assertSame('fixture_second_store', $guestCart->getStore()->getCode()); + self::assertSame($storeCode, $guestCart->getStore()->getCode()); self::assertEquals('1', $guestCart->getCustomerIsGuest()); } - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ public function testSuccessfulWithPredefinedCartId() { $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; @@ -108,16 +111,9 @@ public function testSuccessfulWithPredefinedCartId() self::assertNotEmpty($response['createGuestCart']['cart']); self::assertArrayHasKey('id', $response['createGuestCart']['cart']); self::assertNotEmpty($response['createGuestCart']['cart']['id']); - - $guestCart = $this->guestCartRepository->get($response['createGuestCart']['cart']['id']); - self::assertNotNull($guestCart->getId()); - self::assertNull($guestCart->getCustomer()->getId()); + self::assertEquals($predefinedCartId, $response['createGuestCart']['cart']['id']); } - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ public function testFailIfPredefinedCartIdAlreadyExists() { $this->expectException(\Exception::class); @@ -130,10 +126,6 @@ public function testFailIfPredefinedCartIdAlreadyExists() $this->graphQlMutation($query); } - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - * - */ public function testFailWithWrongPredefinedCartId() { $this->expectException(\Exception::class); From 625dced5ed21443c299fee084640efebe762053e Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Thu, 12 Oct 2023 14:47:19 +0530 Subject: [PATCH 04/11] LYNX-259: New copywrite header for new files and parametrized fixtures for new tests --- .../Model/Resolver/CreateGuestCart.php | 21 ++++-- .../Magento/QuoteGraphQl/etc/schema.graphqls | 10 +-- .../Quote/Customer/CreateGuestCartTest.php | 65 ++++++++++--------- .../Quote/Guest/CreateGuestCartTest.php | 17 ++++- 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index 943415646d526..44bc17bfec535 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -1,7 +1,18 @@ validateMaskedId($predefinedMaskedQuoteId); } - if (0 === $customerId || null === $customerId) { + if ($customerId === 0 || $customerId === null) { $maskedQuoteId = $this->createEmptyCartForGuest->execute($predefinedMaskedQuoteId); $cartId = $this->maskedQuoteIdToQuoteId->execute($maskedQuoteId); $cart = $this->cartRepository->get($cartId); diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 802909f3d5395..54b649a46fea7 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -8,8 +8,8 @@ type Query { } type Mutation { - createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart` for guest and `Query.cart` or `Query.customerCart` for logged in customer") createGuestCart(input: CreateGuestCartInput): CreateGuestCartOutput @doc(description: "Create a new shopping cart") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateGuestCart") + createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart` for guest and `Query.cart` or `Query.customerCart` for logged in customer") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user") addSimpleProductsToCart(input: AddSimpleProductsToCartInput @doc(description: "An input object that defines which simple products to add to the cart.")): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more simple products to the specified cart. We recommend using `addProductsToCart` instead.") addVirtualProductsToCart(input: AddVirtualProductsToCartInput @doc(description: "An input object that defines which virtual products to add to the cart.")): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more virtual products to the specified cart. We recommend using `addProductsToCart` instead.") applyCouponToCart(input: ApplyCouponToCartInput @doc(description: "An input object that defines the coupon code to apply to the cart.")): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") @doc(description:"Apply a pre-defined coupon code to the specified cart.") @@ -34,10 +34,6 @@ input CreateGuestCartInput { cart_uid: ID @doc(description: "Optional client-generated ID") } -type CreateGuestCartOutput { - cart: Cart -} - input createEmptyCartInput @doc(description: "Assigns a specific `cart_id` to the empty cart.") { cart_id: String @doc(description: "The ID to assign to the cart.") } @@ -195,6 +191,10 @@ type CartDiscount @doc(description: "Contains information about discounts applie label: [String!]! @doc(description: "The description of the discount.") } +type CreateGuestCartOutput { + cart: Cart @doc(description: "The newly created cart.") +} + type SetPaymentMethodOnCartOutput @doc(description: "Contains details about the cart after setting the payment method.") { cart: Cart! @doc(description: "The cart after setting the payment method.") } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php index 1d3861d7c942d..654fdd3668da3 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php @@ -1,17 +1,32 @@ customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); - $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class); - $this->quoteResource = $objectManager->get(QuoteResource::class); - $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class); + $this->objectManager = Bootstrap::getObjectManager(); + $this->quoteCollectionFactory = $this->objectManager->get(QuoteCollectionFactory::class); + $this->quoteResource = $this->objectManager->get(QuoteResource::class); + $this->quoteIdMaskFactory = $this->objectManager->get(QuoteIdMaskFactory::class); } - /** - * @magentoApiDataFixture Magento/Customer/_files/customer.php - */ + #[ + DataFixture(Customer::class, as: 'customer') + ] public function testFailForLoggedInUser() { $this->expectException(\Exception::class); $this->expectExceptionMessage("Use `Query.cart` or `Query.customerCart` for logged in customer."); + $customer = DataFixtureStorageManager::getStorage()->get('customer'); + $query = $this->getQuery(); - $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + $this->graphQlMutation( + $query, + [], + '', + $this->objectManager->get(GetCustomerAuthenticationHeader::class)->execute($customer->getEmail()) + ); } /** @@ -76,20 +97,6 @@ private function getQuery(): string QUERY; } - /** - * @param string $username - * @param string $password - * @return array - */ - private function getHeaderMapWithCustomerToken( - string $username = 'customer@example.com', - string $password = 'password' - ): array { - $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password); - $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; - return $headerMap; - } - protected function tearDown(): void { $quoteCollection = $this->quoteCollectionFactory->create(); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php index 338187c56e5de..a02eff67b5f8e 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php @@ -1,7 +1,18 @@ Date: Thu, 12 Oct 2023 17:31:58 +0530 Subject: [PATCH 05/11] LYNX-259: Extracted this validation to a separate class and use it for validation in both new CreateGuestCart and existing CreateEmptyCart --- .../Model/Cart/ValidateMaskedQuoteId.php | 75 ++++++++++++ .../Model/Resolver/CreateEmptyCart.php | 50 ++------ .../Model/Resolver/CreateGuestCart.php | 51 ++------ .../Magento/QuoteGraphQl/etc/schema.graphqls | 2 +- .../Quote/Customer/CreateEmptyCartTest.php | 113 +++++++++++++++++- .../Quote/Customer/CreateGuestCartTest.php | 2 +- .../Quote/Guest/CreateEmptyCartTest.php | 98 ++++++++++++++- 7 files changed, 307 insertions(+), 84 deletions(-) create mode 100644 app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php b/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php new file mode 100644 index 0000000000000..64b48d9e8320b --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php @@ -0,0 +1,75 @@ +maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + } + + /** + * Validate masked id + * + * @param string $maskedId + * @throws GraphQlAlreadyExistsException + * @throws GraphQlInputException + */ + public function execute(string $maskedId): void + { + if (mb_strlen($maskedId) != 32) { + throw new GraphQlInputException(__('Cart ID length should to be 32 symbols.')); + } + + if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) { + throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId)); + } + } + + /** + * Check is quote with such maskedId already exists + * + * @param string $maskedId + * @return bool + */ + private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool + { + try { + $this->maskedQuoteIdToQuoteId->execute($maskedId); + return true; + } catch (NoSuchEntityException $e) { + return false; + } + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php index f020527d958e4..b89bce213d7a7 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php @@ -7,15 +7,13 @@ namespace Magento\QuoteGraphQl\Model\Resolver; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; -use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForCustomer; use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForGuest; +use Magento\QuoteGraphQl\Model\Cart\ValidateMaskedQuoteId; /** * @inheritdoc @@ -37,19 +35,27 @@ class CreateEmptyCart implements ResolverInterface */ private $maskedQuoteIdToQuoteId; + /** + * @var ValidateMaskedQuoteId + */ + private ValidateMaskedQuoteId $validateMaskedQuoteId; + /** * @param CreateEmptyCartForCustomer $createEmptyCartForCustomer * @param CreateEmptyCartForGuest $createEmptyCartForGuest * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + * @param ValidateMaskedQuoteId $validateMaskedQuoteId */ public function __construct( CreateEmptyCartForCustomer $createEmptyCartForCustomer, CreateEmptyCartForGuest $createEmptyCartForGuest, - MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId + MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, + ValidateMaskedQuoteId $validateMaskedQuoteId ) { $this->createEmptyCartForCustomer = $createEmptyCartForCustomer; $this->createEmptyCartForGuest = $createEmptyCartForGuest; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->validateMaskedQuoteId = $validateMaskedQuoteId; } /** @@ -62,7 +68,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $predefinedMaskedQuoteId = null; if (isset($args['input']['cart_id'])) { $predefinedMaskedQuoteId = $args['input']['cart_id']; - $this->validateMaskedId($predefinedMaskedQuoteId); + $this->validateMaskedQuoteId->execute($predefinedMaskedQuoteId); } $maskedQuoteId = (0 === $customerId || null === $customerId) @@ -70,38 +76,4 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value : $this->createEmptyCartForCustomer->execute($customerId, $predefinedMaskedQuoteId); return $maskedQuoteId; } - - /** - * Validate masked id - * - * @param string $maskedId - * @throws GraphQlAlreadyExistsException - * @throws GraphQlInputException - */ - private function validateMaskedId(string $maskedId): void - { - if (mb_strlen($maskedId) != 32) { - throw new GraphQlInputException(__('Cart ID length should to be 32 symbols.')); - } - - if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) { - throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId)); - } - } - - /** - * Check is quote with such maskedId already exists - * - * @param string $maskedId - * @return bool - */ - private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool - { - try { - $this->maskedQuoteIdToQuoteId->execute($maskedId); - return true; - } catch (NoSuchEntityException $e) { - return false; - } - } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index 44bc17bfec535..f7e7805cc9730 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -18,15 +18,14 @@ namespace Magento\QuoteGraphQl\Model\Resolver; -use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForGuest; +use Magento\QuoteGraphQl\Model\Cart\ValidateMaskedQuoteId; /** * Creates a guest cart @@ -48,19 +47,27 @@ class CreateGuestCart implements ResolverInterface */ private CartRepositoryInterface $cartRepository; + /** + * @var ValidateMaskedQuoteId + */ + private ValidateMaskedQuoteId $validateMaskedQuoteId; + /** * @param CreateEmptyCartForGuest $createEmptyCartForGuest * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository + * @param ValidateMaskedQuoteId $validateMaskedQuoteId */ public function __construct( CreateEmptyCartForGuest $createEmptyCartForGuest, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, - CartRepositoryInterface $cartRepository + CartRepositoryInterface $cartRepository, + ValidateMaskedQuoteId $validateMaskedQuoteId ) { $this->createEmptyCartForGuest = $createEmptyCartForGuest; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->cartRepository = $cartRepository; + $this->validateMaskedQuoteId = $validateMaskedQuoteId; } /** @@ -73,7 +80,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $predefinedMaskedQuoteId = null; if (isset($args['input']['cart_uid'])) { $predefinedMaskedQuoteId = $args['input']['cart_uid']; - $this->validateMaskedId($predefinedMaskedQuoteId); + $this->validateMaskedQuoteId->execute($predefinedMaskedQuoteId); } if ($customerId === 0 || $customerId === null) { @@ -82,7 +89,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $cart = $this->cartRepository->get($cartId); } else { throw new GraphQlAlreadyExistsException( - __('Use `Query.cart` or `Query.customerCart` for logged in customer.') + __('Use `Query.customerCart` for logged in customer.') ); } @@ -92,38 +99,4 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value ], ]; } - - /** - * Validate masked id - * - * @param string $maskedId - * @throws GraphQlAlreadyExistsException - * @throws GraphQlInputException - */ - private function validateMaskedId(string $maskedId): void - { - if (mb_strlen($maskedId) != 32) { - throw new GraphQlInputException(__('Cart ID length should be 32 characters.')); - } - - if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) { - throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId)); - } - } - - /** - * Check is quote with such maskedId already exists - * - * @param string $maskedId - * @return bool - */ - private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool - { - try { - $this->maskedQuoteIdToQuoteId->execute($maskedId); - return true; - } catch (NoSuchEntityException $e) { - return false; - } - } } diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index 54b649a46fea7..89473e1554e11 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -9,7 +9,7 @@ type Query { type Mutation { createGuestCart(input: CreateGuestCartInput): CreateGuestCartOutput @doc(description: "Create a new shopping cart") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateGuestCart") - createEmptyCart(input: createEmptyCartInput): String @deprecated(reason: "Use `Mutation.createGuestCart` for guest and `Query.cart` or `Query.customerCart` for logged in customer") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user") + createEmptyCart(input: createEmptyCartInput @doc(description: "An optional input object that assigns the specified ID to the cart.")): String @deprecated(reason: "Use `Mutation.createGuestCart` or `Query.customerCart` for logged in customer") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Create an empty shopping cart for a guest or logged in user") addSimpleProductsToCart(input: AddSimpleProductsToCartInput @doc(description: "An input object that defines which simple products to add to the cart.")): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more simple products to the specified cart. We recommend using `addProductsToCart` instead.") addVirtualProductsToCart(input: AddVirtualProductsToCartInput @doc(description: "An input object that defines which virtual products to add to the cart.")): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart") @doc(description:"Add one or more virtual products to the specified cart. We recommend using `addProductsToCart` instead.") applyCouponToCart(input: ApplyCouponToCartInput @doc(description: "An input object that defines the coupon code to apply to the cart.")): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart") @doc(description:"Apply a pre-defined coupon code to the specified cart.") diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php index 9258451b15185..360e405cab139 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php @@ -58,13 +58,122 @@ protected function setUp(): void /** * @magentoApiDataFixture Magento/Customer/_files/customer.php */ - public function testDeprecatedCreateEmptyCart() + public function testCreateEmptyCart() { $query = $this->getQuery(); $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); self::assertArrayHasKey('createEmptyCart', $response); - self::assertEmpty($response['createEmptyCart']); + self::assertNotEmpty($response['createEmptyCart']); + + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + + self::assertNotNull($guestCart->getId()); + self::assertEquals(1, $guestCart->getCustomer()->getId()); + self::assertEquals('default', $guestCart->getStore()->getCode()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCreateEmptyMultipleRequestsCart() + { + $query = $this->getQuery(); + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + + self::assertArrayHasKey('createEmptyCart', $response); + self::assertNotEmpty($response['createEmptyCart']); + $maskedCartId = $response['createEmptyCart']; + + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + self::assertArrayHasKey('createEmptyCart', $response); + self::assertNotEmpty($response['createEmptyCart']); + + self::assertEquals($maskedCartId, $response['createEmptyCart']); + } + + /** + * @magentoApiDataFixture Magento/Store/_files/second_store.php + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCreateEmptyCartWithNotDefaultStore() + { + $query = $this->getQuery(); + + $headerMap = $this->getHeaderMapWithCustomerToken(); + $headerMap['Store'] = 'fixture_second_store'; + $response = $this->graphQlMutation($query, [], '', $headerMap); + + self::assertArrayHasKey('createEmptyCart', $response); + self::assertNotEmpty($response['createEmptyCart']); + + /* guestCartRepository is used for registered customer to get the cart hash */ + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + + self::assertNotNull($guestCart->getId()); + self::assertEquals(1, $guestCart->getCustomer()->getId()); + self::assertEquals('fixture_second_store', $guestCart->getStore()->getCode()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCreateEmptyCartWithPredefinedCartId() + { + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + + self::assertArrayHasKey('createEmptyCart', $response); + self::assertEquals($predefinedCartId, $response['createEmptyCart']); + + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + self::assertNotNull($guestCart->getId()); + self::assertEquals(1, $guestCart->getCustomer()->getId()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.'); + + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testCreateEmptyCartWithWrongPredefinedCartId() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cart ID length should to be 32 symbols.'); + + $predefinedCartId = '572'; + + $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken()); } /** diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php index 654fdd3668da3..88d69b90ac8f3 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateGuestCartTest.php @@ -68,7 +68,7 @@ protected function setUp(): void public function testFailForLoggedInUser() { $this->expectException(\Exception::class); - $this->expectExceptionMessage("Use `Query.cart` or `Query.customerCart` for logged in customer."); + $this->expectExceptionMessage("Use `Query.customerCart` for logged in customer."); $customer = DataFixtureStorageManager::getStorage()->get('customer'); diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php index ca05e548463bf..67012e75bf272 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php @@ -39,6 +39,11 @@ class CreateEmptyCartTest extends GraphQlAbstract */ private $quoteIdMaskFactory; + /** + * @var string + */ + private $maskedQuoteId; + protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); @@ -48,13 +53,102 @@ protected function setUp(): void $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class); } - public function testDeprecatedCreateEmptyCart() + public function testCreateEmptyCart() + { + $query = $this->getQuery(); + $response = $this->graphQlMutation($query); + + self::assertArrayHasKey('createEmptyCart', $response); + self::assertNotEmpty($response['createEmptyCart']); + + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + self::assertEquals('default', $guestCart->getStore()->getCode()); + self::assertEquals('1', $guestCart->getCustomerIsGuest()); + } + + /** + * @magentoApiDataFixture Magento/Store/_files/second_store.php + */ + public function testCreateEmptyCartWithNotDefaultStore() { $query = $this->getQuery(); + $headerMap = ['Store' => 'fixture_second_store']; + $response = $this->graphQlMutation($query, [], '', $headerMap); + + self::assertArrayHasKey('createEmptyCart', $response); + self::assertNotEmpty($response['createEmptyCart']); + + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + $this->maskedQuoteId = $response['createEmptyCart']; + + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + self::assertSame('fixture_second_store', $guestCart->getStore()->getCode()); + self::assertEquals('1', $guestCart->getCustomerIsGuest()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCreateEmptyCartWithPredefinedCartId() + { + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = <<graphQlMutation($query); self::assertArrayHasKey('createEmptyCart', $response); - self::assertEmpty($response['createEmptyCart']); + self::assertEquals($predefinedCartId, $response['createEmptyCart']); + + $guestCart = $this->guestCartRepository->get($response['createEmptyCart']); + self::assertNotNull($guestCart->getId()); + self::assertNull($guestCart->getCustomer()->getId()); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.'); + + $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4'; + + $query = <<graphQlMutation($query); + $this->graphQlMutation($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * + */ + public function testCreateEmptyCartWithWrongPredefinedCartId() + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('Cart ID length should to be 32 symbols.'); + + $predefinedCartId = '572'; + + $query = <<graphQlMutation($query); } /** From 0af59ef34f75d7e65cfae440e756a38ada857538 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Thu, 12 Oct 2023 17:37:42 +0530 Subject: [PATCH 06/11] LYNX-259: Quote id validation class comment --- .../Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php b/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php index 64b48d9e8320b..054f84d76543a 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/ValidateMaskedQuoteId.php @@ -23,6 +23,9 @@ use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; +/** + * Validates a pre-defined masked quote id + */ class ValidateMaskedQuoteId { /** From 102ced94c3f5cd39c6f0950fc61c0658bd48fca5 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Thu, 12 Oct 2023 18:34:57 +0530 Subject: [PATCH 07/11] LYNX-259: Update test message --- .../Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php index a02eff67b5f8e..5ac8f38067760 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateGuestCartTest.php @@ -140,7 +140,7 @@ public function testFailIfPredefinedCartIdAlreadyExists() public function testFailWithWrongPredefinedCartId() { $this->expectException(\Exception::class); - $this->expectExceptionMessage("Cart ID length should be 32 characters."); + $this->expectExceptionMessage("Cart ID length should to be 32 symbols."); $predefinedCartId = '1234567890'; From f062df2b2d378388be37427ec5773fed923da0ad Mon Sep 17 00:00:00 2001 From: Abhishek Pathak Date: Fri, 13 Oct 2023 15:08:18 +0530 Subject: [PATCH 08/11] LYNX-258: GraphQL | Clear Cart Mutation --- .../Quote/Test/Fixture/MakeCartInactive.php | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 app/code/Magento/Quote/Test/Fixture/MakeCartInactive.php diff --git a/app/code/Magento/Quote/Test/Fixture/MakeCartInactive.php b/app/code/Magento/Quote/Test/Fixture/MakeCartInactive.php new file mode 100644 index 0000000000000..c6e89890f4a9e --- /dev/null +++ b/app/code/Magento/Quote/Test/Fixture/MakeCartInactive.php @@ -0,0 +1,83 @@ +cartRepository = $cartRepository; + $this->quoteFactory = $quoteFactory; + $this->quoteResource = $quoteResource; + } + + /** + * @param array $data + * @return void + * @throws InvalidArgumentException + */ + public function apply(array $data = []): ?DataObject + { + if (empty($data[self::FIELD_CART_ID])) { + throw new InvalidArgumentException(__('"%field" is required', ['field' => self::FIELD_CART_ID])); + } + + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, $data[self::FIELD_CART_ID]); + $quote->setIsActive(false); + $this->cartRepository->save($quote); + + return $quote; + } +} From 86d82a9474855b1e7029df615a41045b42d6dbd2 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Fri, 13 Oct 2023 16:27:42 +0530 Subject: [PATCH 09/11] LYNX-259: Updated new class annotations --- .../QuoteGraphQl/Model/Resolver/CreateGuestCart.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index f7e7805cc9730..89b91330ea27b 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -72,6 +72,16 @@ public function __construct( /** * Creates a guest cart and returns the cart object + * + * @param Field $field + * @param $context + * @param ResolveInfo $info + * @param array|null $value + * @param array|null $args + * @return array[] + * @throws GraphQlAlreadyExistsException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\GraphQl\Exception\GraphQlInputException */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) { From 67ce689e073627af2d7b9e7082ec8e74f4207886 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Fri, 13 Oct 2023 17:59:21 +0530 Subject: [PATCH 10/11] LYNX-259: Updated comments --- .../Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index 89b91330ea27b..9e60275e23587 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -20,6 +20,7 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException; +use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartRepositoryInterface; @@ -74,7 +75,7 @@ public function __construct( * Creates a guest cart and returns the cart object * * @param Field $field - * @param $context + * @param ContextInterface $context * @param ResolveInfo $info * @param array|null $value * @param array|null $args From a85b86529c0ed925d3b06696477d45a8f2c7cff6 Mon Sep 17 00:00:00 2001 From: Sumesh P Date: Mon, 16 Oct 2023 10:27:27 +0530 Subject: [PATCH 11/11] LYNX-259: Update new file annotation --- .../QuoteGraphQl/Model/Resolver/CreateGuestCart.php | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php index 9e60275e23587..5889c8eb721fe 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateGuestCart.php @@ -20,7 +20,6 @@ use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException; -use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartRepositoryInterface; @@ -72,17 +71,7 @@ public function __construct( } /** - * Creates a guest cart and returns the cart object - * - * @param Field $field - * @param ContextInterface $context - * @param ResolveInfo $info - * @param array|null $value - * @param array|null $args - * @return array[] - * @throws GraphQlAlreadyExistsException - * @throws \Magento\Framework\Exception\NoSuchEntityException - * @throws \Magento\Framework\GraphQl\Exception\GraphQlInputException + * @inheritdoc */ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) {