Completed
Push — master ( c66308...141223 )
by Kamil
28:38 queued 09:41
created

UpdateSimpleProductPage::associateProducts()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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