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

theProductForCurrencyAndChannelShouldHave()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 1
eloc 9
nc 1
nop 4
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\IndexPageInterface;
18
use Sylius\Behat\Page\Admin\ProductVariant\UpdatePageInterface;
19
use Sylius\Behat\Service\NotificationCheckerInterface;
20
use Sylius\Behat\Service\Resolver\CurrentPageResolverInterface;
21
use Sylius\Component\Core\Model\ChannelInterface;
22
use Sylius\Component\Core\Model\ProductInterface;
23
use Sylius\Component\Core\Model\ProductVariantInterface;
24
use Sylius\Behat\Service\SharedStorageInterface;
25
use Sylius\Component\Currency\Model\CurrencyInterface;
26
use Sylius\Component\Product\Resolver\DefaultProductVariantResolver;
27
use Webmozart\Assert\Assert;
28
29
/**
30
 * @author Łukasz Chruściel <[email protected]>
31
 */
32
final class ManagingProductVariantsContext implements Context
33
{
34
    /**
35
     * @var SharedStorageInterface
36
     */
37
    private $sharedStorage;
38
39
    /**
40
     * @var DefaultProductVariantResolver
41
     */
42
    private $defaultProductVariantResolver;
43
44
    /**
45
     * @var CreatePageInterface
46
     */
47
    private $createPage;
48
49
    /**
50
     * @var IndexPageInterface
51
     */
52
    private $indexPage;
53
54
    /**
55
     * @var UpdatePageInterface
56
     */
57
    private $updatePage;
58
59
    /**
60
     * @var CurrentPageResolverInterface
61
     */
62
    private $currentPageResolver;
63
64
    /**
65
     * @var NotificationCheckerInterface
66
     */
67
    private $notificationChecker;
68
69
    /**
70
     * @param SharedStorageInterface $sharedStorage
71
     * @param DefaultProductVariantResolver $defaultProductVariantResolver
72
     * @param CreatePageInterface $createPage
73
     * @param IndexPageInterface $indexPage
74
     * @param UpdatePageInterface $updatePage
75
     * @param CurrentPageResolverInterface $currentPageResolver
76
     * @param NotificationCheckerInterface $notificationChecker
77
     */
78
    public function __construct(
79
        SharedStorageInterface $sharedStorage,
80
        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...
81
        CreatePageInterface $createPage,
82
        IndexPageInterface $indexPage,
83
        UpdatePageInterface $updatePage,
84
        CurrentPageResolverInterface $currentPageResolver,
85
        NotificationCheckerInterface $notificationChecker
86
    ) {
87
        $this->sharedStorage = $sharedStorage;
88
        $this->defaultProductVariantResolver = $defaultProductVariantResolver;
89
        $this->createPage = $createPage;
90
        $this->indexPage = $indexPage;
91
        $this->updatePage = $updatePage;
92
        $this->currentPageResolver = $currentPageResolver;
93
        $this->notificationChecker = $notificationChecker;
94
    }
95
96
    /**
97
     * @Given /^I want to create a new variant of (this product)$/
98
     */
99
    public function iWantToCreateANewProduct(ProductInterface $product)
100
    {
101
        $this->createPage->open(['productId' => $product->getId()]);
102
    }
103
104
    /**
105
     * @When I specify its code as :code
106
     * @When I do not specify its code
107
     */
108
    public function iSpecifyItsCodeAs($code = null)
109
    {
110
        $this->createPage->specifyCode($code);
111
    }
112
113
    /**
114
     * @When I name it :name
115
     */
116
    public function iNameItIn($name)
117
    {
118
        $this->createPage->nameIt($name);
119
    }
120
121
    /**
122
     * @When I rename it to :name
123
     */
124
    public function iRenameItTo($name)
125
    {
126
        $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...
127
    }
128
129
    /**
130
     * @When I add it
131
     * @When I try to add it
132
     */
133
    public function iAddIt()
134
    {
135
        $this->createPage->create();
136
    }
137
138
    /**
139
     * @When I disable its inventory tracking
140
     */
141
    public function iDisableItsTracking()
142
    {
143
        $this->updatePage->disableTracking();
144
    }
145
146
    /**
147
     * @When I enable its inventory tracking
148
     */
149
    public function iEnableItsTracking()
150
    {
151
        $this->updatePage->enableTracking();
152
    }
153
154
    /**
155
     * @When /^I set its(?:| default) price to ("(?:€|£|\$)[^"]+")$/
156
     */
157
    public function iSetItsPriceTo($price)
158
    {
159
        $this->createPage->specifyPrice($price);
160
    }
161
162
    /**
163
     * @When I choose :calculatorName calculator
164
     */
165
    public function iChooseCalculator($calculatorName)
166
    {
167
        $this->createPage->choosePricingCalculator($calculatorName);
168
    }
169
170
    /**
171
     * @When /^I set its price to "(?:€|£|\$)([^"]+)" for ("[^"]+" currency) and ("[^"]+" channel)$/
172
     */
173
    public function iSetItsPriceToForCurrencyAndChannel($price, CurrencyInterface $currency, ChannelInterface $channel)
174
    {
175
        $this->createPage->specifyPriceForChannelAndCurrency($price, $channel, $currency);
176
    }
177
178
    /**
179
     * @When I set its :optionName option to :optionValue
180
     */
181
    public function iSetItsOptionAs($optionName, $optionValue)
182
    {
183
        $this->createPage->selectOption($optionName, $optionValue);
184
    }
185
186
    /**
187
     * @Then the :productVariantCode variant of the :product product should appear in the shop
188
     */
189
    public function theProductVariantShouldAppearInTheShop($productVariantCode, ProductInterface $product)
190
    {
191
        $this->iWantToViewAllVariantsOfThisProduct($product);
192
193
        Assert::true(
194
            $this->indexPage->isSingleResourceOnPage(['code' => $productVariantCode]),
195
            sprintf('The product variant with code %s has not been found.', $productVariantCode)
196
        );
197
    }
198
199
    /**
200
     * @When /^I (?:|want to )view all variants of (this product)$/
201
     * @When /^I view(?:| all) variants of the (product "[^"]+")$/
202
     */
203
    public function iWantToViewAllVariantsOfThisProduct(ProductInterface $product)
204
    {
205
        $this->indexPage->open(['productId' => $product->getId()]);
206
    }
207
208
    /**
209
     * @Then I should see :numberOfProductVariants variants in the list
210
     * @Then I should see :numberOfProductVariants variant in the list
211
     */
212
    public function iShouldSeeProductsInTheList($numberOfProductVariants)
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...
213
    {
214
        $foundRows = $this->indexPage->countItems();
215
216
        Assert::same(
217
            (int) $numberOfProductVariants,
218
            $foundRows,
219
            '%s rows with product variants should appear on page, %s rows has been found'
220
        );
221
    }
222
223
    /**
224
     * @When /^I delete the ("[^"]+" variant of product "[^"]+")$/
225
     * @When /^I try to delete the ("[^"]+" variant of product "[^"]+")$/
226
     */
227
    public function iDeleteTheVariantOfProduct(ProductVariantInterface $productVariant)
228
    {
229
        $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...
230
231
        $this->indexPage->deleteResourceOnPage(['code' => $productVariant->getCode()]);
232
    }
233
234
    /**
235
     * @Then /^(this variant) should not exist in the product catalog$/
236
     */
237
    public function productVariantShouldNotExist(ProductVariantInterface $productVariant)
238
    {
239
        $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...
240
241
        Assert::false(
242
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName()]),
243
            sprintf('Product variant with code %s exists but should not.', $productVariant->getName())
244
        );
245
    }
246
247
    /**
248
     * @Then I should be notified that this variant is in use and cannot be deleted
249
     */
250
    public function iShouldBeNotifiedOfFailure()
251
    {
252
        $this->notificationChecker->checkNotification(
253
            "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...
254
            NotificationType::failure()
255
        );
256
    }
257
258
    /**
259
     * @Then /^(this variant) should still exist in the product catalog$/
260
     */
261
    public function productShouldExistInTheProductCatalog(ProductVariantInterface $productVariant)
262
    {
263
        $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...
264
    }
265
266
    /**
267
     * @When /^I want to modify the ("[^"]+" product variant)$/
268
     * @When /^I want to modify (this product variant)$/
269
     */
270
    public function iWantToModifyAProduct(ProductVariantInterface $productVariant)
271
    {
272
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
273
    }
274
275
    /**
276
     * @Then the code field should be disabled
277
     */
278
    public function theCodeFieldShouldBeDisabled()
279
    {
280
        Assert::true(
281
            $this->updatePage->isCodeDisabled(),
282
            'Code should be immutable, but it does not.'
283
        );
284
    }
285
286
    /**
287
     * @Then I should be notified that price is required
288
     */
289
    public function iShouldBeNotifiedThatPriceIsRequired()
290
    {
291
        $this->assertValidationMessage('price', 'Please enter the price.');
292
    }
293
294
    /**
295
     * @When I save my changes
296
     * @When I try to save my changes
297
     */
298
    public function iSaveMyChanges()
299
    {
300
        $this->updatePage->saveChanges();
301
    }
302
303
    /**
304
     * @When /^I change its price to "(?:€|£|\$)([^"]+)"$/
305
     */
306
    public function iChangeItsPriceTo($price)
307
    {
308
        $this->updatePage->specifyPrice($price);
309
    }
310
311
    /**
312
     * @When I remove its name
313
     */
314
    public function iRemoveItsNameFromTranslation()
315
    {
316
        $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...
317
    }
318
319
    /**
320
     * @Then /^the variant "([^"]+)" should have (\d+) items on hand$/
321
     */
322
    public function thisVariantShouldHaveItemsOnHand($productVariantName, $quantity)
323
    {
324
        Assert::true(
325
            $this->indexPage->isSingleResourceWithSpecificElementOnPage(['name' => $productVariantName], sprintf('td > div.ui.label:contains("%s")', $quantity)),
326
            sprintf('The product variant %s should have %s items on hand, but it does not.',$productVariantName, $quantity)
327
        );
328
    }
329
330
    /**
331
     * @Then /^the "([^"]+)" variant of ("[^"]+" product) should have (\d+) items on hand$/
332
     */
333
    public function theVariantOfProductShouldHaveItemsOnHand($productVariantName, ProductInterface $product, $quantity)
334
    {
335
        $this->indexPage->open(['productId' => $product->getId()]);
336
337
        Assert::true(
338
            $this->indexPage->isSingleResourceWithSpecificElementOnPage(['name' => $productVariantName], sprintf('td > div.ui.label:contains("%s")', $quantity)),
339
            sprintf('The product variant %s should have %s items on hand, but it does not.',$productVariantName, $quantity)
340
        );
341
    }
342
343
    /**
344
     * @Then /^inventory of (this variant) should not be tracked$/
345
     */
346
    public function thisProductVariantShouldNotBeTracked(ProductVariantInterface $productVariant)
347
    {
348
        $this->iWantToModifyAProduct($productVariant);
349
350
        Assert::false(
351
            $this->updatePage->isTracked(),
352
            'This variant should not be tracked, but it is.'
353
        );
354
    }
355
356
    /**
357
     * @Then /^inventory of (this variant) should be tracked$/
358
     */
359
    public function thisProductVariantShouldBeTracked(ProductVariantInterface $productVariant)
360
    {
361
        $this->iWantToModifyAProduct($productVariant);
362
363
        Assert::true(
364
            $this->updatePage->isTracked(),
365
            'This variant should be tracked, but it is not.'
366
        );
367
    }
368
369
    /**
370
     * @Then /^I should see that the ("([^"]+)" variant) is not tracked$/
371
     */
372
    public function iShouldSeeThatIsNotTracked(ProductVariantInterface $productVariant)
373
    {
374
        Assert::true(
375
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName(), 'inventory' => 'Not tracked']),
376
            sprintf('This "%s" variant should have label not tracked, but it does not have', $productVariant->getName())
377
        );
378
    }
379
380
    /**
381
     * @Then /^I should see that the ("[^"]+" variant) has zero on hand quantity$/
382
     */
383
    public function iShouldSeeThatTheVariantHasZeroOnHandQuantity(ProductVariantInterface $productVariant)
384
    {
385
        Assert::true(
386
            $this->indexPage->isSingleResourceOnPage(['name' => $productVariant->getName(), 'inventory' => '0 Available on hand']),
387
            sprintf('This "%s" variant should have 0 on hand quantity, but it does not.', $productVariant->getName())
388
        );
389
    }
390
391
    /**
392
     * @Then /^(\d+) units of (this product) should be on hold$/
393
     */
394
    public function unitsOfThisProductShouldBeOnHold($quantity, ProductInterface $product)
395
    {
396
        /** @var ProductVariantInterface $variant */
397
        $variant = $this->defaultProductVariantResolver->getVariant($product);
398
399
        $this->assertOnHoldQuantityOfVariant($quantity, $variant);
400
    }
401
402
    /**
403
     * @Then /^(\d+) units of (this product) should be on hand$/
404
     */
405
    public function unitsOfThisProductShouldBeOnHand($quantity, ProductInterface $product)
406
    {
407
        /** @var ProductVariantInterface $variant */
408
        $variant = $this->defaultProductVariantResolver->getVariant($product);
409
        $actualQuantity = $this->indexPage->getOnHandQuantityFor($variant);
410
411
        Assert::same(
412
            (int) $quantity,
413
            $actualQuantity,
414
            sprintf(
415
                'Unexpected on hand quantity for "%s" variant. It should be "%s" but is "%s"',
416
                $variant->getName(),
417
                $quantity,
418
                $actualQuantity
419
            )
420
        );
421
    }
422
423
    /**
424
     * @Then /^there should be no units of (this product) on hold$/
425
     */
426
    public function thereShouldBeNoUnitsOfThisProductOnHold(ProductInterface $product)
427
    {
428
        /** @var ProductVariantInterface $variant */
429
        $variant = $this->defaultProductVariantResolver->getVariant($product);
430
431
        $this->assertOnHoldQuantityOfVariant(0, $variant);
432
    }
433
434
    /**
435
     * @Then the :variant variant should have :amount items on hold
436
     * @Then /^(this variant) should have (\d+) items on hold$/
437
     */
438
    public function thisVariantShouldHaveItemsOnHold(ProductVariantInterface $variant, $amount)
439
    {
440
        $this->assertOnHoldQuantityOfVariant((int) $amount, $variant);
441
    }
442
443
    /**
444
     * @Then the :variant variant of :product product should have :amount items on hold
445
     */
446
    public function theVariantOfProductShouldHaveItemsOnHold(ProductVariantInterface $variant, ProductInterface $product, $amount)
447
    {
448
        $this->indexPage->open(['productId' => $product->getId()]);
449
450
        $this->assertOnHoldQuantityOfVariant((int) $amount, $variant);
451
    }
452
453
    /**
454
     * @Then /^(variant with code "[^"]+") for ("[^"]+" currency) and ("[^"]+" channel) should have "(?:€|£|\$)([^"]+)"$/
455
     */
456
    public function theProductForCurrencyAndChannelShouldHave(
457
        ProductVariantInterface $productVariant,
458
        CurrencyInterface $currency,
459
        ChannelInterface $channel,
460
        $price
461
    ) {
462
        $this->updatePage->open(['id' => $productVariant->getId(), 'productId' => $productVariant->getProduct()->getId()]);
463
464
        Assert::same(
465
            $this->updatePage->getPricingConfigurationForChannelAndCurrencyCalculator($channel, $currency),
466
            $price
467
        );
468
    }
469
470
    /**
471
     * @param string $element
472
     * @param $message
473
     */
474
    private function assertValidationMessage($element, $message)
475
    {
476
        /** @var CreatePageInterface|UpdatePageInterface $currentPage */
477
        $currentPage = $this->currentPageResolver->getCurrentPageWithForm([$this->createPage, $this->updatePage]);
478
479
        Assert::same($currentPage->getValidationMessage($element), $message);
480
    }
481
482
    /**
483
     * @param int $expectedAmount
484
     * @param ProductVariantInterface $variant
485
     *
486
     * @throws \InvalidArgumentException
487
     */
488
    private function assertOnHoldQuantityOfVariant($expectedAmount, $variant)
489
    {
490
        $actualAmount = $this->indexPage->getOnHoldQuantityFor($variant);
491
492
        Assert::same(
493
            (int) $expectedAmount,
494
            $actualAmount,
495
            sprintf(
496
                'Unexpected on hold quantity for "%s" variant. It should be "%s" but is "%s"',
497
                $variant->getName(),
498
                $expectedAmount,
499
                $actualAmount
500
            )
501
        );
502
    }
503
}
504