Completed
Push — master ( a026a7...7ff053 )
by Kamil
21s
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
     * @Then attribute :attributeName of product :product should be :value
502
     * @Then attribute :attributeName of product :product should be :value in :language
503
     */
504
    public function itsAttributeShouldBe($attributeName, ProductInterface $product, $value, $language = 'en_US')
505
    {
506
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
507
508
        Assert::same($this->updateSimpleProductPage->getAttributeValue($attributeName, $language), $value);
509
    }
510
511
    /**
512
     * @Then /^(product "[^"]+") should not have a "([^"]+)" attribute$/
513
     */
514
    public function productShouldNotHaveAttribute(ProductInterface $product, $attribute)
515
    {
516
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
517
518
        Assert::false($this->updateSimpleProductPage->hasAttribute($attribute));
519
    }
520
521
    /**
522
     * @Then /^product "[^"]+" should not have any attributes$/
523
     * @Then /^product "[^"]+" should have (\d+) attributes?$/
524
     */
525
    public function productShouldNotHaveAnyAttributes($count = 0)
526
    {
527
        Assert::same($this->updateSimpleProductPage->getNumberOfAttributes(), (int) $count);
528
    }
529
530
    /**
531
     * @Given product with :element :value should not be added
532
     */
533
    public function productWithNameShouldNotBeAdded($element, $value)
534
    {
535
        $this->iWantToBrowseProducts();
536
537
        Assert::false($this->indexPage->isSingleResourceOnPage([$element => $value]));
538
    }
539
540
    /**
541
     * @When I remove its name from :language translation
542
     */
543
    public function iRemoveItsNameFromTranslation($language)
544
    {
545
        $currentPage = $this->resolveCurrentPage();
546
547
        $currentPage->nameItIn('', $language);
548
    }
549
550
    /**
551
     * @Then /^this product should have (?:a|an) "([^"]+)" option$/
552
     */
553
    public function thisProductShouldHaveOption($productOption)
554
    {
555
        $this->updateConfigurableProductPage->isProductOptionChosen($productOption);
556
    }
557
558
    /**
559
     * @Then the option field should be disabled
560
     */
561
    public function theOptionFieldShouldBeDisabled()
562
    {
563
        Assert::true($this->updateConfigurableProductPage->isProductOptionsDisabled());
564
    }
565
566
    /**
567
     * @When /^I choose main (taxon "[^"]+")$/
568
     */
569
    public function iChooseMainTaxon(TaxonInterface $taxon)
570
    {
571
        $currentPage = $this->resolveCurrentPage();
572
573
        $currentPage->selectMainTaxon($taxon);
574
    }
575
576
    /**
577
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)"$/
578
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)" (in the "[^"]+" locale)$/
579
     */
580
    public function productSlugShouldBe(ProductInterface $product, $slug, $locale = 'en_US')
581
    {
582
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
583
584
        Assert::same($this->updateSimpleProductPage->getSlug($locale), $slug);
585
    }
586
587
    /**
588
     * @Then /^(this product) main taxon should be "([^"]+)"$/
589
     */
590
    public function thisProductMainTaxonShouldBe(ProductInterface $product, $taxonName)
591
    {
592
        $currentPage = $this->resolveCurrentPage();
593
        $currentPage->open(['id' => $product->getId()]);
594
595
        Assert::true($currentPage->isMainTaxonChosen($taxonName));
596
    }
597
598
    /**
599
     * @Then /^inventory of (this product) should not be tracked$/
600
     */
601
    public function thisProductShouldNotBeTracked(ProductInterface $product)
602
    {
603
        $this->iWantToModifyAProduct($product);
604
605
        Assert::false($this->updateSimpleProductPage->isTracked());
606
    }
607
608
    /**
609
     * @Then /^inventory of (this product) should be tracked$/
610
     */
611
    public function thisProductShouldBeTracked(ProductInterface $product)
612
    {
613
        $this->iWantToModifyAProduct($product);
614
615
        Assert::true($this->updateSimpleProductPage->isTracked());
616
    }
617
618
    /**
619
     * @When I attach the :path image with :type type
620
     * @When I attach the :path image
621
     */
622
    public function iAttachImageWithType($path, $type = null)
623
    {
624
        $currentPage = $this->resolveCurrentPage();
625
626
        $currentPage->attachImage($path, $type);
627
    }
628
629
    /**
630
     * @When I associate as :productAssociationType the :productName product
631
     * @When I associate as :productAssociationType the :firstProductName and :secondProductName products
632
     */
633
    public function iAssociateProductsAsProductAssociation(
634
        ProductAssociationTypeInterface $productAssociationType,
635
        ...$productsNames
636
    ) {
637
        $currentPage = $this->resolveCurrentPage();
638
639
        $currentPage->associateProducts($productAssociationType, $productsNames);
640
    }
641
642
    /**
643
     * @When I remove an associated product :productName from :productAssociationType
644
     */
645
    public function iRemoveAnAssociatedProductFromProductAssociation(
646
        $productName,
647
        ProductAssociationTypeInterface $productAssociationType
648
    ) {
649
        $currentPage = $this->resolveCurrentPage();
650
651
        $currentPage->removeAssociatedProduct($productName, $productAssociationType);
652
    }
653
654
    /**
655
     * @Then /^(?:this product|the product "[^"]+"|it) should(?:| also) have an image with "([^"]*)" type$/
656
     */
657
    public function thisProductShouldHaveAnImageWithType($type)
658
    {
659
        $currentPage = $this->resolveCurrentPage();
660
661
        Assert::true($currentPage->isImageWithTypeDisplayed($type));
662
    }
663
664
    /**
665
     * @Then /^(?:this product|it)(?:| also) should not have any images with "([^"]*)" type$/
666
     */
667
    public function thisProductShouldNotHaveAnyImagesWithType($code)
668
    {
669
        $currentPage = $this->resolveCurrentPage();
670
671
        Assert::false($currentPage->isImageWithTypeDisplayed($code));
672
    }
673
674
    /**
675
     * @When I change the image with the :type type to :path
676
     */
677
    public function iChangeItsImageToPathForTheType($type, $path)
678
    {
679
        $currentPage = $this->resolveCurrentPage();
680
681
        $currentPage->changeImageWithType($type, $path);
682
    }
683
684
    /**
685
     * @When /^I(?:| also) remove an image with "([^"]*)" type$/
686
     */
687
    public function iRemoveAnImageWithType($code)
688
    {
689
        $currentPage = $this->resolveCurrentPage();
690
691
        $currentPage->removeImageWithType($code);
692
    }
693
694
    /**
695
     * @When I remove the first image
696
     */
697
    public function iRemoveTheFirstImage()
698
    {
699
        $currentPage = $this->resolveCurrentPage();
700
701
        $currentPage->removeFirstImage();
702
    }
703
704
    /**
705
     * @When I change the first image type to :type
706
     */
707
    public function iChangeTheFirstImageTypeTo($type)
708
    {
709
        $currentPage = $this->resolveCurrentPage();
710
711
        $currentPage->modifyFirstImageType($type);
712
    }
713
714
    /**
715
     * @Then /^(this product) should not have any images$/
716
     */
717
    public function thisProductShouldNotHaveImages(ProductInterface $product)
718
    {
719
        $this->iWantToModifyAProduct($product);
720
721
        $currentPage = $this->resolveCurrentPage();
722
723
        Assert::same($currentPage->countImages(), 0);
724
    }
725
726
    /**
727
     * @Then /^(this product) should(?:| still) have (?:only one|(\d+)) images?$/
728
     */
729
    public function thereShouldStillBeOnlyOneImageInThisProduct(ProductInterface $product, $count = 1)
730
    {
731
        $this->iWantToModifyAProduct($product);
732
733
        $currentPage = $this->resolveCurrentPage();
734
735
        Assert::same($currentPage->countImages(), (int) $count);
736
    }
737
738
    /**
739
     * @Then /^there should be no reviews of (this product)$/
740
     */
741
    public function thereAreNoProductReviews(ProductInterface $product)
742
    {
743
        $this->productReviewIndexPage->open();
744
745
        Assert::false($this->productReviewIndexPage->isSingleResourceOnPage(['reviewSubject' => $product->getName()]));
746
    }
747
748
    /**
749
     * @Then this product should( also) have an association :productAssociationType with product :productName
750
     * @Then this product should( also) have an association :productAssociationType with products :firstProductName and :secondProductName
751
     */
752
    public function theProductShouldHaveAnAssociationWithProducts(
753
        ProductAssociationTypeInterface $productAssociationType,
754
        ...$productsNames
755
    ) {
756
        foreach ($productsNames as $productName) {
757
            Assert::true(
758
                $this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType),
759
                sprintf(
760
                    'This product should have an association %s with product %s.',
761
                    $productAssociationType->getName(),
762
                    $productName
763
                )
764
            );
765
        }
766
    }
767
768
    /**
769
     * @Then this product should not have an association :productAssociationType with product :productName
770
     */
771
    public function theProductShouldNotHaveAnAssociationWithProduct(
772
        ProductAssociationTypeInterface $productAssociationType,
773
        $productName
774
    ) {
775
        Assert::false($this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType));
776
    }
777
778
    /**
779
     * @Then I should be notified that simple product code has to be unique
780
     */
781
    public function iShouldBeNotifiedThatSimpleProductCodeHasToBeUnique()
782
    {
783
        $this->assertValidationMessage('code', 'Simple product code must be unique among all products and product variants.');
784
    }
785
786
    /**
787
     * @Then I should be notified that slug has to be unique
788
     */
789
    public function iShouldBeNotifiedThatSlugHasToBeUnique()
790
    {
791
        $this->assertValidationMessage('slug', 'Product slug must be unique.');
792
    }
793
794
    /**
795
     * @Then I should be notified that code has to be unique
796
     */
797
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
798
    {
799
        $this->assertValidationMessage('code', 'Product code must be unique.');
800
    }
801
802
    /**
803
     * @Then I should be notified that price must be defined for every channel
804
     */
805
    public function iShouldBeNotifiedThatPriceMustBeDefinedForEveryChannel()
806
    {
807
        $this->assertValidationMessage('channel_pricings', 'You must define price for every channel.');
808
    }
809
810
    /**
811
     * @Then they should have order like :firstProductName, :secondProductName and :thirdProductName
812
     */
813
    public function theyShouldHaveOrderLikeAnd(...$productNames)
814
    {
815
        Assert::true($this->indexPerTaxonPage->hasProductsInOrder($productNames));
816
    }
817
818
    /**
819
     * @When I save my new configuration
820
     */
821
    public function iSaveMyNewConfiguration()
822
    {
823
        $this->indexPerTaxonPage->savePositions();
824
    }
825
826
    /**
827
     * @When I set the position of :productName to :position
828
     */
829
    public function iSetThePositionOfTo($productName, $position)
830
    {
831
        $this->indexPerTaxonPage->setPositionOfProduct($productName, (int) $position);
832
    }
833
834
    /**
835
     * @Then this product should( still) have slug :value in :language
836
     */
837
    public function thisProductElementShouldHaveSlugIn($slug, $language)
838
    {
839
        Assert::same($this->updateSimpleProductPage->getSlug($language), $slug);
840
    }
841
842
    /**
843
     * @When I set its shipping category as :shippingCategoryName
844
     */
845
    public function iSetItsShippingCategoryAs($shippingCategoryName)
846
    {
847
        $this->createSimpleProductPage->selectShippingCategory($shippingCategoryName);
848
    }
849
850
    /**
851
     * @Then /^(it|this product) should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
852
     * @Then /^(product "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
853
     */
854
    public function itShouldBePricedAtForChannel(ProductInterface $product, $price, $channelName)
855
    {
856
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
857
858
        Assert::same($this->updateSimpleProductPage->getPriceForChannel($channelName), $price);
859
    }
860
861
    /**
862
     * @Then /^(its|this products) original price should be "(?:€|£|\$)([^"]+)" for channel "([^"]+)"$/
863
     */
864
    public function itsOriginalPriceForChannel(ProductInterface $product, $originalPrice, $channelName)
865
    {
866
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
867
868
        Assert::same(
869
            $this->updateSimpleProductPage->getOriginalPriceForChannel($channelName),
870
            $originalPrice
871
        );
872
    }
873
874
    /**
875
     * @Then /^(this product) should no longer have price for channel "([^"]+)"$/
876
     */
877
    public function thisProductShouldNoLongerHavePriceForChannel(ProductInterface $product, $channelName)
878
    {
879
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
880
881
        try {
882
            $this->updateSimpleProductPage->getPriceForChannel($channelName);
883
        } catch (ElementNotFoundException $exception) {
884
            return;
885
        }
886
887
        throw new \Exception(
888
            sprintf('Product "%s" should not have price defined for channel "%s".', $product->getName(), $channelName)
889
        );
890
    }
891
892
    /**
893
     * @Then I should be notified that I have to define product variants' prices for newly assigned channels first
894
     */
895
    public function iShouldBeNotifiedThatIHaveToDefineProductVariantsPricesForNewlyAssignedChannelsFirst()
896
    {
897
        Assert::same(
898
            $this->updateConfigurableProductPage->getValidationMessage('channels'),
899
            'You have to define product variants\' prices for newly assigned channels first.'
900
        );
901
    }
902
903
    /**
904
     * @param string $element
905
     * @param string $value
906
     */
907
    private function assertElementValue($element, $value)
908
    {
909
        /** @var UpdatePageInterface $currentPage */
910
        $currentPage = $this->resolveCurrentPage();
911
912
        Assert::isInstanceOf($currentPage, UpdatePageInterface::class);
913
914
        Assert::true(
915
            $currentPage->hasResourceValues([$element => $value]),
916
            sprintf('Product should have %s with %s value.', $element, $value)
917
        );
918
    }
919
920
    /**
921
     * @param string $element
922
     * @param string $message
923
     */
924
    private function assertValidationMessage($element, $message)
925
    {
926
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
927
        $currentPage = $this->resolveCurrentPage();
928
929
        Assert::same($currentPage->getValidationMessage($element), $message);
930
    }
931
932
    /**
933
     * @return SymfonyPageInterface|IndexPageInterface|IndexPerTaxonPageInterface|CreateSimpleProductPageInterface|CreateConfigurableProductPageInterface|UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface
934
     */
935
    private function resolveCurrentPage()
936
    {
937
        return $this->currentPageResolver->getCurrentPageWithForm([
938
            $this->indexPage,
939
            $this->indexPerTaxonPage,
940
            $this->createSimpleProductPage,
941
            $this->createConfigurableProductPage,
942
            $this->updateSimpleProductPage,
943
            $this->updateConfigurableProductPage,
944
        ]);
945
    }
946
}
947