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

CreatePage::moveLeaf()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 16
nc 3
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\Taxon;
13
14
use Behat\Mink\Driver\Selenium2Driver;
15
use Behat\Mink\Element\NodeElement;
16
use Behat\Mink\Exception\ElementNotFoundException;
17
use Behat\Mink\Exception\UnsupportedDriverActionException;
18
use Sylius\Behat\Behaviour\SpecifiesItsCode;
19
use Sylius\Behat\Page\Admin\Crud\CreatePage as BaseCreatePage;
20
use Sylius\Component\Core\Model\TaxonInterface;
21
use Webmozart\Assert\Assert;
22
23
/**
24
 * @author Arkadiusz Krakowiak <[email protected]>
25
 */
26
class CreatePage extends BaseCreatePage implements CreatePageInterface
27
{
28
    use SpecifiesItsCode;
29
30
    /**
31
     * {@inheritdoc}
32
     */
33
    public function countTaxons()
34
    {
35
        return count($this->getLeaves());
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    public function countTaxonsByName($name)
42
    {
43
        $matchedLeavesCounter = 0;
44
        $leaves = $this->getLeaves();
45
        foreach ($leaves as $leaf) {
0 ignored issues
show
Bug introduced by
The expression $leaves of type array<integer,object<Beh...ment\NodeElement>>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
46
            if (strpos($leaf->getText(), $name) !== false) {
47
                $matchedLeavesCounter++;
48
            }
49
        }
50
51
        return $matchedLeavesCounter;
52
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57
    public function chooseParent(TaxonInterface $taxon)
58
    {
59
        $this->getElement('parent')->selectOption($taxon->getName(), false);
60
    }
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function deleteTaxonOnPageByName($name)
66
    {
67
        $leaves = $this->getLeaves();
68
        foreach ($leaves as $leaf) {
0 ignored issues
show
Bug introduced by
The expression $leaves of type array<integer,object<Beh...ment\NodeElement>>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
69
            if ($leaf->getText() === $name) {
70
                $leaf = $leaf->getParent();
71
                $menuButton = $leaf->find('css', '.wrench');
72
                $menuButton->click();
73
                $deleteButton = $leaf->find('css', '.sylius-delete-resource');
74
                $deleteButton->click();
75
76
                $deleteButton->waitFor(5, function () use ($leaf) {
77
                    return null === $leaf->find('css', '.sylius-delete-resource');
78
                });
79
80
                return;
81
            }
82
        }
83
84
        throw new ElementNotFoundException($this->getDriver(), 'Delete button');
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function describeItAs($description, $languageCode)
91
    {
92
        $this->getDocument()->fillField(sprintf('sylius_taxon_translations_%s_description', $languageCode), $description);
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98
    public function hasTaxonWithName($name)
99
    {
100
        return 0 !== $this->countTaxonsByName($name);
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function nameIt($name, $languageCode)
107
    {
108
        $this->getDocument()->fillField(sprintf('sylius_taxon_translations_%s_name', $languageCode), $name);
109
110
        $this->waitForSlugGenerationIfNecessary();
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function specifySlug($slug)
117
    {
118
        $this->getDocument()->fillField('Slug', $slug);
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function attachImage($path, $code = null)
125
    {
126
        $filesPath = $this->getParameter('files_path');
127
128
        $this->getDocument()->find('css', '[data-form-collection="add"]')->click();
129
130
        $imageForm = $this->getLastImageElement();
131
        $imageForm->fillField('Code', $code);
132
        $imageForm->find('css', 'input[type="file"]')->attachFile($filesPath.$path);
133
    }
134
135
    /**
136
     * {@inheritDoc}
137
     */
138
    public function moveUp(TaxonInterface $taxon)
139
    {
140
        $this->moveLeaf($taxon, self::MOVE_DIRECTION_UP);
141
    }
142
143
    /**
144
     * {@inheritDoc}
145
     */
146
    public function moveDown(TaxonInterface $taxon)
147
    {
148
        $this->moveLeaf($taxon, self::MOVE_DIRECTION_DOWN);
149
    }
150
151
    /**
152
     * {@inheritDoc}
153
     */
154
    public function getFirstLeafName(TaxonInterface $parentTaxon = null)
155
    {
156
        return $this->getLeaves($parentTaxon)[0]->getText();
157
    }
158
159
    /**
160
     * {@inheritDoc}
161
     */
162
    public function insertBefore(TaxonInterface $draggableTaxon, TaxonInterface $targetTaxon)
163
    {
164
        $seleniumDriver = $this->getSeleniumDriver();
165
        $draggableTaxonLocator = sprintf('.item[data-id="%s"]', $draggableTaxon->getId());
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $draggableTaxonLocator 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...
166
        $targetTaxonLocator = sprintf('.item[data-id="%s"]', $targetTaxon->getId());
167
168
        $script = <<<JS
169
(function ($) {
170
    $('$draggableTaxonLocator').simulate('drag-n-drop',{
171
        dragTarget: $('$targetTaxonLocator'),
172
        interpolation: {stepWidth: 10, stepDelay: 30} 
173
    });    
174
})(jQuery);
175
JS;
176
177
        $seleniumDriver->executeScript($script);
178
        $this->getDocument()->waitFor(5, function () use ($draggableTaxonLocator) {
179
            return !$this->getDocument()->find('css', $draggableTaxonLocator)->hasClass('dragging-started');
180
        });
181
    }
182
183
    /**
184
     * {@inheritdoc}
185
     */
186
    public function getLeaves(TaxonInterface $parentTaxon = null)
187
    {
188
        $tree = $this->getElement('tree');
189
        Assert::notNull($tree);
190
        /** @var NodeElement[] $leaves */
191
        $leaves = $tree->findAll('css', '.item > .content > .header');
192
193
        if (null === $parentTaxon) {
194
            return $leaves;
195
        }
196
197
        foreach ($leaves as $leaf) {
198
            if ($leaf->getText() === $parentTaxon->getName()) {
199
                return $leaf->findAll('css', '.item > .content > .header');
200
            }
201
        }
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207
    protected function getDefinedElements()
208
    {
209
        return array_merge(parent::getDefinedElements(), [
210
            'code' => '#sylius_taxon_code',
211
            'description' => '#sylius_taxon_translations_en_US_description',
212
            'images' => '#sylius_taxon_images',
213
            'name' => '#sylius_taxon_translations_en_US_name',
214
            'parent' => '#sylius_taxon_parent',
215
            'slug' => '#sylius_taxon_translations_en_US_slug',
216
            'tree' => '.ui.list',
217
        ]);
218
    }
219
220
    /**
221
     * @param TaxonInterface $taxon
222
     * @param string $direction
223
     *
224
     * @throws ElementNotFoundException
225
     */
226
    private function moveLeaf(TaxonInterface $taxon, $direction)
227
    {
228
        Assert::oneOf($direction, [self::MOVE_DIRECTION_UP, self::MOVE_DIRECTION_DOWN]);
229
230
        $leaves = $this->getLeaves();
231
        foreach ($leaves as $leaf) {
0 ignored issues
show
Bug introduced by
The expression $leaves of type array<integer,object<Beh...ment\NodeElement>>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
232
            if ($leaf->getText() === $taxon->getName()) {
233
                $leaf = $leaf->getParent();
234
                $menuButton = $leaf->find('css', '.wrench');
235
                $menuButton->click();
236
                $moveButton = $leaf->find('css', sprintf('.%s', $direction));
237
                $moveButton->click();
238
                $moveButton->waitFor(5, function () use ($taxon) {
239
                    return $this->getFirstLeafName() === $taxon->getName();
240
                });
241
242
                return;
243
            }
244
        }
245
246
        throw new ElementNotFoundException(
247
            $this->getDriver(),
248
            sprintf('Move %s button for %s taxon', $direction, $taxon->getName())
249
        );
250
    }
251
252
    /**
253
     * @return NodeElement
254
     */
255
    private function getLastImageElement()
256
    {
257
        $images = $this->getElement('images');
258
        $items = $images->findAll('css', 'div[data-form-collection="item"]');
259
260
        Assert::notEmpty($items);
261
262
        return end($items);
263
    }
264
265
    /**
266
     * @return Selenium2Driver
267
     *
268
     * @throws UnsupportedDriverActionException
269
     */
270
    private function getSeleniumDriver()
271
    {
272
        /** @var Selenium2Driver $driver */
273
        $driver = $this->getDriver();
274
        if (!$driver instanceof Selenium2Driver) {
275
            throw new UnsupportedDriverActionException('This action is not supported by %s', $driver);
276
        }
277
278
        return $driver;
279
    }
280
281
    private function waitForSlugGenerationIfNecessary()
282
    {
283
        if ($this->getDriver() instanceof Selenium2Driver) {
284
            $this->getDocument()->waitFor(10, function () {
285
                return '' !== $this->getElement('slug')->getValue();
286
            });
287
        }
288
    }
289
}
290