Completed
Push — locale-in-url ( c8ed20...ec55a8 )
by Kamil
46:19 queued 21:47
created

iAttachImageWithoutACode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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