Completed
Push — master ( a026a7...7ff053 )
by Kamil
21s
created

CreateSimpleProductPage   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 317
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 32
lcom 1
cbo 9
dl 0
loc 317
rs 9.6
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A getRouteName() 0 4 1
A nameItIn() 0 7 1
A specifySlugIn() 0 6 1
A specifyPrice() 0 4 1
A attachImage() 0 15 2
B associateProducts() 0 26 2
A removeAssociatedProduct() 0 10 1
A choosePricingCalculator() 0 4 1
A checkChannel() 0 4 1
A specifyPriceForChannelAndCurrency() 0 11 1
A activateLanguageTab() 0 11 3
A selectShippingCategory() 0 4 1
A getElement() 0 8 2
A specifyOriginalPrice() 0 4 1
A addAttribute() 0 13 1
A removeAttribute() 0 6 1
B getDefinedElements() 0 27 1
A selectElementFromAttributesDropdown() 0 9 1
A waitForFormElement() 0 7 1
A clickTabIfItsNotActive() 0 7 2
A clickTab() 0 5 1
A clickLocaleTabIfItsNotActive() 0 7 2
A getLastImageElement() 0 9 1
A waitForSlugGenerationIfNecessary() 0 8 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
namespace Sylius\Behat\Page\Admin\Product;
13
14
use Behat\Mink\Driver\Selenium2Driver;
15
use Behat\Mink\Element\NodeElement;
16
use Sylius\Behat\Behaviour\SpecifiesItsCode;
17
use Sylius\Behat\Page\Admin\Crud\CreatePage as BaseCreatePage;
18
use Sylius\Component\Core\Model\ChannelInterface;
19
use Sylius\Component\Currency\Model\CurrencyInterface;
20
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
21
use Webmozart\Assert\Assert;
22
23
/**
24
 * @author Łukasz Chruściel <[email protected]>
25
 * @author Gorka Laucirica <[email protected]>
26
 */
27
class CreateSimpleProductPage extends BaseCreatePage implements CreateSimpleProductPageInterface
28
{
29
    use SpecifiesItsCode;
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    public function getRouteName()
35
    {
36
        return parent::getRouteName() . '_simple';
37
    }
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    public function nameItIn($name, $localeCode)
43
    {
44
        $this->activateLanguageTab($localeCode);
45
        $this->getElement('name', ['%locale%' => $localeCode])->setValue($name);
46
47
        $this->waitForSlugGenerationIfNecessary($localeCode);
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function specifySlugIn($slug, $locale)
54
    {
55
        $this->activateLanguageTab($locale);
56
57
        $this->getElement('slug', ['%locale%' => $locale])->setValue($slug);
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function specifyPrice($channelName, $price)
64
    {
65
        $this->getElement('price', ['%channelName%' => $channelName])->setValue($price);
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function specifyOriginalPrice($channelName, $originalPrice)
72
    {
73
        $this->getElement('original_price', ['%channelName%' => $channelName])->setValue($originalPrice);
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79
    public function addAttribute($attributeName, $value, $localeCode)
80
    {
81
        $this->clickTabIfItsNotActive('attributes');
82
        $this->clickLocaleTabIfItsNotActive($localeCode);
83
84
        $attributeOption = $this->getElement('attributes_choice')->find('css', sprintf('option:contains("%s")', $attributeName));
85
        $this->selectElementFromAttributesDropdown($attributeOption->getAttribute('value'));
86
87
        $this->getDocument()->pressButton('Add attributes');
88
        $this->waitForFormElement();
89
90
        $this->getElement('attribute_value', ['%attributeName%' => $attributeName, '%localeCode%' => $localeCode])->setValue($value);
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    public function removeAttribute($attributeName, $localeCode)
97
    {
98
        $this->clickTabIfItsNotActive('attributes');
99
100
        $this->getElement('attribute_delete_button', ['%attributeName%' => $attributeName, '%localeCode%' => $localeCode])->press();
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function attachImage($path, $type = null)
107
    {
108
        $this->clickTabIfItsNotActive('media');
109
110
        $filesPath = $this->getParameter('files_path');
111
112
        $this->getDocument()->clickLink('Add');
113
114
        $imageForm = $this->getLastImageElement();
115
        if (null !== $type) {
116
            $imageForm->fillField('Type', $type);
117
        }
118
119
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function associateProducts(ProductAssociationTypeInterface $productAssociationType, array $productsNames)
126
    {
127
        $this->clickTab('associations');
128
129
        Assert::isInstanceOf($this->getDriver(), Selenium2Driver::class);
130
131
        $dropdown = $this->getElement('association_dropdown', [
132
            '%association%' => $productAssociationType->getName()
133
        ]);
134
        $dropdown->click();
135
136
        foreach ($productsNames as $productName) {
137
            $dropdown->waitFor(5, function () use ($productName, $productAssociationType) {
138
                return $this->hasElement('association_dropdown_item', [
139
                    '%association%' => $productAssociationType->getName(),
140
                    '%item%' => $productName,
141
                ]);
142
            });
143
144
            $item = $this->getElement('association_dropdown_item', [
145
                '%association%' => $productAssociationType->getName(),
146
                '%item%' => $productName,
147
            ]);
148
            $item->click();
149
        }
150
    }
151
152
    /**
153
     * {@inheritdoc}
154
     */
155
    public function removeAssociatedProduct($productName, ProductAssociationTypeInterface $productAssociationType)
156
    {
157
        $this->clickTabIfItsNotActive('associations');
158
159
        $item = $this->getElement('association_dropdown_item_selected', [
160
            '%association%' => $productAssociationType->getName(),
161
            '%item%' => $productName,
162
        ]);
163
        $item->find('css', 'i.delete')->click();
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function choosePricingCalculator($name)
170
    {
171
        $this->getElement('price_calculator')->selectOption($name);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function checkChannel($channelName)
178
    {
179
        $this->getElement('channel_checkbox', ['%channelName%' => $channelName])->check();
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185
    public function specifyPriceForChannelAndCurrency($price, ChannelInterface $channel, CurrencyInterface $currency)
186
    {
187
        $calculatorElement = $this->getElement('calculator');
188
        $calculatorElement
189
            ->waitFor(5, function () use ($channel, $currency) {
190
                return $this->getElement('calculator')->hasField(sprintf('%s %s', $channel->getName(), $currency->getCode()));
191
            })
192
        ;
193
194
        $calculatorElement->fillField(sprintf('%s %s', $channel->getName(), $currency->getCode()), $price);
195
    }
196
197
    /**
198
     * {@inheritdoc}
199
     */
200
    public function activateLanguageTab($locale)
201
    {
202
        if (!$this->getDriver() instanceof Selenium2Driver) {
203
            return;
204
        }
205
206
        $languageTabTitle = $this->getElement('language_tab', ['%locale%' => $locale]);
207
        if (!$languageTabTitle->hasClass('active')) {
208
            $languageTabTitle->click();
209
        }
210
    }
211
212
    /**
213
     * {@inheritdoc}
214
     */
215
    public function selectShippingCategory($shippingCategoryName)
216
    {
217
        $this->getElement('shipping_category')->selectOption($shippingCategoryName);
218
    }
219
220
221
    /**
222
     * {@inheritdoc}
223
     */
224
    protected function getElement($name, array $parameters = [])
225
    {
226
        if (!isset($parameters['%locale%'])) {
227
            $parameters['%locale%'] = 'en_US';
228
        }
229
230
        return parent::getElement($name, $parameters);
231
    }
232
233
    /**
234
     * {@inheritdoc}
235
     */
236
    protected function getDefinedElements()
237
    {
238
        return array_merge(parent::getDefinedElements(), [
239
            'association_dropdown' => '.field > label:contains("%association%") ~ .product-select',
240
            'association_dropdown_item' => '.field > label:contains("%association%") ~ .product-select > div.menu > div.item:contains("%item%")',
241
            'association_dropdown_item_selected' => '.field > label:contains("%association%") ~ .product-select > a.label:contains("%item%")',
242
            'attribute_delete_button' => '.tab[data-tab="%localeCode%"] .attribute .label:contains("%attributeName%") ~ button',
243
            'attribute_value' => '.tab[data-tab="%localeCode%"] .attribute .label:contains("%attributeName%") ~ input',
244
            'attributes_choice' => '#sylius_product_attribute_choice',
245
            'calculator' => '#sylius_calculator_container',
246
            'channel_checkbox' => '.checkbox:contains("%channelName%") input',
247
            'channel_pricings' => '#sylius_product_variant_channelPricings',
248
            'code' => '#sylius_product_code',
249
            'form' => 'form[name="sylius_product"]',
250
            'images' => '#sylius_product_images',
251
            'language_tab' => '[data-locale="%locale%"] .title',
252
            'locale_tab' => '#attributesContainer .menu [data-tab="%localeCode%"]',
253
            'name' => '#sylius_product_translations_%locale%_name',
254
            'price' => '#sylius_product_variant_channelPricings > .field:contains("%channelName%") input[name$="[price]"]',
255
            'original_price' => '#sylius_product_variant_channelPricings > .field:contains("%channelName%") input[name$="[originalPrice]"]',
256
            'price_calculator' => '#sylius_product_variant_pricingCalculator',
257
            'shipping_category' => '#sylius_product_variant_shippingCategory',
258
            'slug' => '#sylius_product_translations_%locale%_slug',
259
            'tab' => '.menu [data-tab="%name%"]',
260
            'toggle_slug_modification_button' => '.toggle-product-slug-modification',
261
        ]);
262
    }
263
264
    /**
265
     * @param int $id
266
     */
267
    private function selectElementFromAttributesDropdown($id)
268
    {
269
        /** @var Selenium2Driver $driver */
270
        $driver = $this->getDriver();
271
        Assert::isInstanceOf($driver, Selenium2Driver::class);
272
273
        $driver->executeScript('$(\'#sylius_product_attribute_choice\').dropdown(\'show\');');
274
        $driver->executeScript(sprintf('$(\'#sylius_product_attribute_choice\').dropdown(\'set selected\', \'%s\');', $id));
275
    }
276
277
    /**
278
     * @param int $timeout
279
     */
280
    private function waitForFormElement($timeout = 5)
281
    {
282
        $form = $this->getElement('form');
283
        $this->getDocument()->waitFor($timeout, function () use ($form) {
284
            return false === strpos($form->getAttribute('class'), 'loading');
285
        });
286
    }
287
288
    /**
289
     * @param string $tabName
290
     */
291
    private function clickTabIfItsNotActive($tabName)
292
    {
293
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
294
        if (!$attributesTab->hasClass('active')) {
295
            $attributesTab->click();
296
        }
297
    }
298
299
    /**
300
     * @param string $tabName
301
     */
302
    private function clickTab($tabName)
303
    {
304
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
305
        $attributesTab->click();
306
    }
307
308
    /**
309
     * @param string $localeCode
310
     */
311
    private function clickLocaleTabIfItsNotActive($localeCode)
312
    {
313
        $localeTab = $this->getElement('locale_tab', ['%localeCode%' => $localeCode]);
314
        if (!$localeTab->hasClass('active')) {
315
            $localeTab->click();
316
        }
317
    }
318
319
    /**
320
     * @return NodeElement
321
     */
322
    private function getLastImageElement()
323
    {
324
        $images = $this->getElement('images');
325
        $items = $images->findAll('css', 'div[data-form-collection="item"]');
326
327
        Assert::notEmpty($items);
328
329
        return end($items);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression end($items); of type Behat\Mink\Element\NodeElement|false adds false to the return on line 329 which is incompatible with the return type documented by Sylius\Behat\Page\Admin\...ge::getLastImageElement of type Behat\Mink\Element\NodeElement. It seems like you forgot to handle an error condition.
Loading history...
330
    }
331
332
    /**
333
     * @param string $locale
334
     */
335
    private function waitForSlugGenerationIfNecessary($locale)
336
    {
337
        if ($this->getDriver() instanceof Selenium2Driver) {
338
            $this->getDocument()->waitFor(10, function () use ($locale) {
339
                return '' !== $this->getElement('slug', ['%locale%' => $locale])->getValue();
340
            });
341
        }
342
    }
343
}
344