Completed
Push — master ( 968507...279808 )
by Paweł
10:20
created

theProductWithCodeShouldNotHaveShippingRequired()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
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