Completed
Push — symfony3-fqcn-sylius-2 ( 026c63...c92ad2 )
by Kamil
31:21 queued 13:20
created

UpdateSimpleProductPage::isSlugReadOnlyIn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
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 Behat\Mink\Exception\ElementNotFoundException;
17
use Sylius\Behat\Behaviour\ChecksCodeImmutability;
18
use Sylius\Behat\Page\Admin\Crud\UpdatePage as BaseUpdatePage;
19
use Sylius\Component\Core\Model\ChannelInterface;
20
use Sylius\Component\Core\Model\TaxonInterface;
21
use Sylius\Component\Currency\Model\CurrencyInterface;
22
use Sylius\Component\Product\Model\ProductAssociationTypeInterface;
23
use Webmozart\Assert\Assert;
24
25
/**
26
 * @author Łukasz Chruściel <[email protected]>
27
 */
28
class UpdateSimpleProductPage extends BaseUpdatePage implements UpdateSimpleProductPageInterface
29
{
30
    use ChecksCodeImmutability;
31
32
    /**
33
     * {@inheritdoc}
34
     */
35
    public function nameItIn($name, $localeCode)
36
    {
37
        $this->activateLanguageTab($localeCode);
38
        $this->getElement('name', ['%locale%' => $localeCode])->setValue($name);
39
40
        $this->waitForSlugGenerationIfNecessary($localeCode);
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function specifyPrice($price)
47
    {
48
        $this->getDocument()->fillField('Price', $price);
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function getAttributeValue($attribute)
55
    {
56
        $attributesTab = $this->getElement('tab', ['%name%' => 'attributes']);
57
        if (!$attributesTab->hasClass('active')) {
58
            $attributesTab->click();
59
        }
60
61
        return $this->getElement('attribute', ['%attribute%' => $attribute])->getValue();
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     */
67
    public function hasAttribute($attribute)
68
    {
69
        return null !== $this->getDocument()->find('css', sprintf('.attribute .label:contains("%s")', $attribute));
70
    }
71
72
    /**
73
     * {@inheritdoc}
74
     */
75
    public function selectMainTaxon(TaxonInterface $taxon)
76
    {
77
        $this->openTaxonBookmarks();
78
79
        Assert::isInstanceOf($this->getDriver(), Selenium2Driver::class);
80
81
        $this->getDriver()->executeScript(sprintf('$(\'input.search\').val(\'%s\')', $taxon->getName()));
82
        $this->getElement('search')->click();
83
        $this->getElement('search')->waitFor(10,
84
            function () {
85
                return $this->hasElement('search_item_selected');
86
            });
87
        $itemSelected = $this->getElement('search_item_selected');
88
        $itemSelected->click();
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function isMainTaxonChosen($taxonName)
95
    {
96
        $this->openTaxonBookmarks();
97
98
        return $taxonName === $this->getDocument()->find('css', '.search > .text')->getText();
99
    }
100
101
    public function disableTracking()
102
    {
103
        $this->getElement('tracked')->uncheck();
104
    }
105
106
    public function enableTracking()
107
    {
108
        $this->getElement('tracked')->check();
109
    }
110
111
    /**
112
     * {@inheritdoc}
113
     */
114
    public function isTracked()
115
    {
116
        return $this->getElement('tracked')->isChecked();
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122
    public function enableSlugModification($locale)
123
    {
124
        $this->getElement('toggle_slug_modification_button', ['%locale%' => $locale])->press();
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130
    public function isImageWithCodeDisplayed($code)
131
    {
132
        $imageElement = $this->getImageElementByCode($code);
133
134
        if (null === $imageElement) {
135
            return false;
136
        }
137
138
        $imageUrl = $imageElement->find('css', 'img')->getAttribute('src');
139
        $this->getDriver()->visit($imageUrl);
140
        $pageText = $this->getDocument()->getText();
141
        $this->getDriver()->back();
142
143
        return false === stripos($pageText, '404 Not Found');
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149
    public function attachImage($path, $code = null)
150
    {
151
        $this->clickTabIfItsNotActive('media');
152
153
        $filesPath = $this->getParameter('files_path');
154
155
        $this->getDocument()->clickLink('Add');
156
157
        $imageForm = $this->getLastImageElement();
158
        if (null !== $code) {
159
            $imageForm->fillField('Code', $code);
160
        }
161
162
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function changeImageWithCode($code, $path)
169
    {
170
        $filesPath = $this->getParameter('files_path');
171
172
        $imageForm = $this->getImageElementByCode($code);
173
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
174
    }
175
176
    /**
177
     * {@inheritdoc}
178
     */
179
    public function removeImageWithCode($code)
180
    {
181
        $this->clickTabIfItsNotActive('media');
182
183
        $imageElement = $this->getImageElementByCode($code);
184
        $imageElement->clickLink('Delete');
185
    }
186
187
    public function removeFirstImage()
188
    {
189
        $imageElement = $this->getFirstImageElement();
190
        $imageElement->clickLink('Delete');
191
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196
    public function countImages()
197
    {
198
        $imageElements = $this->getImageElements();
199
200
        return count($imageElements);
201
    }
202
203
    /**
204
     * {@inheritdoc}
205
     */
206
    public function isImageCodeDisabled()
207
    {
208
        return 'disabled' === $this->getLastImageElement()->findField('Code')->getAttribute('disabled');
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214
    public function isSlugReadOnlyIn($locale)
215
    {
216
        return 'readonly' === $this->getElement('slug', ['%locale%' => $locale])->getAttribute('readonly');
217
    }
218
219
    /**
220
     * {@inheritdoc}
221
     */
222
    public function getValidationMessageForImage()
223
    {
224
        $this->clickTabIfItsNotActive('media');
225
226
        $imageForm = $this->getLastImageElement();
227
228
        $foundElement = $imageForm->find('css', '.sylius-validation-error');
229
        if (null === $foundElement) {
230
            throw new ElementNotFoundException($this->getSession(), 'Tag', 'css', '.sylius-validation-error');
231
        }
232
233
        return $foundElement->getText();
234
    }
235
236
    /**
237
     * {@inheritdoc}
238
     */
239
    public function associateProducts(ProductAssociationTypeInterface $productAssociationType, array $productsNames)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $productAssociationType 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...
240
    {
241
        $this->clickTab('associations');
242
243
        Assert::isInstanceOf($this->getDriver(), Selenium2Driver::class);
244
245
        $dropdown = $this->getElement('association_dropdown', [
246
            '%association%' => $productAssociationType->getName()
247
        ]);
248
        $dropdown->click();
249
250
        foreach ($productsNames as $productName) {
251
            $dropdown->waitFor(5, function () use ($productName, $productAssociationType) {
252
                return $this->hasElement('association_dropdown_item', [
253
                    '%association%' => $productAssociationType->getName(),
254
                    '%item%' => $productName,
255
                ]);
256
            });
257
258
            $item = $this->getElement('association_dropdown_item', [
259
                '%association%' => $productAssociationType->getName(),
260
                '%item%' => $productName,
261
            ]);
262
            $item->click();
263
        }
264
    }
265
266
    /**
267
     * {@inheritdoc}
268
     */
269
    public function hasAssociatedProduct($productName, ProductAssociationTypeInterface $productAssociationType)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $productAssociationType 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...
270
    {
271
        $this->clickTabIfItsNotActive('associations');
272
273
        return $this->hasElement('association_dropdown_item', [
274
            '%association%' => $productAssociationType->getName(),
275
            '%item%' => $productName,
276
        ]);
277
    }
278
279
    /**
280
     * {@inheritdoc}
281
     */
282
    public function removeAssociatedProduct($productName, ProductAssociationTypeInterface $productAssociationType)
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $productAssociationType 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...
283
    {
284
        $this->clickTabIfItsNotActive('associations');
285
286
        $item = $this->getElement('association_dropdown_item_selected', [
287
            '%association%' => $productAssociationType->getName(),
288
            '%item%' => $productName,
289
        ]);
290
291
        $deleteIcon = $item->find('css', 'i.delete');
292
        Assert::notNull($deleteIcon);
293
        $deleteIcon->click();
294
    }
295
296
    /**
297
     * {@inheritdoc}
298
     */
299
    public function getPricingConfigurationForChannelAndCurrencyCalculator(ChannelInterface $channel, CurrencyInterface $currency)
300
    {
301
        $priceConfigurationElement = $this->getElement('pricing_configuration');
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $priceConfigurationElement 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...
302
        $priceElement = $priceConfigurationElement
303
            ->find('css', sprintf('label:contains("%s %s")', $channel->getCode(), $currency->getCode()))->getParent();
304
305
        return $priceElement->find('css', 'input')->getValue();
306
    }
307
308
    /**
309
     * {@inheritdoc}
310
     */
311
    public function getSlug($locale)
312
    {
313
        $this->activateLanguageTab($locale);
314
315
        return $this->getElement('slug', ['%locale%' => $locale])->getValue();
316
    }
317
318
    /**
319
     * {@inheritdoc}
320
     */
321
    public function specifySlugIn($slug, $locale)
322
    {
323
        $this->activateLanguageTab($locale);
324
325
        $this->getElement('slug', ['%locale%' => $locale])->setValue($slug);
326
    }
327
328
    /**
329
     * {@inheritdoc}
330
     */
331
    public function activateLanguageTab($locale)
332
    {
333
        if (!$this->getDriver() instanceof Selenium2Driver) {
334
            return;
335
        }
336
337
        $languageTabTitle = $this->getElement('language_tab', ['%locale%' => $locale]);
338
        if (!$languageTabTitle->hasClass('active')) {
339
            $languageTabTitle->click();
340
        }
341
    }
342
343
    /**
344
     * {@inheritdoc}
345
     */
346
    protected function getElement($name, array $parameters = [])
347
    {
348
        if (!isset($parameters['%locale%'])) {
349
            $parameters['%locale%'] = 'en_US';
350
        }
351
352
        return parent::getElement($name, $parameters);
353
    }
354
355
    /**
356
     * {@inheritdoc}
357
     */
358
    protected function getCodeElement()
359
    {
360
        return $this->getElement('code');
361
    }
362
363
    /**
364
     * {@inheritdoc}
365
     */
366
    protected function getDefinedElements()
367
    {
368
        return array_merge(parent::getDefinedElements(), [
369
            'association_dropdown' => '.field > label:contains("%association%") ~ .product-select',
370
            'association_dropdown_item' => '.field > label:contains("%association%") ~ .product-select > div.menu > div.item:contains("%item%")',
371
            'association_dropdown_item_selected' => '.field > label:contains("%association%") ~ .product-select > a.label:contains("%item%")',
372
            'attribute' => '.attribute .label:contains("%attribute%") ~ input',
373
            'code' => '#sylius_product_code',
374
            'images' => '#sylius_product_images',
375
            'language_tab' => '[data-locale="%locale%"] .title',
376
            'name' => '#sylius_product_translations_%locale%_name',
377
            'price' => '#sylius_product_variant_price',
378
            'pricing_configuration' => '#sylius_calculator_container',
379
            'search' => '.ui.fluid.search.selection.dropdown',
380
            'search_item_selected' => 'div.menu > div.item.selected',
381
            'slug' => '#sylius_product_translations_%locale%_slug',
382
            'tab' => '.menu [data-tab="%name%"]',
383
            'taxonomy' => 'a[data-tab="taxonomy"]',
384
            'tracked' => '#sylius_product_variant_tracked',
385
            'toggle_slug_modification_button' => '[data-locale="%locale%"] .toggle-product-slug-modification',
386
        ]);
387
    }
388
389
    private function openTaxonBookmarks()
390
    {
391
        $this->getElement('taxonomy')->click();
392
    }
393
394
    /**
395
     * @param string $tabName
396
     */
397
    private function clickTabIfItsNotActive($tabName)
398
    {
399
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
400
        if (!$attributesTab->hasClass('active')) {
401
            $attributesTab->click();
402
        }
403
    }
404
405
    /**
406
     * @param string $tabName
407
     */
408
    private function clickTab($tabName)
409
    {
410
        $attributesTab = $this->getElement('tab', ['%name%' => $tabName]);
411
        $attributesTab->click();
412
    }
413
414
    /**
415
     * @param string $code
416
     *
417
     * @return NodeElement
418
     */
419
    private function getImageElementByCode($code)
420
    {
421
        $images = $this->getElement('images');
422
        $inputCode = $images->find('css', 'input[value="'.$code.'"]');
423
424
        if (null === $inputCode) {
425
            return null;
426
        }
427
428
        return $inputCode->getParent()->getParent()->getParent();
429
    }
430
431
    /**
432
     * @return NodeElement[]
433
     */
434
    private function getImageElements()
435
    {
436
        $images = $this->getElement('images');
437
438
        return $images->findAll('css', 'div[data-form-collection="item"]');
439
    }
440
441
    /**
442
     * @return NodeElement
443
     */
444
    private function getLastImageElement()
445
    {
446
        $imageElements = $this->getImageElements();
447
448
        Assert::notEmpty($imageElements);
449
450
        return end($imageElements);
451
    }
452
453
    /**
454
     * @return NodeElement
455
     */
456
    private function getFirstImageElement()
457
    {
458
        $imageElements = $this->getImageElements();
459
460
        Assert::notEmpty($imageElements);
461
462
        return reset($imageElements);
463
    }
464
465
    /**
466
     * @param string $locale
467
     */
468
    private function waitForSlugGenerationIfNecessary($locale)
469
    {
470
        if (!$this->getDriver() instanceof Selenium2Driver) {
471
            return;
472
        }
473
474
        $slugElement = $this->getElement('slug', ['%locale%' => $locale]);
475
        if ($slugElement->hasAttribute('readonly')) {
476
            return;
477
        }
478
479
        $value = $slugElement->getValue();
480
        $this->getDocument()->waitFor(10, function () use ($slugElement, $value) {
481
            return $value !== $slugElement->getValue();
482
        });
483
    }
484
}
485