Completed
Push — remove-content-bundle ( fd7705...1b4274 )
by Kamil
18:36
created

ManagingProductsContext::iChooseCalculator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
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 Sylius\Behat\NotificationType;
16
use Sylius\Behat\Page\Admin\Crud\CreatePageInterface;
17
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface;
18
use Sylius\Behat\Page\Admin\Product\CreateConfigurableProductPageInterface;
19
use Sylius\Behat\Page\Admin\Product\CreateSimpleProductPageInterface;
20
use Sylius\Behat\Page\Admin\Product\IndexPageInterface;
21
use Sylius\Behat\Page\Admin\Product\UpdateConfigurableProductPageInterface;
22
use Sylius\Behat\Page\Admin\Product\UpdateSimpleProductPageInterface;
23
use Sylius\Behat\Page\Admin\ProductReview\IndexPageInterface as ProductReviewIndexPageInterface;
24
use Sylius\Behat\Service\NotificationCheckerInterface;
25
use Sylius\Behat\Service\Resolver\CurrentProductPageResolverInterface;
26
use Sylius\Component\Core\Model\ChannelInterface;
27
use Sylius\Component\Core\Model\ProductInterface;
28
use Sylius\Behat\Service\SharedStorageInterface;
29
use Sylius\Component\Currency\Model\CurrencyInterface;
30
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
31
use Sylius\Component\Taxonomy\Model\TaxonInterface;
32
use Webmozart\Assert\Assert;
33
34
/**
35
 * @author Kamil Kokot <[email protected]>
36
 * @author Magdalena Banasiak <[email protected]>
37
 * @author Łukasz Chruściel <[email protected]>
38
 */
39
final class ManagingProductsContext implements Context
40
{
41
    /**
42
     * @var SharedStorageInterface
43
     */
44
    private $sharedStorage;
45
46
    /**x
47
     * @var CreateSimpleProductPageInterface
48
     */
49
    private $createSimpleProductPage;
50
51
    /**
52
     * @var CreateConfigurableProductPageInterface
53
     */
54
    private $createConfigurableProductPage;
55
56
    /**
57
     * @var IndexPageInterface
58
     */
59
    private $indexPage;
60
61
    /**
62
     * @var UpdateSimpleProductPageInterface
63
     */
64
    private $updateSimpleProductPage;
65
66
    /**
67
     * @var UpdateConfigurableProductPageInterface
68
     */
69
    private $updateConfigurableProductPage;
70
71
    /**
72
     * @var ProductReviewIndexPageInterface
73
     */
74
    private $productReviewIndexPage;
75
76
    /**
77
     * @var CurrentProductPageResolverInterface
78
     */
79
    private $currentPageResolver;
80
81
    /**
82
     * @var NotificationCheckerInterface
83
     */
84
    private $notificationChecker;
85
86
    /**
87
     * @param SharedStorageInterface $sharedStorage
88
     * @param CreateSimpleProductPageInterface $createSimpleProductPage
89
     * @param CreateConfigurableProductPageInterface $createConfigurableProductPage
90
     * @param IndexPageInterface $indexPage
91
     * @param UpdateSimpleProductPageInterface $updateSimpleProductPage
92
     * @param UpdateConfigurableProductPageInterface $updateConfigurableProductPage
93
     * @param ProductReviewIndexPageInterface $productReviewIndexPage
94
     * @param CurrentProductPageResolverInterface $currentPageResolver
95
     * @param NotificationCheckerInterface $notificationChecker
96
     */
97
    public function __construct(
98
        SharedStorageInterface $sharedStorage,
99
        CreateSimpleProductPageInterface $createSimpleProductPage,
100
        CreateConfigurableProductPageInterface $createConfigurableProductPage,
101
        IndexPageInterface $indexPage,
102
        UpdateSimpleProductPageInterface $updateSimpleProductPage,
103
        UpdateConfigurableProductPageInterface $updateConfigurableProductPage,
104
        ProductReviewIndexPageInterface $productReviewIndexPage,
105
        CurrentProductPageResolverInterface $currentPageResolver,
106
        NotificationCheckerInterface $notificationChecker
107
    ) {
108
        $this->sharedStorage = $sharedStorage;
109
        $this->createSimpleProductPage = $createSimpleProductPage;
110
        $this->createConfigurableProductPage = $createConfigurableProductPage;
111
        $this->indexPage = $indexPage;
112
        $this->updateSimpleProductPage = $updateSimpleProductPage;
113
        $this->updateConfigurableProductPage = $updateConfigurableProductPage;
114
        $this->productReviewIndexPage = $productReviewIndexPage;
115
        $this->currentPageResolver = $currentPageResolver;
116
        $this->notificationChecker = $notificationChecker;
117
    }
118
119
    /**
120
     * @Given I want to create a new simple product
121
     */
122
    public function iWantToCreateANewSimpleProduct()
123
    {
124
        $this->createSimpleProductPage->open();
125
    }
126
127
    /**
128
     * @Given I want to create a new configurable product
129
     */
130
    public function iWantToCreateANewConfigurableProduct()
131
    {
132
        $this->createConfigurableProductPage->open();
133
    }
134
135
    /**
136
     * @When I specify its code as :code
137
     * @When I do not specify its code
138
     */
139
    public function iSpecifyItsCodeAs($code = null)
140
    {
141
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
142
            $this->createSimpleProductPage,
143
            $this->createConfigurableProductPage,
144
        ]);
145
146
        $currentPage->specifyCode($code);
147
    }
148
149
    /**
150
     * @When I name it :name in :language
151
     */
152
    public function iNameItIn($name, $language)
153
    {
154
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
155
            $this->createSimpleProductPage,
156
            $this->createConfigurableProductPage,
157
        ]);
158
159
        $currentPage->nameItIn($name, $language);
160
    }
161
162
    /**
163
     * @When I rename it to :name in :language
164
     */
165
    public function iRenameItToIn($name, $language)
166
    {
167
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
168
            $this->updateSimpleProductPage,
169
            $this->updateConfigurableProductPage,
170
        ], $this->sharedStorage->get('product'));
171
172
        $currentPage->nameItIn($name, $language);
173
    }
174
175
    /**
176
     * @When I add it
177
     * @When I try to add it
178
     */
179
    public function iAddIt()
180
    {
181
        /** @var CreatePageInterface $currentPage */
182
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
183
            $this->createSimpleProductPage,
184
            $this->createConfigurableProductPage,
185
        ]);
186
187
        Assert::isInstanceOf($currentPage, CreatePageInterface::class);
188
189
        $currentPage->create();
190
    }
191
192
    /**
193
     * @When I disable its inventory tracking
194
     */
195
    public function iDisableItsTracking()
196
    {
197
        $this->updateSimpleProductPage->disableTracking();
198
    }
199
200
    /**
201
     * @When I enable its inventory tracking
202
     */
203
    public function iEnableItsTracking()
204
    {
205
        $this->updateSimpleProductPage->enableTracking();
206
    }
207
208
    /**
209
     * @When /^I set its(?:| default) price to ("(?:€|£|\$)[^"]+")$/
210
     */
211
    public function iSetItsPriceTo($price)
212
    {
213
        $this->createSimpleProductPage->specifyPrice($price);
214
    }
215
216
    /**
217
     * @When I choose :calculatorName calculator
218
     */
219
    public function iChooseCalculator($calculatorName)
220
    {
221
        $this->createSimpleProductPage->choosePricingCalculator($calculatorName);
222
    }
223
224
    /**
225
     * @When /^I set its price to "(?:€|£|\$)([^"]+)" for ("[^"]+" currency) and ("[^"]+" channel)$/
226
     */
227
    public function iSetItsPriceToForCurrencyAndChannel($price, CurrencyInterface $currency, ChannelInterface $channel)
228
    {
229
        $this->createSimpleProductPage->specifyPriceForChannelAndCurrency($price, $channel, $currency);
230
    }
231
232
    /**
233
     * @When I set its slug to :slug
234
     * @When I remove its slug
235
     */
236
    public function iSetItsSlugTo($slug = null)
237
    {
238
        $this->createSimpleProductPage->specifySlug($slug);
239
    }
240
241
    /**
242
     * @When I enable slug modification
243
     */
244
    public function iEnableSlugModification()
245
    {
246
        $this->createSimpleProductPage->enableSlugModification();
247
    }
248
249
    /**
250
     * @Then the product :productName should appear in the shop
251
     * @Then the product :productName should be in the shop
252
     * @Then this product should still be named :productName
253
     */
254
    public function theProductShouldAppearInTheShop($productName)
255
    {
256
        $this->iWantToBrowseProducts();
257
258
        Assert::true(
259
            $this->indexPage->isSingleResourceOnPage(['name' => $productName]),
260
            sprintf('The product with name %s has not been found.', $productName)
261
        );
262
    }
263
264
    /**
265
     * @Given I am browsing products
266
     * @When I want to browse products
267
     */
268
    public function iWantToBrowseProducts()
269
    {
270
        $this->indexPage->open();
271
    }
272
273
    /**
274
     * @When I filter them by :taxonName taxon
275
     */
276
    public function iFilterThemByTaxon($taxonName)
277
    {
278
        $this->indexPage->filterByTaxon($taxonName);
279
    }
280
281
    /**
282
     * @Then I should( still) see a product with :field :value
283
     */
284
    public function iShouldSeeProductWith($field, $value)
285
    {
286
        Assert::true(
287
            $this->indexPage->isSingleResourceOnPage([$field => $value]),
288
            sprintf('The product with %s "%s" has not been found.', $field, $value)
289
        );
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(
298
            $this->indexPage->isSingleResourceOnPage([$field => $value]),
299
            sprintf('The product with %s "%s" has been found.', $field, $value)
300
        );
301
    }
302
303
    /**
304
     * @Then the first product on the list should have :field :value
305
     */
306
    public function theFirstProductOnTheListShouldHave($field, $value)
307
    {
308
        $actualValue = $this->indexPage->getColumnFields($field)[0];
309
310
        Assert::same(
311
            $actualValue,
312
            $value,
313
            sprintf('Expected first product\'s %s to be "%s", but it is "%s".', $field, $value, $actualValue)
314
        );
315
    }
316
317
    /**
318
     * @When I switch the way products are sorted by :field
319
     * @When I start sorting products by :field
320
     * @Given the products are already sorted by :field
321
     */
322
    public function iSortProductsBy($field)
323
    {
324
        $this->indexPage->sortBy($field);
325
    }
326
327
    /**
328
     * @Then I should see :numberOfProducts products in the list
329
     */
330
    public function iShouldSeeProductsInTheList($numberOfProducts)
331
    {
332
        $foundRows = $this->indexPage->countItems();
333
334
        Assert::same(
335
            (int) $numberOfProducts,
336
            $foundRows,
337
            '%s rows with products should appear on page, %s rows has been found'
338
        );
339
    }
340
341
    /**
342
     * @When I delete the :product product
343
     * @When I try to delete the :product product
344
     */
345
    public function iDeleteProduct(ProductInterface $product)
346
    {
347
        $this->sharedStorage->set('product', $product);
348
349
        $this->iWantToBrowseProducts();
350
        $this->indexPage->deleteResourceOnPage(['name' => $product->getName()]);
351
    }
352
353
    /**
354
     * @Then /^(this product) should not exist in the product catalog$/
355
     */
356
    public function productShouldNotExist(ProductInterface $product)
357
    {
358
        $this->iWantToBrowseProducts();
359
360
        Assert::false(
361
            $this->indexPage->isSingleResourceOnPage(['code' => $product->getCode()]),
362
            sprintf('Product with code %s exists but should not.', $product->getCode())
363
        );
364
    }
365
366
    /**
367
     * @Then I should be notified that this product is in use and cannot be deleted
368
     */
369
    public function iShouldBeNotifiedOfFailure()
370
    {
371
        $this->notificationChecker->checkNotification(
372
            "Cannot delete, the product is in use.",
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal Cannot delete, the product is in use. does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
373
            NotificationType::failure()
374
        );
375
    }
376
377
    /**
378
     * @Then /^(this product) should still exist in the product catalog$/
379
     */
380
    public function productShouldExistInTheProductCatalog(ProductInterface $product)
381
    {
382
        $this->theProductShouldAppearInTheShop($product->getName());
383
    }
384
385
    /**
386
     * @When I want to modify the :product product
387
     * @When /^I want to modify (this product)$/
388
     */
389
    public function iWantToModifyAProduct(ProductInterface $product)
390
    {
391
        $this->sharedStorage->set('product', $product);
392
393
        if ($product->isSimple()) {
394
            $this->updateSimpleProductPage->open(['id' => $product->getId()]);
395
            return;
396
        }
397
398
        $this->updateConfigurableProductPage->open(['id' => $product->getId()]);
399
    }
400
401
    /**
402
     * @Then the code field should be disabled
403
     */
404
    public function theCodeFieldShouldBeDisabled()
405
    {
406
        /** @var UpdatePageInterface $currentPage */
407
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
408
            $this->updateSimpleProductPage,
409
            $this->updateConfigurableProductPage,
410
        ], $this->sharedStorage->get('product'));
411
412
        Assert::true(
413
            $currentPage->isCodeDisabled(),
414
            'Code should be immutable, but it does not.'
415
        );
416
    }
417
418
    /**
419
     * @Then the slug field should not be editable
420
     */
421
    public function theSlugFieldShouldNotBeEditable()
422
    {
423
        Assert::true(
424
            $this->updateSimpleProductPage->isSlugReadOnly(),
425
            'Slug should be immutable, but it does not.'
426
        );
427
    }
428
429
    /**
430
     * @Then /^this product price should be "(?:€|£|\$)([^"]+)"$/
431
     */
432
    public function thisProductPriceShouldBeEqualTo($price)
433
    {
434
        $this->assertElementValue('price', $price);
435
    }
436
437
    /**
438
     * @Then this product name should be :name
439
     */
440
    public function thisProductElementShouldBe($name)
441
    {
442
        $this->assertElementValue('name', $name);
443
    }
444
445
    /**
446
     * @Then /^I should be notified that (code|name|slug) is required$/
447
     */
448
    public function iShouldBeNotifiedThatIsRequired($element)
449
    {
450
        $this->assertValidationMessage($element, sprintf('Please enter product %s.', $element));
451
    }
452
453
    /**
454
     * @Then I should be notified that price is required
455
     */
456
    public function iShouldBeNotifiedThatPriceIsRequired()
457
    {
458
        $this->assertValidationMessage('price', 'Please enter the price.');
459
    }
460
461
    /**
462
     * @When I save my changes
463
     * @When I try to save my changes
464
     */
465
    public function iSaveMyChanges()
466
    {
467
        /** @var UpdatePageInterface $currentPage */
468
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
469
            $this->updateSimpleProductPage,
470
            $this->updateConfigurableProductPage,
471
        ], $this->sharedStorage->get('product'));
472
473
        Assert::isInstanceOf($currentPage, UpdatePageInterface::class);
474
475
        $currentPage->saveChanges();
476
    }
477
478
    /**
479
     * @When /^I change its price to "(?:€|£|\$)([^"]+)"$/
480
     */
481
    public function iChangeItsPriceTo($price)
482
    {
483
        $this->updateSimpleProductPage->specifyPrice($price);
484
    }
485
486
    /**
487
     * @Given I add the :optionName option to it
488
     */
489
    public function iAddTheOptionToIt($optionName)
490
    {
491
        $this->createConfigurableProductPage->selectOption($optionName);
492
    }
493
494
    /**
495
     * @When I set its :attribute attribute to :value
496
     */
497
    public function iSetItsAttributeTo($attribute, $value)
498
    {
499
        $this->createSimpleProductPage->addAttribute($attribute, $value);
500
    }
501
502
    /**
503
     * @When I remove its :attribute attribute
504
     */
505
    public function iRemoveItsAttribute($attribute)
506
    {
507
        $this->createSimpleProductPage->removeAttribute($attribute);
508
    }
509
510
    /**
511
     * @Then /^attribute "([^"]+)" of (product "[^"]+") should be "([^"]+)"$/
512
     */
513
    public function itsAttributeShouldBe($attribute, ProductInterface $product, $value)
514
    {
515
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
516
517
        Assert::same(
518
            $value,
519
            $this->updateSimpleProductPage->getAttributeValue($attribute),
520
            sprintf('ProductAttribute "%s" should have value "%s" but it does not.', $attribute, $value)
521
        );
522
    }
523
524
    /**
525
     * @Then /^(product "[^"]+") should not have a "([^"]+)" attribute$/
526
     */
527
    public function productShouldNotHaveAttribute(ProductInterface $product, $attribute)
528
    {
529
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
530
531
        Assert::false(
532
            $this->updateSimpleProductPage->hasAttribute($attribute),
533
            sprintf('Product "%s" should not have attribute "%s" but it does.', $product->getName(), $attribute)
534
        );
535
    }
536
537
    /**
538
     * @Given product with :element :value should not be added
539
     */
540
    public function productWithNameShouldNotBeAdded($element, $value)
541
    {
542
        $this->iWantToBrowseProducts();
543
544
        Assert::false(
545
            $this->indexPage->isSingleResourceOnPage([$element => $value]),
546
            sprintf('Product with %s %s was created, but it should not.', $element, $value)
547
        );
548
    }
549
550
    /**
551
     * @When I remove its name from :language translation
552
     */
553
    public function iRemoveItsNameFromTranslation($language)
554
    {
555
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
556
            $this->updateSimpleProductPage,
557
            $this->updateConfigurableProductPage,
558
        ], $this->sharedStorage->get('product'));
559
560
        $currentPage->nameItIn('', $language);
561
    }
562
563
    /**
564
     * @Then /^this product should have (?:a|an) "([^"]+)" option$/
565
     */
566
    public function thisProductShouldHaveOption($productOption)
567
    {
568
        $this->updateConfigurableProductPage->isProductOptionChosen($productOption);
569
    }
570
571
    /**
572
     * @Then the option field should be disabled
573
     */
574
    public function theOptionFieldShouldBeDisabled()
575
    {
576
        Assert::true(
577
            $this->updateConfigurableProductPage->isProductOptionsDisabled(),
578
            'Options field should be immutable, but it does not.'
579
        );
580
    }
581
582
    /**
583
     * @When /^I choose main (taxon "([^"]+)")$/
584
     */
585
    public function iChooseMainTaxon(TaxonInterface $taxon)
586
    {
587
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
588
            $this->updateSimpleProductPage,
589
            $this->updateConfigurableProductPage,
590
        ], $this->sharedStorage->get('product'));
591
592
        $currentPage->selectMainTaxon($taxon);
593
    }
594
595
    /**
596
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)"$/
597
     */
598
    public function productSlugShouldBe(ProductInterface $product, $slug)
599
    {
600
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
601
602
        Assert::true(
603
            $this->updateSimpleProductPage->hasResourceValues(['slug' => $slug]),
604
            sprintf('Product\'s slug should be %s.', $slug)
605
        );
606
    }
607
608
    /**
609
     * @Then /^(this product) main taxon should be "([^"]+)"$/
610
     */
611
    public function thisProductMainTaxonShouldBe(ProductInterface $product, $taxonName)
612
    {
613
        /** @var UpdatePageInterface $currentPage */
614
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
615
            $this->updateSimpleProductPage,
616
            $this->updateConfigurableProductPage,
617
        ], $this->sharedStorage->get('product'));
618
619
        $currentPage->open(['id' => $product->getId()]);
620
621
        Assert::true(
622
            $this->updateConfigurableProductPage->isMainTaxonChosen($taxonName),
623
            sprintf('The main taxon %s should be chosen, but it does not.', $taxonName)
624
        );
625
    }
626
627
    /**
628
     * @Then /^inventory of (this product) should not be tracked$/
629
     */
630
    public function thisProductShouldNotBeTracked(ProductInterface $product)
631
    {
632
        $this->iWantToModifyAProduct($product);
633
634
        Assert::false(
635
            $this->updateSimpleProductPage->isTracked(),
636
            '"%s" should not be tracked, but it is.'
637
        );
638
    }
639
640
    /**
641
     * @Then /^inventory of (this product) should be tracked$/
642
     */
643
    public function thisProductShouldBeTracked(ProductInterface $product)
644
    {
645
        $this->iWantToModifyAProduct($product);
646
647
        Assert::true(
648
            $this->updateSimpleProductPage->isTracked(),
649
            '"%s" should be tracked, but it is not.'
650
        );
651
    }
652
653
    /**
654
     * @When I attach the :path image with a code :code
655
     */
656
    public function iAttachImageWithACode($path, $code)
657
    {
658
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
659
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
660
            $this->createSimpleProductPage,
661
            $this->createConfigurableProductPage,
662
            $this->updateSimpleProductPage,
663
            $this->updateConfigurableProductPage,
664
        ], $this->sharedStorage->has('product') ? $this->sharedStorage->get('product') : null);
665
666
        $currentPage->attachImage($path, $code);
667
    }
668
669
    /**
670
     * @When I attach the :path image without a code
671
     */
672
    public function iAttachImageWithoutACode($path)
673
    {
674
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
675
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
676
            $this->updateSimpleProductPage,
677
            $this->updateConfigurableProductPage,
678
        ], $this->sharedStorage->get('product'));
679
680
        $currentPage->attachImage($path);
681
    }
682
683
    /**
684
     * @When I associate as :productAssociationType the :productName product
685
     * @When I associate as :productAssociationType the :firstProductName and :secondProductName products
686
     */
687
    public function iAssociateProductsAsProductAssociation(
688
        ProductAssociationTypeInterface $productAssociationType,
689
        ...$productsNames
690
    ) {
691
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
692
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
693
            $this->createSimpleProductPage,
694
            $this->updateSimpleProductPage,
695
        ], $this->sharedStorage->get('product'));
696
697
        $currentPage->associateProducts($productAssociationType, $productsNames);
0 ignored issues
show
Bug introduced by
The method associateProducts does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...bleProductPageInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
698
    }
699
700
    /**
701
     * @When I remove an associated product :productName from :productAssociationType
702
     */
703
    public function iRemoveAnAssociatedProductFromProductAssociation(
704
        $productName,
705
        ProductAssociationTypeInterface $productAssociationType
706
    ) {
707
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
708
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
709
            $this->createSimpleProductPage,
710
            $this->updateSimpleProductPage,
711
        ], $this->sharedStorage->get('product'));
712
713
        $currentPage->removeAssociatedProduct($productName, $productAssociationType);
0 ignored issues
show
Bug introduced by
The method removeAssociatedProduct does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...bleProductPageInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
714
    }
715
716
    /**
717
     * @Then /^(this product) should have(?:| also) an image with a code "([^"]*)"$/
718
     * @Then /^the (product "[^"]+") should have(?:| also) an image with a code "([^"]*)"$/
719
     */
720
    public function thisProductShouldHaveAnImageWithCode(ProductInterface $product, $code)
721
    {
722
        $this->sharedStorage->set('product', $product);
723
724
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
725
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
726
            $this->updateSimpleProductPage,
727
            $this->updateConfigurableProductPage,
728
        ], $product);
729
730
        Assert::true(
731
            $currentPage->isImageWithCodeDisplayed($code),
732
            sprintf('Image with a code %s should have been displayed.', $code)
733
        );
734
    }
735
736
    /**
737
     * @Then /^(this product) should not have(?:| also) an image with a code "([^"]*)"$/
738
     */
739
    public function thisProductShouldNotHaveAnImageWithCode(ProductInterface $product, $code)
740
    {
741
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
742
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
743
            $this->updateSimpleProductPage,
744
            $this->updateConfigurableProductPage,
745
        ], $product);
746
747
        Assert::false(
748
            $currentPage->isImageWithCodeDisplayed($code),
749
            sprintf('Image with a code %s should not have been displayed.', $code)
750
        );
751
    }
752
753
    /**
754
     * @When I change the image with the :code code to :path
755
     */
756
    public function iChangeItsImageToPathForTheCode($path, $code)
757
    {
758
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
759
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
760
            $this->updateSimpleProductPage,
761
            $this->updateConfigurableProductPage,
762
        ], $this->sharedStorage->get('product'));
763
764
        $currentPage->changeImageWithCode($code, $path);
765
    }
766
767
    /**
768
     * @When /^I remove(?:| also) an image with a code "([^"]*)"$/
769
     */
770
    public function iRemoveAnImageWithACode($code)
771
    {
772
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
773
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
774
            $this->updateSimpleProductPage,
775
            $this->updateConfigurableProductPage,
776
        ], $this->sharedStorage->get('product'));
777
778
        $currentPage->removeImageWithCode($code);
779
    }
780
781
    /**
782
     * @When I remove the first image
783
     */
784
    public function iRemoveTheFirstImage()
785
    {
786
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
787
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
788
            $this->updateSimpleProductPage,
789
            $this->updateConfigurableProductPage,
790
        ], $this->sharedStorage->get('product'));
791
792
        $currentPage->removeFirstImage();
793
    }
794
795
    /**
796
     * @Then /^(this product) should not have any images$/
797
     */
798
    public function thisProductShouldNotHaveImages(ProductInterface $product)
799
    {
800
        $this->iWantToModifyAProduct($product);
801
802
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
803
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
804
            $this->updateSimpleProductPage,
805
            $this->updateConfigurableProductPage,
806
        ], $this->sharedStorage->get('product'));
807
808
        Assert::same(
809
            0,
810
            $currentPage->countImages(),
811
            'This product has %2$s, but it should not have.'
812
        );
813
    }
814
815
    /**
816
     * @Then the image code field should be disabled
817
     */
818
    public function theImageCodeFieldShouldBeDisabled()
819
    {
820
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
821
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
822
            $this->updateSimpleProductPage,
823
            $this->updateConfigurableProductPage,
824
        ], $this->sharedStorage->get('product'));
825
826
        Assert::true(
827
            $currentPage->isImageCodeDisabled(),
828
            'Image code field should be disabled but it is not.'
829
        );
830
    }
831
832
    /**
833
     * @Then I should be notified that the image with this code already exists
834
     */
835
    public function iShouldBeNotifiedThatTheImageWithThisCodeAlreadyExists()
836
    {
837
        Assert::same($this->updateSimpleProductPage->getValidationMessageForImage('code'), 'Image code must be unique within this product.');
0 ignored issues
show
Unused Code introduced by
The call to UpdateSimpleProductPageI...dationMessageForImage() has too many arguments starting with 'code'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
838
    }
839
840
    /**
841
     * @Then I should be notified that an image code is required
842
     */
843
    public function iShouldBeNotifiedThatAnImageCodeIsRequired()
844
    {
845
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
846
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
847
            $this->updateSimpleProductPage,
848
            $this->updateConfigurableProductPage,
849
        ], $this->sharedStorage->get('product'));
850
851
        Assert::same(
852
            $currentPage->getValidationMessageForImage(),
853
            'Please enter an image code.'
854
        );
855
    }
856
857
    /**
858
     * @Then there should still be only one image in the :product product
859
     */
860
    public function thereShouldStillBeOnlyOneImageInThisTaxon(ProductInterface $product)
861
    {
862
        $this->iWantToModifyAProduct($product);
863
864
        /** @var UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface $currentPage */
865
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
866
            $this->updateSimpleProductPage,
867
            $this->updateConfigurableProductPage,
868
        ], $product);
869
870
        Assert::same(
871
            1,
872
            $currentPage->countImages(),
873
            'This product has %2$s images, but it should have only one.'
874
        );
875
    }
876
877
    /**
878
     * @Then /^there should be no reviews of (this product)$/
879
     */
880
    public function thereAreNoProductReviews(ProductInterface $product)
881
    {
882
        $this->productReviewIndexPage->open();
883
884
        Assert::false(
885
            $this->productReviewIndexPage->isSingleResourceOnPage(['reviewSubject' => $product->getName()]),
886
            sprintf('There should be no reviews of %s.', $product->getName())
887
        );
888
    }
889
890
    /**
891
     * @Then /^the product for ("[^"]+" currency) and ("[^"]+" channel) should have "(?:€|£|\$)([^"]+)"$/
892
     */
893
    public function theProductForCurrencyAndChannelShouldHave(CurrencyInterface $currency, ChannelInterface $channel, $price)
894
    {
895
        Assert::same(
896
            $this->updateSimpleProductPage->getPricingConfigurationForChannelAndCurrencyCalculator($channel, $currency),
897
            $price
898
        );
899
    }
900
901
    /**
902
     * @Then this product should( also) have an association :productAssociationType with product :productName
903
     * @Then this product should( also) have an association :productAssociationType with products :firstProductName and :secondProductName
904
     */
905
    public function theProductShouldHaveAnAssociationWithProducts(
906
        ProductAssociationTypeInterface $productAssociationType,
907
        ...$productsNames
908
    ) {
909
        foreach ($productsNames as $productName) {
910
            Assert::true(
911
                $this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType),
912
                sprintf(
913
                    'This product should have an association %s with product %s, but it does not.',
914
                    $productAssociationType->getName(),
915
                    $productName
916
                )
917
            );
918
        }
919
    }
920
921
    /**
922
     * @Then this product should not have an association :productAssociationType with product :productName
923
     */
924
    public function theProductShouldNotHaveAnAssociationWithProducts(
925
        ProductAssociationTypeInterface $productAssociationType,
926
        $productName
927
    ) {
928
        Assert::false(
929
            $this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType),
930
            sprintf(
931
                'This product should not have an association %s with product %s, but it does.',
932
                $productAssociationType->getName(),
933
                $productName
934
            )
935
        );
936
    }
937
938
    /**
939
     * @param string $element
940
     * @param string $value
941
     */
942
    private function assertElementValue($element, $value)
943
    {
944
        /** @var UpdatePageInterface $currentPage */
945
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
946
            $this->updateSimpleProductPage,
947
            $this->updateConfigurableProductPage,
948
        ], $this->sharedStorage->get('product'));
949
950
        Assert::isInstanceOf($currentPage, UpdatePageInterface::class);
951
952
        Assert::true(
953
            $currentPage->hasResourceValues(
954
                [$element => $value]
955
            ),
956
            sprintf('Product should have %s with %s value.', $element, $value)
957
        );
958
    }
959
960
    /**
961
     * @param string $element
962
     * @param string $message
963
     */
964
    private function assertValidationMessage($element, $message)
965
    {
966
        $product = $this->sharedStorage->has('product') ? $this->sharedStorage->get('product') : null;
967
968
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
969
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([
970
            $this->createSimpleProductPage,
971
            $this->createConfigurableProductPage,
972
            $this->updateSimpleProductPage,
973
            $this->updateConfigurableProductPage,
974
        ], $product);
975
976
        Assert::same($currentPage->getValidationMessage($element), $message);
977
    }
978
}
979