ManagingProductsContext   F
last analyzed

Complexity

Total Complexity 92

Size/Duplication

Total Lines 967
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 16

Importance

Changes 0
Metric Value
wmc 92
lcom 3
cbo 16
dl 0
loc 967
rs 1.633
c 0
b 0
f 0

89 Methods

Rating   Name   Duplication   Size   Complexity  
A theProductShouldAppearInTheShop() 0 6 1
A __construct() 0 23 1
A iWantToCreateANewSimpleProduct() 0 4 1
A iWantToCreateANewConfigurableProduct() 0 4 1
A iSpecifyItsCodeAs() 0 6 1
A iRenameItToIn() 0 6 1
A iAddIt() 0 7 1
A iDisableItsTracking() 0 4 1
A iEnableItsTracking() 0 4 1
A iSetItsPriceTo() 0 4 1
A iSetItsOriginalPriceTo() 0 4 1
A iMakeItAvailableInChannel() 0 4 1
A iAssignItToChannel() 0 5 1
A iChooseCalculator() 0 4 1
A iSetItsSlugToIn() 0 4 1
A iEnableSlugModification() 0 5 1
A iWantToBrowseProducts() 0 4 1
A iAmBrowsingProductsFromTaxon() 0 4 1
A iFilterThemByTaxon() 0 4 1
A iCheckTheProduct() 0 4 1
A iDeleteThem() 0 4 1
A iShouldSeeProductWith() 0 4 1
A iShouldNotSeeAnyProductWith() 0 4 1
A theFirstProductOnTheListShouldHave() 0 6 1
A theLastProductOnTheListShouldHave() 0 6 1
A iSortProductsBy() 0 4 1
A iShouldSeeProductsInTheList() 0 4 1
A iDeleteProduct() 0 7 1
A productShouldNotExist() 0 6 1
A iShouldBeNotifiedOfFailure() 0 7 1
A productShouldExistInTheProductCatalog() 0 4 1
A iWantToModifyAProduct() 0 12 2
A theCodeFieldShouldBeDisabled() 0 6 1
A theSlugFieldShouldNotBeEditable() 0 4 1
A thisProductElementShouldBe() 0 4 1
A iShouldBeNotifiedThatIsRequired() 0 4 1
A iSaveMyChanges() 0 6 1
A iChangeItsPriceTo() 0 4 1
A iChangeItsOriginalPriceTo() 0 4 1
A iAddTheOptionToIt() 0 4 1
A iSetItsAttributeTo() 0 4 1
A iRemoveItsAttribute() 0 4 1
A iTryToAddNewAttributes() 0 4 1
A iDoNotWantToHaveShippingRequiredForThisProduct() 0 4 1
A itsAttributeShouldBe() 0 6 1
A productShouldNotHaveAttribute() 0 6 1
A productShouldNotHaveAnyAttributes() 0 4 1
A productWithNameShouldNotBeAdded() 0 6 1
A iRemoveItsNameFromTranslation() 0 6 1
A thisProductShouldHaveOption() 0 4 1
A theOptionFieldShouldBeDisabled() 0 4 1
A iChooseMainTaxon() 0 6 1
A productSlugShouldBe() 0 6 1
A thisProductMainTaxonShouldBe() 0 7 1
A thisProductShouldNotBeTracked() 0 6 1
A thisProductShouldBeTracked() 0 6 1
A iAttachImageWithType() 0 6 1
A iAssociateProductsAsProductAssociation() 0 8 1
A iRemoveAnAssociatedProductFromProductAssociation() 0 8 1
A thisProductShouldHaveAnImageWithType() 0 6 1
A thisProductShouldNotHaveAnyImagesWithType() 0 6 1
A iChangeItsImageToPathForTheType() 0 6 1
A iRemoveAnImageWithType() 0 6 1
A iRemoveTheFirstImage() 0 6 1
A iChangeTheFirstImageTypeTo() 0 6 1
A thisProductShouldNotHaveImages() 0 8 1
A thereShouldStillBeOnlyOneImageInThisProduct() 0 8 1
A thereAreNoProductReviews() 0 6 1
A theProductShouldHaveAnAssociationWithProducts() 0 15 2
A theProductShouldNotHaveAnAssociationWithProduct() 0 6 1
A iShouldBeNotifiedThatSimpleProductCodeHasToBeUnique() 0 4 1
A iShouldBeNotifiedThatSlugHasToBeUnique() 0 4 1
A iShouldBeNotifiedThatCodeHasToBeUnique() 0 4 1
A iShouldBeNotifiedThatPriceMustBeDefinedForEveryChannel() 0 4 1
A theyShouldHaveOrderLikeAnd() 0 4 1
A iSaveMyNewConfiguration() 0 4 1
A iSetThePositionOfTo() 0 4 1
A thisProductElementShouldHaveSlugIn() 0 4 1
A iSetItsShippingCategoryAs() 0 4 1
A itShouldBePricedAtForChannel() 0 6 1
A itsOriginalPriceForChannel() 0 9 1
A thisProductShouldNoLongerHavePriceForChannel() 0 14 2
A iShouldBeNotifiedThatIHaveToDefineProductVariantsPricesForNewlyAssignedChannelsFirst() 0 7 1
A theProductWithCodeShouldNotHaveShippingRequired() 0 6 1
A iShouldBeNotifiedThatIHaveToDefineTheAttributeIn() 0 7 1
A iShouldBeNotifiedThatTheAttributeInShouldBeLongerThan() 0 7 1
A assertElementValue() 0 12 1
A assertValidationMessage() 0 7 1
A resolveCurrentPage() 0 11 1

How to fix   Complexity   

Complex Class

Complex classes like ManagingProductsContext often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ManagingProductsContext, and based on these observations, apply Extract Interface, too.

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
declare(strict_types=1);
13
14
namespace Sylius\Behat\Context\Ui\Admin;
15
16
use Behat\Behat\Context\Context;
17
use Behat\Mink\Exception\ElementNotFoundException;
18
use Sylius\Behat\NotificationType;
19
use Sylius\Behat\Page\Admin\Crud\CreatePageInterface;
20
use Sylius\Behat\Page\Admin\Crud\UpdatePageInterface;
21
use Sylius\Behat\Page\Admin\Product\CreateConfigurableProductPageInterface;
22
use Sylius\Behat\Page\Admin\Product\CreateSimpleProductPageInterface;
23
use Sylius\Behat\Page\Admin\Product\IndexPageInterface;
24
use Sylius\Behat\Page\Admin\Product\IndexPerTaxonPageInterface;
25
use Sylius\Behat\Page\Admin\Product\UpdateConfigurableProductPageInterface;
26
use Sylius\Behat\Page\Admin\Product\UpdateSimpleProductPageInterface;
27
use Sylius\Behat\Page\Admin\ProductReview\IndexPageInterface as ProductReviewIndexPageInterface;
28
use Sylius\Behat\Service\NotificationCheckerInterface;
29
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
30
use Sylius\Behat\Service\SharedStorageInterface;
31
use Sylius\Component\Core\Model\ProductInterface;
32
use Sylius\Component\Core\Model\TaxonInterface;
33
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
34
use Webmozart\Assert\Assert;
35
36
final class ManagingProductsContext implements Context
37
{
38
    /**
39
     * @var SharedStorageInterface
40
     */
41
    private $sharedStorage;
42
43
    /**
44
     * @var CreateSimpleProductPageInterface
45
     */
46
    private $createSimpleProductPage;
47
48
    /**
49
     * @var CreateConfigurableProductPageInterface
50
     */
51
    private $createConfigurableProductPage;
52
53
    /**
54
     * @var IndexPageInterface
55
     */
56
    private $indexPage;
57
58
    /**
59
     * @var UpdateSimpleProductPageInterface
60
     */
61
    private $updateSimpleProductPage;
62
63
    /**
64
     * @var UpdateConfigurableProductPageInterface
65
     */
66
    private $updateConfigurableProductPage;
67
68
    /**
69
     * @var ProductReviewIndexPageInterface
70
     */
71
    private $productReviewIndexPage;
72
73
    /**
74
     * @var IndexPerTaxonPageInterface
75
     */
76
    private $indexPerTaxonPage;
77
78
    /**
79
     * @var CurrentPageResolverInterface
80
     */
81
    private $currentPageResolver;
82
83
    /**
84
     * @var NotificationCheckerInterface
85
     */
86
    private $notificationChecker;
87
88
    /**
89
     * @param SharedStorageInterface $sharedStorage
90
     * @param CreateSimpleProductPageInterface $createSimpleProductPage
91
     * @param CreateConfigurableProductPageInterface $createConfigurableProductPage
92
     * @param IndexPageInterface $indexPage
93
     * @param UpdateSimpleProductPageInterface $updateSimpleProductPage
94
     * @param UpdateConfigurableProductPageInterface $updateConfigurableProductPage
95
     * @param ProductReviewIndexPageInterface $productReviewIndexPage
96
     * @param IndexPerTaxonPageInterface $indexPerTaxonPage
97
     * @param CurrentPageResolverInterface $currentPageResolver
98
     * @param NotificationCheckerInterface $notificationChecker
99
     */
100
    public function __construct(
101
        SharedStorageInterface $sharedStorage,
102
        CreateSimpleProductPageInterface $createSimpleProductPage,
103
        CreateConfigurableProductPageInterface $createConfigurableProductPage,
104
        IndexPageInterface $indexPage,
105
        UpdateSimpleProductPageInterface $updateSimpleProductPage,
106
        UpdateConfigurableProductPageInterface $updateConfigurableProductPage,
107
        ProductReviewIndexPageInterface $productReviewIndexPage,
108
        IndexPerTaxonPageInterface $indexPerTaxonPage,
109
        CurrentPageResolverInterface $currentPageResolver,
110
        NotificationCheckerInterface $notificationChecker
111
    ) {
112
        $this->sharedStorage = $sharedStorage;
113
        $this->createSimpleProductPage = $createSimpleProductPage;
114
        $this->createConfigurableProductPage = $createConfigurableProductPage;
115
        $this->indexPage = $indexPage;
116
        $this->updateSimpleProductPage = $updateSimpleProductPage;
117
        $this->updateConfigurableProductPage = $updateConfigurableProductPage;
118
        $this->productReviewIndexPage = $productReviewIndexPage;
119
        $this->indexPerTaxonPage = $indexPerTaxonPage;
120
        $this->currentPageResolver = $currentPageResolver;
121
        $this->notificationChecker = $notificationChecker;
122
    }
123
124
    /**
125
     * @Given I want to create a new simple product
126
     */
127
    public function iWantToCreateANewSimpleProduct()
128
    {
129
        $this->createSimpleProductPage->open();
130
    }
131
132
    /**
133
     * @Given I want to create a new configurable product
134
     */
135
    public function iWantToCreateANewConfigurableProduct()
136
    {
137
        $this->createConfigurableProductPage->open();
138
    }
139
140
    /**
141
     * @When I specify its code as :code
142
     * @When I do not specify its code
143
     */
144
    public function iSpecifyItsCodeAs($code = null)
145
    {
146
        $currentPage = $this->resolveCurrentPage();
147
148
        $currentPage->specifyCode($code);
0 ignored issues
show
Bug introduced by
The method specifyCode does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...pleProductPageInterface.

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...
149
    }
150
151
    /**
152
     * @When I name it :name in :language
153
     * @When I rename it to :name in :language
154
     */
155
    public function iRenameItToIn($name, $language)
156
    {
157
        $currentPage = $this->resolveCurrentPage();
158
159
        $currentPage->nameItIn($name, $language);
0 ignored issues
show
Bug introduced by
The method nameItIn does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
160
    }
161
162
    /**
163
     * @When I add it
164
     * @When I try to add it
165
     */
166
    public function iAddIt()
167
    {
168
        /** @var CreatePageInterface $currentPage */
169
        $currentPage = $this->resolveCurrentPage();
170
171
        $currentPage->create();
172
    }
173
174
    /**
175
     * @When I disable its inventory tracking
176
     */
177
    public function iDisableItsTracking()
178
    {
179
        $this->updateSimpleProductPage->disableTracking();
180
    }
181
182
    /**
183
     * @When I enable its inventory tracking
184
     */
185
    public function iEnableItsTracking()
186
    {
187
        $this->updateSimpleProductPage->enableTracking();
188
    }
189
190
    /**
191
     * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
192
     */
193
    public function iSetItsPriceTo($price, $channelName)
194
    {
195
        $this->createSimpleProductPage->specifyPrice($channelName, $price);
196
    }
197
198
    /**
199
     * @When /^I set its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
200
     */
201
    public function iSetItsOriginalPriceTo($originalPrice, $channelName)
202
    {
203
        $this->createSimpleProductPage->specifyOriginalPrice($channelName, $originalPrice);
204
    }
205
206
    /**
207
     * @When I make it available in channel :channel
208
     */
209
    public function iMakeItAvailableInChannel($channel)
210
    {
211
        $this->createSimpleProductPage->checkChannel($channel);
212
    }
213
214
    /**
215
     * @When I assign it to channel :channel
216
     */
217
    public function iAssignItToChannel($channel)
218
    {
219
        // Temporary solution until we will make current page resolver work with product pages
220
        $this->updateConfigurableProductPage->checkChannel($channel);
221
    }
222
223
    /**
224
     * @When I choose :calculatorName calculator
225
     */
226
    public function iChooseCalculator($calculatorName)
227
    {
228
        $this->createSimpleProductPage->choosePricingCalculator($calculatorName);
229
    }
230
231
    /**
232
     * @When I set its slug to :slug
233
     * @When I set its slug to :slug in :language
234
     * @When I remove its slug
235
     */
236
    public function iSetItsSlugToIn($slug = null, $language = 'en_US')
237
    {
238
        $this->createSimpleProductPage->specifySlugIn($slug, $language);
239
    }
240
241
    /**
242
     * @When I enable slug modification
243
     * @When I enable slug modification in :localeCode
244
     */
245
    public function iEnableSlugModification($localeCode = 'en_US')
246
    {
247
        $this->updateSimpleProductPage->activateLanguageTab($localeCode);
248
        $this->updateSimpleProductPage->enableSlugModification($localeCode);
249
    }
250
251
    /**
252
     * @Then I should see the product :productName in the list
253
     * @Then the product :productName should appear in the store
254
     * @Then the product :productName should be in the shop
255
     * @Then this product should still be named :productName
256
     */
257
    public function theProductShouldAppearInTheShop(string $productName): void
258
    {
259
        $this->iWantToBrowseProducts();
260
261
        Assert::true($this->indexPage->isSingleResourceOnPage(['name' => $productName]));
262
    }
263
264
    /**
265
     * @Given I am browsing products
266
     * @When I browse products
267
     * @When I want to browse products
268
     */
269
    public function iWantToBrowseProducts()
270
    {
271
        $this->indexPage->open();
272
    }
273
274
    /**
275
     * @When /^I am browsing products from ("([^"]+)" taxon)$/
276
     */
277
    public function iAmBrowsingProductsFromTaxon(TaxonInterface $taxon)
278
    {
279
        $this->indexPerTaxonPage->open(['taxonId' => $taxon->getId()]);
280
    }
281
282
    /**
283
     * @When I filter them by :taxonName taxon
284
     */
285
    public function iFilterThemByTaxon($taxonName)
286
    {
287
        $this->indexPage->filterByTaxon($taxonName);
288
    }
289
290
    /**
291
     * @When I check (also) the :productName product
292
     */
293
    public function iCheckTheProduct(string $productName): void
294
    {
295
        $this->indexPage->checkResourceOnPage(['name' => $productName]);
296
    }
297
298
    /**
299
     * @When I delete them
300
     */
301
    public function iDeleteThem(): void
302
    {
303
        $this->indexPage->bulkDelete();
304
    }
305
306
    /**
307
     * @Then I should( still) see a product with :field :value
308
     */
309
    public function iShouldSeeProductWith($field, $value)
310
    {
311
        Assert::true($this->indexPage->isSingleResourceOnPage([$field => $value]));
312
    }
313
314
    /**
315
     * @Then I should not see any product with :field :value
316
     */
317
    public function iShouldNotSeeAnyProductWith($field, $value)
318
    {
319
        Assert::false($this->indexPage->isSingleResourceOnPage([$field => $value]));
320
    }
321
322
    /**
323
     * @Then the first product on the list should have :field :value
324
     */
325
    public function theFirstProductOnTheListShouldHave($field, $value)
326
    {
327
        $currentPage = $this->resolveCurrentPage();
328
329
        Assert::same($currentPage->getColumnFields($field)[0], $value);
0 ignored issues
show
Bug introduced by
The method getColumnFields does only exist in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface, but not in Sylius\Behat\Page\Admin\...pleProductPageInterface.

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...
330
    }
331
332
    /**
333
     * @Then the last product on the list should have :field :value
334
     */
335
    public function theLastProductOnTheListShouldHave($field, $value)
336
    {
337
        $values = $this->indexPerTaxonPage->getColumnFields($field);
338
339
        Assert::same(end($values), $value);
340
    }
341
342
    /**
343
     * @When I switch the way products are sorted by :field
344
     * @When I start sorting products by :field
345
     * @Given the products are already sorted by :field
346
     */
347
    public function iSortProductsBy($field)
348
    {
349
        $this->indexPage->sortBy($field);
350
    }
351
352
    /**
353
     * @Then I should see a single product in the list
354
     * @Then I should see :numberOfProducts products in the list
355
     */
356
    public function iShouldSeeProductsInTheList(int $numberOfProducts = 1): void
357
    {
358
        Assert::same($this->indexPage->countItems(), (int) $numberOfProducts);
359
    }
360
361
    /**
362
     * @When I delete the :product product
363
     * @When I try to delete the :product product
364
     */
365
    public function iDeleteProduct(ProductInterface $product)
366
    {
367
        $this->sharedStorage->set('product', $product);
368
369
        $this->iWantToBrowseProducts();
370
        $this->indexPage->deleteResourceOnPage(['name' => $product->getName()]);
371
    }
372
373
    /**
374
     * @Then /^(this product) should not exist in the product catalog$/
375
     */
376
    public function productShouldNotExist(ProductInterface $product)
377
    {
378
        $this->iWantToBrowseProducts();
379
380
        Assert::false($this->indexPage->isSingleResourceOnPage(['code' => $product->getCode()]));
381
    }
382
383
    /**
384
     * @Then I should be notified that this product is in use and cannot be deleted
385
     */
386
    public function iShouldBeNotifiedOfFailure()
387
    {
388
        $this->notificationChecker->checkNotification(
389
            'Cannot delete, the product is in use.',
390
            NotificationType::failure()
391
        );
392
    }
393
394
    /**
395
     * @Then /^(this product) should still exist in the product catalog$/
396
     */
397
    public function productShouldExistInTheProductCatalog(ProductInterface $product)
398
    {
399
        $this->theProductShouldAppearInTheShop($product->getName());
400
    }
401
402
    /**
403
     * @When I want to modify the :product product
404
     * @When /^I want to modify (this product)$/
405
     */
406
    public function iWantToModifyAProduct(ProductInterface $product)
407
    {
408
        $this->sharedStorage->set('product', $product);
409
410
        if ($product->isSimple()) {
411
            $this->updateSimpleProductPage->open(['id' => $product->getId()]);
412
413
            return;
414
        }
415
416
        $this->updateConfigurableProductPage->open(['id' => $product->getId()]);
417
    }
418
419
    /**
420
     * @Then the code field should be disabled
421
     */
422
    public function theCodeFieldShouldBeDisabled()
423
    {
424
        $currentPage = $this->resolveCurrentPage();
425
426
        Assert::true($currentPage->isCodeDisabled());
0 ignored issues
show
Bug introduced by
The method isCodeDisabled does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
427
    }
428
429
    /**
430
     * @Then the slug field should not be editable
431
     * @Then the slug field in :localeCode (also )should not be editable
432
     */
433
    public function theSlugFieldShouldNotBeEditable($localeCode = 'en_US')
434
    {
435
        Assert::true($this->updateSimpleProductPage->isSlugReadonlyIn($localeCode));
436
    }
437
438
    /**
439
     * @Then this product name should be :name
440
     */
441
    public function thisProductElementShouldBe($name)
442
    {
443
        $this->assertElementValue('name', $name);
444
    }
445
446
    /**
447
     * @Then /^I should be notified that (code|name|slug) is required$/
448
     */
449
    public function iShouldBeNotifiedThatIsRequired($element)
450
    {
451
        $this->assertValidationMessage($element, sprintf('Please enter product %s.', $element));
452
    }
453
454
    /**
455
     * @When I save my changes
456
     * @When I try to save my changes
457
     */
458
    public function iSaveMyChanges()
459
    {
460
        $currentPage = $this->resolveCurrentPage();
461
462
        $currentPage->saveChanges();
0 ignored issues
show
Bug introduced by
The method saveChanges does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
463
    }
464
465
    /**
466
     * @When /^I change its price to (?:€|£|\$)([^"]+) for "([^"]+)" channel$/
467
     */
468
    public function iChangeItsPriceTo($price, $channelName)
469
    {
470
        $this->updateSimpleProductPage->specifyPrice($channelName, $price);
471
    }
472
473
    /**
474
     * @When /^I change its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
475
     */
476
    public function iChangeItsOriginalPriceTo($price, $channelName)
477
    {
478
        $this->updateSimpleProductPage->specifyOriginalPrice($channelName, $price);
479
    }
480
481
    /**
482
     * @Given I add the :optionName option to it
483
     */
484
    public function iAddTheOptionToIt($optionName)
485
    {
486
        $this->createConfigurableProductPage->selectOption($optionName);
487
    }
488
489
    /**
490
     * @When I set its :attribute attribute to :value
491
     * @When I set its :attribute attribute to :value in :language
492
     * @When I do not set its :attribute attribute in :language
493
     */
494
    public function iSetItsAttributeTo($attribute, $value = null, $language = 'en_US')
495
    {
496
        $this->createSimpleProductPage->addAttribute($attribute, $value, $language);
497
    }
498
499
    /**
500
     * @When I remove its :attribute attribute
501
     * @When I remove its :attribute attribute from :language
502
     */
503
    public function iRemoveItsAttribute($attribute, $language = 'en_US')
504
    {
505
        $this->createSimpleProductPage->removeAttribute($attribute, $language);
506
    }
507
508
    /**
509
     * @When I try to add new attributes
510
     */
511
    public function iTryToAddNewAttributes()
512
    {
513
        $this->updateSimpleProductPage->addSelectedAttributes();
514
    }
515
516
    /**
517
     * @When I do not want to have shipping required for this product
518
     */
519
    public function iDoNotWantToHaveShippingRequiredForThisProduct()
520
    {
521
        $this->createSimpleProductPage->setShippingRequired(false);
522
    }
523
524
    /**
525
     * @Then attribute :attributeName of product :product should be :value
526
     * @Then attribute :attributeName of product :product should be :value in :language
527
     */
528
    public function itsAttributeShouldBe($attributeName, ProductInterface $product, $value, $language = 'en_US')
529
    {
530
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
531
532
        Assert::same($this->updateSimpleProductPage->getAttributeValue($attributeName, $language), $value);
533
    }
534
535
    /**
536
     * @Then /^(product "[^"]+") should not have a "([^"]+)" attribute$/
537
     */
538
    public function productShouldNotHaveAttribute(ProductInterface $product, $attribute)
539
    {
540
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
541
542
        Assert::false($this->updateSimpleProductPage->hasAttribute($attribute));
543
    }
544
545
    /**
546
     * @Then /^product "[^"]+" should not have any attributes$/
547
     * @Then /^product "[^"]+" should have (\d+) attributes?$/
548
     */
549
    public function productShouldNotHaveAnyAttributes($count = 0)
550
    {
551
        Assert::same($this->updateSimpleProductPage->getNumberOfAttributes(), (int) $count);
552
    }
553
554
    /**
555
     * @Given product with :element :value should not be added
556
     */
557
    public function productWithNameShouldNotBeAdded($element, $value)
558
    {
559
        $this->iWantToBrowseProducts();
560
561
        Assert::false($this->indexPage->isSingleResourceOnPage([$element => $value]));
562
    }
563
564
    /**
565
     * @When I remove its name from :language translation
566
     */
567
    public function iRemoveItsNameFromTranslation($language)
568
    {
569
        $currentPage = $this->resolveCurrentPage();
570
571
        $currentPage->nameItIn('', $language);
0 ignored issues
show
Bug introduced by
The method nameItIn does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
572
    }
573
574
    /**
575
     * @Then /^this product should have (?:a|an) "([^"]+)" option$/
576
     */
577
    public function thisProductShouldHaveOption($productOption)
578
    {
579
        $this->updateConfigurableProductPage->isProductOptionChosen($productOption);
580
    }
581
582
    /**
583
     * @Then the option field should be disabled
584
     */
585
    public function theOptionFieldShouldBeDisabled()
586
    {
587
        Assert::true($this->updateConfigurableProductPage->isProductOptionsDisabled());
588
    }
589
590
    /**
591
     * @When /^I choose main (taxon "[^"]+")$/
592
     */
593
    public function iChooseMainTaxon(TaxonInterface $taxon)
594
    {
595
        $currentPage = $this->resolveCurrentPage();
596
597
        $currentPage->selectMainTaxon($taxon);
0 ignored issues
show
Bug introduced by
The method selectMainTaxon does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
598
    }
599
600
    /**
601
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)"$/
602
     * @Then /^the slug of the ("[^"]+" product) should(?:| still) be "([^"]+)" (in the "[^"]+" locale)$/
603
     */
604
    public function productSlugShouldBe(ProductInterface $product, $slug, $locale = 'en_US')
605
    {
606
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
607
608
        Assert::same($this->updateSimpleProductPage->getSlug($locale), $slug);
609
    }
610
611
    /**
612
     * @Then /^(this product) main taxon should be "([^"]+)"$/
613
     */
614
    public function thisProductMainTaxonShouldBe(ProductInterface $product, $taxonName)
615
    {
616
        $currentPage = $this->resolveCurrentPage();
617
        $currentPage->open(['id' => $product->getId()]);
618
619
        Assert::true($currentPage->isMainTaxonChosen($taxonName));
0 ignored issues
show
Bug introduced by
The method isMainTaxonChosen does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
620
    }
621
622
    /**
623
     * @Then /^inventory of (this product) should not be tracked$/
624
     */
625
    public function thisProductShouldNotBeTracked(ProductInterface $product)
626
    {
627
        $this->iWantToModifyAProduct($product);
628
629
        Assert::false($this->updateSimpleProductPage->isTracked());
630
    }
631
632
    /**
633
     * @Then /^inventory of (this product) should be tracked$/
634
     */
635
    public function thisProductShouldBeTracked(ProductInterface $product)
636
    {
637
        $this->iWantToModifyAProduct($product);
638
639
        Assert::true($this->updateSimpleProductPage->isTracked());
640
    }
641
642
    /**
643
     * @When I attach the :path image with :type type
644
     * @When I attach the :path image
645
     */
646
    public function iAttachImageWithType($path, $type = null)
647
    {
648
        $currentPage = $this->resolveCurrentPage();
649
650
        $currentPage->attachImage($path, $type);
0 ignored issues
show
Bug introduced by
The method attachImage does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
651
    }
652
653
    /**
654
     * @When I associate as :productAssociationType the :productName product
655
     * @When I associate as :productAssociationType the :firstProductName and :secondProductName products
656
     */
657
    public function iAssociateProductsAsProductAssociation(
658
        ProductAssociationTypeInterface $productAssociationType,
659
        ...$productsNames
660
    ) {
661
        $currentPage = $this->resolveCurrentPage();
662
663
        $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...
664
    }
665
666
    /**
667
     * @When I remove an associated product :productName from :productAssociationType
668
     */
669
    public function iRemoveAnAssociatedProductFromProductAssociation(
670
        $productName,
671
        ProductAssociationTypeInterface $productAssociationType
672
    ) {
673
        $currentPage = $this->resolveCurrentPage();
674
675
        $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...
676
    }
677
678
    /**
679
     * @Then /^(?:this product|the product "[^"]+"|it) should(?:| also) have an image with "([^"]*)" type$/
680
     */
681
    public function thisProductShouldHaveAnImageWithType($type)
682
    {
683
        $currentPage = $this->resolveCurrentPage();
684
685
        Assert::true($currentPage->isImageWithTypeDisplayed($type));
0 ignored issues
show
Bug introduced by
The method isImageWithTypeDisplayed does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
686
    }
687
688
    /**
689
     * @Then /^(?:this product|it)(?:| also) should not have any images with "([^"]*)" type$/
690
     */
691
    public function thisProductShouldNotHaveAnyImagesWithType($code)
692
    {
693
        $currentPage = $this->resolveCurrentPage();
694
695
        Assert::false($currentPage->isImageWithTypeDisplayed($code));
0 ignored issues
show
Bug introduced by
The method isImageWithTypeDisplayed does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
696
    }
697
698
    /**
699
     * @When I change the image with the :type type to :path
700
     */
701
    public function iChangeItsImageToPathForTheType($type, $path)
702
    {
703
        $currentPage = $this->resolveCurrentPage();
704
705
        $currentPage->changeImageWithType($type, $path);
0 ignored issues
show
Bug introduced by
The method changeImageWithType does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
706
    }
707
708
    /**
709
     * @When /^I(?:| also) remove an image with "([^"]*)" type$/
710
     */
711
    public function iRemoveAnImageWithType($code)
712
    {
713
        $currentPage = $this->resolveCurrentPage();
714
715
        $currentPage->removeImageWithType($code);
0 ignored issues
show
Bug introduced by
The method removeImageWithType does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
716
    }
717
718
    /**
719
     * @When I remove the first image
720
     */
721
    public function iRemoveTheFirstImage()
722
    {
723
        $currentPage = $this->resolveCurrentPage();
724
725
        $currentPage->removeFirstImage();
0 ignored issues
show
Bug introduced by
The method removeFirstImage does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
726
    }
727
728
    /**
729
     * @When I change the first image type to :type
730
     */
731
    public function iChangeTheFirstImageTypeTo($type)
732
    {
733
        $currentPage = $this->resolveCurrentPage();
734
735
        $currentPage->modifyFirstImageType($type);
0 ignored issues
show
Bug introduced by
The method modifyFirstImageType does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
736
    }
737
738
    /**
739
     * @Then /^(this product) should not have any images$/
740
     */
741
    public function thisProductShouldNotHaveImages(ProductInterface $product)
742
    {
743
        $this->iWantToModifyAProduct($product);
744
745
        $currentPage = $this->resolveCurrentPage();
746
747
        Assert::same($currentPage->countImages(), 0);
0 ignored issues
show
Bug introduced by
The method countImages does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
748
    }
749
750
    /**
751
     * @Then /^(this product) should(?:| still) have (?:only one|(\d+)) images?$/
752
     */
753
    public function thereShouldStillBeOnlyOneImageInThisProduct(ProductInterface $product, $count = 1)
754
    {
755
        $this->iWantToModifyAProduct($product);
756
757
        $currentPage = $this->resolveCurrentPage();
758
759
        Assert::same($currentPage->countImages(), (int) $count);
0 ignored issues
show
Bug introduced by
The method countImages does only exist in Sylius\Behat\Page\Admin\...pleProductPageInterface, but not in Sylius\Behat\Page\Admin\...exPerTaxonPageInterface.

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...
760
    }
761
762
    /**
763
     * @Then /^there should be no reviews of (this product)$/
764
     */
765
    public function thereAreNoProductReviews(ProductInterface $product)
766
    {
767
        $this->productReviewIndexPage->open();
768
769
        Assert::false($this->productReviewIndexPage->isSingleResourceOnPage(['reviewSubject' => $product->getName()]));
770
    }
771
772
    /**
773
     * @Then this product should( also) have an association :productAssociationType with product :productName
774
     * @Then this product should( also) have an association :productAssociationType with products :firstProductName and :secondProductName
775
     */
776
    public function theProductShouldHaveAnAssociationWithProducts(
777
        ProductAssociationTypeInterface $productAssociationType,
778
        ...$productsNames
779
    ) {
780
        foreach ($productsNames as $productName) {
781
            Assert::true(
782
                $this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType),
783
                sprintf(
784
                    'This product should have an association %s with product %s.',
785
                    $productAssociationType->getName(),
786
                    $productName
787
                )
788
            );
789
        }
790
    }
791
792
    /**
793
     * @Then this product should not have an association :productAssociationType with product :productName
794
     */
795
    public function theProductShouldNotHaveAnAssociationWithProduct(
796
        ProductAssociationTypeInterface $productAssociationType,
797
        $productName
798
    ) {
799
        Assert::false($this->updateSimpleProductPage->hasAssociatedProduct($productName, $productAssociationType));
800
    }
801
802
    /**
803
     * @Then I should be notified that simple product code has to be unique
804
     */
805
    public function iShouldBeNotifiedThatSimpleProductCodeHasToBeUnique()
806
    {
807
        $this->assertValidationMessage('code', 'Simple product code must be unique among all products and product variants.');
808
    }
809
810
    /**
811
     * @Then I should be notified that slug has to be unique
812
     */
813
    public function iShouldBeNotifiedThatSlugHasToBeUnique()
814
    {
815
        $this->assertValidationMessage('slug', 'Product slug must be unique.');
816
    }
817
818
    /**
819
     * @Then I should be notified that code has to be unique
820
     */
821
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
822
    {
823
        $this->assertValidationMessage('code', 'Product code must be unique.');
824
    }
825
826
    /**
827
     * @Then I should be notified that price must be defined for every channel
828
     */
829
    public function iShouldBeNotifiedThatPriceMustBeDefinedForEveryChannel()
830
    {
831
        $this->assertValidationMessage('channel_pricings', 'You must define price for every channel.');
832
    }
833
834
    /**
835
     * @Then they should have order like :firstProductName, :secondProductName and :thirdProductName
836
     */
837
    public function theyShouldHaveOrderLikeAnd(...$productNames)
838
    {
839
        Assert::true($this->indexPerTaxonPage->hasProductsInOrder($productNames));
840
    }
841
842
    /**
843
     * @When I save my new configuration
844
     */
845
    public function iSaveMyNewConfiguration()
846
    {
847
        $this->indexPerTaxonPage->savePositions();
848
    }
849
850
    /**
851
     * @When I set the position of :productName to :position
852
     */
853
    public function iSetThePositionOfTo($productName, $position)
854
    {
855
        $this->indexPerTaxonPage->setPositionOfProduct($productName, (int) $position);
856
    }
857
858
    /**
859
     * @Then this product should( still) have slug :value in :language
860
     */
861
    public function thisProductElementShouldHaveSlugIn($slug, $language)
862
    {
863
        Assert::same($this->updateSimpleProductPage->getSlug($language), $slug);
864
    }
865
866
    /**
867
     * @When I set its shipping category as :shippingCategoryName
868
     */
869
    public function iSetItsShippingCategoryAs($shippingCategoryName)
870
    {
871
        $this->createSimpleProductPage->selectShippingCategory($shippingCategoryName);
872
    }
873
874
    /**
875
     * @Then /^(it|this product) should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
876
     * @Then /^(product "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
877
     */
878
    public function itShouldBePricedAtForChannel(ProductInterface $product, $price, $channelName)
879
    {
880
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
881
882
        Assert::same($this->updateSimpleProductPage->getPriceForChannel($channelName), $price);
883
    }
884
885
    /**
886
     * @Then /^(its|this products) original price should be "(?:€|£|\$)([^"]+)" for channel "([^"]+)"$/
887
     */
888
    public function itsOriginalPriceForChannel(ProductInterface $product, $originalPrice, $channelName)
889
    {
890
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
891
892
        Assert::same(
893
            $this->updateSimpleProductPage->getOriginalPriceForChannel($channelName),
894
            $originalPrice
895
        );
896
    }
897
898
    /**
899
     * @Then /^(this product) should no longer have price for channel "([^"]+)"$/
900
     */
901
    public function thisProductShouldNoLongerHavePriceForChannel(ProductInterface $product, $channelName)
902
    {
903
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
904
905
        try {
906
            $this->updateSimpleProductPage->getPriceForChannel($channelName);
907
        } catch (ElementNotFoundException $exception) {
908
            return;
909
        }
910
911
        throw new \Exception(
912
            sprintf('Product "%s" should not have price defined for channel "%s".', $product->getName(), $channelName)
913
        );
914
    }
915
916
    /**
917
     * @Then I should be notified that I have to define product variants' prices for newly assigned channels first
918
     */
919
    public function iShouldBeNotifiedThatIHaveToDefineProductVariantsPricesForNewlyAssignedChannelsFirst()
920
    {
921
        Assert::same(
922
            $this->updateConfigurableProductPage->getValidationMessage('channels'),
923
            'You have to define product variants\' prices for newly assigned channels first.'
924
        );
925
    }
926
927
    /**
928
     * @Then /^the (product "[^"]+") should not have shipping required$/
929
     */
930
    public function theProductWithCodeShouldNotHaveShippingRequired(ProductInterface $product)
931
    {
932
        $this->updateSimpleProductPage->open(['id' => $product->getId()]);
933
934
        Assert::false($this->updateSimpleProductPage->isShippingRequired());
935
    }
936
937
    /**
938
     * @Then I should be notified that I have to define the :attribute attribute in :language
939
     */
940
    public function iShouldBeNotifiedThatIHaveToDefineTheAttributeIn($attribute, $language)
941
    {
942
        Assert::same(
943
            $this->resolveCurrentPage()->getAttributeValidationErrors($attribute, $language),
0 ignored issues
show
Bug introduced by
The method getAttributeValidationErrors 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...
944
            'This value should not be blank.'
945
        );
946
    }
947
948
    /**
949
     * @Then I should be notified that the :attribute attribute in :language should be longer than :number
950
     */
951
    public function iShouldBeNotifiedThatTheAttributeInShouldBeLongerThan($attribute, $language, $number)
952
    {
953
        Assert::same(
954
            $this->resolveCurrentPage()->getAttributeValidationErrors($attribute, $language),
0 ignored issues
show
Bug introduced by
The method getAttributeValidationErrors 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...
955
            sprintf('This value is too short. It should have %s characters or more.', $number)
956
        );
957
    }
958
959
    /**
960
     * @param string $element
961
     * @param string $value
962
     */
963
    private function assertElementValue($element, $value)
964
    {
965
        /** @var UpdatePageInterface $currentPage */
966
        $currentPage = $this->resolveCurrentPage();
967
968
        Assert::isInstanceOf($currentPage, UpdatePageInterface::class);
969
970
        Assert::true(
971
            $currentPage->hasResourceValues([$element => $value]),
972
            sprintf('Product should have %s with %s value.', $element, $value)
973
        );
974
    }
975
976
    /**
977
     * @param string $element
978
     * @param string $message
979
     */
980
    private function assertValidationMessage($element, $message)
981
    {
982
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
983
        $currentPage = $this->resolveCurrentPage();
984
985
        Assert::same($currentPage->getValidationMessage($element), $message);
986
    }
987
988
    /**
989
     * @return IndexPageInterface|IndexPerTaxonPageInterface|CreateSimpleProductPageInterface|CreateConfigurableProductPageInterface|UpdateSimpleProductPageInterface|UpdateConfigurableProductPageInterface
990
     */
991
    private function resolveCurrentPage()
992
    {
993
        return $this->currentPageResolver->getCurrentPageWithForm([
994
            $this->indexPage,
995
            $this->indexPerTaxonPage,
996
            $this->createSimpleProductPage,
997
            $this->createConfigurableProductPage,
998
            $this->updateSimpleProductPage,
999
            $this->updateConfigurableProductPage,
1000
        ]);
1001
    }
1002
}
1003