1. WITH BEHAT, UI AND API
BUSINESS LOGIC TESTING
@mpzalewski
Zales0123
MATEUSZ ZALEWSKI
2. BEHAVIOUR DRIVEN
DEVELOPMENT
BDD is a process designed to aid the management and the delivery of
software development projects by improving communication between
engineers and business professionals.
https://inviqa.com/insights/bdd-guide
2
8. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
8
9. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
9
10. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
@ui
10
11. Given the store has a product "T-shirt banana" priced at "$12.54"
/**
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt(
string $productName,
int $price = 100
): void {
$product = $this->createProduct($productName, $price, $channel);
$this->saveProduct($product);
}
11
12. Given the store has a product "T-shirt banana" priced at "$12.54"
/**
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt(
string $productName,
int $price = 100
): void {
$product = $this->createProduct($productName, $price, $channel);
$this->saveProduct($product);
}
$product = $this->createProduct($productName, $price, $channel);
12
14. Given the store has a product "T-shirt banana" priced at "$12.54"
/**
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt(
string $productName,
int $price = 100
): void {
$product = $this->createProduct($productName, $price, $channel);
$this->saveProduct($product);
}
priced at ("[^"]+")
int $price = 100
14
15. /**
* @Transform /^"(-)?(?:€|£|¥|$)((?:d+.)?d+)"$/
*/
public function getPriceFromString(string $sign, string $price): int
{
$this->validatePriceString($price);
$price = (int) round((float) $price * 100, 2);
if ('-' === $sign) {
$price *= -1;
}
return $price;
}
15
16. When I add this product to the cart
/**
* @When /^I (?:add|added) (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCart();
}
@ui
16
17. When I add this product to the cart
/**
* @When /^I (?:add|added) (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCart();
}
(this product)
ProductInterface $product
17 @ui
18. /**
* @Transform /^(?:this|that|the) ([^"]+)$/
*/
public function getResource(mixed $resource): mixed
{
return $this->sharedStorage->get(
StringInflector::nameToCode($resource)
);
}
18
19. private function saveProduct(ProductInterface $product)
{
$this->productRepository->add($product);
$this->sharedStorage->set('product', $product);
}
public function set($key, $resource): void
{
$this->clipboard[$key] = $resource;
$this->latestKey = $key;
}
19
20. private function saveProduct(ProductInterface $product)
{
$this->productRepository->add($product);
$this->sharedStorage->set('product', $product);
}
/**
* @Transform /^(?:this|that|the) ([^"]+)$/
*/
public function getResource(string $resource): mixed
{
return $this->sharedStorage->get(
StringInflector::nameToCode($resource)
);
}
/**
* @Given /^I (?:add|added) (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCart();
}
20
21. $this->productShowPage->open(['slug' => $product->getSlug()]);
public function open(array $urlParameters = []): void
{
$this->tryToOpen($urlParameters);
$this->verify($urlParameters);
}
public function tryToOpen(array $urlParameters = []): void
{
$this->getSession()->visit($this->getUrl($urlParameters));
}
public function verify(array $urlParameters = []): void
{
$this->verifyStatusCode();
$this->verifyUrl($urlParameters);
}
21 @ui
22. $this->productShowPage->addToCart();
public function addToCart(): void
{
$this->getElement('add_to_cart_button')->click();
}
protected function getDefinedElements(): array
{
return array_merge(parent::getDefinedElements(), [
'add_to_cart_button' => '#addToCart button',
// ...
]);
}
22 @ui
23. Then there should be one item in my cart
/**
* @Then there should be one item in my cart
*/
public function thereShouldBeOneItemInMyCart()
{
Assert::true($this->summaryPage->isSingleItemOnPage());
}
@ui
23
27. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui @api
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
27
28. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui @api
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
@api
28
29. Given the store has a product "T-shirt banana" priced at "$12.54"
/**
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt(
string $productName,
int $price = 100
): void {
$product = $this->createProduct($productName, $price, $channel);
$this->saveProduct($product);
}
29
30. When I add this product to the cart
/**
* @When /^I (?:add|added) (this product) to the (cart)$/
*/
public function iAddThisProductToTheCart(
ProductInterface $product,
?string $tokenValue
): void {
$tokenValue = $this->pickupCart();
$request = Request::customItemAction(
'shop', 'orders', $tokenValue, HttpRequest::METHOD_POST, 'items'
);
$request->updateContent([
'productVariant' => // variant identifier,
'quantity' => 1,
]);
$this->cartClient->executeCustomRequest($request);
$this->sharedStorage->set('product', $product);
}
30 @api
31. When I add this product to the cart
/**
* @When /^I (?:add|added) (this product) to the (cart)$/
*/
public function iAddThisProductToTheCart(
ProductInterface $product,
?string $tokenValue
): void {
$tokenValue = $this->pickupCart();
$request = Request::customItemAction(
'shop', 'orders', $tokenValue, HttpRequest::METHOD_POST, 'items'
);
$request->updateContent([
'productVariant' => // variant identifier,
'quantity' => 1,
]);
$this->cartClient->executeCustomRequest($request);
$this->sharedStorage->set('product', $product);
}
$request = Request::customItemAction(
'shop', 'orders', $tokenValue, HttpRequest::METHOD_POST, 'items'
);
@api
31
35. Then there should be one item in my cart
/**
* @Then there should be one item in my cart
*/
public function thereShouldBeOneItemInMyCart(): void
{
$response = $this->cartsClient->getLastResponse();
$items = $this->responseChecker->getValue($response, 'items');
Assert::count($items, 1);
}
35 @api
39. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui @api @application
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
39
40. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui @api @application
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
@application
40
41. Given the store has a product "T-shirt banana" priced at "$12.54"
/**
* @Given /^the store has a product "([^"]+)" priced at ("[^"]+")$/
*/
public function storeHasAProductPricedAt(
string $productName,
int $price = 100
): void {
$product = $this->createProduct($productName, $price, $channel);
$this->saveProduct($product);
}
41
42. When I add this product to the cart
@application
/**
* @When /^I add (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$cart = $this->cartContext->getCart();
try {
$this
->commandBus
->dispatch(new AddToCart($cart, $product, 1))
;
} catch (HandlerFailedException $exception) {
$this
->sharedStorage
->set('last_exception', $exception->getPrevious())
;
}
}
42
43. When I add this product to the cart
/**
* @When /^I add (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$cart = $this->cartContext->getCart();
try {
$this
->commandBus
->dispatch(new AddToCart($cart, $product, 1))
;
} catch (HandlerFailedException $exception) {
$this
->sharedStorage
->set('last_exception', $exception->getPrevious())
;
}
}
$this
->sharedStorage
->set('last_exception', $exception->getPrevious())
;
And I should be notified that the product has been successfully added
@application
43
44. final readonly class AddToCart
{
public function __construct(
public OrderInterface $cart,
public ProductInterface $product,
public int $quantity,
) {
}
}
44 @application
45. final class AddToCartHandler implements MessageHandlerInterface
{
public function __construct(
private FactoryInterface $orderItemFactory,
private OrderModifierInterface $orderModifier,
private OrderItemQuantityModifierInterface $orderItemQuantityModifier,
private ProductVariantResolverInterface $productVariantResolver,
private EntityManagerInterface $entityManager,
) {
}
public function __invoke(AddToCart $command): void
{
$variant = $this->productVariantResolver->getVariant($command->product);
$orderItem = $this->orderItemFactory->createNew();
$orderItem->setVariant($variant);
$this->orderItemQuantityModifier->modify($orderItem, $command->quantity);
$this->orderModifier->addToOrder($command->cart, $orderItem);
$this->entityManager->persist($command->cart);
$this->entityManager->flush();
}
}
@application
45
46. Then there should be one item in my cart
/**
* @Then there should be one item in my cart
*/
public function thereShouldBeOneItemInMyCart(): void
{
$cart = ($this->latestCartQuery)();
Assert::count($cart->getItems(), 1);
$cartItem = $cart->getItems()->first();
$this->sharedStorage->set('item', $cartItem);
}
46 @application
47. final class LatestCartQuery
{
public function __construct(private OrderRepositoryInterface $orderRepository)
{
}
public function __invoke(): OrderInterface
{
return $this->orderRepository->findLatestCart();
}
}
@application
47
53. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui @api @application @mixed
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
54
54. When I add this product to the cart
/**
* @Given /^I (?:add|added) (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCart();
}
@mixed
55
Then there should be one item in my cart
/**
* @Then there should be one item in my cart
*/
public function thereShouldBeOneItemInMyCart(): void
{
$cart = $this->cartRepository->getLatest();
Assert::count($cart->getItems(), 1);
$cartItem = $cart->getItems()->first();
}
55. When I add this product to the cart
/**
* @Given /^I (?:add|added) (this product) to the cart$/
*/
public function iAddProductToTheCart(ProductInterface $product): void
{
$this->productShowPage->open(['slug' => $product->getSlug()]);
$this->productShowPage->addToCart();
}
@mixed
56
Then there should be one item in my cart
/**
* @Then there should be one item in my cart
*/
public function thereShouldBeOneItemInMyCart(): void
{
$cart = $this->cartRepository->getLatest();
Assert::count($cart->getItems(), 1);
$cartItem = $cart->getItems()->first();
}
?
63. Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
64
64. Feature: Adding a simple product to the cart
In order to select products for purchase
As a Visitor
I want to be able to add simple products to cart
Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
65
65. 66
Feature: Adding a simple product to the cart
In order to start the checkout process with the desired products
As a Visitor
I want to be able to add simple products to cart
Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"
66. 67
Feature: Adding a simple product to the cart
In order to start the process of changing my clothing style
As a Visitor
I want to be able to add simple products to cart
Background:
Given the store operates on a single channel in "United States"
And the store has a product "T-shirt banana" priced at "$12.54"
And the store ships everywhere for free
@ui
Scenario: Adding a simple product to the cart
When I add this product to the cart
Then I should be on my cart summary page
And I should be notified that the product has been successfully added
And there should be one item in my cart
And this item should have name "T-shirt banana"