Completed
Push — menu-builders ( ef8ea6...aa4c7a )
by Kamil
18:07
created

UpdateSimpleProductPage::getElement()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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