Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Api][Cart] Fix for Cart access tests #11830

Merged
merged 7 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,7 @@ Feature: Allowing access only for correctly logged in users
And the customer has specified address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
And the customer has completed the addressing step
And the customer logged out
When the visitor try to proceed with "UPS" shipping method in the customer cart
Then the visitor has no access to customer's cart
Then the visitor has no access to proceed with "UPS" shipping method in the customer cart

@api
Scenario: Denying access to add payment method to the customer cart by the visitor
Expand All @@ -154,8 +153,7 @@ Feature: Allowing access only for correctly logged in users
And the customer has completed the addressing step
And the customer has proceeded "UPS" shipping method
And the customer logged out
When the visitor try to proceed with "offline" payment in the customer cart
Then the visitor has no access to customer's cart
Then the visitor has no access to proceed with "offline" payment in the customer cart

@api
Scenario: Denying access to complete the customer cart by the visitor
Expand All @@ -166,16 +164,14 @@ Feature: Allowing access only for correctly logged in users
And the customer has proceeded "UPS" shipping method
And the customer has proceeded "offline" payment
And the customer logged out
When the visitor try to confirm the customer order
Then the visitor has no access to customer's cart
Then the visitor has no access to confirm the customer order

@api
Scenario: Denying to increase quantity of an item in the customer cart by the visitor
Given the customer logged in
And the customer has product "Stark T-Shirt" in the cart
And the customer logged out
When the visitor try to change product "Stark T-Shirt" quantity to 2 in the customer cart
Then the visitor has no access to customer's cart
Then the visitor has no access to change product "Stark T-Shirt" quantity to 2 in the customer cart

@api
Scenario: Accessing to the customers cart by the admin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ Feature: Clearing cart after logging out
And I am a logged in customer
And I have product "Stark T-Shirt" in the cart

@ui @api
@ui
Scenario: Clearing cart after logging out
When I log out
And I see the summary of my cart
Then my cart should be empty

@api
Scenario: Clearing cart after logging out
When I log out
Then I don't have access to see the summary of my cart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Feature: Checking out as guest with a registered email
And the store allows paying offline
And there is a customer account "john@example.com"

@ui @api
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step is temporarily disabled and will be fixed in next iteration, We have secured the customers cart against operating by unauthorized visitor. But now user that has account in shop and try to buy something without login can't do this. Blocked by query in OrderGetMethodItemExtension.php and OrderMethodsItemExtension.php , As a visitor the query allow to get or to set order for situation when: customer == null or customer.user == null, but in this specific case should allow to continue shops when customer.user == certainUser, Possibility solution: create context that will be store customer id after addressing step.

@ui
Scenario: Successfully placing an order
Given I have product "PHP T-Shirt" in the cart
When I complete addressing step with email "john@example.com" and "United States" based billing address
Expand Down
91 changes: 71 additions & 20 deletions src/Sylius/Behat/Context/Api/Shop/CartContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ final class CartContext implements Context
/** @var ApiClientInterface */
private $productsClient;

/** @var ApiClientInterface */
private $ordersAdminClient;

/** @var ResponseCheckerInterface */
private $responseChecker;

Expand All @@ -51,13 +54,15 @@ final class CartContext implements Context
public function __construct(
ApiClientInterface $cartsClient,
ApiClientInterface $productsClient,
ApiClientInterface $ordersAdminClient,
ResponseCheckerInterface $responseChecker,
AdminToShopIriConverterInterface $adminToShopIriConverter,
SharedStorageInterface $sharedStorage,
ProductVariantResolverInterface $productVariantResolver
) {
$this->cartsClient = $cartsClient;
$this->productsClient = $productsClient;
$this->ordersAdminClient = $ordersAdminClient;
$this->responseChecker = $responseChecker;
$this->adminToShopIriConverter = $adminToShopIriConverter;
$this->sharedStorage = $sharedStorage;
Expand All @@ -74,14 +79,22 @@ public function iClearMyCart(string $tokenValue): void

/**
* @When /^I see the summary of my (cart)$/
* @When /^the (?:visitor|administrator) try to see the summary of (?:customer|visitor)'s (cart)$/
* @When /^the visitor try to see the summary of (?:customer|visitor)'s (cart)$/
* @When /^the (?:visitor|customer) see the summary of (?:their) (cart)$/
*/
public function iSeeTheSummaryOfMyCart(string $tokenValue): void
{
$this->cartsClient->show($tokenValue);
}

/**
* @When /^the administrator try to see the summary of (?:customer|visitor)'s (cart)$/
*/
public function theAdministratorTryToSeeTheSummaryOfCart(string $tokenValue): void
{
$this->ordersAdminClient->show($tokenValue);
}

/**
* @When /^I (?:add|added) (this product) to the (cart)$/
* @When /^I (?:add|added) ("[^"]+" product) to the (cart)$/
Expand Down Expand Up @@ -130,6 +143,14 @@ public function iRemoveProductFromTheCart(ProductInterface $product, string $tok
$this->removeOrderItemFromCart($itemId, $tokenValue);
}

/**
* @Then I don't have access to see the summary of my cart
*/
public function iDoNotHaveAccessToSeeTheSummaryOfMyCart(): void
{
Assert::same($this->getCart()['code'], 404);
}

/**
* @Then my cart should be cleared
*/
Expand All @@ -156,7 +177,6 @@ public function myCartSTotalShouldBe(string $tokenValue, int $total): void

/**
* @Then /^my (cart) should be empty$/
* @Then /^the visitor has no access to customer's (cart)$/
*/
public function myCartShouldBeEmpty(string $tokenValue): void
{
Expand All @@ -168,6 +188,19 @@ public function myCartShouldBeEmpty(string $tokenValue): void
);
}

/**
* @Then /^the visitor has no access to customer's (cart)$/
*/
public function theVisitorHasNoAccessToCustomer(string $tokenValue): void
{
$response = $this->cartsClient->show($tokenValue);

Assert::false(
$this->responseChecker->isShowSuccessful($response),
SprintfResponseEscaper::provideMessageWithEscapedResponseContent('Cart has not been created.', $response)
);
}

/**
* @Then I should be on my cart summary page
*/
Expand Down Expand Up @@ -242,28 +275,19 @@ public function thisItemShouldHaveCode(array $item, string $variantCode): void

/**
* @Then I should see :productName with quantity :quantity in my cart
* @Then /^the administrator should see ("[^"]+" product) with quantity ([^"]+) in the (?:customer|visitor) cart$/
* @Then /^the (?:customer|visitor) should see (product "[^"]+") with quantity (\d+) in his cart$/
* @Then /^the (?:customer|visitor) should see product "([^"]+)" with quantity (\d+) in his cart$/
*/
public function iShouldSeeWithQuantityInMyCart(string $productName, int $quantity): void
{
$cartResponse = $this->cartsClient->getLastResponse();
$items = $this->responseChecker->getValue($cartResponse, 'items');

foreach ($items as $item) {
$productResponse = $this->getProductForItem($item);
$this->checkProductQuantity($this->cartsClient->getLastResponse(), $productName, $quantity);
}

if ($this->responseChecker->hasTranslation($productResponse, 'en_US', 'name', $productName)) {
Assert::same(
$item['quantity'],
$quantity,
SprintfResponseEscaper::provideMessageWithEscapedResponseContent(
sprintf('Quantity did not match. Expected %s.', $quantity),
$cartResponse
)
);
}
}
/**
* @Then /^the administrator should see "([^"]+)" product with quantity (\d+) in the (?:customer|visitor) cart$/
*/
public function theAdministratorShouldSeeProductWithQuantityInTheCart(string $productName, int $quantity): void
lchrusciel marked this conversation as resolved.
Show resolved Hide resolved
{
$this->checkProductQuantity($this->ordersAdminClient->getLastResponse(), $productName, $quantity);
}

/**
Expand Down Expand Up @@ -414,4 +438,31 @@ private function hasItemWithNameAndQuantity(Response $response, string $productN

return false;
}

private function checkProductQuantity(Response $cartResponse, string $productName, int $quantity): void
{
$items = $this->responseChecker->getValue($cartResponse, 'items');

foreach ($items as $item) {
$productResponse = $this->getProductForItem($item);

if ($this->responseChecker->hasTranslation($productResponse, 'en_US', 'name', $productName)) {
Assert::same(
$item['quantity'],
$quantity,
SprintfResponseEscaper::provideMessageWithEscapedResponseContent(
sprintf('Quantity did not match. Expected %s.', $quantity),
$cartResponse
)
);
}
}
}

private function getCart(): array
{
$response = $this->cartsClient->show($this->sharedStorage->get('cart_token'));

return $this->responseChecker->getResponseContent($response);
}
}
14 changes: 11 additions & 3 deletions src/Sylius/Behat/Context/Api/Shop/CheckoutContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ public function iProvideAdditionalNotesLike(string $notes): void
* @When I confirm my order
* @When I try to confirm my order
* @When /^the (?:visitor|customer) confirm his order$/
* @When /^the visitor try to confirm the customer order$/
*/
public function iConfirmMyOrder(): void
{
Expand Down Expand Up @@ -250,7 +249,6 @@ public function iConfirmMyOrder(): void
* @When I select :shippingMethod shipping method
* @When /^the (?:visitor|customer) proceed with ("[^"]+" shipping method)$/
* @Given /^the (?:visitor|customer) has proceeded ("[^"]+" shipping method)$/
* @When /^the visitor try to proceed with ("[^"]+" shipping method) in the customer cart$/
*/
public function iProceededWithShippingMethod(ShippingMethodInterface $shippingMethod): void
{
Expand All @@ -270,6 +268,17 @@ public function iProceededWithShippingMethod(ShippingMethodInterface $shippingMe
);
}

/**
* @Then the visitor has no access to proceed with :shippingMethod shipping method in the customer cart
* @Then the visitor has no access to proceed with :paymentMethod payment in the customer cart
* @Then the visitor has no access to confirm the customer order
* @Then the visitor has no access to change product :product quantity to :quantity in the customer cart
*/
public function theVisitorHasNoProceedWithShippingMethodInTheCustomerCart(): void
{
Assert::same($this->getCart()['code'], 404);
}

/**
* @When I complete the shipping step with first shipping method
*/
Expand All @@ -286,7 +295,6 @@ public function iCompleteTheShippingStepWithFirstShippingMethod(): void
* @When I select :paymentMethod payment method
* @When /^the (?:customer|visitor) proceed with ("[^"]+" payment)$/
* @Given /^the (?:customer|visitor) has proceeded ("[^"]+" payment)$/
* @Given /^the visitor try to proceed with ("[^"]+" payment) in the customer cart$/
*/
public function iChoosePaymentMethod(PaymentMethodInterface $paymentMethod): void
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<service id="sylius.behat.context.api.shop.cart" class="Sylius\Behat\Context\Api\Shop\CartContext">
<argument type="service" id="sylius.behat.api_platform_client.shop.cart" />
<argument type="service" id="sylius.behat.api_platform_client.shop.product" />
<argument type="service" id="sylius.behat.api_platform_client.admin.order" />
<argument type="service" id="Sylius\Behat\Client\ResponseCheckerInterface" />
<argument type="service" id="sylius.admin_to_shop_iri_converter" />
<argument type="service" id="sylius.behat.shared_storage" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Bundle\ApiBundle\Serializer\ContextKeys;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
Expand All @@ -43,35 +44,37 @@ public function applyToItem(
string $operationName = null,
array $context = []
) {
$operationName = strtoupper($operationName);

if (!is_a($resourceClass, OrderInterface::class, true)) {
return;
}

if ($operationName !== Request::METHOD_GET) {
if ($context[ContextKeys::HTTP_REQUEST_METHOD_TYPE] !== Request::METHOD_GET) {
return;
}

$rootAlias = $queryBuilder->getRootAliases()[0];
$user = $this->userContext->getUser();

$this->applyToItemForGetMethod($user, $queryBuilder, $operationName, $rootAlias);
$this->applyToItemForGetMethod($user, $queryBuilder, $rootAlias);
}

private function applyToItemForGetMethod(
?UserInterface $user,
QueryBuilder $queryBuilder,
string $operationName,
string $rootAlias
): void {
if ($user === null) {
$queryBuilder->andWhere(sprintf('%s.customer IS NULL', $rootAlias));
$queryBuilder
->leftJoin(sprintf('%s.customer', $rootAlias), 'customer')
->leftJoin('customer.user', 'user')
->andWhere('user IS NULL')
->orWhere(sprintf('%s.customer IS NULL', $rootAlias))
;

return;
}

if ($user instanceof ShopUserInterface && in_array('ROLE_API_ACCESS', $user->getRoles(), true)) {
if ($user instanceof ShopUserInterface && in_array('ROLE_USER', $user->getRoles(), true)) {
$queryBuilder
->andWhere(sprintf('%s.customer = :customer', $rootAlias))
->setParameter('customer', $user->getCustomer()->getId())
Expand Down