Completed
Push — master ( bcb54c...8151ca )
by Kamil
05:51 queued 19s
created

CompletePage::getShippingTotal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Behat\Page\Shop\Checkout;
15
16
use Behat\Mink\Driver\Selenium2Driver;
17
use Behat\Mink\Element\NodeElement;
18
use Behat\Mink\Session;
19
use FriendsOfBehat\PageObjectExtension\Page\SymfonyPage;
20
use Sylius\Behat\Service\Accessor\TableAccessorInterface;
21
use Sylius\Component\Core\Model\AddressInterface;
22
use Sylius\Component\Core\Model\ProductInterface;
23
use Sylius\Component\Core\Model\ShippingMethodInterface;
24
use Symfony\Component\Intl\Intl;
25
use Symfony\Component\Routing\RouterInterface;
26
27
class CompletePage extends SymfonyPage implements CompletePageInterface
28
{
29
    /** @var TableAccessorInterface */
30
    private $tableAccessor;
31
32
    public function __construct(
33
        Session $session,
34
        $minkParameters,
35
        RouterInterface $router,
36
        TableAccessorInterface $tableAccessor
37
    ) {
38
        parent::__construct($session, $minkParameters, $router);
39
40
        $this->tableAccessor = $tableAccessor;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getRouteName(): string
47
    {
48
        return 'sylius_shop_checkout_complete';
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function hasItemWithProductAndQuantity($productName, $quantity)
55
    {
56
        $table = $this->getElement('items_table');
57
58
        try {
59
            $this->tableAccessor->getRowWithFields($table, ['item' => $productName, 'qty' => $quantity]);
60
        } catch (\InvalidArgumentException $exception) {
61
            return false;
62
        }
63
64
        return true;
65
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70
    public function hasShippingAddress(AddressInterface $address)
71
    {
72
        $shippingAddress = $this->getElement('shipping_address')->getText();
73
74
        return $this->isAddressValid($shippingAddress, $address);
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function hasBillingAddress(AddressInterface $address)
81
    {
82
        $billingAddress = $this->getElement('billing_address')->getText();
83
84
        return $this->isAddressValid($billingAddress, $address);
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function hasShippingMethod(ShippingMethodInterface $shippingMethod)
91
    {
92
        if (!$this->hasElement('shipping_method')) {
93
            return false;
94
        }
95
96
        return false !== strpos($this->getElement('shipping_method')->getText(), $shippingMethod->getName());
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102
    public function getPaymentMethodName()
103
    {
104
        return $this->getElement('payment_method')->getText();
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110
    public function hasPaymentMethod()
111
    {
112
        return $this->hasElement('payment_method');
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function hasProductDiscountedUnitPriceBy(ProductInterface $product, $amount)
119
    {
120
        $columns = $this->getProductRowElement($product)->findAll('css', 'td');
121
        $priceWithoutDiscount = $this->getPriceFromString($columns[1]->getText());
122
        $priceWithDiscount = $this->getPriceFromString($columns[3]->getText());
123
        $discount = $priceWithoutDiscount - $priceWithDiscount;
124
125
        return $discount === $amount;
126
    }
127
128
    /**
129
     * {@inheritdoc}
130
     */
131
    public function hasOrderTotal($total)
132
    {
133
        if (!$this->hasElement('order_total')) {
134
            return false;
135
        }
136
137
        return $this->getTotalFromString($this->getElement('order_total')->getText()) === $total;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function getBaseCurrencyOrderTotal()
144
    {
145
        return $this->getBaseTotalFromString($this->getElement('base_order_total')->getText());
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function addNotes($notes)
152
    {
153
        $this->getElement('extra_notes')->setValue($notes);
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function hasPromotionTotal($promotionTotal)
160
    {
161
        return false !== strpos($this->getElement('promotion_total')->getText(), $promotionTotal);
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function hasPromotion($promotionName)
168
    {
169
        return false !== stripos($this->getElement('promotion_discounts')->getText(), $promotionName);
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175
    public function hasShippingPromotion(string $promotionName): bool
176
    {
177
        /** @var NodeElement $shippingPromotions */
178
        $shippingPromotions = $this->getElement('promotions_shipping_details');
179
180
        return false !== strpos($shippingPromotions->getAttribute('data-html'), $promotionName);
181
    }
182
183
    public function getTaxTotal(): string
184
    {
185
        return $this->getElement('tax_total')->getText();
186
    }
187
188
    public function getShippingTotal(): string
189
    {
190
        return $this->getElement('shipping_total')->getText();
191
    }
192
193
    public function hasShippingTotal(): bool
194
    {
195
        return $this->hasElement('shipping_total');
196
    }
197
198
    /**
199
     * {@inheritdoc}
200
     */
201
    public function hasProductUnitPrice(ProductInterface $product, $price)
202
    {
203
        $productRowElement = $this->getProductRowElement($product);
204
205
        return null !== $productRowElement->find('css', sprintf('td:contains("%s")', $price));
206
    }
207
208
    /**
209
     * {@inheritdoc}
210
     */
211
    public function hasProductOutOfStockValidationMessage(ProductInterface $product)
212
    {
213
        $message = sprintf('%s does not have sufficient stock.', $product->getName());
214
215
        return $this->getElement('validation_errors')->getText() === $message;
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221
    public function getValidationErrors()
222
    {
223
        return $this->getElement('validation_errors')->getText();
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229
    public function hasLocale($localeName)
230
    {
231
        return false !== strpos($this->getElement('locale')->getText(), $localeName);
232
    }
233
234
    /**
235
     * {@inheritdoc}
236
     */
237
    public function hasCurrency($currencyCode)
238
    {
239
        return false !== strpos($this->getElement('currency')->getText(), $currencyCode);
240
    }
241
242
    /**
243
     * {@inheritdoc}
244
     */
245
    public function confirmOrder()
246
    {
247
        $this->getElement('confirm_button')->press();
248
    }
249
250
    public function changeAddress()
251
    {
252
        $this->getElement('addressing_step_label')->click();
253
    }
254
255
    public function changeShippingMethod()
256
    {
257
        $this->getElement('shipping_step_label')->click();
258
    }
259
260
    public function changePaymentMethod()
261
    {
262
        $this->getElement('payment_step_label')->click();
263
    }
264
265
    /**
266
     * {@inheritdoc}
267
     */
268
    public function hasShippingProvinceName($provinceName)
269
    {
270
        $shippingAddressText = $this->getElement('shipping_address')->getText();
271
272
        return false !== stripos($shippingAddressText, $provinceName);
273
    }
274
275
    /**
276
     * {@inheritdoc}
277
     */
278
    public function hasBillingProvinceName($provinceName)
279
    {
280
        $billingAddressText = $this->getElement('billing_address')->getText();
281
282
        return false !== stripos($billingAddressText, $provinceName);
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288
    public function getShippingPromotionDiscount($promotionName)
289
    {
290
        return $this->getElement('promotion_shipping_discounts')->find('css', '.description')->getText();
291
    }
292
293
    /**
294
     * {@inheritdoc}
295
     */
296
    public function tryToOpen(array $urlParameters = []): void
297
    {
298
        if ($this->getDriver() instanceof Selenium2Driver) {
299
            $start = microtime(true);
300
            $end = $start + 15;
301
            do {
302
                parent::tryToOpen($urlParameters);
303
                sleep(3);
304
            } while (!$this->isOpen() && microtime(true) < $end);
305
306
            return;
307
        }
308
309
        parent::tryToOpen($urlParameters);
310
    }
311
312
    public function hasShippingPromotionWithDiscount(string $promotionName, string $discount): bool
313
    {
314
        $promotionWithDiscount = sprintf('%s: %s', $promotionName, $discount);
315
316
        /** @var NodeElement $shippingPromotions */
317
        $shippingPromotions = $this->getElement('promotions_shipping_details');
318
319
        return false !== strpos($shippingPromotions->getAttribute('data-html'), $promotionWithDiscount);
320
    }
321
322
    public function hasOrderPromotion(string $promotionName): bool
323
    {
324
        /** @var NodeElement $shippingPromotions */
325
        $shippingPromotions = $this->getElement('order_promotions_details');
326
327
        return false !== strpos($shippingPromotions->getAttribute('data-html'), $promotionName);
328
    }
329
330
    /**
331
     * {@inheritdoc}
332
     */
333
    protected function getDefinedElements(): array
334
    {
335
        return array_merge(parent::getDefinedElements(), [
336
            'addressing_step_label' => '.steps a:contains("Address")',
337
            'base_order_total' => '#base-total',
338
            'billing_address' => '#sylius-billing-address',
339
            'confirm_button' => 'form button',
340
            'currency' => '#sylius-order-currency-code',
341
            'extra_notes' => '#sylius_checkout_complete_notes',
342
            'items_table' => '#sylius-order',
343
            'locale' => '#sylius-order-locale-name',
344
            'order_promotions_details' => '#order-promotions-details',
345
            'order_total' => 'td:contains("Total")',
346
            'payment_method' => '#sylius-payment-method',
347
            'payment_step_label' => '.steps a:contains("Payment")',
348
            'product_row' => 'tbody tr:contains("%name%")',
349
            'promotion_discounts' => '#promotion-discounts',
350
            'promotions_shipping_details' => '#shipping-promotion-details',
351
            'promotion_shipping_discounts' => '#promotion-shipping-discounts',
352
            'promotion_total' => '#promotion-total',
353
            'shipping_address' => '#sylius-shipping-address',
354
            'shipping_method' => '#sylius-shipping-method',
355
            'shipping_step_label' => '.steps a:contains("Shipping")',
356
            'shipping_total' => '#shipping-total',
357
            'tax_total' => '[data-test="tax-total"]',
358
            'validation_errors' => '.sylius-validation-error',
359
        ]);
360
    }
361
362
    /**
363
     * @return NodeElement
364
     */
365
    private function getProductRowElement(ProductInterface $product)
366
    {
367
        return $this->getElement('product_row', ['%name%' => $product->getName()]);
368
    }
369
370
    /**
371
     * @param string $displayedAddress
372
     *
373
     * @return bool
374
     */
375
    private function isAddressValid($displayedAddress, AddressInterface $address)
376
    {
377
        return
378
            $this->hasAddressPart($displayedAddress, $address->getCompany(), true) &&
379
            $this->hasAddressPart($displayedAddress, $address->getFirstName()) &&
380
            $this->hasAddressPart($displayedAddress, $address->getLastName()) &&
381
            $this->hasAddressPart($displayedAddress, $address->getPhoneNumber(), true) &&
382
            $this->hasAddressPart($displayedAddress, $address->getStreet()) &&
383
            $this->hasAddressPart($displayedAddress, $address->getCity()) &&
384
            $this->hasAddressPart($displayedAddress, $address->getProvinceCode(), true) &&
385
            $this->hasAddressPart($displayedAddress, $this->getCountryName($address->getCountryCode())) &&
386
            $this->hasAddressPart($displayedAddress, $address->getPostcode())
387
        ;
388
    }
389
390
    /**
391
     * @param string $address
392
     * @param string $addressPart
393
     *
394
     * @return bool
395
     */
396
    private function hasAddressPart($address, $addressPart, $optional = false)
397
    {
398
        if ($optional && null === $addressPart) {
399
            return true;
400
        }
401
402
        return false !== strpos($address, $addressPart);
403
    }
404
405
    /**
406
     * @param string $countryCode
407
     *
408
     * @return string
409
     */
410
    private function getCountryName($countryCode)
411
    {
412
        return strtoupper(Intl::getRegionBundle()->getCountryName($countryCode, 'en'));
413
    }
414
415
    private function getPriceFromString(string $price): int
416
    {
417
        return (int) round((float) str_replace(['€', '£', '$'], '', $price) * 100, 2);
418
    }
419
420
    /**
421
     * @param string $total
422
     *
423
     * @return int
424
     */
425
    private function getTotalFromString($total)
426
    {
427
        $total = str_replace('Total:', '', $total);
428
429
        return $this->getPriceFromString($total);
430
    }
431
432
    /**
433
     * @param string $total
434
     *
435
     * @return int
436
     */
437
    private function getBaseTotalFromString($total)
438
    {
439
        $total = str_replace('Total in base currency:', '', $total);
440
441
        return $this->getPriceFromString($total);
442
    }
443
}
444