Completed
Push — unused-definitions ( d9908f )
by Kamil
18:33
created

theVariantOfProductShouldHaveItemsOnHand()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 3
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\ProductVariant\CreatePageInterface;
17
use Sylius\Behat\Page\Admin\ProductVariant\GeneratePageInterface;
18
use Sylius\Behat\Page\Admin\ProductVariant\IndexPageInterface;
19
use Sylius\Behat\Page\Admin\ProductVariant\UpdatePageInterface;
20
use Sylius\Behat\Service\NotificationCheckerInterface;
21
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
22
use Sylius\Component\Core\Model\ChannelInterface;
23
use Sylius\Component\Core\Model\ProductInterface;
24
use Sylius\Component\Core\Model\ProductVariantInterface;
25
use Sylius\Behat\Service\SharedStorageInterface;
26
use Sylius\Component\Currency\Model\CurrencyInterface;
27
use Sylius\Component\Product\Resolver\DefaultProductVariantResolver;
28
use Webmozart\Assert\Assert;
29
30
/**
31
 * @author Łukasz Chruściel <[email protected]>
32
 */
33
final class ManagingProductVariantsContext implements Context
34
{
35
    /**
36
     * @var SharedStorageInterface
37
     */
38
    private $sharedStorage;
39
40
    /**
41
     * @var DefaultProductVariantResolver
42
     */
43
    private $defaultProductVariantResolver;
44
45
    /**
46
     * @var CreatePageInterface
47
     */
48
    private $createPage;
49
50
    /**
51
     * @var IndexPageInterface
52
     */
53
    private $indexPage;
54
55
    /**
56
     * @var UpdatePageInterface
57
     */
58
    private $updatePage;
59
60
    /**
61
     * @var GeneratePageInterface
62
     */
63
    private $generatePage;
64
65
    /**
66
     * @var CurrentPageResolverInterface
67
     */
68
    private $currentPageResolver;
69
70
    /**
71
     * @var NotificationCheckerInterface
72
     */
73
    private $notificationChecker;
74
75
    /**
76
     * @param SharedStorageInterface $sharedStorage
77
     * @param DefaultProductVariantResolver $defaultProductVariantResolver
78
     * @param CreatePageInterface $createPage
79
     * @param IndexPageInterface $indexPage
80
     * @param UpdatePageInterface $updatePage
81
     * @param GeneratePageInterface $generatePage
82
     * @param CurrentPageResolverInterface $currentPageResolver
83
     * @param NotificationCheckerInterface $notificationChecker
84
     */
85
    public function __construct(
86
        SharedStorageInterface $sharedStorage,
87
        DefaultProductVariantResolver $defaultProductVariantResolver,
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $defaultProductVariantResolver exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
88
        CreatePageInterface $createPage,
89
        IndexPageInterface $indexPage,
90
        UpdatePageInterface $updatePage,
91
        GeneratePageInterface $generatePage,
92
        CurrentPageResolverInterface $currentPageResolver,
93
        NotificationCheckerInterface $notificationChecker
94
    ) {
95
        $this->sharedStorage = $sharedStorage;
96
        $this->defaultProductVariantResolver = $defaultProductVariantResolver;
97
        $this->createPage = $createPage;
98
        $this->indexPage = $indexPage;
99
        $this->updatePage = $updatePage;
100
        $this->generatePage = $generatePage;
101
        $this->currentPageResolver = $currentPageResolver;
102
        $this->notificationChecker = $notificationChecker;
103
    }
104
105
    /**
106
     * @Given /^I want to create a new variant of (this product)$/
107
     */
108
    public function iWantToCreateANewProduct(ProductInterface $product)
109
    {
110
        $this->createPage->open(['productId' => $product->getId()]);
111
    }
112
113
    /**
114
     * @When I specify its code as :code
115
     * @When I do not specify its code
116
     */
117
    public function iSpecifyItsCodeAs($code = null)
118
    {
119
        $this->createPage->specifyCode($code);
120
    }
121
122
    /**
123
     * @When I name it :name in :language
124
     */
125
    public function iNameItIn($name, $language)
126
    {
127
        $this->createPage->nameItIn($name, $language);
128
    }
129
130
    /**
131
     * @When I rename it to :name
132
     */
133
    public function iRenameItTo($name)
134
    {
135
        $this->updatePage->nameIt($name);
0 ignored issues
show
Bug introduced by
The method nameIt() does not seem to exist on object<Sylius\Behat\Page...nt\UpdatePageInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
136
    }
137
138
    /**
139
     * @When I add it
140
     * @When I try to add it
141
     */
142
    public function iAddIt()
143
    {
144
        $this->createPage->create();
145
    }
146
147
    /**
148
     * @When I disable its inventory tracking
149
     */
150
    public function iDisableItsTracking()
151
    {
152
        $this->updatePage->disableTracking();
153
    }
154
155
    /**
156
     * @When I enable its inventory tracking
157
     */
158
    public function iEnableItsTracking()
159
    {
160
        $this->updatePage->enableTracking();
161
    }
162
163
    /**
164
     * @When /^I set its(?:| default) price to "(?:€|£|\$)([^"]+)" for "([^"]+)" channel$/
165
     * @When I do not set its price
166
     */
167
    public function iSetItsPriceTo($price = null, $channel = null)
168
    {
169
        $this->createPage->specifyPrice($price, (null === $channel) ? $this->sharedStorage->get('channel') :$channel);
170
    }
171
172
    /**
173
     * @When I set its height, width, depth and weight to :number
174
     */
175
    public function iSetItsDimensionsTo($value)
176
    {
177
        $this->createPage->specifyHeightWidthDepthAndWeight($value, $value, $value, $value);
178
    }
179
180
    /**
181
     * @When I do not specify its current stock
182
     */
183
    public function iDoNetSetItsCurrentStockTo()
184
    {
185
        $this->createPage->specifyCurrentStock('');
186
    }
187
188
    /**
189
     * @When I choose :calculatorName calculator
190
     */
191
    public function iChooseCalculator($calculatorName)
192
    {
193
        $this->createPage->choosePricingCalculator($calculatorName);
194
    }
195
196
    /**
197
     * @When I set its :optionName option to :optionValue
198
     */
199
    public function iSetItsOptionAs($optionName, $optionValue)
200
    {
201
        $this->createPage->selectOption($optionName, $optionValue);
202
    }
203
204
    /**
205
     * @Then the :productVariantCode variant of the :product product should appear in the store
206
     */
207
    public function theProductVariantShouldAppearInTheShop($productVariantCode, ProductInterface $product)
208
    {
209
        $this->iWantToViewAllVariantsOfThisProduct($product);
210
211
        Assert::true(
212
            $this->indexPage->isSingleResourceOnPage(['code' => $productVariantCode]),
213
            sprintf('The product variant with code %s has not been found.', $productVariantCode)
214
        );
215
    }
216
217
    /**
218
     * @Then the :productVariantCode variant of the :product product should not appear in the store
219
     */
220
    public function theProductVariantShouldNotAppearInTheShop($productVariantCode, ProductInterface $product)
221
    {
222
        $this->iWantToViewAllVariantsOfThisProduct($product);
223
224
        Assert::false(
225
            $this->indexPage->isSingleResourceOnPage(['code' => $productVariantCode]),
226
            sprintf('The product variant with code %s has not been found.', $productVariantCode)
227
        );
228
    }
229
230
    /**
231
     * @Then the :product product should have no variants
232
     */
233
    public function theProductShouldHaveNoVariants(ProductInterface $product)
234
    {
235
        $this->assertNumberOfVariantsOnProductPage($product, 0);
236
    }
237
238
    /**
239
     * @Then the :product product should have only one variant
240
     */
241
    public function theProductShouldHaveOnlyOneVariant(ProductInterface $product)
242
    {
243
        $this->assertNumberOfVariantsOnProductPage($product, 1);
244
    }
245
246
    /**
247
     * @Then /^the (variant with code "[^"]+") should be priced at (?:€|£|\$)([^"]+) for channel "([^"]+)"$/
248
     */
249
    public function theVariantWithCodeShouldBePricedAtForChannel(ProductVariantInterface $productVariant, $price, $channelName)
250
    {
251
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
252
253
        Assert::same(
254
            $this->updatePage->getPriceForChannel($channelName),
255
            $price
256
        );
257
    }
258
259
    /**
260
     * @Then /^the (variant with code "[^"]+") should be named "([^"]+)" in ("([^"]+)" locale)$/
261
     */
262
    public function theVariantWithCodeShouldBeNamedIn(ProductVariantInterface $productVariant, $name, $language)
263
    {
264
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
265
266
        Assert::same($name, $this->updatePage->getNameInLanguage($language));
267
    }
268
269
    /**
270
     * @When /^I (?:|want to )view all variants of (this product)$/
271
     * @When /^I view(?:| all) variants of the (product "[^"]+")$/
272
     */
273
    public function iWantToViewAllVariantsOfThisProduct(ProductInterface $product)
274
    {
275
        $this->indexPage->open(['productId' => $product->getId()]);
276
    }
277
278
    /**
279
     * @Then I should see :numberOfProductVariants variants in the list
280
     * @Then I should see :numberOfProductVariants variant in the list
281
     * @Then I should not see any variants in the list
282
     */
283
    public function iShouldSeeProductVariantsInTheList($numberOfProductVariants = 0)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $numberOfProductVariants exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
284
    {
285
        $foundRows = $this->indexPage->countItems();
286
287
        Assert::same(
288
            (int) $numberOfProductVariants,
289
            $foundRows,
290
            '%s rows with product variants should appear on page, %s rows has been found'
291
        );
292
    }
293
294
    /**
295
     * @When /^I delete the ("[^"]+" variant of product "[^"]+")$/
296
     * @When /^I try to delete the ("[^"]+" variant of product "[^"]+")$/
297
     */
298
    public function iDeleteTheVariantOfProduct(ProductVariantInterface $productVariant)
299
    {
300
        $this->iWantToViewAllVariantsOfThisProduct($productVariant->getProduct());
0 ignored issues
show
Compatibility introduced by
$productVariant->getProduct() of type object<Sylius\Component\...Model\ProductInterface> is not a sub-type of object<Sylius\Component\...Model\ProductInterface>. It seems like you assume a child interface of the interface Sylius\Component\Product\Model\ProductInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
301
302
        $this->indexPage->deleteResourceOnPage(['code' => $productVariant->getCode()]);
303
    }
304
305
    /**
306
     * @Then /^(this variant) should not exist in the product catalog$/
307
     */
308
    public function productVariantShouldNotExist(ProductVariantInterface $productVariant)
309
    {
310
        $this->iWantToViewAllVariantsOfThisProduct($productVariant->getProduct());
0 ignored issues
show
Compatibility introduced by
$productVariant->getProduct() of type object<Sylius\Component\...Model\ProductInterface> is not a sub-type of object<Sylius\Component\...Model\ProductInterface>. It seems like you assume a child interface of the interface Sylius\Component\Product\Model\ProductInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
311
312
        Assert::false(
313
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName()]),
314
            sprintf('Product variant with code %s exists but should not.', $productVariant->getName())
315
        );
316
    }
317
318
    /**
319
     * @Then I should be notified that this variant is in use and cannot be deleted
320
     */
321
    public function iShouldBeNotifiedOfFailure()
322
    {
323
        $this->notificationChecker->checkNotification(
324
            "Cannot delete, the product variant is in use.",
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal Cannot delete, the product variant 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...
325
            NotificationType::failure()
326
        );
327
    }
328
329
    /**
330
     * @Then /^(this variant) should still exist in the product catalog$/
331
     */
332
    public function productShouldExistInTheProductCatalog(ProductVariantInterface $productVariant)
333
    {
334
        $this->theProductVariantShouldAppearInTheShop($productVariant->getCode(), $productVariant->getProduct());
0 ignored issues
show
Compatibility introduced by
$productVariant->getProduct() of type object<Sylius\Component\...Model\ProductInterface> is not a sub-type of object<Sylius\Component\...Model\ProductInterface>. It seems like you assume a child interface of the interface Sylius\Component\Product\Model\ProductInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
335
    }
336
337
    /**
338
     * @When /^I want to modify the ("[^"]+" product variant)$/
339
     */
340
    public function iWantToModifyAProduct(ProductVariantInterface $productVariant)
341
    {
342
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
343
    }
344
345
    /**
346
     * @Then the code field should be disabled
347
     */
348
    public function theCodeFieldShouldBeDisabled()
349
    {
350
        Assert::true(
351
            $this->updatePage->isCodeDisabled(),
352
            'Code should be immutable, but it does not.'
353
        );
354
    }
355
356
    /**
357
     * @Then I should be notified that :element is required
358
     */
359
    public function iShouldBeNotifiedThatIsRequired($element)
360
    {
361
        $this->assertValidationMessage($element, sprintf('Please enter the %s.', $element));
362
    }
363
364
    /**
365
     * @Then I should be notified that code has to be unique
366
     */
367
    public function iShouldBeNotifiedThatCodeHasToBeUnique()
368
    {
369
        $this->assertValidationMessage('code', 'Product variant code must be unique.');
370
    }
371
372
    /**
373
     * @Then I should be notified that current stock is required
374
     */
375
    public function iShouldBeNotifiedThatOnHandIsRequired()
376
    {
377
        $this->assertValidationMessage('on_hand', 'Please enter on hand.');
378
    }
379
380
    /**
381
     * @Then I should be notified that height, width, depth and weight cannot be lower than 0
382
     */
383
    public function iShouldBeNotifiedThatIsHeightWidthDepthWeightCannotBeLowerThan()
384
    {
385
        $this->assertValidationMessage('height', 'Height cannot be negative.');
386
        $this->assertValidationMessage('width', 'Width cannot be negative.');
387
        $this->assertValidationMessage('depth', 'Depth cannot be negative.');
388
        $this->assertValidationMessage('weight', 'Weight cannot be negative.');
389
    }
390
391
    /**
392
     * @Then I should be notified that price cannot be lower than 0.01
393
     */
394
    public function iShouldBeNotifiedThatPriceCannotBeLowerThen()
395
    {
396
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
397
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
398
399
        Assert::same($currentPage->getFirstPriceValidationMessage(), 'Price must be at least 0.01.');
0 ignored issues
show
Bug introduced by
The method getFirstPriceValidationMessage 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...
400
    }
401
402
    /**
403
     * @Then I should be notified that this variant already exists
404
     */
405
    public function iShouldBeNotifiedThatThisVariantAlreadyExists()
406
    {
407
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
408
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
409
410
        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...
411
    }
412
413
    /**
414
     * @Then /^I should be notified that code is required for the (\d)(?:st|nd|rd|th) variant$/
415
     */
416
    public function iShouldBeNotifiedThatCodeIsRequiredForVariant($position)
417
    {
418
        Assert::same(
419
            $this->generatePage->getValidationMessage('code', $position - 1),
420
            'Please enter the code.'
421
        );
422
    }
423
424
    /**
425
     * @Then /^I should be notified that prices in all channels must be defined for the (\d)(?:st|nd|rd|th) variant$/
426
     */
427
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefinedForTheVariant($position)
428
    {
429
        Assert::same(
430
            $this->generatePage->getPricesValidationMessage($position - 1),
431
            'You must define price for every channel.'
432
        );
433
    }
434
435
    /**
436
     * @Then /^I should be notified that variant code must be unique within this product for the (\d)(?:st|nd|rd|th) variant$/
437
     */
438
    public function iShouldBeNotifiedThatVariantCodeMustBeUniqueWithinThisProductForYheVariant($position)
439
    {
440
        Assert::same(
441
            $this->generatePage->getValidationMessage('code', $position - 1),
442
            'This code must be unique within this product.'
443
        );
444
    }
445
446
    /**
447
     * @Then I should be notified that prices in all channels must be defined
448
     */
449
    public function iShouldBeNotifiedThatPricesInAllChannelsMustBeDefined()
450
    {
451
        Assert::same(
452
            $this->createPage->getPricesValidationMessage(),
453
            'You must define price for every channel.'
454
        );
455
    }
456
457
    /**
458
     * @When I save my changes
459
     * @When I try to save my changes
460
     */
461
    public function iSaveMyChanges()
462
    {
463
        $this->updatePage->saveChanges();
464
    }
465
466
    /**
467
     * @When I remove its name
468
     */
469
    public function iRemoveItsNameFromTranslation()
470
    {
471
        $this->updatePage->nameIt('');
0 ignored issues
show
Bug introduced by
The method nameIt() does not seem to exist on object<Sylius\Behat\Page...nt\UpdatePageInterface>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
472
    }
473
474
    /**
475
     * @Then /^the variant "([^"]+)" should have (\d+) items on hand$/
476
     */
477
    public function thisVariantShouldHaveItemsOnHand($productVariantName, $quantity)
478
    {
479
        Assert::true(
480
            $this->indexPage->isSingleResourceWithSpecificElementOnPage(['name' => $productVariantName], sprintf('td > div.ui.label:contains("%s")', $quantity)),
481
            sprintf('The product variant %s should have %s items on hand, but it does not.', $productVariantName, $quantity)
482
        );
483
    }
484
485
    /**
486
     * @Then /^the "([^"]+)" variant of ("[^"]+" product) should have (\d+) items on hand$/
487
     */
488
    public function theVariantOfProductShouldHaveItemsOnHand($productVariantName, ProductInterface $product, $quantity)
489
    {
490
        $this->indexPage->open(['productId' => $product->getId()]);
491
492
        Assert::true(
493
            $this->indexPage->isSingleResourceWithSpecificElementOnPage(['name' => $productVariantName], sprintf('td > div.ui.label:contains("%s")', $quantity)),
494
            sprintf('The product variant %s should have %s items on hand, but it does not.', $productVariantName, $quantity)
495
        );
496
    }
497
498
    /**
499
     * @Then /^inventory of (this variant) should not be tracked$/
500
     */
501
    public function thisProductVariantShouldNotBeTracked(ProductVariantInterface $productVariant)
502
    {
503
        $this->iWantToModifyAProduct($productVariant);
504
505
        Assert::false(
506
            $this->updatePage->isTracked(),
507
            'This variant should not be tracked, but it is.'
508
        );
509
    }
510
511
    /**
512
     * @Then /^inventory of (this variant) should be tracked$/
513
     */
514
    public function thisProductVariantShouldBeTracked(ProductVariantInterface $productVariant)
515
    {
516
        $this->iWantToModifyAProduct($productVariant);
517
518
        Assert::true(
519
            $this->updatePage->isTracked(),
520
            'This variant should be tracked, but it is not.'
521
        );
522
    }
523
524
    /**
525
     * @Then /^I should see that the ("([^"]+)" variant) is not tracked$/
526
     */
527
    public function iShouldSeeThatIsNotTracked(ProductVariantInterface $productVariant)
528
    {
529
        Assert::true(
530
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName(), 'inventory' => 'Not tracked']),
531
            sprintf('This "%s" variant should have label not tracked, but it does not have', $productVariant->getName())
532
        );
533
    }
534
535
    /**
536
     * @Then /^I should see that the ("[^"]+" variant) has zero on hand quantity$/
537
     */
538
    public function iShouldSeeThatTheVariantHasZeroOnHandQuantity(ProductVariantInterface $productVariant)
539
    {
540
        Assert::true(
541
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName(), 'inventory' => '0 Available on hand']),
542
            sprintf('This "%s" variant should have 0 on hand quantity, but it does not.', $productVariant->getName())
543
        );
544
    }
545
546
    /**
547
     * @Then /^(\d+) units of (this product) should be on hold$/
548
     */
549
    public function unitsOfThisProductShouldBeOnHold($quantity, ProductInterface $product)
550
    {
551
        /** @var ProductVariantInterface $variant */
552
        $variant = $this->defaultProductVariantResolver->getVariant($product);
553
554
        $this->assertOnHoldQuantityOfVariant($quantity, $variant);
555
    }
556
557
    /**
558
     * @Then /^(\d+) units of (this product) should be on hand$/
559
     */
560
    public function unitsOfThisProductShouldBeOnHand($quantity, ProductInterface $product)
561
    {
562
        /** @var ProductVariantInterface $variant */
563
        $variant = $this->defaultProductVariantResolver->getVariant($product);
564
        $actualQuantity = $this->indexPage->getOnHandQuantityFor($variant);
565
566
        Assert::same(
567
            (int) $quantity,
568
            $actualQuantity,
569
            sprintf(
570
                'Unexpected on hand quantity for "%s" variant. It should be "%s" but is "%s"',
571
                $variant->getName(),
572
                $quantity,
573
                $actualQuantity
574
            )
575
        );
576
    }
577
578
    /**
579
     * @Then /^there should be no units of (this product) on hold$/
580
     */
581
    public function thereShouldBeNoUnitsOfThisProductOnHold(ProductInterface $product)
582
    {
583
        /** @var ProductVariantInterface $variant */
584
        $variant = $this->defaultProductVariantResolver->getVariant($product);
585
586
        $this->assertOnHoldQuantityOfVariant(0, $variant);
587
    }
588
589
    /**
590
     * @Then the :variant variant should have :amount items on hold
591
     */
592
    public function thisVariantShouldHaveItemsOnHold(ProductVariantInterface $variant, $amount)
593
    {
594
        $this->assertOnHoldQuantityOfVariant((int) $amount, $variant);
595
    }
596
597
    /**
598
     * @Then the :variant variant of :product product should have :amount items on hold
599
     */
600
    public function theVariantOfProductShouldHaveItemsOnHold(ProductVariantInterface $variant, ProductInterface $product, $amount)
601
    {
602
        $this->indexPage->open(['productId' => $product->getId()]);
603
604
        $this->assertOnHoldQuantityOfVariant((int) $amount, $variant);
605
    }
606
607
    /**
608
     * @When /^I want to generate new variants for (this product)$/
609
     */
610
    public function iWantToGenerateNewVariantsForThisProduct(ProductInterface $product)
611
    {
612
        $this->generatePage->open(['productId' => $product->getId()]);
613
    }
614
615
    /**
616
     * @When I generate it
617
     * @When I try to generate it
618
     */
619
    public function iClickGenerate()
620
    {
621
        $this->generatePage->generate();
622
    }
623
624
    /**
625
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code and costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
626
     */
627
    public function iSpecifyThereAreVariantsIdentifiedByCodeWithCost($nthVariant, $code, $price, $channelName)
628
    {
629
        $this->generatePage->specifyCode($nthVariant - 1, $code);
630
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
631
    }
632
633
    /**
634
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant is identified by "([^"]+)" code$/
635
     */
636
    public function iSpecifyThereAreVariantsIdentifiedByCode($nthVariant, $code)
637
    {
638
        $this->generatePage->specifyCode($nthVariant - 1, $code);
639
    }
640
641
    /**
642
     * @When /^I specify that the (\d)(?:st|nd|rd|th) variant costs "(?:€|£|\$)([^"]+)" in ("[^"]+") channel$/
643
     */
644
    public function iSpecifyThereAreVariantsWithCost($nthVariant, $price, $channelName)
645
    {
646
        $this->generatePage->specifyPrice($nthVariant - 1, $price, $channelName);
647
    }
648
649
    /**
650
     * @When /^I remove (\d)(?:st|nd|rd|th) variant from the list$/
651
     */
652
    public function iRemoveVariantFromTheList($nthVariant)
653
    {
654
        $this->generatePage->removeVariant($nthVariant - 1);
655
    }
656
657
    /**
658
     * @Then I should be notified that it has been successfully generated
659
     */
660
    public function iShouldBeNotifiedThatItHasBeenSuccessfullyGenerated()
661
    {
662
        $this->notificationChecker->checkNotification('Success Product variants have been successfully generated.', NotificationType::success());
663
    }
664
665
    /**
666
     * @When I set its shipping category as :shippingCategoryName
667
     */
668
    public function iSetItsShippingCategoryAs($shippingCategoryName)
669
    {
670
        $this->createPage->selectShippingCategory($shippingCategoryName);
671
    }
672
673
    /**
674
     * @When I do not specify any information about variants
675
     */
676
    public function iDoNotSpecifyAnyInformationAboutVariants()
677
    {
678
        // Intentionally left blank to fulfill context expectation
679
    }
680
681
    /**
682
     * @param string $element
683
     * @param $message
684
     */
685
    private function assertValidationMessage($element, $message)
686
    {
687
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
688
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
689
690
        Assert::same($currentPage->getValidationMessage($element), $message);
691
    }
692
693
    /**
694
     * @param int $expectedAmount
695
     * @param ProductVariantInterface $variant
696
     *
697
     * @throws \InvalidArgumentException
698
     */
699
    private function assertOnHoldQuantityOfVariant($expectedAmount, $variant)
700
    {
701
        $actualAmount = $this->indexPage->getOnHoldQuantityFor($variant);
702
703
        Assert::same(
704
            (int) $expectedAmount,
705
            $actualAmount,
706
            sprintf(
707
                'Unexpected on hold quantity for "%s" variant. It should be "%s" but is "%s"',
708
                $variant->getName(),
709
                $expectedAmount,
710
                $actualAmount
711
            )
712
        );
713
    }
714
715
    /**
716
     * @param ProductInterface $product
717
     * @param int $amount
718
     */
719
    private function assertNumberOfVariantsOnProductPage(ProductInterface $product, $amount)
720
    {
721
        $this->iWantToViewAllVariantsOfThisProduct($product);
722
723
        Assert::same((int) $this->indexPage->countItems(), $amount, 'Product has %d variants, but should have %d');
724
    }
725
}
726