Completed
Push — checkout-consistent-prices ( af49ca )
by Kamil
13:24
created

CartContext   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 418
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 7

Importance

Changes 0
Metric Value
wmc 44
lcom 3
cbo 7
dl 0
loc 418
rs 8.8798
c 0
b 0
f 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A iOpenCartSummaryPage() 0 4 1
A iUpdateMyCart() 0 4 1
A iShouldBeNotifiedThatMyCartIsEmpty() 0 6 1
A iRemoveProductFromTheCart() 0 5 1
A iChangeQuantityTo() 0 5 1
A myCartTotalShouldBe() 0 6 1
A myBaseCartTotalShouldBe() 0 6 1
A myCartTaxesShouldBe() 0 6 1
A myIncludedInPriceTaxesShouldBe() 0 6 1
A thereShouldBeNoTaxesCharged() 0 6 1
A myCartShippingFeeShouldBe() 0 6 1
A myDiscountShouldBe() 0 6 1
A thereShouldBeNoShippingFee() 0 12 2
A thereShouldBeNoDiscount() 0 12 2
A itsPriceShouldBeDecreasedBy() 0 10 1
A productPriceShouldNotBeDecreased() 0 6 1
A iAddProductToTheCart() 0 7 1
A iAddMultipleProductsToTheCart() 0 6 2
A iAddProductToTheCartSelectingVariant() 0 7 1
A iAddQuantityOfProductsToTheCart() 0 5 1
A iAddProductsToTheCart() 0 7 1
A shouldBeOnMyCartSummaryPage() 0 6 1
A iShouldBeNotifiedThatItHasBeenSuccessfullyAdded() 0 4 1
A thereShouldBeOneItemInMyCart() 0 4 1
A thisProductShouldHaveName() 0 4 1
A thisItemShouldHaveVariant() 0 4 1
A thisItemShouldHaveCode() 0 4 1
A iAddThisProductWithToTheCart() 0 6 1
A thisItemShouldHaveOptionValue() 0 4 1
A iClearMyCart() 0 4 1
A iShouldSeeWithQuantityInMyCart() 0 4 1
A iShouldSeeProductWithUnitPriceInMyCart() 0 4 1
A iUseCouponWithCode() 0 4 1
A iShouldBeNotifiedThatCouponIsInvalid() 0 4 1
A thisItemPriceShouldBe() 0 6 1
A iShouldBeNotifiedThatThisProductDoesNotHaveSufficientStock() 0 4 1
A iShouldNotBeNotifiedThatThisProductCannotBeUpdated() 0 4 1
A myCartSTotalShouldBe() 0 6 1
A itemShouldHaveImageDisplayed() 0 4 1
A getPriceFromString() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like CartContext often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CartContext, and based on these observations, apply Extract Interface, too.

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\Context\Ui\Shop;
15
16
use Behat\Behat\Context\Context;
17
use Behat\Mink\Exception\ElementNotFoundException;
18
use Sylius\Behat\NotificationType;
19
use Sylius\Behat\Page\Shop\Cart\SummaryPageInterface;
20
use Sylius\Behat\Page\Shop\Product\ShowPageInterface;
21
use Sylius\Behat\Service\NotificationCheckerInterface;
22
use Sylius\Behat\Service\SharedStorageInterface;
23
use Sylius\Component\Product\Model\ProductInterface;
24
use Sylius\Component\Product\Model\ProductOptionInterface;
25
use Webmozart\Assert\Assert;
26
27
final class CartContext implements Context
28
{
29
    /** @var SharedStorageInterface */
30
    private $sharedStorage;
31
32
    /** @var SummaryPageInterface */
33
    private $summaryPage;
34
35
    /** @var ShowPageInterface */
36
    private $productShowPage;
37
38
    /** @var NotificationCheckerInterface */
39
    private $notificationChecker;
40
41
    public function __construct(
42
        SharedStorageInterface $sharedStorage,
43
        SummaryPageInterface $summaryPage,
44
        ShowPageInterface $productShowPage,
45
        NotificationCheckerInterface $notificationChecker
46
    ) {
47
        $this->sharedStorage = $sharedStorage;
48
        $this->summaryPage = $summaryPage;
49
        $this->productShowPage = $productShowPage;
50
        $this->notificationChecker = $notificationChecker;
51
    }
52
53
    /**
54
     * @When I see the summary of my cart
55
     */
56
    public function iOpenCartSummaryPage()
57
    {
58
        $this->summaryPage->open();
59
    }
60
61
    /**
62
     * @When I update my cart
63
     */
64
    public function iUpdateMyCart()
65
    {
66
        $this->summaryPage->updateCart();
67
    }
68
69
    /**
70
     * @Then my cart should be empty
71
     * @Then cart should be empty with no value
72
     */
73
    public function iShouldBeNotifiedThatMyCartIsEmpty()
74
    {
75
        $this->summaryPage->open();
76
77
        Assert::true($this->summaryPage->isEmpty());
78
    }
79
80
    /**
81
     * @Given I removed product :productName from the cart
82
     * @When I remove product :productName from the cart
83
     */
84
    public function iRemoveProductFromTheCart(string $productName): void
85
    {
86
        $this->summaryPage->open();
87
        $this->summaryPage->removeProduct($productName);
88
    }
89
90
    /**
91
     * @Given I change :productName quantity to :quantity
92
     */
93
    public function iChangeQuantityTo($productName, $quantity)
94
    {
95
        $this->summaryPage->open();
96
        $this->summaryPage->changeQuantity($productName, $quantity);
97
    }
98
99
    /**
100
     * @Then the grand total value should be :total
101
     * @Then my cart total should be :total
102
     */
103
    public function myCartTotalShouldBe($total)
104
    {
105
        $this->summaryPage->open();
106
107
        Assert::same($this->summaryPage->getGrandTotal(), $total);
108
    }
109
110
    /**
111
     * @Then the grand total value in base currency should be :total
112
     */
113
    public function myBaseCartTotalShouldBe($total)
114
    {
115
        $this->summaryPage->open();
116
117
        Assert::same($this->summaryPage->getBaseGrandTotal(), $total);
118
    }
119
120
    /**
121
     * @Then my cart taxes should be :taxTotal
122
     */
123
    public function myCartTaxesShouldBe(string $taxTotal): void
124
    {
125
        $this->summaryPage->open();
126
127
        Assert::same($this->summaryPage->getExcludedTaxTotal(), $taxTotal);
128
    }
129
130
    /**
131
     * @Then my included in price taxes should be :taxTotal
132
     */
133
    public function myIncludedInPriceTaxesShouldBe(string $taxTotal): void
134
    {
135
        $this->summaryPage->open();
136
137
        Assert::same($this->summaryPage->getIncludedTaxTotal(), $taxTotal);
138
    }
139
140
    /**
141
     * @Then there should be no taxes charged
142
     */
143
    public function thereShouldBeNoTaxesCharged(): void
144
    {
145
        $this->summaryPage->open();
146
147
        Assert::false($this->summaryPage->areTaxesCharged());
148
    }
149
150
    /**
151
     * @Then my cart shipping total should be :shippingTotal
152
     * @Then my cart shipping should be for free
153
     */
154
    public function myCartShippingFeeShouldBe($shippingTotal = '$0.00')
155
    {
156
        $this->summaryPage->open();
157
158
        Assert::same($this->summaryPage->getShippingTotal(), $shippingTotal);
159
    }
160
161
    /**
162
     * @Then my discount should be :promotionsTotal
163
     */
164
    public function myDiscountShouldBe($promotionsTotal)
165
    {
166
        $this->summaryPage->open();
167
168
        Assert::same($this->summaryPage->getPromotionTotal(), $promotionsTotal);
169
    }
170
171
    /**
172
     * @Given /^there should be no shipping fee$/
173
     */
174
    public function thereShouldBeNoShippingFee()
175
    {
176
        $this->summaryPage->open();
177
178
        try {
179
            $this->summaryPage->getShippingTotal();
180
        } catch (ElementNotFoundException $exception) {
181
            return;
182
        }
183
184
        throw new \DomainException('Get shipping total should throw an exception!');
185
    }
186
187
    /**
188
     * @Given /^there should be no discount$/
189
     */
190
    public function thereShouldBeNoDiscount()
191
    {
192
        $this->summaryPage->open();
193
194
        try {
195
            $this->summaryPage->getPromotionTotal();
196
        } catch (ElementNotFoundException $exception) {
197
            return;
198
        }
199
200
        throw new \DomainException('Get promotion total should throw an exception!');
201
    }
202
203
    /**
204
     * @Then /^(its|theirs) price should be decreased by ("[^"]+")$/
205
     * @Then /^(product "[^"]+") price should be decreased by ("[^"]+")$/
206
     */
207
    public function itsPriceShouldBeDecreasedBy(ProductInterface $product, $amount)
208
    {
209
        $this->summaryPage->open();
210
211
        $quantity = $this->summaryPage->getQuantity($product->getName());
212
        $itemTotal = $this->summaryPage->getItemTotal($product->getName());
213
        $regularUnitPrice = $this->summaryPage->getItemUnitRegularPrice($product->getName());
214
215
        Assert::same($this->getPriceFromString($itemTotal), ($quantity * $regularUnitPrice) - $amount);
216
    }
217
218
    /**
219
     * @Then /^(product "[^"]+") price should not be decreased$/
220
     */
221
    public function productPriceShouldNotBeDecreased(ProductInterface $product)
222
    {
223
        $this->summaryPage->open();
224
225
        Assert::false($this->summaryPage->isItemDiscounted($product->getName()));
226
    }
227
228
    /**
229
     * @Given /^I (?:add|added) (this product) to the cart$/
230
     * @Given I added product :product to the cart
231
     * @Given /^I (?:have|had) (product "[^"]+") in the cart$/
232
     * @When I add product :product to the cart
233
     */
234
    public function iAddProductToTheCart(ProductInterface $product)
235
    {
236
        $this->productShowPage->open(['slug' => $product->getSlug()]);
237
        $this->productShowPage->addToCart();
238
239
        $this->sharedStorage->set('product', $product);
240
    }
241
242
    /**
243
     * @When /^I add (products "([^"]+)" and "([^"]+)") to the cart$/
244
     * @When /^I add (products "([^"]+)", "([^"]+)" and "([^"]+)") to the cart$/
245
     */
246
    public function iAddMultipleProductsToTheCart(array $products)
247
    {
248
        foreach ($products as $product) {
249
            $this->iAddProductToTheCart($product);
250
        }
251
    }
252
253
    /**
254
     * @When I add :variantName variant of product :product to the cart
255
     * @When /^I add "([^"]+)" variant of (this product) to the cart$/
256
     * @Given I have :variantName variant of product :product in the cart
257
     */
258
    public function iAddProductToTheCartSelectingVariant($variantName, ProductInterface $product)
259
    {
260
        $this->productShowPage->open(['slug' => $product->getSlug()]);
261
        $this->productShowPage->addToCartWithVariant($variantName);
262
263
        $this->sharedStorage->set('product', $product);
264
    }
265
266
    /**
267
     * @When /^I add (\d+) of (them) to (?:the|my) cart$/
268
     */
269
    public function iAddQuantityOfProductsToTheCart($quantity, ProductInterface $product)
270
    {
271
        $this->productShowPage->open(['slug' => $product->getSlug()]);
272
        $this->productShowPage->addToCartWithQuantity($quantity);
273
    }
274
275
    /**
276
     * @Given /^I have(?:| added) (\d+) (products "([^"]+)") (?:to|in) the cart$/
277
     * @When /^I add(?:|ed)(?:| again) (\d+) (products "([^"]+)") to the cart$/
278
     */
279
    public function iAddProductsToTheCart($quantity, ProductInterface $product)
280
    {
281
        $this->productShowPage->open(['slug' => $product->getSlug()]);
282
        $this->productShowPage->addToCartWithQuantity($quantity);
283
284
        $this->sharedStorage->set('product', $product);
285
    }
286
287
    /**
288
     * @Then /^I should be(?: on| redirected to) my cart summary page$/
289
     */
290
    public function shouldBeOnMyCartSummaryPage()
291
    {
292
        $this->summaryPage->waitForRedirect(3);
293
294
        $this->summaryPage->verify();
295
    }
296
297
    /**
298
     * @Then I should be notified that the product has been successfully added
299
     */
300
    public function iShouldBeNotifiedThatItHasBeenSuccessfullyAdded()
301
    {
302
        $this->notificationChecker->checkNotification('Item has been added to cart', NotificationType::success());
303
    }
304
305
    /**
306
     * @Then there should be one item in my cart
307
     */
308
    public function thereShouldBeOneItemInMyCart()
309
    {
310
        Assert::true($this->summaryPage->isSingleItemOnPage());
311
    }
312
313
    /**
314
     * @Then this item should have name :itemName
315
     */
316
    public function thisProductShouldHaveName($itemName)
317
    {
318
        Assert::true($this->summaryPage->hasItemNamed($itemName));
319
    }
320
321
    /**
322
     * @Then this item should have variant :variantName
323
     */
324
    public function thisItemShouldHaveVariant($variantName)
325
    {
326
        Assert::true($this->summaryPage->hasItemWithVariantNamed($variantName));
327
    }
328
329
    /**
330
     * @Then this item should have code :variantCode
331
     */
332
    public function thisItemShouldHaveCode($variantCode)
333
    {
334
        Assert::true($this->summaryPage->hasItemWithCode($variantCode));
335
    }
336
337
    /**
338
     * @Given I have :product with :productOption :productOptionValue in the cart
339
     * @When I add :product with :productOption :productOptionValue to the cart
340
     */
341
    public function iAddThisProductWithToTheCart(ProductInterface $product, ProductOptionInterface $productOption, $productOptionValue)
342
    {
343
        $this->productShowPage->open(['slug' => $product->getSlug()]);
344
345
        $this->productShowPage->addToCartWithOption($productOption, $productOptionValue);
346
    }
347
348
    /**
349
     * @Given /^(this product) should have ([^"]+) "([^"]+)"$/
350
     */
351
    public function thisItemShouldHaveOptionValue(ProductInterface $product, $optionName, $optionValue)
352
    {
353
        Assert::true($this->summaryPage->hasItemWithOptionValue($product->getName(), $optionName, $optionValue));
354
    }
355
356
    /**
357
     * @When I clear my cart
358
     */
359
    public function iClearMyCart()
360
    {
361
        $this->summaryPage->clearCart();
362
    }
363
364
    /**
365
     * @Then /^I should see "([^"]+)" with quantity (\d+) in my cart$/
366
     */
367
    public function iShouldSeeWithQuantityInMyCart($productName, $quantity)
368
    {
369
        Assert::same($this->summaryPage->getQuantity($productName), (int) $quantity);
370
    }
371
372
    /**
373
     * @Then /^I should see "([^"]+)" with unit price ("[^"]+") in my cart$/
374
     */
375
    public function iShouldSeeProductWithUnitPriceInMyCart($productName, $unitPrice)
376
    {
377
        Assert::same($this->summaryPage->getItemUnitPrice($productName), $unitPrice);
378
    }
379
380
    /**
381
     * @Given I use coupon with code :couponCode
382
     */
383
    public function iUseCouponWithCode($couponCode)
384
    {
385
        $this->summaryPage->applyCoupon($couponCode);
386
    }
387
388
    /**
389
     * @Then I should be notified that the coupon is invalid
390
     */
391
    public function iShouldBeNotifiedThatCouponIsInvalid()
392
    {
393
        Assert::same($this->summaryPage->getPromotionCouponValidationMessage(), 'Coupon code is invalid.');
394
    }
395
396
    /**
397
     * @Then total price of :productName item should be :productPrice
398
     */
399
    public function thisItemPriceShouldBe($productName, $productPrice)
400
    {
401
        $this->summaryPage->open();
402
403
        Assert::same($this->summaryPage->getItemTotal($productName), $productPrice);
404
    }
405
406
    /**
407
     * @Then /^I should be notified that (this product) cannot be updated$/
408
     */
409
    public function iShouldBeNotifiedThatThisProductDoesNotHaveSufficientStock(ProductInterface $product)
410
    {
411
        Assert::true($this->summaryPage->hasProductOutOfStockValidationMessage($product));
0 ignored issues
show
Compatibility introduced by
$product of type object<Sylius\Component\...Model\ProductInterface> is not a sub-type of object<Sylius\Component\...Model\ProductInterface>. It seems like you assume a child interface of the interface Sylius\Component\Product\Model\ProductInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
412
    }
413
414
    /**
415
     * @Then /^I should not be notified that (this product) cannot be updated$/
416
     */
417
    public function iShouldNotBeNotifiedThatThisProductCannotBeUpdated(ProductInterface $product)
418
    {
419
        Assert::false($this->summaryPage->hasProductOutOfStockValidationMessage($product));
0 ignored issues
show
Compatibility introduced by
$product of type object<Sylius\Component\...Model\ProductInterface> is not a sub-type of object<Sylius\Component\...Model\ProductInterface>. It seems like you assume a child interface of the interface Sylius\Component\Product\Model\ProductInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
420
    }
421
422
    /**
423
     * @Then my cart's total should be :total
424
     */
425
    public function myCartSTotalShouldBe($total)
426
    {
427
        $this->summaryPage->open();
428
429
        Assert::same($this->summaryPage->getCartTotal(), $total);
430
    }
431
432
    /**
433
     * @Then /^(\d)(st|nd|rd|th) item in my cart should have "([^"]+)" image displayed$/
434
     */
435
    public function itemShouldHaveImageDisplayed(int $itemNumber, string $image): void
436
    {
437
        Assert::contains($this->summaryPage->getItemImage($itemNumber), $image);
438
    }
439
440
    private function getPriceFromString(string $price): int
441
    {
442
        return (int) round((float) str_replace(['€', '£', '$'], '', $price) * 100, 2);
443
    }
444
}
445