Completed
Push — master ( 7c7881...78efce )
by Michał
26:17 queued 05:58
created

SummaryPage::getCartTotal()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 5
nc 2
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
namespace Sylius\Behat\Page\Shop\Cart;
13
14
use Behat\Mink\Exception\ElementNotFoundException;
15
use Sylius\Behat\Page\SymfonyPage;
16
use Sylius\Component\Core\Model\ProductInterface;
17
use Symfony\Component\Routing\RouterInterface;
18
19
/**
20
 * @author Mateusz Zalewski <[email protected]>
21
 * @author Anna Walasek <[email protected]>
22
 */
23
class SummaryPage extends SymfonyPage implements SummaryPageInterface
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    public function getRouteName()
29
    {
30
        return 'sylius_shop_cart_summary';
31
    }
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function getGrandTotal()
37
    {
38
        $totalElement = $this->getElement('grand_total');
39
40
        return $totalElement->getText();
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function getTaxTotal()
47
    {
48
        $taxTotalElement = $this->getElement('tax_total');
49
50
        return $taxTotalElement->getText();
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function getShippingTotal()
57
    {
58
        $shippingTotalElement = $this->getElement('shipping_total');
59
60
        return $shippingTotalElement->getText();
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    public function getPromotionTotal()
67
    {
68
        $shippingTotalElement = $this->getElement('promotion_total');
69
70
        return $shippingTotalElement->getText();
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76
    public function getItemTotal($productName)
77
    {
78
        $itemTotalElement = $this->getElement('product_total', ['%name%' => $productName]);
79
80
        return  $itemTotalElement->getText();
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function getItemUnitRegularPrice($productName)
87
    {
88
        $regularUnitPrice = $this->getElement('product_unit_regular_price', ['%name%' => $productName]);
89
90
        return $this->getPriceFromString(trim($regularUnitPrice->getText()));
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function getItemUnitPrice($productName)
97
    {
98
        $unitPrice = $this->getElement('product_unit_price', ['%name%' => $productName]);
99
100
        return $this->getPriceFromString(trim($unitPrice->getText()));
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function isItemDiscounted($productName)
107
    {
108
        return $this->hasElement('product_unit_regular_price', ['%name%' => $productName]);
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function removeProduct($productName)
115
    {
116
        $itemElement = $this->getElement('product_row', ['%name%' => $productName]);
117
        $itemElement->find('css', 'a.sylius-cart-remove-button')->click();
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function applyCoupon($couponCode)
124
    {
125
        $this->getElement('coupon_field')->setValue($couponCode);
126
        $this->getElement('apply_coupon_button')->press();
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132
    public function changeQuantity($productName, $quantity)
133
    {
134
        $itemElement = $this->getElement('product_row', ['%name%' => $productName]);
135
        $itemElement->find('css', 'input[type=number]')->setValue($quantity);
136
137
        $this->getElement('save_button')->click();
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function isSingleItemOnPage()
144
    {
145
        $items = $this->getElement('cart_items')->findAll('css', 'tbody > tr');
146
147
        return 1 === count($items);
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153
    public function hasItemNamed($name)
154
    {
155
       return $this->hasItemWith($name, '.sylius-product-name');
156
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161
    public function hasItemWithVariantNamed($variantName)
162
    {
163
       return $this->hasItemWith($variantName, '.sylius-product-variant-name');
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function hasItemWithOptionValue($productName, $optionName, $optionValue)
170
    {
171
        $itemElement = $this->getElement('product_row', ['%name%' => $productName]);
172
173
        $selector = sprintf('.sylius-product-options > .item[data-sylius-option-name="%s"]', $optionName);
174
        $optionValueElement = $itemElement->find('css', $selector);
175
176
        if (null === $optionValueElement) {
177
            throw new ElementNotFoundException($this->getSession(), sprintf('Option value of "%s"', $optionName), 'css', $selector);
178
        }
179
180
        return $optionValue === $optionValueElement->getText();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $optionValue === ...alueElement->getText(); (boolean) is incompatible with the return type declared by the interface Sylius\Behat\Page\Shop\C...:hasItemWithOptionValue of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
181
    }
182
183
    /**
184
     * {@inheritdoc]
185
     */
186
    public function hasProductOutOfStockValidationMessage(ProductInterface $product)
187
    {
188
        $message = sprintf('%s does not have sufficient stock.', $product->getName());
189
190
        try {
191
            return $this->getElement('validation_errors')->getText() === $message;
192
        } catch (ElementNotFoundException $exception) {
193
            return false;
194
        }
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function isEmpty()
201
    {
202
        return false !== strpos($this->getDocument()->find('css', '.message')->getText(), 'Your cart is empty');
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208
    public function getQuantity($productName)
209
    {
210
        $itemElement = $this->getElement('product_row', ['%name%' => $productName]);
211
212
        return (int) $itemElement->find('css', 'input[type=number]')->getValue();
213
    }
214
215
    /**
216
     * {@inheritdoc}
217
     */
218
    public function getCartTotal()
219
    {
220
        $cartTotalText = $this->getElement('cart_total')->getText();
221
222
        if (strpos($cartTotalText, ',') !== false ) {
223
            return strstr($cartTotalText, ',', true);
224
        }
225
226
        return $cartTotalText;
227
    }
228
229
    public function clearCart()
230
    {
231
        $this->getElement('clear_button')->click();
232
    }
233
234
    public function updateCart()
235
    {
236
        $this->getElement('update_button')->click();
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242
    protected function getDefinedElements()
243
    {
244
        return array_merge(parent::getDefinedElements(), [
245
            'apply_coupon_button' => 'button:contains("Apply coupon")',
246
            'cart_items' => '#sylius-cart-items',
247
            'cart_total' => '#sylius-cart-button',
248
            'clear_button' => '#sylius-cart-clear',
249
            'coupon_field' => '#sylius_cart_promotionCoupon',
250
            'grand_total' => '#sylius-cart-grand-total',
251
            'product_discounted_total' => '#sylius-cart-items tr:contains("%name%") .sylius-discounted-total',
252
            'product_row' => '#sylius-cart-items tbody tr:contains("%name%")',
253
            'product_total' => '#sylius-cart-items tr:contains("%name%") .sylius-total',
254
            'product_unit_price' => '#sylius-cart-items tr:contains("%name%") .sylius-unit-price',
255
            'product_unit_regular_price' => '#sylius-cart-items tr:contains("%name%") .sylius-regular-unit-price',
256
            'promotion_total' => '#sylius-cart-promotion-total',
257
            'save_button' => '#sylius-save',
258
            'shipping_total' => '#sylius-cart-shipping-total',
259
            'tax_total' => '#sylius-cart-tax-total',
260
            'update_button' => '#sylius-cart-update',
261
            'validation_errors' => '.sylius-validation-error',
262
        ]);
263
    }
264
265
    /**
266
     * @param $attributeName
267
     * @param $selector
268
     *
269
     * @return bool
270
     *
271
     * @throws ElementNotFoundException
272
     */
273
    private function hasItemWith($attributeName, $selector)
274
    {
275
        $itemsAttributes = $this->getElement('cart_items')->findAll('css', $selector);
276
277
        foreach ($itemsAttributes as $itemAttribute) {
278
            if ($attributeName === $itemAttribute->getText()) {
279
                return true;
280
            }
281
        }
282
283
        return false;
284
    }
285
286
    /**
287
     * @param string $price
288
     *
289
     * @return int
290
     */
291
    private function getPriceFromString($price)
292
    {
293
        return (int) round((str_replace(['€', '£', '$'], '', $price) * 100), 2);
294
    }
295
}
296