Merge pull request #5882 from Arminek/verify-complete-checkout

[Checkout][Inventory] Verify complete checkout
This commit is contained in:
Paweł Jędrzejewski 2016-08-29 12:01:42 +02:00 committed by GitHub
commit 66d152dc69
14 changed files with 163 additions and 10 deletions

View file

@ -1,4 +1,4 @@
@shopping_cart
@inventory
Feature: Inability to add a specific product to the cart when it is out of stock
In order to buy only available products
As a Visitor

View file

@ -0,0 +1,43 @@
@inventory
Feature: Being unable to buy products that are out of stock
In order to be sure that products I buy are available
As a Customer
I want to be prevented from placing an order with products that are out of stock
Background:
Given the store operates on a single channel in "United States"
And the store has a product "Iron Maiden T-Shirt" priced at "12.54"
And the store also has a product "2Pac T-Shirt" priced at "13.24"
And "Iron Maiden T-Shirt" product is tracked by the inventory
And "2Pac T-Shirt" product is also tracked by the inventory
And there are 5 units of product "Iron Maiden T-Shirt" available in the inventory
And there are 10 units of product "2Pac T-Shirt" available in the inventory
And the store ships everywhere for free
And the store allows paying offline
And I am a logged in customer
@ui
Scenario: Placing an order with products that have sufficient quantity
Given I have added 3 products "Iron Maiden T-Shirt" to the cart
And I have proceeded selecting "Offline" payment method
When I confirm my order
Then I should see the thank you page
@ui
Scenario: Being unable to place an order with product that is out of stock
Given I have added 5 products "Iron Maiden T-Shirt" to the cart
And I have proceeded selecting "Offline" payment method
When other customer has bought 2 "Iron Maiden T-Shirt" products by this time
And I confirm my order
Then I should not see the thank you page
And I should be notified that this product does not have sufficient stock
@ui
Scenario: Being unable to place an order with products that are out of stock
Given I have added 5 products "Iron Maiden T-Shirt" to the cart
And I have added 5 products "2Pac T-Shirt" to the cart
And I have proceeded selecting "Offline" payment method
When other customer has bought 7 "2Pac T-Shirt" products by this time
And I confirm my order
Then I should not see the thank you page
And I should be notified that this product does not have sufficient stock

View file

@ -126,7 +126,7 @@ final class ProductContext implements Context
/**
* @Given the store has a product :productName
* @Given the store has a :productName product
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
* @Given /^the store(?:| also) has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt($productName, $price = 0)
{
@ -331,7 +331,8 @@ final class ProductContext implements Context
}
/**
* @Given /^there (?:is|are) (\d+) item(?:s) of (product "([^"]+)") available in the inventory$/
* @Given /^there (?:is|are) (\d+) (?:item|unit)(?:s) of (product "([^"]+)") available in the inventory$/
* @When product :product quantity is changed to :quantity
*/
public function thereIsQuantityOfProducts($quantity, ProductInterface $product)
{
@ -348,6 +349,30 @@ final class ProductContext implements Context
$this->setProductsQuantity($product, 0);
}
/**
* @When other customer has bought :quantity :product products by this time
*/
public function otherCustomerHasBoughtProductsByThisTime($quantity, ProductInterface $product)
{
/** @var ProductVariantInterface $productVariant */
$productVariant = $this->defaultVariantResolver->getVariant($product);
$productQuantity = $productVariant->getOnHand() - $quantity;
$this->setProductsQuantity($product, $productQuantity);
}
/**
* @Given /^(this product) is tracked by the inventory$/
* @Given /^("[^"]+" product) is(?:| also) tracked by the inventory$/
*/
public function thisProductIsTrackedByTheInventory(ProductInterface $product)
{
$variant = $this->defaultVariantResolver->getVariant($product);
$variant->setTracked(true);
$this->objectManager->flush();
}
/**
* @Given /^(this product) is available in "([^"]+)" size priced at ("[^"]+")$/
*/

View file

@ -34,9 +34,8 @@ final class ProductContext implements Context
}
/**
* @Transform /^product "([^"]+)"$/
* @Transform /^"([^"]+)" product$/
* @Transform /^"([^"]+)" products$/
* @Transform /^product(?:|s) "([^"]+)"$/
* @Transform /^"([^"]+)" product(?:|s)$/
* @Transform /^(?:a|an) "([^"]+)"$/
* @Transform :product
*/

View file

@ -487,6 +487,17 @@ final class CheckoutContext implements Context
);
}
/**
* @Then I should not see the thank you page
*/
public function iShouldNotSeeTheThankYouPage()
{
Assert::false(
$this->thankYouPage->isOpen(),
'I should not see thank you message, but I do'
);
}
/**
* @Given I should be informed with :paymentMethod payment method instructions
*/
@ -915,6 +926,17 @@ final class CheckoutContext implements Context
);
}
/**
* @Given /^I should be notified that (this product) does not have sufficient stock$/
*/
public function iShouldBeNotifiedThatThisProductDoesNotHaveSufficientStock(ProductInterface $product)
{
Assert::true(
$this->completePage->hasProductOutOfStockValidationMessage($product),
sprintf('I should see validation message for %s product', $product->getName())
);
}
/**
* @return AddressInterface
*/

View file

@ -303,10 +303,10 @@ final class CartContext implements Context
}
/**
* @Given I have :quantity products :product in the cart
* @When I add :quantity products :product to the cart
* @Given /^I have(?:| added) (\d+) (products "([^"]+)") (?:to|in) the cart$/
* @When /^I add(?:|ed) (\d+) (products "([^"]+)") to the cart$/
*/
public function iAddProductsToTheCart(ProductInterface $product, $quantity)
public function iAddProductsToTheCart($quantity, ProductInterface $product)
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCartWithQuantity($quantity);

View file

@ -193,6 +193,16 @@ class CompletePage extends SymfonyPage implements CompletePageInterface
return null !== $productRowElement->find('css', sprintf('td:contains("%s")', $price));
}
/**
* {@inheritdoc}
*/
public function hasProductOutOfStockValidationMessage(ProductInterface $product)
{
$message = sprintf('%s does not have sufficient stock.', $product->getName());
return $this->getElement('validation_errors')->getText() === $message;
}
public function confirmOrder()
{
$this->getDocument()->pressButton('Place order');
@ -234,6 +244,7 @@ class CompletePage extends SymfonyPage implements CompletePageInterface
'shipping_step_label' => '.steps a:contains("Shipping")',
'shipping_total' => '#shipping-total',
'tax_total' => '#tax-total',
'validation_errors' => '.sylius-validation-error',
]);
}

View file

@ -114,6 +114,13 @@ interface CompletePageInterface
*/
public function hasProductUnitPrice(ProductInterface $product, $price);
/**
* @param ProductInterface $product
*
* @return bool
*/
public function hasProductOutOfStockValidationMessage(ProductInterface $product);
public function changeAddress();
public function changeShippingMethod();

View file

@ -29,6 +29,7 @@ imports:
- suites/ui/checkout/paying_for_order.yml
- suites/ui/currency/currencies.yml
- suites/ui/currency/managing_currencies.yml
- suites/ui/inventory/inventory.yml
- suites/ui/locale/locales.yml
- suites/ui/locale/managing_locales.yml
- suites/ui/order/managing_orders.yml

View file

@ -0,0 +1,33 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
default:
suites:
ui_inventory:
contexts_as_services:
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.currency
- sylius.behat.context.setup.geographical
- sylius.behat.context.setup.payment
- sylius.behat.context.setup.product
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.shop_security
- sylius.behat.context.setup.user
- sylius.behat.context.transform.addressing
- sylius.behat.context.transform.lexical
- sylius.behat.context.transform.payment
- sylius.behat.context.transform.product
- sylius.behat.context.transform.product_option
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.ui.checkout
- sylius.behat.context.ui.paypal
- sylius.behat.context.ui.shop.cart
- sylius.behat.context.ui.shop.product
- sylius.behat.context.ui.user
filters:
tags: "@inventory && @ui"

View file

@ -127,7 +127,10 @@
<class name="Sylius\Component\Cart\Model\CartItem">
<constraint name="Sylius\Bundle\InventoryBundle\Validator\Constraints\InStock">
<option name="stockablePath">variant</option>
<option name="groups">sylius</option>
<option name="groups">
<value>sylius_checkout_complete</value>
<value>sylius</value>
</option>
</constraint>
</class>

View file

@ -140,6 +140,8 @@ sylius_shop_checkout_complete:
redirect: sylius_shop_checkout_thank_you
form:
type: sylius_checkout_complete
options:
validation_groups: 'sylius_checkout_complete'
sylius_shop_checkout_thank_you:
path: /thank-you

View file

@ -7,6 +7,7 @@
{% include '@SyliusShop/Checkout/_steps.html.twig' with {'active': 'complete'} %}
<div class="ui padded segment">
{{ form_start(form, {'action': path('sylius_shop_checkout_complete'), 'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}
{{ form_errors(form) }}
<input type="hidden" name="_method" value="PUT" />
{% include 'SyliusShopBundle:Common/Order:_summary.html.twig' %}

View file

@ -12,11 +12,17 @@
namespace Sylius\Component\Variation\Resolver;
use Sylius\Component\Variation\Model\VariableInterface;
use Sylius\Component\Variation\Model\VariantInterface;
/**
* @author Anna Walasek <anna.walasek@lakion.com>
*/
interface VariantResolverInterface
{
/**
* @param VariableInterface $subject
*
* @return VariantInterface
*/
public function getVariant(VariableInterface $subject);
}