diff --git a/features/cart/shopping_cart/viewing_cart_summary.feature b/features/cart/shopping_cart/viewing_cart_summary.feature index 40ef32bfea9..cc056096033 100644 --- a/features/cart/shopping_cart/viewing_cart_summary.feature +++ b/features/cart/shopping_cart/viewing_cart_summary.feature @@ -7,7 +7,7 @@ Feature: Viewing a cart summary Background: Given the store operates on a single channel in "United States" - @ui + @ui @api Scenario: Viewing information about empty cart When I see the summary of my cart Then my cart should be empty diff --git a/src/Sylius/Behat/Client/ApiClientInterface.php b/src/Sylius/Behat/Client/ApiClientInterface.php index 173d175cc73..1fe53c88c80 100644 --- a/src/Sylius/Behat/Client/ApiClientInterface.php +++ b/src/Sylius/Behat/Client/ApiClientInterface.php @@ -26,7 +26,7 @@ public function subResourceIndex(string $subResource, string $id): Response; public function show(string $id): Response; - public function create(): Response; + public function create(?RequestInterface $request = null): Response; public function update(): Response; diff --git a/src/Sylius/Behat/Client/ApiPlatformClient.php b/src/Sylius/Behat/Client/ApiPlatformClient.php index ec58c48bfa4..8bc318c81c8 100644 --- a/src/Sylius/Behat/Client/ApiPlatformClient.php +++ b/src/Sylius/Behat/Client/ApiPlatformClient.php @@ -61,9 +61,9 @@ public function show(string $id): Response return $this->request(Request::show($this->resource, $id, $this->sharedStorage->get('token'))); } - public function create(): Response + public function create(?RequestInterface $request = null): Response { - return $this->request($this->request); + return $this->request($request ?? $this->request); } public function update(): Response @@ -118,7 +118,8 @@ public function upload(): Response public function buildCreateRequest(): void { - $this->request = Request::create($this->resource, $this->sharedStorage->get('token')); + $this->request = Request::create($this->resource); + $this->request->authorize($this->sharedStorage->get('token')); } public function buildUpdateRequest(string $id): void diff --git a/src/Sylius/Behat/Client/Request.php b/src/Sylius/Behat/Client/Request.php index ea3294599e2..6e702be49ef 100644 --- a/src/Sylius/Behat/Client/Request.php +++ b/src/Sylius/Behat/Client/Request.php @@ -67,12 +67,12 @@ public static function show(string $resource, string $id, string $token): Reques ); } - public static function create(string $resource, string $token): RequestInterface + public static function create(string $resource): RequestInterface { return new self( sprintf('/new-api/%s', $resource), HttpRequest::METHOD_POST, - ['CONTENT_TYPE' => 'application/json', 'HTTP_Authorization' => 'Bearer ' . $token] + ['CONTENT_TYPE' => 'application/ld+json'] ); } @@ -190,6 +190,11 @@ public function removeSubResource(string $subResource, string $id): void } } + public function authorize(string $token): void + { + $this->headers['HTTP_Authorization'] = 'Bearer ' . $token; + } + private function mergeArraysUniquely(array $firstArray, array $secondArray): array { foreach ($secondArray as $key => $value) { diff --git a/src/Sylius/Behat/Client/RequestInterface.php b/src/Sylius/Behat/Client/RequestInterface.php index fc7291991e9..596082e0170 100644 --- a/src/Sylius/Behat/Client/RequestInterface.php +++ b/src/Sylius/Behat/Client/RequestInterface.php @@ -21,7 +21,7 @@ public static function subResourceIndex(string $resource, string $id, string $su public static function show(string $resource, string $id, string $token): self; - public static function create(string $resource, string $token): self; + public static function create(string $resource): self; public static function update(string $resource, string $id, string $token): self; @@ -56,4 +56,6 @@ public function updateFiles(array $newFiles): void; public function addSubResource(string $key, array $subResource): void; public function removeSubResource(string $subResource, string $id): void; + + public function authorize(string $token): void; } diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php index 71feb378866..0e05ed6ebaa 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingOrdersContext.php @@ -75,7 +75,7 @@ public function iBrowseOrders(): void */ public function iSeeTheOrder(OrderInterface $order): void { - $this->client->show($order->getNumber()); + $this->client->show($order->getTokenValue()); } /** @@ -84,7 +84,7 @@ public function iSeeTheOrder(OrderInterface $order): void public function iCancelThisOrder(OrderInterface $order): void { $this->client->applyTransition( - $this->responseChecker->getValue($this->client->show($order->getNumber()), 'number'), + $this->responseChecker->getValue($this->client->show($order->getTokenValue()), 'tokenValue'), OrderTransitions::TRANSITION_CANCEL ); } @@ -129,9 +129,10 @@ public function iShouldSeeASingleOrderFromCustomer(CustomerInterface $customer): */ public function iShouldBeNotifiedAboutItHasBeenSuccessfullyCanceled(): void { + $response = $this->client->getLastResponse(); Assert::true( - $this->responseChecker->isUpdateSuccessful($this->client->getLastResponse()), - 'Resource could not be completed' + $this->responseChecker->isUpdateSuccessful($response), + 'Resource could not be completed. Reason: ' . $response->getContent() ); } @@ -143,7 +144,7 @@ public function itsStateShouldBe(string $state): void { /** @var OrderInterface $order */ $order = $this->sharedStorage->get('order'); - $orderState = $this->responseChecker->getValue($this->client->show($order->getNumber()), 'state'); + $orderState = $this->responseChecker->getValue($this->client->show($order->getTokenValue()), 'state'); Assert::same($orderState, strtolower($state)); } @@ -154,7 +155,7 @@ public function itsStateShouldBe(string $state): void public function itShouldHaveShipmentState(string $state): void { $shipmentsIri = $this->responseChecker->getValue( - $this->client->show($this->sharedStorage->get('order')->getNumber()), + $this->client->show($this->sharedStorage->get('order')->getTokenValue()), 'shipments' ); @@ -170,7 +171,7 @@ public function itShouldHaveShipmentState(string $state): void public function itShouldHavePaymentState($state): void { $paymentsIri = $this->responseChecker->getValue( - $this->client->show($this->sharedStorage->get('order')->getNumber()), + $this->client->show($this->sharedStorage->get('order')->getTokenValue()), 'payments' ); @@ -186,7 +187,7 @@ public function itShouldHavePaymentState($state): void public function theOrderShouldHaveNumberOfPayments(int $number): void { Assert::count( - $this->responseChecker->getValue($this->client->show($this->sharedStorage->get('order')->getNumber()), 'payments'), + $this->responseChecker->getValue($this->client->show($this->sharedStorage->get('order')->getTokenValue()), 'payments'), $number ); } @@ -197,8 +198,8 @@ public function theOrderShouldHaveNumberOfPayments(int $number): void public function theOrderShouldHavePaymentState(OrderInterface $order, string $paymentState): void { Assert::true( - $this->responseChecker->hasValue($this->client->show($order->getNumber()), 'paymentState', strtolower($paymentState)), - sprintf('Order %s does not have %s payment state', $order->getNumber(), $paymentState) + $this->responseChecker->hasValue($this->client->show($order->getTokenValue()), 'paymentState', strtolower($paymentState)), + sprintf('Order %s does not have %s payment state', $order->getTokenValue(), $paymentState) ); } diff --git a/src/Sylius/Behat/Context/Api/Admin/ManagingPaymentsContext.php b/src/Sylius/Behat/Context/Api/Admin/ManagingPaymentsContext.php index 91509b1c977..ba23840a30a 100644 --- a/src/Sylius/Behat/Context/Api/Admin/ManagingPaymentsContext.php +++ b/src/Sylius/Behat/Context/Api/Admin/ManagingPaymentsContext.php @@ -135,12 +135,12 @@ public function thePaymentOfTheOrderShouldBeFor( } /** - * @Then /^I should see payment for (the "[^"]+" order) as (\d+)(?:|st|nd|rd|th) in the list$/ + * @Then /^I should see payment for the ("[^"]+" order) as (\d+)(?:|st|nd|rd|th) in the list$/ */ - public function iShouldSeePaymentForTheOrderInTheList(string $orderNumber, int $position): void + public function iShouldSeePaymentForTheOrderInTheList(OrderInterface $order, int $position): void { Assert::true($this->responseChecker->hasItemOnPositionWithValue( - $this->client->getLastResponse(), $position - 1, 'order', sprintf('/new-api/orders/%s', $orderNumber) + $this->client->getLastResponse(), $position - 1, 'order', sprintf('/new-api/orders/%s', $order->getTokenValue()) )); } diff --git a/src/Sylius/Behat/Context/Api/Shop/CartContext.php b/src/Sylius/Behat/Context/Api/Shop/CartContext.php new file mode 100644 index 00000000000..e3cf890210a --- /dev/null +++ b/src/Sylius/Behat/Context/Api/Shop/CartContext.php @@ -0,0 +1,55 @@ +cartsClient = $cartsClient; + $this->responseChecker = $responseChecker; + } + + /** + * @When I see the summary of my cart + */ + public function iSeeTheSummaryOfMyCart(): void + { + $this->cartsClient->create(Request::create('orders')); + } + + /** + * @Then my cart should be empty + */ + public function myCartShouldBeEmpty(): void + { + $response = $this->cartsClient->getLastResponse(); + Assert::true( + $this->responseChecker->isCreationSuccessful($response), + 'Cart has not been created. Reason: ' . $response->getContent() + ); + } +} diff --git a/src/Sylius/Behat/Resources/config/services/api.xml b/src/Sylius/Behat/Resources/config/services/api.xml index 5838547c115..df69a01bb64 100644 --- a/src/Sylius/Behat/Resources/config/services/api.xml +++ b/src/Sylius/Behat/Resources/config/services/api.xml @@ -74,6 +74,10 @@ provinces + + carts + + shipping-categories diff --git a/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml b/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml index bf4309eff73..56e6a42bfbf 100644 --- a/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml +++ b/src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml @@ -18,6 +18,11 @@ + + + + + diff --git a/src/Sylius/Behat/Resources/config/suites.yml b/src/Sylius/Behat/Resources/config/suites.yml index 9c9dd2e0620..b3d820dc6f1 100644 --- a/src/Sylius/Behat/Resources/config/suites.yml +++ b/src/Sylius/Behat/Resources/config/suites.yml @@ -7,6 +7,7 @@ imports: - suites/api/addressing/managing_countries.yml - suites/api/addressing/managing_zones.yml - suites/api/admin/login.yml + - suites/api/cart/shopping_cart.yml - suites/api/channel/managing_channels.yml - suites/api/currency/managing_currencies.yml - suites/api/currency/managing_exchange_rates.yml diff --git a/src/Sylius/Behat/Resources/config/suites/api/cart/shopping_cart.yml b/src/Sylius/Behat/Resources/config/suites/api/cart/shopping_cart.yml new file mode 100644 index 00000000000..a07e462c9da --- /dev/null +++ b/src/Sylius/Behat/Resources/config/suites/api/cart/shopping_cart.yml @@ -0,0 +1,15 @@ +# This file is part of the Sylius package. +# (c) Paweł Jędrzejewski + +default: + suites: + api_shopping_cart: + contexts: + - sylius.behat.context.hook.doctrine_orm + + - sylius.behat.context.setup.channel + + - sylius.behat.context.api.shop.cart + + filters: + tags: "@shopping_cart && @api" diff --git a/src/Sylius/Bundle/ApiBundle/Command/PickupCart.php b/src/Sylius/Bundle/ApiBundle/Command/PickupCart.php new file mode 100644 index 00000000000..daa83460040 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/Command/PickupCart.php @@ -0,0 +1,21 @@ +cartFactory = $cartFactory; + $this->channelContext = $channelContext; + $this->orderManager = $orderManager; + $this->generator = $generator; + } + + public function __invoke(PickupCart $pickupCart) + { + /** @var OrderInterface $cart */ + $cart = $this->cartFactory->createNew(); + + /** @var ChannelInterface $channel */ + $channel = $this->channelContext->getChannel(); + /** @var LocaleInterface $locale */ + $locale = $channel->getDefaultLocale(); + /** @var CurrencyInterface $currency */ + $currency = $channel->getBaseCurrency(); + + $cart->setChannel($channel); + $cart->setLocaleCode($locale->getCode()); + $cart->setCurrencyCode($currency->getCode()); + $cart->setTokenValue($this->generator->generateUriSafeString(10)); + + $this->orderManager->persist($cart); + + return $cart; + } +} diff --git a/src/Sylius/Bundle/ApiBundle/PropertyInfo/Extractor/EmptyPropertyListExtractor.php b/src/Sylius/Bundle/ApiBundle/PropertyInfo/Extractor/EmptyPropertyListExtractor.php new file mode 100644 index 00000000000..749b699ff96 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/PropertyInfo/Extractor/EmptyPropertyListExtractor.php @@ -0,0 +1,28 @@ + is_granted('ROLE_API_ACCESS') + + is_granted('IS_AUTHENTICATED_ANONYMOUSLY') + + Pickup a new cart + + input + Sylius\Bundle\ApiBundle\Command\PickupCart + @@ -51,7 +59,8 @@ - + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml index 07653d6dde4..dd2bc9ebc82 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/serialization/Order.xml @@ -55,5 +55,9 @@ order:read + + + order:read + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml index 5ece3e81d67..ccb697727ba 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services.xml @@ -62,5 +62,9 @@ + + + + diff --git a/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml b/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml index 7df18ffc729..5cc2b2352d8 100644 --- a/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml +++ b/src/Sylius/Bundle/ApiBundle/Resources/config/services/command_handlers.xml @@ -22,5 +22,13 @@ + + + + + + + + diff --git a/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/PickupCartHandlerSpec.php b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/PickupCartHandlerSpec.php new file mode 100644 index 00000000000..ee3af17e7fa --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/CommandHandler/PickupCartHandlerSpec.php @@ -0,0 +1,79 @@ +beConstructedWith($cartFactory, $channelContext, $orderManager, $generator); + } + + function it_is_a_message_handler(): void + { + $this->shouldImplement(MessageHandlerInterface::class); + } + + function it_pick_ups_a_cart( + FactoryInterface $cartFactory, + ChannelContextInterface $channelContext, + ObjectManager $orderManager, + RandomnessGeneratorInterface $generator, + OrderInterface $cart, + ChannelInterface $channel, + CurrencyInterface $currency, + LocaleInterface $locale + ): void { + $cartFactory->createNew()->willReturn($cart); + $channelContext->getChannel()->willReturn($channel); + $generator->generateUriSafeString(10)->willReturn('urisafestr'); + + $channel->getBaseCurrency()->willReturn($currency); + $channel->getDefaultLocale()->willReturn($locale); + + $currency->getCode()->willReturn('USD'); + + $locale->getCode()->willReturn('en_US'); + + $cart->setChannel($channel)->shouldBeCalled(); + $cart->setCurrencyCode('USD')->shouldBeCalled(); + $cart->setLocaleCode('en_US')->shouldBeCalled(); + $cart->setTokenValue('urisafestr')->shouldBeCalled(); + + $orderManager->persist($cart)->shouldBeCalled(); + + $this(new PickupCart()); + } +} diff --git a/src/Sylius/Bundle/ApiBundle/spec/PropertyInfo/Extractor/EmptyPropertyListExtractorSpec.php b/src/Sylius/Bundle/ApiBundle/spec/PropertyInfo/Extractor/EmptyPropertyListExtractorSpec.php new file mode 100644 index 00000000000..0f1176708e9 --- /dev/null +++ b/src/Sylius/Bundle/ApiBundle/spec/PropertyInfo/Extractor/EmptyPropertyListExtractorSpec.php @@ -0,0 +1,36 @@ +shouldImplement(PropertyListExtractorInterface::class); + } + + function it_provides_empty_list_if_requested_class_exists(): void + { + $this->getProperties(PickupCart::class, [])->shouldReturn([]); + } + + function it_provides_null_if_requested_class_does_not_exist(): void + { + $this->getProperties(\Serializable::class, [])->shouldReturn(null); + } +}