Completed
Push — 1.5 ( f514d1...5a0e7f )
by Kamil
24:29 queued 10:54
created

iShouldSeeTheOptionAs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Behat\Context\Ui\Admin;
15
16
use Behat\Behat\Context\Context;
17
use Sylius\Behat\NotificationType;
18
use Sylius\Behat\Page\Admin\ProductVariant\CreatePageInterface;
19
use Sylius\Behat\Page\Admin\ProductVariant\GeneratePageInterface;
20
use Sylius\Behat\Page\Admin\ProductVariant\IndexPageInterface;
21
use Sylius\Behat\Page\Admin\ProductVariant\UpdatePageInterface;
22
use Sylius\Behat\Service\NotificationCheckerInterface;
23
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
24
use Sylius\Behat\Service\SharedStorageInterface;
25
use Sylius\Component\Core\Model\ProductInterface;
26
use Sylius\Component\Core\Model\ProductVariantInterface;
27
use Webmozart\Assert\Assert;
28
29
final class ManagingProductVariantsContext implements Context
30
{
31
    /** @var SharedStorageInterface */
32
    private $sharedStorage;
33
34
    /** @var CreatePageInterface */
35
    private $createPage;
36
37
    /** @var IndexPageInterface */
38
    private $indexPage;
39
40
    /** @var UpdatePageInterface */
41
    private $updatePage;
42
43
    /** @var GeneratePageInterface */
44
    private $generatePage;
45
46
    /** @var CurrentPageResolverInterface */
47
    private $currentPageResolver;
48
49
    /** @var NotificationCheckerInterface */
50
    private $notificationChecker;
51
52
    public function __construct(
53
        SharedStorageInterface $sharedStorage,
54
        CreatePageInterface $createPage,
55
        IndexPageInterface $indexPage,
56
        UpdatePageInterface $updatePage,
57
        GeneratePageInterface $generatePage,
58
        CurrentPageResolverInterface $currentPageResolver,
59
        NotificationCheckerInterface $notificationChecker
60
    ) {
61
        $this->sharedStorage = $sharedStorage;
62
        $this->createPage = $createPage;
63
        $this->indexPage = $indexPage;
64
        $this->updatePage = $updatePage;
65
        $this->generatePage = $generatePage;
66
        $this->currentPageResolver = $currentPageResolver;
67
        $this->notificationChecker = $notificationChecker;
68
    }
69
70
    /**
71
     * @Given /^I want to create a new variant of (this product)$/
72
     */
73
    public function iWantToCreateANewProduct(ProductInterface $product)
74
    {
75
        $this->createPage->open(['productId' => $product->getId()]);
76
    }
77
78
    /**
79
     * @When I specify its code as :code
80
     * @When I do not specify its code
81
     */
82
    public function iSpecifyItsCodeAs($code = null)
83
    {
84
        $this->createPage->specifyCode($code ?? '');
85
    }
86
87
    /**
88
     * @When I name it :name in :language
89
     */
90
    public function iNameItIn($name, $language)
91
    {
92
        $this->createPage->nameItIn($name, $language);
93
    }
94
95
    /**
96
     * @When I add it
97
     * @When I try to add it
98
     */
99
    public function iAddIt()
100
    {
101
        $this->createPage->create();
102
    }
103
104
    /**
105
     * @When I change its :optionName option to :optionValue
106
     */
107
    public function iChangeItsOptionTo(string $optionName, string $optionValue): void
108
    {
109
        $this->updatePage->selectOption(strtoupper($optionName), $optionValue);
110
    }
111
112
    /**
113
     * @When I disable its inventory tracking
114
     */
115
    public function iDisableItsTracking()
116
    {
117
        $this->updatePage->disableTracking();
118
    }
119
120
    /**
121
     * @When I enable its inventory tracking
122
     */
123
    public function iEnableItsTracking()
124
    {
125
        $this->updatePage->enableTracking();
126
    }
127
128
    /**
129
     * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
130
     * @When I do not set its price
131
     */
132
    public function iSetItsPriceTo(?string $price = null, $channelName = null)
133
    {
134
        $this->createPage->specifyPrice($price ?? '', $channelName ?? (string) $this->sharedStorage->get('channel'));
135
    }
136
137
    /**
138
     * @When /^I set its original price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
139
     */
140
    public function iSetItsOriginalPriceTo($originalPrice, $channelName)
141
    {
142
        $this->createPage->specifyOriginalPrice($originalPrice, $channelName);
143
    }
144
145
    /**
146
     * @When I set its height, width, depth and weight to :number
147
     */
148
    public function iSetItsDimensionsTo($value)
149
    {
150
        $this->createPage->specifyHeightWidthDepthAndWeight($value, $value, $value, $value);
151
    }
152
153
    /**
154
     * @When I do not specify its current stock
155
     */
156
    public function iDoNetSetItsCurrentStockTo()
157
    {
158
        $this->createPage->specifyCurrentStock('');
159
    }
160
161
    /**
162
     * @When I choose :calculatorName calculator
163
     */
164
    public function iChooseCalculator($calculatorName)
165
    {
166
        $this->createPage->choosePricingCalculator($calculatorName);
167
    }
168
169
    /**
170
     * @When I set its :optionName option to :optionValue
171
     */
172
    public function iSetItsOptionAs($optionName, $optionValue)
173
    {
174
        $this->createPage->selectOption($optionName, $optionValue);
175
    }
176
177
    /**
178
     * @When I set the position of :name to :position
179
     */
180
    public function iSetThePositionOfTo($name, int $position)
181
    {
182
        $this->indexPage->setPosition($name, $position);
183
    }
184
185
    /**
186
     * @When I save my new configuration
187
     */
188
    public function iSaveMyNewConfiguration()
189
    {
190
        $this->indexPage->savePositions();
191
    }
192
193
    /**
194
     * @When I do not want to have shipping required for this product
195
     */
196
    public function iDoNotWantToHaveShippingRequiredForThisProduct()
197
    {
198
        $this->createPage->setShippingRequired(false);
199
    }
200
201
    /**
202
     * @When I check (also) the :productVariantName product variant
203
     */
204
    public function iCheckTheProductVariantName(string $productVariantName): void
205
    {
206
        $this->indexPage->checkResourceOnPage(['name' => $productVariantName]);
207
    }
208
209
    /**
210
     * @When I delete them
211
     */
212
    public function iDeleteThem(): void
213
    {
214
        $this->indexPage->bulkDelete();
215
    }
216
217
    /**
218
     * @Then /^the (variant with code "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
219
     */
220
    public function theVariantWithCodeShouldBePricedAtForChannel(ProductVariantInterface $productVariant, string $price, $channelName)
221
    {
222
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
223
224
        Assert::same($this->updatePage->getPriceForChannel($channelName), $price);
225
    }
226
227
    /**
228
     * @Then /^the (variant with code "[^"]+") should be named "([^"]+)" in ("([^"]+)" locale)$/
229
     */
230
    public function theVariantWithCodeShouldBeNamedIn(ProductVariantInterface $productVariant, $name, $language)
231
    {
232
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
233
234
        Assert::same($this->updatePage->getNameInLanguage($language), $name);
235
    }
236
237
    /**
238
     * @Then /^the (variant with code "[^"]+") should have an original price of (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
239
     */
240
    public function theVariantWithCodeShouldHaveAnOriginalPriceOfForChannel(ProductVariantInterface $productVariant, $originalPrice, $channelName)
241
    {
242
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
243
244
        Assert::same(
245
            $this->updatePage->getOriginalPriceForChannel($channelName),
246
            $originalPrice
247
        );
248
    }
249
250
    /**
251
     * @When /^I delete the ("[^"]+" variant of product "[^"]+")$/
252
     * @When /^I try to delete the ("[^"]+" variant of product "[^"]+")$/
253
     */
254
    public function iDeleteTheVariantOfProduct(ProductVariantInterface $productVariant)
255
    {
256
        $this->indexPage->open(['productId' => $productVariant->getProduct()->getId()]);
257
258
        $this->indexPage->deleteResourceOnPage(['code' => $productVariant->getCode()]);
259
    }
260
261
    /**
262
     * @Then I should be notified that this variant is in use and cannot be deleted
263
     */
264
    public function iShouldBeNotifiedOfFailure()
265
    {
266
        $this->notificationChecker->checkNotification(
267
            'Cannot delete, the product variant is in use.',
268
            NotificationType::failure()
269
        );
270
    }
271
272
    /**
273
     * @When /^I want to modify the ("[^"]+" product variant)$/
274
     */
275
    public function iWantToModifyAProduct(ProductVariantInterface $productVariant)
276
    {
277
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
278
    }
279
280
    /**
281
     * @Then the code field should be disabled
282
     */
283
    public function theCodeFieldShouldBeDisabled()
284
    {
285
        Assert::true($this->updatePage->isCodeDisabled());
286
    }
287
288
    /**
289
     * @Then I should be notified that :element is required
290
     */
291
    public function iShouldBeNotifiedThatIsRequired($element)
292
    {
293
        $this->assertValidationMessage($element, sprintf('Please enter the %s.', $element));
294
    }
295
296
    /**
297
     * @Then I should be notified that code has to be unique
298
     */
299
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
300
    {
301
        $this->assertValidationMessage('code', 'Product variant code must be unique.');
302
    }
303
304
    /**
305
     * @Then I should be notified that current stock is required
306
     */
307
    public function iShouldBeNotifiedThatOnHandIsRequired()
308
    {
309
        $this->assertValidationMessage('on_hand', 'Please enter on hand.');
310
    }
311
312
    /**
313
     * @Then I should be notified that height, width, depth and weight cannot be lower than 0
314
     */
315
    public function iShouldBeNotifiedThatIsHeightWidthDepthWeightCannotBeLowerThan()
316
    {
317
        $this->assertValidationMessage('height', 'Height cannot be negative.');
318
        $this->assertValidationMessage('width', 'Width cannot be negative.');
319
        $this->assertValidationMessage('depth', 'Depth cannot be negative.');
320
        $this->assertValidationMessage('weight', 'Weight cannot be negative.');
321
    }
322
323
    /**
324
     * @Then I should be notified that price cannot be lower than 0.01
325
     */
326
    public function iShouldBeNotifiedThatPriceCannotBeLowerThen()
327
    {
328
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
329
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
330
331
        Assert::contains($currentPage->getPricesValidationMessage(), 'Price must be at least 0.01.');
0 ignored issues
show
Bug introduced by
The method getPricesValidationMessage does only exist in Sylius\Behat\Page\Admin\...ant\CreatePageInterface, but not in Sylius\Behat\Page\Admin\...ant\UpdatePageInterface.

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...
332
    }
333
334
    /**
335
     * @Then I should be notified that this variant already exists
336
     */
337
    public function iShouldBeNotifiedThatThisVariantAlreadyExists()
338
    {
339
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
340
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
341
342
        Assert::same($currentPage->getValidationMessageForForm(), 'Variant with this option set already exists.');
0 ignored issues
show
Bug introduced by
The method getValidationMessageForForm does only exist in Sylius\Behat\Page\Admin\...ant\CreatePageInterface, but not in Sylius\Behat\Page\Admin\...ant\UpdatePageInterface.

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...
343
    }
344
345
    /**
346
     * @Then /^I should be notified that code is required for the (\d)(?:st|nd|rd|th) variant$/
347
     */
348
    public function iShouldBeNotifiedThatCodeIsRequiredForVariant($position)
349
    {
350
        Assert::same(
351
            $this->generatePage->getValidationMessage('code', $position - 1),
352
            'Please enter the code.'
353
        );
354
    }
355
356
    /**
357
     * @Then /^I should be notified that prices in all channels must be defined for the (\d)(?:st|nd|rd|th) variant$/
358
     */
359
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefinedForTheVariant($position)
360
    {
361
        Assert::same(
362
            $this->generatePage->getPricesValidationMessage($position - 1),
363
            'You must define price for every channel.'
364
        );
365
    }
366
367
    /**
368
     * @Then /^I should be notified that variant code must be unique within this product for the (\d)(?:st|nd|rd|th) variant$/
369
     */
370
    public function iShouldBeNotifiedThatVariantCodeMustBeUniqueWithinThisProductForYheVariant($position)
371
    {
372
        Assert::same(
373
            $this->generatePage->getValidationMessage('code', $position - 1),
374
            'This code must be unique within this product.'
375
        );
376
    }
377
378
    /**
379
     * @Then I should be notified that prices in all channels must be defined
380
     */
381
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefined()
382
    {
383
        Assert::contains(
384
            $this->createPage->getPricesValidationMessage(),
385
            'You must define price for every channel.'
386
        );
387
    }
388
389
    /**
390
     * @When I save my changes
391
     * @When I try to save my changes
392
     */
393
    public function iSaveMyChanges()
394
    {
395
        $this->updatePage->saveChanges();
396
    }
397
398
    /**
399
     * @Then /^inventory of (this variant) should not be tracked$/
400
     */
401
    public function thisProductVariantShouldNotBeTracked(ProductVariantInterface $productVariant)
402
    {
403
        $this->iWantToModifyAProduct($productVariant);
404
405
        Assert::false($this->updatePage->isTracked());
406
    }
407
408
    /**
409
     * @Then /^inventory of (this variant) should be tracked$/
410
     */
411
    public function thisProductVariantShouldBeTracked(ProductVariantInterface $productVariant)
412
    {
413
        $this->iWantToModifyAProduct($productVariant);
414
415
        Assert::true($this->updatePage->isTracked());
416
    }
417
418
    /**
419
     * @When I generate it
420
     * @When I try to generate it
421
     */
422
    public function iClickGenerate()
423
    {
424
        $this->generatePage->generate();
425
    }
426
427
    /**
428
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code and costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
429
     */
430
    public function iSpecifyThereAreVariantsIdentifiedByCodeWithCost($nthVariant, $code, int $price, $channelName)
431
    {
432
        $this->generatePage->specifyCode($nthVariant - 1, $code);
433
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
434
    }
435
436
    /**
437
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code$/
438
     */
439
    public function iSpecifyThereAreVariantsIdentifiedByCode($nthVariant, $code)
440
    {
441
        $this->generatePage->specifyCode($nthVariant - 1, $code);
442
    }
443
444
    /**
445
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
446
     */
447
    public function iSpecifyThereAreVariantsWithCost($nthVariant, int $price, $channelName)
448
    {
449
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
450
    }
451
452
    /**
453
     * @When /^I remove (\d)(?:st|nd|rd|th) variant from the list$/
454
     */
455
    public function iRemoveVariantFromTheList($nthVariant)
456
    {
457
        $this->generatePage->removeVariant($nthVariant - 1);
458
    }
459
460
    /**
461
     * @Then I should be notified that it has been successfully generated
462
     */
463
    public function iShouldBeNotifiedThatItHasBeenSuccessfullyGenerated()
464
    {
465
        $this->notificationChecker->checkNotification('Success Product variants have been successfully generated.', NotificationType::success());
466
    }
467
468
    /**
469
     * @Then I should not be able to generate any variants
470
     */
471
    public function iShouldNotBeAbleToGenerateAnyVariants(): void
472
    {
473
        Assert::false($this->generatePage->isGenerationPossible());
474
    }
475
476
    /**
477
     * @When I set its shipping category as :shippingCategoryName
478
     */
479
    public function iSetItsShippingCategoryAs($shippingCategoryName)
480
    {
481
        $this->createPage->selectShippingCategory($shippingCategoryName);
482
    }
483
484
    /**
485
     * @When I do not specify any information about variants
486
     */
487
    public function iDoNotSpecifyAnyInformationAboutVariants()
488
    {
489
        // Intentionally left blank to fulfill context expectation
490
    }
491
492
    /**
493
     * @When I change its quantity of inventory to :amount
494
     */
495
    public function iChangeItsQuantityOfInventoryTo(int $amount)
496
    {
497
        $this->updatePage->specifyCurrentStock($amount);
498
    }
499
500
    /**
501
     * @Then /^the (variant with code "[^"]+") should not have shipping required$/
502
     */
503
    public function theVariantWithCodeShouldNotHaveShippingRequired(ProductVariantInterface $productVariant)
504
    {
505
        $this->updatePage->open(['productId' => $productVariant->getProduct()->getId(), 'id' => $productVariant->getId()]);
506
507
        Assert::false($this->updatePage->isShippingRequired());
508
    }
509
510
    /**
511
     * @Then I should be notified that on hand quantity must be greater than the number of on hold units
512
     */
513
    public function iShouldBeNotifiedThatOnHandQuantityMustBeGreaterThanTheNumberOfOnHoldUnits()
514
    {
515
        Assert::same(
516
            $this->updatePage->getValidationMessage('on_hand'),
517
            'On hand must be greater than the number of on hold units'
518
        );
519
    }
520
521
    /**
522
     * @Then I should be notified that variants cannot be generated from options without any values
523
     */
524
    public function iShouldBeNotifiedThatVariantsCannotBeGeneratedFromOptionsWithoutAnyValues(): void
525
    {
526
        $this->notificationChecker->checkNotification('Cannot generate variants for a product without options values', NotificationType::failure());
527
    }
528
529
    /**
530
     * @Then I should see the :optionName option as :valueName
531
     */
532
    public function iShouldSeeTheOptionAs(string $optionName, string $valueName): void
533
    {
534
        Assert::true($this->updatePage->isSelectedOptionValueOnPage($optionName, $valueName));
535
    }
536
537
    /**
538
     * @When /^I want to generate new variants for (this product)$/
539
     * @When /^I try to generate new variants for (this product)$/
540
     */
541
    public function iTryToGenerateNewVariantsForThisProduct(ProductInterface $product): void
542
    {
543
        $this->generatePage->open(['productId' => $product->getId()]);
544
    }
545
546
    /**
547
     * @param string $element
548
     * @param string $message
549
     */
550
    private function assertValidationMessage($element, $message)
551
    {
552
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
553
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
554
555
        Assert::same($currentPage->getValidationMessage($element), $message);
556
    }
557
}
558