SlideShare una empresa de Scribd logo
1 de 68
Descargar para leer sin conexión
WITH BEHAT, UI AND API
BUSINESS LOGIC TESTING
@mpzalewski
Zales0123
MATEUSZ ZALEWSKI
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
3
4
5
GOALS
6
Substitutability
Reusability
Fun
7
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
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
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
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
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
private function createProduct(
string $productName,
int $price = 100,
ChannelInterface $channel = null
): ProductInterface {
// ...
$product = $this->productFactory->createWithVariant();
$product->setCode(StringInflector::nameToUppercaseCode($productName));
$product->setName($productName);
// ...
$productVariant = $this->defaultVariantResolver->getVariant($product);
$productVariant->addChannelPricing(
$this->createChannelPricingForChannel($price, $channel)
);
// ...
return $product;
}
13
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
/**
* @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
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
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
/**
* @Transform /^(?:this|that|the) ([^"]+)$/
*/
public function getResource(mixed $resource): mixed
{
return $this->sharedStorage->get(
StringInflector::nameToCode($resource)
);
}
18
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
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
$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
$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
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
$this->summaryPage->isSingleItemOnPage();
public function isSingleItemOnPage(): bool
{
$items = $this
->getElement('cart_items')
->findAll('css', '[data-test-cart-product-row]')
;
return 1 === count($items);
}
24 @ui
SCENARIO CONTEXT PAGE
UI
Substitutability
25
26
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
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
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
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
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
Request::customItemAction
public static function customItemAction(
?string $section,
string $resource,
string $id,
string $type,
string $action
): RequestInterface {
return new self(
sprintf('/api/v2/%s/%s/%s/%s', $section, $resource, $id, $action),
$type,
['CONTENT_TYPE' => self::resolveHttpMethod($type)],
);
}
32 @api
<itemOperation name="shop_add_item">
<attribute name="method">POST</attribute>
<attribute name="path">/shop/orders/{tokenValue}/items</attribute>
<attribute name="messenger">input</attribute>
<attribute name=„input">SyliusBundleApiBundleCommandCartAddItemToCart</attribute>
<attribute name="normalization_context">
<attribute name="groups">shop:cart:read</attribute>
</attribute>
<attribute name="denormalization_context">
<attribute name="groups">shop:cart:add_item</attribute>
</attribute>
<attribute name="openapi_context">
<attribute name="summary">Adds Item to cart</attribute>
</attribute>
</itemOperation>
@api
33
POST /api/v2/shop/orders/HcgfktTi8E/items HTTP/2
host: demo.sylius.com
accept: application/json
content-type: application/json
content-length: 90
{
"productVariant": "/api/v2/shop/product-variants/variant1",
"quantity": 3
}
34
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
public function getValue(Response $response, string $key): mixed
{
$content = json_decode($response->getContent(), true);
Assert::isArray($content);
Assert::keyExists($content, $key);
return $content[$key];
}
$items = $this->responseChecker->getValue($response, 'items');
@api
36
{
"@context": "/api/v2/contexts/Order",
"@id": "/api/v2/shop/orders/{orderToken}",
"@type": „Order",
// ...
"items": [
{
"@id": "/api/v2/shop/order-items/866997",
"@type": "OrderItem",
"variant": "/api/v2/shop/product-variants/variant1",
// ...
}
],
// ...
}
37
SCENARIO
UI CONTEXT PAGE
UI
API CONTEXT CLIENT
Reusability
38
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
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
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
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
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
final readonly class AddToCart
{
public function __construct(
public OrderInterface $cart,
public ProductInterface $product,
public int $quantity,
) {
}
}
44 @application
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
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
final class LatestCartQuery
{
public function __construct(private OrderRepositoryInterface $orderRepository)
{
}
public function __invoke(): OrderInterface
{
return $this->orderRepository->findLatestCart();
}
}
@application
47
imports:
- suites/application/cart/shopping_cart.yaml
# ...
- suites/api/admin/login.yml
- suites/api/cart/accessing_cart.yml
- suites/api/cart/shopping_cart.yml
- suites/api/channel/channels.yml
- suites/api/channel/managing_channels.yml
# ...
- suites/ui/admin/locale.yml
- suites/ui/admin/login.yml
- suites/ui/cart/shopping_cart.yml
- suites/ui/channel/channels.yml
# ...
49
default:
suites:
application_shopping_cart:
contexts:
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.transform.channel
- sylius.behat.context.transform.currency
- sylius.behat.context.transform.lexical
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.transform.product
- sylius.behat.context.transform.product_option
- sylius.behat.context.transform.product_variant
- sylius.behat.context.transform.shipping_category
- sylius.behat.context.transform.tax_category
- sylius.behat.context.transform.zone
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.currency
- sylius.behat.context.setup.exchange_rate
- sylius.behat.context.setup.product
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.shipping_category
- sylius.behat.context.setup.shop_security
- sylius.behat.context.setup.taxation
- sylius.behat.context.setup.user
- sylius.behat.context.setup.zone
- SyliusBehatContextApplicationCartContext
filters:
tags: "@shopping_cart && @application"
50
default:
suites:
application_shopping_cart:
contexts:
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.transform.channel
- sylius.behat.context.transform.currency
- sylius.behat.context.transform.lexical
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.transform.product
- sylius.behat.context.transform.product_option
- sylius.behat.context.transform.product_variant
- sylius.behat.context.transform.shipping_category
- sylius.behat.context.transform.tax_category
- sylius.behat.context.transform.zone
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.currency
- sylius.behat.context.setup.exchange_rate
- sylius.behat.context.setup.product
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.shipping_category
- sylius.behat.context.setup.shop_security
- sylius.behat.context.setup.taxation
- sylius.behat.context.setup.user
- sylius.behat.context.setup.zone
- SyliusBehatContextApplicationCartContext
filters:
tags: "@shopping_cart && @application"
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.transform.channel
- sylius.behat.context.transform.currency
- sylius.behat.context.transform.lexical
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.transform.product
- sylius.behat.context.transform.product_option
- sylius.behat.context.transform.product_variant
- sylius.behat.context.transform.shipping_category
- sylius.behat.context.transform.tax_category
- sylius.behat.context.transform.zone
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.currency
- sylius.behat.context.setup.exchange_rate
- sylius.behat.context.setup.product
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.shipping_category
- sylius.behat.context.setup.shop_security
- sylius.behat.context.setup.taxation
- sylius.behat.context.setup.user
- sylius.behat.context.setup.zone
- SyliusBehatContextApplicationCartContext
51
default:
suites:
application_shopping_cart:
contexts:
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.transform.channel
- sylius.behat.context.transform.currency
- sylius.behat.context.transform.lexical
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.transform.product
- sylius.behat.context.transform.product_option
- sylius.behat.context.transform.product_variant
- sylius.behat.context.transform.shipping_category
- sylius.behat.context.transform.tax_category
- sylius.behat.context.transform.zone
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.currency
- sylius.behat.context.setup.exchange_rate
- sylius.behat.context.setup.product
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.shipping_category
- sylius.behat.context.setup.shop_security
- sylius.behat.context.setup.taxation
- sylius.behat.context.setup.user
- sylius.behat.context.setup.zone
- SyliusBehatContextApplicationCartContext
filters:
tags: "@shopping_cart && @application"
tags: "@shopping_cart && @application"
52
default:
suites:
api_v1_shopping_cart:
contexts:
- SyliusBehatContextApiV1CartContext
filters:
tags: "@shopping_cart && @api && @v1”
api_v2_shopping_cart:
contexts:
- SyliusBehatContextApiV2CartContext
filters:
tags: "@shopping_cart && @api && @v2"
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
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();
}
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();
}
?
? Fun
57
$this->shopClient->executeCustomRequest($request);
$this->adminClient->index(Resources::PRODUCT_VARIANTS);
$this->client->index();
<service id="sylius.behat.api_platform_client.admin.exchange_rate"
class="SyliusBehatClientApiPlatformClient" parent="sylius.behat.api_platform_client">
<argument>exchange-rates</argument>
<argument>admin</argument>
</service>
<service id=„sylius.behat.context.api.admin.managing_exchange_rates"
class="SyliusBehatContextApiAdminManagingExchangeRatesContext">
<argument type="service" id="sylius.behat.api_platform_client.admin.exchange_rate" />
...
</service>
58
59
60
61
Substitutability
Reusability
Fun
62
63
WHY? AND WHAT FOR?
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
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
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"
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"
@mpzalewski
Zales0123
mpzalewski.com
68
THANK YOU
QR CODE
@CommerceWeavers
@Sylius QR CODE
@mpzalewski Zales0123

Más contenido relacionado

Similar a [PHPers Summit 2023] Business logic testing

Write a program that mimics the operations of several vending machin.pdf
Write a program that mimics the operations of several vending machin.pdfWrite a program that mimics the operations of several vending machin.pdf
Write a program that mimics the operations of several vending machin.pdf
eyebolloptics
 
I finished most of the program, but having trouble with some key fea.pdf
I finished most of the program, but having trouble with some key fea.pdfI finished most of the program, but having trouble with some key fea.pdf
I finished most of the program, but having trouble with some key fea.pdf
hardjasonoco14599
 
c++main.cpp#include iostream#include store.h#includ.docx
c++main.cpp#include iostream#include store.h#includ.docxc++main.cpp#include iostream#include store.h#includ.docx
c++main.cpp#include iostream#include store.h#includ.docx
humphrieskalyn
 

Similar a [PHPers Summit 2023] Business logic testing (20)

[ForumPHP 2023] Lights and shadows of BDD in Sylius (and probably other compa...
[ForumPHP 2023] Lights and shadows of BDD in Sylius (and probably other compa...[ForumPHP 2023] Lights and shadows of BDD in Sylius (and probably other compa...
[ForumPHP 2023] Lights and shadows of BDD in Sylius (and probably other compa...
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Optimizing Magento by Preloading Data
Optimizing Magento by Preloading DataOptimizing Magento by Preloading Data
Optimizing Magento by Preloading Data
 
APIs for catalogs
APIs for catalogsAPIs for catalogs
APIs for catalogs
 
laravel tricks in 50minutes
laravel tricks in 50minuteslaravel tricks in 50minutes
laravel tricks in 50minutes
 
50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes50 Laravel Tricks in 50 Minutes
50 Laravel Tricks in 50 Minutes
 
Write a program that mimics the operations of several vending machin.pdf
Write a program that mimics the operations of several vending machin.pdfWrite a program that mimics the operations of several vending machin.pdf
Write a program that mimics the operations of several vending machin.pdf
 
[PHPCon 2023] Blaski i cienie BDD
[PHPCon 2023] Blaski i cienie BDD[PHPCon 2023] Blaski i cienie BDD
[PHPCon 2023] Blaski i cienie BDD
 
Practical Event Sourcing
Practical Event SourcingPractical Event Sourcing
Practical Event Sourcing
 
Getting started with ExtBase
Getting started with ExtBaseGetting started with ExtBase
Getting started with ExtBase
 
I finished most of the program, but having trouble with some key fea.pdf
I finished most of the program, but having trouble with some key fea.pdfI finished most of the program, but having trouble with some key fea.pdf
I finished most of the program, but having trouble with some key fea.pdf
 
Technology and Science News - ABC News
Technology and Science News - ABC NewsTechnology and Science News - ABC News
Technology and Science News - ABC News
 
CodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPigCodingSerbia2014-JavaVSPig
CodingSerbia2014-JavaVSPig
 
Symfony day 2016
Symfony day 2016Symfony day 2016
Symfony day 2016
 
c++main.cpp#include iostream#include store.h#includ.docx
c++main.cpp#include iostream#include store.h#includ.docxc++main.cpp#include iostream#include store.h#includ.docx
c++main.cpp#include iostream#include store.h#includ.docx
 
Wordpress plugin development from Scratch
Wordpress plugin development from ScratchWordpress plugin development from Scratch
Wordpress plugin development from Scratch
 
Oop php 5
Oop php 5Oop php 5
Oop php 5
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 
Implement rich snippets in your webshop
Implement rich snippets in your webshopImplement rich snippets in your webshop
Implement rich snippets in your webshop
 

Último

%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
masabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 

Último (20)

AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 

[PHPers Summit 2023] Business logic testing

  • 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
  • 3. 3
  • 4. 4
  • 5. 5
  • 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
  • 13. private function createProduct( string $productName, int $price = 100, ChannelInterface $channel = null ): ProductInterface { // ... $product = $this->productFactory->createWithVariant(); $product->setCode(StringInflector::nameToUppercaseCode($productName)); $product->setName($productName); // ... $productVariant = $this->defaultVariantResolver->getVariant($product); $productVariant->addChannelPricing( $this->createChannelPricingForChannel($price, $channel) ); // ... return $product; } 13
  • 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
  • 24. $this->summaryPage->isSingleItemOnPage(); public function isSingleItemOnPage(): bool { $items = $this ->getElement('cart_items') ->findAll('css', '[data-test-cart-product-row]') ; return 1 === count($items); } 24 @ui
  • 26. 26
  • 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
  • 32. Request::customItemAction public static function customItemAction( ?string $section, string $resource, string $id, string $type, string $action ): RequestInterface { return new self( sprintf('/api/v2/%s/%s/%s/%s', $section, $resource, $id, $action), $type, ['CONTENT_TYPE' => self::resolveHttpMethod($type)], ); } 32 @api
  • 33. <itemOperation name="shop_add_item"> <attribute name="method">POST</attribute> <attribute name="path">/shop/orders/{tokenValue}/items</attribute> <attribute name="messenger">input</attribute> <attribute name=„input">SyliusBundleApiBundleCommandCartAddItemToCart</attribute> <attribute name="normalization_context"> <attribute name="groups">shop:cart:read</attribute> </attribute> <attribute name="denormalization_context"> <attribute name="groups">shop:cart:add_item</attribute> </attribute> <attribute name="openapi_context"> <attribute name="summary">Adds Item to cart</attribute> </attribute> </itemOperation> @api 33
  • 34. POST /api/v2/shop/orders/HcgfktTi8E/items HTTP/2 host: demo.sylius.com accept: application/json content-type: application/json content-length: 90 { "productVariant": "/api/v2/shop/product-variants/variant1", "quantity": 3 } 34
  • 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
  • 36. public function getValue(Response $response, string $key): mixed { $content = json_decode($response->getContent(), true); Assert::isArray($content); Assert::keyExists($content, $key); return $content[$key]; } $items = $this->responseChecker->getValue($response, 'items'); @api 36
  • 37. { "@context": "/api/v2/contexts/Order", "@id": "/api/v2/shop/orders/{orderToken}", "@type": „Order", // ... "items": [ { "@id": "/api/v2/shop/order-items/866997", "@type": "OrderItem", "variant": "/api/v2/shop/product-variants/variant1", // ... } ], // ... } 37
  • 38. SCENARIO UI CONTEXT PAGE UI API CONTEXT CLIENT Reusability 38
  • 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
  • 48. imports: - suites/application/cart/shopping_cart.yaml # ... - suites/api/admin/login.yml - suites/api/cart/accessing_cart.yml - suites/api/cart/shopping_cart.yml - suites/api/channel/channels.yml - suites/api/channel/managing_channels.yml # ... - suites/ui/admin/locale.yml - suites/ui/admin/login.yml - suites/ui/cart/shopping_cart.yml - suites/ui/channel/channels.yml # ... 49
  • 49. default: suites: application_shopping_cart: contexts: - sylius.behat.context.hook.doctrine_orm - sylius.behat.context.transform.channel - sylius.behat.context.transform.currency - sylius.behat.context.transform.lexical - sylius.behat.context.transform.shared_storage - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option - sylius.behat.context.transform.product_variant - sylius.behat.context.transform.shipping_category - sylius.behat.context.transform.tax_category - sylius.behat.context.transform.zone - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency - sylius.behat.context.setup.exchange_rate - sylius.behat.context.setup.product - sylius.behat.context.setup.promotion - sylius.behat.context.setup.shipping - sylius.behat.context.setup.shipping_category - sylius.behat.context.setup.shop_security - sylius.behat.context.setup.taxation - sylius.behat.context.setup.user - sylius.behat.context.setup.zone - SyliusBehatContextApplicationCartContext filters: tags: "@shopping_cart && @application" 50
  • 50. default: suites: application_shopping_cart: contexts: - sylius.behat.context.hook.doctrine_orm - sylius.behat.context.transform.channel - sylius.behat.context.transform.currency - sylius.behat.context.transform.lexical - sylius.behat.context.transform.shared_storage - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option - sylius.behat.context.transform.product_variant - sylius.behat.context.transform.shipping_category - sylius.behat.context.transform.tax_category - sylius.behat.context.transform.zone - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency - sylius.behat.context.setup.exchange_rate - sylius.behat.context.setup.product - sylius.behat.context.setup.promotion - sylius.behat.context.setup.shipping - sylius.behat.context.setup.shipping_category - sylius.behat.context.setup.shop_security - sylius.behat.context.setup.taxation - sylius.behat.context.setup.user - sylius.behat.context.setup.zone - SyliusBehatContextApplicationCartContext filters: tags: "@shopping_cart && @application" - sylius.behat.context.hook.doctrine_orm - sylius.behat.context.transform.channel - sylius.behat.context.transform.currency - sylius.behat.context.transform.lexical - sylius.behat.context.transform.shared_storage - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option - sylius.behat.context.transform.product_variant - sylius.behat.context.transform.shipping_category - sylius.behat.context.transform.tax_category - sylius.behat.context.transform.zone - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency - sylius.behat.context.setup.exchange_rate - sylius.behat.context.setup.product - sylius.behat.context.setup.promotion - sylius.behat.context.setup.shipping - sylius.behat.context.setup.shipping_category - sylius.behat.context.setup.shop_security - sylius.behat.context.setup.taxation - sylius.behat.context.setup.user - sylius.behat.context.setup.zone - SyliusBehatContextApplicationCartContext 51
  • 51. default: suites: application_shopping_cart: contexts: - sylius.behat.context.hook.doctrine_orm - sylius.behat.context.transform.channel - sylius.behat.context.transform.currency - sylius.behat.context.transform.lexical - sylius.behat.context.transform.shared_storage - sylius.behat.context.transform.product - sylius.behat.context.transform.product_option - sylius.behat.context.transform.product_variant - sylius.behat.context.transform.shipping_category - sylius.behat.context.transform.tax_category - sylius.behat.context.transform.zone - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency - sylius.behat.context.setup.exchange_rate - sylius.behat.context.setup.product - sylius.behat.context.setup.promotion - sylius.behat.context.setup.shipping - sylius.behat.context.setup.shipping_category - sylius.behat.context.setup.shop_security - sylius.behat.context.setup.taxation - sylius.behat.context.setup.user - sylius.behat.context.setup.zone - SyliusBehatContextApplicationCartContext filters: tags: "@shopping_cart && @application" tags: "@shopping_cart && @application" 52
  • 52. default: suites: api_v1_shopping_cart: contexts: - SyliusBehatContextApiV1CartContext filters: tags: "@shopping_cart && @api && @v1” api_v2_shopping_cart: contexts: - SyliusBehatContextApiV2CartContext filters: tags: "@shopping_cart && @api && @v2" 53
  • 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(); } ?
  • 58. 59
  • 59. 60
  • 60. 61
  • 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"
  • 68. THANK YOU QR CODE @CommerceWeavers @Sylius QR CODE @mpzalewski Zales0123