File: D:/HostingSpaces/blijegasten/blijegasten.be/app/Komma/Shop/Tests/Browser/CheckoutTest.php
<?php
namespace App\Komma\Shop\Tests\Browser;
use App\Komma\Addresses\Models\Address;
use App\Komma\Globalization\RegionInfo;
use App\Komma\Globalization\RegionInfoInterface;
use App\Komma\Kms\QualityAssurance\ExtraDuskTools;
use App\Komma\Shop\Cart\ShoppingCartService;
use App\Komma\Shop\Orders\Models\Order;
use App\Komma\Shop\Orders\OrderStatus;
use App\Komma\Shop\Orders\Product\OrderedProduct;
use App\Komma\Shop\Orders\ProductComposite\OrderedProductComposite;
use App\Komma\Shop\Orders\ProductGroup\OrderedProductGroup;
use App\Komma\Shop\Payment\TransactionStatus;
use App\Komma\Shop\Products\Product\Product;
use App\Komma\Shop\Products\ProductComposite\ProductComposite;
use App\Komma\Shop\Products\ProductGroup\ProductGroup;
use App\Komma\Shop\Tests\Browser\Pages\ShoppingCartTestPage;
use App\Komma\Shop\Tests\DuskTestCase;
use App\Komma\Shop\Vat\Models\Rate;
use App\Komma\Users\Models\SiteUser;
use Illuminate\Database\Eloquent\Collection;
use Laravel\Dusk\Browser;
class CheckoutTest extends DuskTestCase
{
// use DatabaseTransactions; //Automatically rolls back database actions after tests. Note: when you enable this, assertProductVisible creates a user but cannot be logged in somehow. Laravel dusk problem i think.
/**
* @group Checkout
* @test
* @throws \Throwable
*/
public function assertCartEmpty()
{
$shoppingCartService = new ShoppingCartService();
$shoppingCartService->clear(); //Clear the cart if it not already was
$regionInfo = app(RegionInfoInterface::class);
$counter = 0;
$this->browse(function (Browser $browser) use($regionInfo) {
$browser->loginAs(SiteUser::find(1), 'site')
->visit(new ShoppingCartTestPage())
->assertSee(__('shop/cart.cart'))
->assertSeeIn('@subtotal', $regionInfo->getCurrencySymbol().' 0');
});
}
/**
* Test coupon codes in checkout
*
* @group Checkout
* @test
* @throws \Throwable
*/
public function testCouponAndVat()
{
/** @var SiteUser $user */
$user = factory(SiteUser::class)->create();
/** @var Address $address */
$address = factory(Address::class)->create();
$user->addresses()->save($address);
$this->assertDatabaseHas('site_users', [
'id' => $user->id
]);
$product = Product::find(1);
$regionInfo = app(RegionInfoInterface::class);
$this->browse(function (Browser $browser) use($user, $product, $address, $regionInfo) {
$browser->logout('site'); //Make sure we dont have a session
$browser->loginAs($user->id, 'site')
->visit(new ShoppingCartTestPage())
->click('@addProductWithId1')
->waitUntil('document.querySelector(\'[dusk="shoppingCartItemList"]\').childElementCount == 1')
->click('@checkout')
->assertSee(__('shop/checkout.invoice_address'))
->assertSee(__('shop/checkout.shipping_address'))
->scrollToElement('[dusk="checkout"]') //See extra dusk tools
->assertVisible('[dusk="checkout"]')
->assertSee(__('shop/checkout.agree_to_terms'))
->type('@coupon_code', 'Absolute5') //Add 5 euro discount
->click('@add_coupon')
->pause(100)
->scrollToElement('[dusk="Absolute5"]') //See extra dusk tools
->assertVisible('[dusk="Absolute5"]')
->select('shipping_country', 'GBR')->pause(150)
//The product is added 10 times thanks to cart.js addProductToShoppingcart method. 500 is 500 cents from Absolute5 coupon. And 1499 is the shipping costs of GBR
->assertSee($regionInfo->getNumberFormat()->centsToCurrency($product->getTotal() * 10))
->assertSee($regionInfo->getNumberFormat()->centsToCurrency(round((((($product->getTotal() * 10) + 1499) - 500) * 0.21))));
});
}
/**
* @group Checkout
* @test
* @see ExtraDuskTools
* @throws \Throwable
*/
public function assertCartNotEmptyWhenRandomProductAdded()
{
$shoppingCartService = new ShoppingCartService();
$shoppingCartService->clear(); //Clear the cart if it not already was
$regionInfo = app(RegionInfoInterface::class);
$this->browse(function (Browser $browser) use($regionInfo, $shoppingCartService) {
$browser->loginAs(SiteUser::find(1), 'site');
$browser->visit(new ShoppingCartTestPage())
->assertSee(__('shop/cart.cart'))
->pause(500)
->assertSeeIn('@subtotal', $regionInfo->getCurrencySymbol().' 0')
->waitFor('@addRandomProduct')
->waitUntil('document.readyState === "complete"')->pause(500) //Also wait till javascript is loaded completely.
->click('@addRandomProduct')
->waitUntil('document.querySelectorAll(\'[dusk="shoppingCartItemList"] > li\').length === 1') //Wait until one item is visible in the list of shopping cart items
->assertDontSeeIn('@subtotal', $regionInfo->getCurrencySymbol().' 0');
});
}
/**
* Test a successful checkout with payment
*
* @group Checkout
* @test
* @throws \Throwable
*/
public function testCheckoutForm()
{
/** @var SiteUser $user */
$user = factory(SiteUser::class)->create();
/** @var Address $address */
$address = factory(Address::class)->create();
$user->addresses()->save($address);
$this->assertDatabaseHas('site_users', [
'id' => $user->id
]);
$regionInfo = app(RegionInfoInterface::class);
$product = Product::find(1);
$this->browse(function (Browser $browser) use($user, $product, $regionInfo, $address) {
$browser->loginAs($user->id, 'site')
->visit(new ShoppingCartTestPage())
->click('@addProductWithId1')
->waitForReload()
->click('@checkout')
->assertSee(__('shop/checkout.invoice_address'))
->assertSee(__('shop/checkout.shipping_address'))
->scrollToElement('[dusk="checkout"]') //See extra dusk tools
->assertVisible('[dusk="checkout"]')
->assertSee(__('shop/checkout.agree_to_terms'))
->assertRadioSelected('@new_invoice_address', '-1') //-1 Means that the backend could see that this is a new address instead of an existing one (bigger as 0 value);
->assertRadioSelected('@new_shipping_address', '-1')
->type('@invoice_street', $address->street)
->type('@invoice_house_number', $address->house_number)
->type('@invoice_postal_code', $address->postal_code)
->type('@invoice_city', $address->city)
->type('@invoice_phone', $address->telephone)
->select('@invoice_country', $address->country_iso3)
->type('@shipping_street', $address->street)
->type('@shipping_house_number', $address->house_number)
->type('@shipping_postal_code', $address->postal_code)
->type('@shipping_city', $address->city)
->type('@shipping_phone', $address->telephone)
->select('@shipping_country', $address->country_iso3)
->type('@remarks', 'None')
->assertInputValue('@invoice_street', $address->street)
->assertInputValue('@invoice_house_number', $address->house_number)
->assertInputValue('@invoice_postal_code', $address->postal_code)
->assertInputValue('@invoice_city', $address->city)
->assertInputValue('@invoice_phone', $address->telephone)
->assertSelected('@invoice_country', $address->country_iso3)
->assertInputValue('@shipping_street', $address->street)
->assertInputValue('@shipping_house_number', $address->house_number)
->assertInputValue('@shipping_postal_code', $address->postal_code)
->assertInputValue('@shipping_city', $address->city)
->assertInputValue('@shipping_phone', $address->telephone)
->assertSelected('@shipping_country', $address->country_iso3)
->assertInputValue('@remarks', 'None')
->assertSee($product->getDisplayName());
$browser->driver->executeScript('window.scrollTo(0,document.body.scrollHeight);'); //Scroll to bottom
$browser
->check('@terms_and_conditions')
->click('@checkout')
->pause(500)
->assertSee('Welkom bij KommaPSP')
->select('@payment_status', TransactionStatus::PAYMENT_PAID)
->click('@redir') //Pay
->assertSee('We have received your payment')
->assertSee(TransactionStatus::PAYMENT_PAID)
->assertSee(OrderStatus::AWAITING_FULFILLMENT);
});
}
/**
* Test a successful checkout with payment
*
* @group Checkout
* @test
* @throws \Throwable
*/
public function testInvalidCheckoutForm()
{
/** @var SiteUser $user */
$user = factory(SiteUser::class)->create();
/** @var Address $address */
$address = factory(Address::class)->create();
$user->addresses()->save($address);
$this->assertDatabaseHas('site_users', [
'id' => $user->id
]);
$regionInfo = app(RegionInfoInterface::class);
$product = Product::find(1);
$this->browse(function (Browser $browser) use($user, $product, $regionInfo, $address) {
$browser->loginAs($user->id, 'site')
->visit(new ShoppingCartTestPage())
->click('@addProductWithId1')
->waitForReload()
->click('@checkout')
->assertSee(__('shop/checkout.invoice_address'))
->assertSee(__('shop/checkout.shipping_address'))
->scrollToElement('[dusk="checkout"]') //See extra dusk tools
->assertVisible('[dusk="checkout"]')
->assertSee(__('shop/checkout.agree_to_terms'))
->assertRadioSelected('@new_invoice_address', '-1') //-1 Means that the backend could see that this is a new address instead of an existing one (bigger as 0 value);
->assertRadioSelected('@new_shipping_address', '-1')
->pause(10)
->assertSee($product->getDisplayName());
$browser->driver->executeScript('window.scrollTo(0,document.body.scrollHeight);'); //Scroll to bottom
$browser->pause(10)
->click('@checkout')
->pause(250);
foreach(['shipping', 'invoice'] as $type) {
foreach([
$type.'_street',
$type.'_house_number',
$type.'_postal_code',
$type.'_city',
$type.'_phone',
] as $attribute) {
$browser->assertSee(__('shop/checkout.validation.required_if', ['attribute' => __('validation.attributes.'.$attribute)]));
}
}
});
}
/**
* Test thanks for order mail contents
*
* @group Checkout
* @test
* @throws \Throwable
*/
public function testThanksForOrderMailContents()
{
$orderStatus = OrderStatus::PENDING;
/** @var Order $order */
$order = Order::inRandomOrder()->first();
$orderedProductComposites = $order->orderedProductComposites()->get();
$orderedProductGroups = $order->orderedGroups()->get();
$orderedProducts = $order->orderedProducts()->get();
$self = $this;
$route = route('preview.mail.order_status', ['status' => $orderStatus, 'staffOrCustomer' => 'customer', 'order' => $order->id]); //Thanks for your order mail
$this->browse(function (Browser $browser) use($route, $orderStatus, $order, $orderedProducts, $orderedProductGroups, $orderedProductComposites, $self) {
$browser->visit($route)
//Assert general texts
->assertSee(__('shop/orders.mail.'.$orderStatus.'.customer.body'))
->assertSee(__('shop/orders.mail.'.$orderStatus.'.customer.button_text'))
->assertSee(__('shop/orders.mail.'.$orderStatus.'.customer.closure'))
->assertSee(config('site.company.name'));
$self->assertProductableNamesVisible($browser, $orderedProducts);
$self->assertProductableNamesVisible($browser, $orderedProductGroups);
$self->assertProductableNamesVisible($browser, $orderedProductComposites);
});
}
/**
* Test the contents of the mail that is sent to the customer and staff
* when he completed the payment
*
* @group Checkout
* @test
* @throws \Throwable
*/
public function testCustomerPaidMailToCustomerAndStaff()
{
$orderStatus = OrderStatus::AWAITING_FULFILLMENT;
/** @var Order $order */
$order = Order::inRandomOrder()->first();
$orderedProductComposites = $order->orderedProductComposites()->get();
$orderedProductGroups = $order->orderedGroups()->get();
$orderedProducts = $order->orderedProducts()->get();
$self = $this;
foreach(['customer', 'staff'] as $type) {
$route = route('preview.mail.order_status', ['status' => $orderStatus, 'staffOrCustomer' => $type, 'order' => $order->id]); //Thanks for your order mail
$this->browse(function (Browser $browser) use($route, $orderStatus, $type, $order, $orderedProducts, $orderedProductGroups, $orderedProductComposites, $self) {
$browser->visit($route)
//Assert general text
->assertSee(__('shop/orders.mail.'.$orderStatus.'.'.$type.'.body'))
->assertSee(__('shop/orders.mail.'.$orderStatus.'.'.$type.'.button_text'))
->assertSee(__('shop/orders.mail.'.$orderStatus.'.'.$type.'.closure'))
->assertSee(config('site.company.name'));
$self->assertProductableNamesVisible($browser, $orderedProducts);
$self->assertProductableNamesVisible($browser, $orderedProductGroups);
$self->assertProductableNamesVisible($browser, $orderedProductComposites);
});
}
}
/**
* Helper function that tests if it can see a productable
*
* @param Browser $browser
* @param Collection $orderedProductableCollection
*/
private function assertProductableNamesVisible(Browser $browser, Collection $orderedProductableCollection)
{
foreach($orderedProductableCollection as $orderedProductable)
{
$name = '';
switch (get_class($orderedProductable))
{
case OrderedProduct::class:
/** @var OrderedProduct $orderedProductable */
$product = $orderedProductable->product()->first();
/** @var Product $name */
$name = $product->getDisplayName();
break;
case OrderedProductGroup::class:
/** @var OrderedProductGroup $orderedProductable */
$productGroup = $orderedProductable->productGroup()->first();
/** @var ProductGroup $productGroup */
$name = $productGroup->getDisplayName();
break;
case OrderedProductComposite::class:
/** @var OrderedProductComposite $orderedProductable */
$orderedProductable = $orderedProductable->productComposite()->first();
/** @var ProductComposite $orderedProductable */
$name = $orderedProductable->getDisplayName();
break;
default:
return;
}
if($name != '') $browser->assertSee($name);
}
}
}