Completed
Push — master ( a026a7...7ff053 )
by Kamil
21s
created

iChangeItsOriginalPriceTo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
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