Completed
Push — master ( 0d15f5...3f1a6d )
by Kamil
22:42
created

ManagingProductsContext::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
cc 1
eloc 21
nc 1
nop 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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\Context\Ui\Admin;
13
14
use Behat\Behat\Context\Context;
15
use Behat\Mink\Exception\ElementNotFoundException;
16
use Sylius\Behat\NotificationType;
17
use Sylius\Behat\Page\Admin\Crud\CreatePageInterface;
18
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface;
19
use Sylius\Behat\Page\Admin\Product\CreateConfigurableProductPageInterface;
20
use Sylius\Behat\Page\Admin\Product\CreateSimpleProductPageInterface;
21
use Sylius\Behat\Page\Admin\Product\IndexPageInterface;
22
use Sylius\Behat\Page\Admin\Product\IndexPerTaxonPageInterface;
23
use Sylius\Behat\Page\Admin\Product\UpdateConfigurableProductPageInterface;
24
use Sylius\Behat\Page\Admin\Product\UpdateSimpleProductPageInterface;
25
use Sylius\Behat\Page\Admin\ProductReview\IndexPageInterface as ProductReviewIndexPageInterface;
26
use Sylius\Behat\Page\SymfonyPageInterface;
27
use Sylius\Behat\Service\NotificationCheckerInterface;
28
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
29
use Sylius\Behat\Service\SharedStorageInterface;
30
use Sylius\Component\Core\Model\ProductInterface;
31
use Sylius\Component\Core\Model\TaxonInterface;
32
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
33
use Webmozart\Assert\Assert;
34
35
/**
36
 * @author Kamil Kokot <[email protected]>
37
 * @author Magdalena Banasiak <[email protected]>
38
 * @author Łukasz Chruściel <[email protected]>
39
 * @author Gorka Laucirica <[email protected]>
40
 */
41
final class ManagingProductsContext implements Context
42
{
43
    /**
44
     * @var SharedStorageInterface
45
     */
46
    private $sharedStorage;
47
48
    /**x
49
     * @var CreateSimpleProductPageInterface
50
     */
51
    private $createSimpleProductPage;
52
53
    /**
54
     * @var CreateConfigurableProductPageInterface
55
     */
56
    private $createConfigurableProductPage;
57
58
    /**
59
     * @var IndexPageInterface
60
     */
61
    private $indexPage;
62
63
    /**
64
     * @var UpdateSimpleProductPageInterface
65
     */
66
    private $updateSimpleProductPage;
67
68
    /**
69
     * @var UpdateConfigurableProductPageInterface
70
     */
71
    private $updateConfigurableProductPage;
72
73
    /**
74
     * @var ProductReviewIndexPageInterface
75
     */
76
    private $productReviewIndexPage;
77
78
    /**
79
     * @var IndexPerTaxonPageInterface
80
     */
81
    private $indexPerTaxonPage;
82
83
    /**
84
     * @var CurrentPageResolverInterface
85
     */
86
    private $currentPageResolver;
87
88
    /**
89
     * @var NotificationCheckerInterface
90
     */
91
    private $notificationChecker;
92
93
    /**
94
     * @param SharedStorageInterface $sharedStorage
95
     * @param CreateSimpleProductPageInterface $createSimpleProductPage
96
     * @param CreateConfigurableProductPageInterface $createConfigurableProductPage
97
     * @param IndexPageInterface $indexPage
98
     * @param UpdateSimpleProductPageInterface $updateSimpleProductPage
99
     * @param UpdateConfigurableProductPageInterface $updateConfigurableProductPage
100
     * @param ProductReviewIndexPageInterface $productReviewIndexPage
101
     * @param IndexPerTaxonPageInterface $indexPerTaxonPage
102
     * @param CurrentPageResolverInterface $currentPageResolver
103
     * @param NotificationCheckerInterface $notificationChecker
104
     */
105
    public function __construct(
106
        SharedStorageInterface $sharedStorage,
107
        CreateSimpleProductPageInterface $createSimpleProductPage,
108
        CreateConfigurableProductPageInterface $createConfigurableProductPage,
109
        IndexPageInterface $indexPage,
110
        UpdateSimpleProductPageInterface $updateSimpleProductPage,
111
        UpdateConfigurableProductPageInterface $updateConfigurableProductPage,
112
        ProductReviewIndexPageInterface $productReviewIndexPage,
113
        IndexPerTaxonPageInterface $indexPerTaxonPage,
114
        CurrentPageResolverInterface $currentPageResolver,
115
        NotificationCheckerInterface $notificationChecker
116
    ) {
117
        $this->sharedStorage = $sharedStorage;
118
        $this->createSimpleProductPage = $createSimpleProductPage;
119
        $this->createConfigurableProductPage = $createConfigurableProductPage;
120
        $this->indexPage = $indexPage;
121
        $this->updateSimpleProductPage = $updateSimpleProductPage;
122
        $this->updateConfigurableProductPage = $updateConfigurableProductPage;
123
        $this->productReviewIndexPage = $productReviewIndexPage;
124
        $this->indexPerTaxonPage = $indexPerTaxonPage;
125
        $this->currentPageResolver = $currentPageResolver;
126
        $this->notificationChecker = $notificationChecker;
127
    }
128
129
    /**
130
     * @Given I want to create a new simple product
131
     */
132
    public function iWantToCreateANewSimpleProduct()
133
    {
134
        $this->createSimpleProductPage->open();
135
    }
136
137
    /**
138
     * @Given I want to create a new configurable product
139
     */
140
    public function iWantToCreateANewConfigurableProduct()
141
    {
142
        $this->createConfigurableProductPage->open();
143
    }
144
145
    /**
146
     * @When I specify its code as :code
147
     * @When I do not specify its code
148
     */
149
    public function iSpecifyItsCodeAs($code = null)
150
    {
151
        $currentPage = $this->resolveCurrentPage();
152
153
        $currentPage->specifyCode($code);
154
    }
155
156
    /**
157
     * @When I name it :name in :language
158
     * @When I rename it to :name in :language
159
     */
160
    public function iRenameItToIn($name, $language)
161
    {
162
        $currentPage = $this->resolveCurrentPage();
163
164
        $currentPage->nameItIn($name, $language);
165
    }
166
167
    /**
168
     * @When I add it
169
     * @When I try to add it
170
     */
171
    public function iAddIt()
172
    {
173
        /** @var CreatePageInterface $currentPage */
174
        $currentPage = $this->resolveCurrentPage();
175
176
        $currentPage->create();
177
    }
178
179
    /**
180
     * @When I disable its inventory tracking
181
     */
182
    public function iDisableItsTracking()
183
    {
184
        $this->updateSimpleProductPage->disableTracking();
185
    }
186
187
    /**
188
     * @When I enable its inventory tracking
189
     */
190
    public function iEnableItsTracking()
191
    {
192
        $this->updateSimpleProductPage->enableTracking();
193
    }
194
195
    /**
196
     * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
197
     */
198
    public function iSetItsPriceTo($price, $channelName)
199
    {
200
        $this->createSimpleProductPage->specifyPrice($channelName, $price);
201
    }
202
203
    /**
204
     * @When /^I set its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
205
     */
206
    public function iSetItsOriginalPriceTo($originalPrice, $channelName)
207
    {
208
        $this->createSimpleProductPage->specifyOriginalPrice($channelName, $originalPrice);
209
    }
210
211
    /**
212
     * @When I make it available in channel :channel
213
     */
214
    public function iMakeItAvailableInChannel($channel)
215
    {
216
        $this->createSimpleProductPage->checkChannel($channel);
217
    }
218
219
    /**
220
     * @When I assign it to channel :channel
221
     */
222
    public function iAssignItToChannel($channel)
223
    {
224
        // Temporary solution until we will make current page resolver work with product pages
225
        $this->updateConfigurableProductPage->checkChannel($channel);
226
    }
227
228
    /**
229
     * @When I choose :calculatorName calculator
230
     */
231
    public function iChooseCalculator($calculatorName)
232
    {
233
        $this->createSimpleProductPage->choosePricingCalculator($calculatorName);
234
    }
235
236
    /**
237
     * @When I set its slug to :slug
238
     * @When I set its slug to :slug in :language
239
     * @When I remove its slug
240
     */
241
    public function iSetItsSlugToIn($slug = null, $language = 'en_US')
242
    {
243
        $this->createSimpleProductPage->specifySlugIn($slug, $language);
244
    }
245
246
    /**
247
     * @When I enable slug modification
248
     * @When I enable slug modification in :localeCode
249
     */
250
    public function iEnableSlugModification($localeCode = 'en_US')
251
    {
252
        $this->updateSimpleProductPage->activateLanguageTab($localeCode);
253
        $this->updateSimpleProductPage->enableSlugModification($localeCode);
254
    }
255
256
    /**
257
     * @Then the product :productName should appear in the store
258
     * @Then the product :productName should be in the shop
259
     * @Then this product should still be named :productName
260
     */
261
    public function theProductShouldAppearInTheShop($productName)
262
    {
263
        $this->iWantToBrowseProducts();
264
265
        Assert::true($this->indexPage->isSingleResourceOnPage(['name' => $productName]));
266
    }
267
268
    /**
269
     * @Given I am browsing products
270
     * @When I want to browse products
271
     */
272
    public function iWantToBrowseProducts()
273
    {
274
        $this->indexPage->open();
275
    }
276
277
    /**
278
     * @When /^I am browsing products from ("([^"]+)" taxon)$/
279
     */
280
    public function iAmBrowsingProductsFromTaxon(TaxonInterface $taxon)
281
    {
282
        $this->indexPerTaxonPage->open(['taxonId' => $taxon->getId()]);
283
    }
284
285
    /**
286
     * @When I filter them by :taxonName taxon
287
     */
288
    public function iFilterThemByTaxon($taxonName)
289
    {
290
        $this->indexPage->filterByTaxon($taxonName);
291
    }
292
293
    /**
294
     * @Then I should( still) see a product with :field :value
295
     */
296
    public function iShouldSeeProductWith($field, $value)
297
    {
298
        Assert::true($this->indexPage->isSingleResourceOnPage([$field => $value]));
299
    }
300
301
    /**
302
     * @Then I should not see any product with :field :value
303
     */
304
    public function iShouldNotSeeAnyProductWith($field, $value)
305
    {
306
        Assert::false($this->indexPage->isSingleResourceOnPage([$field => $value]));
307
    }
308
309
    /**
310
     * @Then the first product on the list should have :field :value
311
     */
312
    public function theFirstProductOnTheListShouldHave($field, $value)
313
    {
314
        $currentPage = $this->resolveCurrentPage();
315
316
        Assert::same($currentPage->getColumnFields($field)[0], $value);
317
    }
318
319
    /**
320
     * @Then the last product on the list should have :field :value
321
     */
322
    public function theLastProductOnTheListShouldHave($field, $value)
323
    {
324
        $values = $this->indexPerTaxonPage->getColumnFields($field);
325
326
        Assert::same(end($values), $value);
327
    }
328
329
    /**
330
     * @When I switch the way products are sorted by :field
331
     * @When I start sorting products by :field
332
     * @Given the products are already sorted by :field
333
     */
334
    public function iSortProductsBy($field)
335
    {
336
        $this->indexPage->sortBy($field);
337
    }
338
339
    /**
340
     * @Then I should see :numberOfProducts products in the list
341
     */
342
    public function iShouldSeeProductsInTheList($numberOfProducts)
343
    {
344
        Assert::same($this->indexPage->countItems(), (int) $numberOfProducts);
345
    }
346
347
    /**
348
     * @When I delete the :product product
349
     * @When I try to delete the :product product
350
     */
351
    public function iDeleteProduct(ProductInterface $product)
352
    {
353
        $this->sharedStorage->set('product', $product);
354
355
        $this->iWantToBrowseProducts();
356
        $this->indexPage->deleteResourceOnPage(['name' => $product->getName()]);
357
    }
358
359
    /**
360
     * @Then /^(this product) should not exist in the product catalog$/
361
     */
362
    public function productShouldNotExist(ProductInterface $product)
363
    {
364
        $this->iWantToBrowseProducts();
365
366
        Assert::false($this->indexPage->isSingleResourceOnPage(['code' => $product->getCode()]));
367
    }
368
369
    /**
370
     * @Then I should be notified that this product is in use and cannot be deleted
371
     */
372
    public function iShouldBeNotifiedOfFailure()
373
    {
374
        $this->notificationChecker->checkNotification(
375
            'Cannot delete, the product is in use.',
376
            NotificationType::failure()
377
        );
378
    }
379
380
    /**
381
     * @Then /^(this product) should still exist in the product catalog$/
382
     */
383
    public function productShouldExistInTheProductCatalog(ProductInterface $product)
384
    {
385
        $this->theProductShouldAppearInTheShop($product->getName());
386
    }
387
388
    /**
389
     * @When I want to modify the :product product
390
     * @When /^I want to modify (this product)$/
391
     */
392
    public function iWantToModifyAProduct(ProductInterface $product)
393
    {
394
        $this->sharedStorage->set('product', $product);
395
396
        if ($product->isSimple()) {
397
            $this->updateSimpleProductPage->open(['id' => $product->getId()]);
398
            return;
399
        }
400
401
        $this->updateConfigurableProductPage->open(['id' => $product->getId()]);
402
    }
403
404
    /**
405
     * @Then the code field should be disabled
406
     */
407
    public function theCodeFieldShouldBeDisabled()
408
    {
409
        $currentPage = $this->resolveCurrentPage();
410
411
        Assert::true($currentPage->isCodeDisabled());
412
    }
413
414
    /**
415
     * @Then the slug field should not be editable
416
     * @Then the slug field in :localeCode (also )should not be editable
417
     */
418
    public function theSlugFieldShouldNotBeEditable($localeCode = 'en_US')
419
    {
420
        Assert::true($this->updateSimpleProductPage->isSlugReadOnlyIn($localeCode));
421
    }
422
423
    /**
424
     * @Then this product name should be :name
425
     */
426
    public function thisProductElementShouldBe($name)
427
    {
428
        $this->assertElementValue('name', $name);
429
    }
430
431
    /**
432
     * @Then /^I should be notified that (code|name|slug) is required$/
433
     */
434
    public function iShouldBeNotifiedThatIsRequired($element)
435
    {
436
        $this->assertValidationMessage($element, sprintf('Please enter product %s.', $element));
437
    }
438
439
    /**
440
     * @When I save my changes
441
     * @When I try to save my changes
442
     */
443
    public function iSaveMyChanges()
444
    {
445
        $currentPage = $this->resolveCurrentPage();
446
447
        $currentPage->saveChanges();
448
    }
449
450
    /**
451
     * @When /^I change its price to (?:€|£|\$)([^"]+) for "([^"]+)" channel$/
452
     */
453
    public function iChangeItsPriceTo($price, $channelName)
454
    {
455
        $this->updateSimpleProductPage->specifyPrice($channelName, $price);
456
    }
457
458
    /**
459
     * @When /^I change its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
460
     */
461
    public function iChangeItsOriginalPriceTo($price, $channelName)
462
    {
463
        $this->updateSimpleProductPage->specifyOriginalPrice($channelName, $price);
464
    }
465
466
    /**
467
     * @Given I add the :optionName option to it
468
     */
469
    public function iAddTheOptionToIt($optionName)
470
    {
471
        $this->createConfigurableProductPage->selectOption($optionName);
472
    }
473
474
    /**
475
     * @When I set its :attribute attribute to :value
476
     * @When I set its :attribute attribute to :value in :language
477
     */
478
    public function iSetItsAttributeTo($attribute, $value, $language = 'en_US')
479
    {
480
        $this->createSimpleProductPage->addAttribute($attribute, $value, $language);
481
    }
482
483
    /**
484
     * @When I remove its :attribute attribute
485
     * @When I remove its :attribute attribute from :language
486
     */
487
    public function iRemoveItsAttribute($attribute, $language = 'en_US')
488
    {
489
        $this->createSimpleProductPage->removeAttribute($attribute, $language);
490
    }
491
492
    /**
493
     * @When I try to add new attributes
494
     */
495
    public function iTryToAddNewAttributes()
496
    {
497
        $this->updateSimpleProductPage->addSelectedAttributes();
498
    }
499
500
    /**
501
     * @When I do not want to have shipping required for this product
502
     */
503
    public function iDoNotWantToHaveShippingRequiredForThisProduct()
504
    {
505
        $this->createSimpleProductPage->setShippingRequired(false);
506
    }
507
508
    /**
509
     * @Then attribute :attributeName of product :product should be :value
510
     * @Then attribute :attributeName of product :product should be :value in :language
511
     */
512
    public function itsAttributeShouldBe($attributeName, ProductInterface $product, $value, $language = 'en_US')
513
    {
514
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
515
516
        Assert::same($this->updateSimpleProductPage->getAttributeValue($attributeName, $language), $value);
517
    }
518
519
    /**
520
     * @Then /^(product "[^"]+") should not have a "([^"]+)" attribute$/
521
     */
522
    public function productShouldNotHaveAttribute(ProductInterface $product, $attribute)
523
    {
524
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
525
526
        Assert::false($this->updateSimpleProductPage->hasAttribute($attribute));
527
    }
528
529
    /**
530
     * @Then /^product "[^"]+" should not have any attributes$/
531
     * @Then /^product "[^"]+" should have (\d+) attributes?$/
532
     */
533
    public function productShouldNotHaveAnyAttributes($count = 0)
534
    {
535
        Assert::same($this->updateSimpleProductPage->getNumberOfAttributes(), (int) $count);
536
    }
537
538
    /**
539
     * @Given product with :element :value should not be added
540
     */
541
    public function productWithNameShouldNotBeAdded($element, $value)
542
    {
543
        $this->iWantToBrowseProducts();
544
545
        Assert::false($this->indexPage->isSingleResourceOnPage([$element => $value]));
546
    }
547
548
    /**
549
     * @When I remove its name from :language translation
550
     */
551
    public function iRemoveItsNameFromTranslation($language)
552
    {
553
        $currentPage = $this->resolveCurrentPage();
554
555
        $currentPage->nameItIn('', $language);
556
    }
557
558
    /**
559
     * @Then /^this product should have (?:a|an) "([^"]+)" option$/
560
     */
561
    public function thisProductShouldHaveOption($productOption)
562
    {
563
        $this->updateConfigurableProductPage->isProductOptionChosen($productOption);
564
    }
565
566
    /**
567
     * @Then the option field should be disabled
568
     */
569
    public function theOptionFieldShouldBeDisabled()
570
    {
571
        Assert::true($this->updateConfigurableProductPage->isProductOptionsDisabled());
572
    }
573
574
    /**
575
     * @When /^I choose main (taxon "[^"]+")$/
576
     */
577
    public function iChooseMainTaxon(TaxonInterface $taxon)
578
    {
579
        $currentPage = $this->resolveCurrentPage();
580
581
        $currentPage->selectMainTaxon($taxon);
582
    }
583
584
    /**
585
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)"$/
586
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)" (in the "[^"]+" locale)$/
587
     */
588
    public function productSlugShouldBe(ProductInterface $product, $slug, $locale = 'en_US')
589
    {
590
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
591
592
        Assert::same($this->updateSimpleProductPage->getSlug($locale), $slug);
593
    }
594
595
    /**
596
     * @Then /^(this product) main taxon should be "([^"]+)"$/
597
     */
598
    public function thisProductMainTaxonShouldBe(ProductInterface $product, $taxonName)
599
    {
600
        $currentPage = $this->resolveCurrentPage();
601
        $currentPage->open(['id' => $product->getId()]);
602
603
        Assert::true($currentPage->isMainTaxonChosen($taxonName));
604
    }
605
606
    /**
607
     * @Then /^inventory of (this product) should not be tracked$/
608
     */
609
    public function thisProductShouldNotBeTracked(ProductInterface $product)
610
    {
611
        $this->iWantToModifyAProduct($product);
612
613
        Assert::false($this->updateSimpleProductPage->isTracked());
614
    }
615
616
    /**
617
     * @Then /^inventory of (this product) should be tracked$/
618
     */
619
    public function thisProductShouldBeTracked(ProductInterface $product)
620
    {
621
        $this->iWantToModifyAProduct($product);
622
623
        Assert::true($this->updateSimpleProductPage->isTracked());
624
    }
625
626
    /**
627
     * @When I attach the :path image with :type type
628
     * @When I attach the :path image
629
     */
630
    public function iAttachImageWithType($path, $type = null)
631
    {
632
        $currentPage = $this->resolveCurrentPage();
633
634
        $currentPage->attachImage($path, $type);
635
    }
636
637
    /**
638
     * @When I associate as :productAssociationType the :productName product
639
     * @When I associate as :productAssociationType the :firstProductName and :secondProductName products
640
     */
641
    public function iAssociateProductsAsProductAssociation(
642
        ProductAssociationTypeInterface $productAssociationType,
643
        ...$productsNames
644
    ) {
645
        $currentPage = $this->resolveCurrentPage();
646
647
        $currentPage->associateProducts($productAssociationType, $productsNames);
648
    }
649
650
    /**
651
     * @When I remove an associated product :productName from :productAssociationType
652
     */
653
    public function iRemoveAnAssociatedProductFromProductAssociation(
654
        $productName,
655
        ProductAssociationTypeInterface $productAssociationType
656
    ) {
657
        $currentPage = $this->resolveCurrentPage();
658
659
        $currentPage->removeAssociatedProduct($productName, $productAssociationType);
660
    }
661
662
    /**
663
     * @Then /^(?:this product|the product "[^"]+"|it) should(?:| also) have an image with "([^"]*)" type$/
664
     */
665
    public function thisProductShouldHaveAnImageWithType($type)
666
    {
667
        $currentPage = $this->resolveCurrentPage();
668
669
        Assert::true($currentPage->isImageWithTypeDisplayed($type));
670
    }
671
672
    /**
673
     * @Then /^(?:this product|it)(?:| also) should not have any images with "([^"]*)" type$/
674
     */
675
    public function thisProductShouldNotHaveAnyImagesWithType($code)
676
    {
677
        $currentPage = $this->resolveCurrentPage();
678
679
        Assert::false($currentPage->isImageWithTypeDisplayed($code));
680
    }
681
682
    /**
683
     * @When I change the image with the :type type to :path
684
     */
685
    public function iChangeItsImageToPathForTheType($type, $path)
686
    {
687
        $currentPage = $this->resolveCurrentPage();
688
689
        $currentPage->changeImageWithType($type, $path);
690
    }
691
692
    /**
693
     * @When /^I(?:| also) remove an image with "([^"]*)" type$/
694
     */
695
    public function iRemoveAnImageWithType($code)
696
    {
697
        $currentPage = $this->resolveCurrentPage();
698
699
        $currentPage->removeImageWithType($code);
700
    }
701
702
    /**
703
     * @When I remove the first image
704
     */
705
    public function iRemoveTheFirstImage()
706
    {
707
        $currentPage = $this->resolveCurrentPage();
708
709
        $currentPage->removeFirstImage();
710
    }
711
712
    /**
713
     * @When I change the first image type to :type
714
     */
715
    public function iChangeTheFirstImageTypeTo($type)
716
    {
717
        $currentPage = $this->resolveCurrentPage();
718
719
        $currentPage->modifyFirstImageType($type);
720
    }
721
722
    /**
723
     * @Then /^(this product) should not have any images$/
724
     */
725
    public function thisProductShouldNotHaveImages(ProductInterface $product)
726
    {
727
        $this->iWantToModifyAProduct($product);
728
729
        $currentPage = $this->resolveCurrentPage();
730
731
        Assert::same($currentPage->countImages(), 0);
732
    }
733
734
    /**
735
     * @Then /^(this product) should(?:| still) have (?:only one|(\d+)) images?$/
736
     */
737
    public function thereShouldStillBeOnlyOneImageInThisProduct(ProductInterface $product, $count = 1)
738
    {
739
        $this->iWantToModifyAProduct($product);
740
741
        $currentPage = $this->resolveCurrentPage();
742
743
        Assert::same($currentPage->countImages(), (int) $count);
744
    }
745
746
    /**
747
     * @Then /^there should be no reviews of (this product)$/
748
     */
749
    public function thereAreNoProductReviews(ProductInterface $product)
750
    {
751
        $this->productReviewIndexPage->open();
752
753
        Assert::false($this->productReviewIndexPage->isSingleResourceOnPage(['reviewSubject' => $product->getName()]));
754
    }
755
756
    /**
757
     * @Then this product should( also) have an association :productAssociationType with product :productName
758
     * @Then this product should( also) have an association :productAssociationType with products :firstProductName and :secondProductName
759
     */
760
    public function theProductShouldHaveAnAssociationWithProducts(
761
        ProductAssociationTypeInterface $productAssociationType,
762
        ...$productsNames
763
    ) {
764
        foreach ($productsNames as $productName) {
765
            Assert::true(
766
                $this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType),
767
                sprintf(
768
                    'This product should have an association %s with product %s.',
769
                    $productAssociationType->getName(),
770
                    $productName
771
                )
772
            );
773
        }
774
    }
775
776
    /**
777
     * @Then this product should not have an association :productAssociationType with product :productName
778
     */
779
    public function theProductShouldNotHaveAnAssociationWithProduct(
780
        ProductAssociationTypeInterface $productAssociationType,
781
        $productName
782
    ) {
783
        Assert::false($this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType));
784
    }
785
786
    /**
787
     * @Then I should be notified that simple product code has to be unique
788
     */
789
    public function iShouldBeNotifiedThatSimpleProductCodeHasToBeUnique()
790
    {
791
        $this->assertValidationMessage('code', 'Simple product code must be unique among all products and product variants.');
792
    }
793
794
    /**
795
     * @Then I should be notified that slug has to be unique
796
     */
797
    public function iShouldBeNotifiedThatSlugHasToBeUnique()
798
    {
799
        $this->assertValidationMessage('slug', 'Product slug must be unique.');
800
    }
801
802
    /**
803
     * @Then I should be notified that code has to be unique
804
     */
805
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
806
    {
807
        $this->assertValidationMessage('code', 'Product code must be unique.');
808
    }
809
810
    /**
811
     * @Then I should be notified that price must be defined for every channel
812
     */
813
    public function iShouldBeNotifiedThatPriceMustBeDefinedForEveryChannel()
814
    {
815
        $this->assertValidationMessage('channel_pricings', 'You must define price for every channel.');
816
    }
817
818
    /**
819
     * @Then they should have order like :firstProductName, :secondProductName and :thirdProductName
820
     */
821
    public function theyShouldHaveOrderLikeAnd(...$productNames)
822
    {
823
        Assert::true($this->indexPerTaxonPage->hasProductsInOrder($productNames));
824
    }
825
826
    /**
827
     * @When I save my new configuration
828
     */
829
    public function iSaveMyNewConfiguration()
830
    {
831
        $this->indexPerTaxonPage->savePositions();
832
    }
833
834
    /**
835
     * @When I set the position of :productName to :position
836
     */
837
    public function iSetThePositionOfTo($productName, $position)
838
    {
839
        $this->indexPerTaxonPage->setPositionOfProduct($productName, (int) $position);
840
    }
841
842
    /**
843
     * @Then this product should( still) have slug :value in :language
844
     */
845
    public function thisProductElementShouldHaveSlugIn($slug, $language)
846
    {
847
        Assert::same($this->updateSimpleProductPage->getSlug($language), $slug);
848
    }
849
850
    /**
851
     * @When I set its shipping category as :shippingCategoryName
852
     */
853
    public function iSetItsShippingCategoryAs($shippingCategoryName)
854
    {
855
        $this->createSimpleProductPage->selectShippingCategory($shippingCategoryName);
856
    }
857
858
    /**
859
     * @Then /^(it|this product) should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
860
     * @Then /^(product "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
861
     */
862
    public function itShouldBePricedAtForChannel(ProductInterface $product, $price, $channelName)
863
    {
864
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
865
866
        Assert::same($this->updateSimpleProductPage->getPriceForChannel($channelName), $price);
867
    }
868
869
    /**
870
     * @Then /^(its|this products) original price should be "(?:€|£|\$)([^"]+)" for channel "([^"]+)"$/
871
     */
872
    public function itsOriginalPriceForChannel(ProductInterface $product, $originalPrice, $channelName)
873
    {
874
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
875
876
        Assert::same(
877
            $this->updateSimpleProductPage->getOriginalPriceForChannel($channelName),
878
            $originalPrice
879
        );
880
    }
881
882
    /**
883
     * @Then /^(this product) should no longer have price for channel "([^"]+)"$/
884
     */
885
    public function thisProductShouldNoLongerHavePriceForChannel(ProductInterface $product, $channelName)
886
    {
887
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
888
889
        try {
890
            $this->updateSimpleProductPage->getPriceForChannel($channelName);
891
        } catch (ElementNotFoundException $exception) {
892
            return;
893
        }
894
895
        throw new \Exception(
896
            sprintf('Product "%s" should not have price defined for channel "%s".', $product->getName(), $channelName)
897
        );
898
    }
899
900
    /**
901
     * @Then I should be notified that I have to define product variants' prices for newly assigned channels first
902
     */
903
    public function iShouldBeNotifiedThatIHaveToDefineProductVariantsPricesForNewlyAssignedChannelsFirst()
904
    {
905
        Assert::same(
906
            $this->updateConfigurableProductPage->getValidationMessage('channels'),
907
            'You have to define product variants\' prices for newly assigned channels first.'
908
        );
909
    }
910
911
    /**
912
     * @Then /^the (product "[^"]+") should not have shipping required$/
913
     */
914
    public function theProductWithCodeShouldNotHaveShippingRequired(ProductInterface $product)
915
    {
916
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
917
918
        Assert::false($this->updateSimpleProductPage->isShippingRequired());
919
    }
920
921
    /**
922
     * @param string $element
923
     * @param string $value
924
     */
925
    private function assertElementValue($element, $value)
926
    {
927
        /** @var UpdatePageInterface $currentPage */
928
        $currentPage = $this->resolveCurrentPage();
929
930
        Assert::isInstanceOf($currentPage, UpdatePageInterface::class);
931
932
        Assert::true(
933
            $currentPage->hasResourceValues([$element => $value]),
934
            sprintf('Product should have %s with %s value.', $element, $value)
935
        );
936
    }
937
938
    /**
939
     * @param string $element
940
     * @param string $message
941
     */
942
    private function assertValidationMessage($element, $message)
943
    {
944
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
945
        $currentPage = $this->resolveCurrentPage();
946
947
        Assert::same($currentPage->getValidationMessage($element), $message);
948
    }
949
950
    /**
951
     * @return SymfonyPageInterface|IndexPageInterface|IndexPerTaxonPageInterface|CreateSimpleProductPageInterface|CreateConfigurableProductPageInterface|UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface
952
     */
953
    private function resolveCurrentPage()
954
    {
955
        return $this->currentPageResolver->getCurrentPageWithForm([
956
            $this->indexPage,
957
            $this->indexPerTaxonPage,
958
            $this->createSimpleProductPage,
959
            $this->createConfigurableProductPage,
960
            $this->updateSimpleProductPage,
961
            $this->updateConfigurableProductPage,
962
        ]);
963
    }
964
}
965