Completed
Push — master ( ef9fce...66659a )
by
unknown
14s
created

VictoireContext   F

Complexity

Total Complexity 84

Size/Duplication

Total Lines 655
Duplicated Lines 21.22 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 84
c 1
b 1
f 0
lcom 1
cbo 13
dl 139
loc 655
rs 3.0571

39 Methods

Rating   Name   Duplication   Size   Complexity  
A iFollowTheDropTrigger() 10 10 2
A iSubmitTheWidget() 0 10 2
A iEditTheWidget() 0 15 2
A shouldPrecedeForTheQuery() 0 14 2
A iSelectTheOptionInTheDropdown() 0 7 1
A attachImageToVictoireScript() 0 5 1
A iShouldFindCssWithSelectorAndValue() 0 11 2
A gatherContexts() 0 5 1
A resetViewsReference() 0 5 1
C lookForJSErrors() 0 28 7
A iAmLoggedInAsUser() 0 7 1
A ivisitHomepageThroughDomain() 0 7 1
A iFillInWysiwygOnFieldWith() 0 5 1
A iSelectFromTheSelectOfSlot() 0 6 1
A iSwitchToMode() 10 10 2
A iOpenTheHamburgerMenu() 10 14 2
A iOpenTheWidgetModeDrop() 13 13 2
A iOpenTheWidgetStyleTab() 0 13 2
A iFollowTheFloatAction() 13 13 2
A iOpenTheWidgetQuantumCollapse() 14 14 2
A iOpenTheWidgetQuantumCollapseWhenStatic() 14 14 2
A iOpenTheSettingsMenu() 14 14 2
A iOpenTheAdditionalsMenuDrop() 14 14 2
A iFollowTheTab() 0 15 3
A iFollowTheDropAnchor() 0 16 4
A iShouldSeeDisableDropAnchor() 9 9 2
A iShouldSeeDisableTab() 9 9 2
A iMoveWidgetUnder() 0 9 2
A iRenameQuantumWith() 0 15 1
A iSelectQuantum() 0 8 1
A iCreateANewQuantum() 0 7 1
A iLoginAsVisitor() 0 7 1
C iSelectFromTheCollapseMenu() 0 29 7
A findOrRetry() 7 16 3
A iFillInSelect2InputWithAndSelect() 0 7 1
A openField() 0 13 3
A fillSearchField() 0 19 4
A selectValue() 0 13 3
A waitForLoadingResults() 0 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like VictoireContext often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use VictoireContext, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Victoire\Tests\Features\Context;
4
5
use Behat\Behat\Hook\Scope\AfterStepScope;
6
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
7
use Behat\Mink\Driver\Selenium2Driver;
8
use Behat\Mink\Element\DocumentElement;
9
use Behat\Mink\Element\Element;
10
use Behat\Mink\Session;
11
use Behat\Symfony2Extension\Context\KernelDictionary;
12
use Knp\FriendlyContexts\Context\RawMinkContext;
13
14
/**
15
 * This class gives some usefull methods for Victoire navigation.
16
 *
17
 * @property MinkContext minkContext
18
 */
19
class VictoireContext extends RawMinkContext
20
{
21
    use KernelDictionary;
22
    protected $minkContext;
23
24
    /**
25
     * @BeforeScenario
26
     *
27
     * @param BeforeScenarioScope $scope
28
     */
29
    public function gatherContexts(BeforeScenarioScope $scope)
30
    {
31
        $environment = $scope->getEnvironment();
32
        $this->minkContext = $environment->getContext('Victoire\Tests\Features\Context\MinkContext');
33
    }
34
35
    /**
36
     * @BeforeScenario
37
     *
38
     * @param BeforeScenarioScope $scope
39
     */
40
    public function resetViewsReference(BeforeScenarioScope $scope)
0 ignored issues
show
Unused Code introduced by
The parameter $scope is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
41
    {
42
        $viewsReferences = $this->getContainer()->get('victoire_core.view_helper')->buildViewsReferences();
43
        $this->getContainer()->get('victoire_view_reference.manager')->saveReferences($viewsReferences);
44
    }
45
46
    /**
47
     * @AfterStep
48
     *
49
     * @param AfterStepScope $scope
50
     *
51
     * @throws \Exception
52
     */
53
    public function lookForJSErrors(AfterStepScope $scope)
54
    {
55
        /* @var Session $session */
56
        $session = $this->getSession();
57
58
        if (!($session->getDriver() instanceof Selenium2Driver)) {
59
            return;
60
        }
61
62
        try {
63
            $errors = $session->evaluateScript('window.jsErrors');
64
            $session->evaluateScript('window.jsErrors = []');
65
        } catch (\Exception $e) {
66
            throw $e;
67
        }
68
        if (!$errors || empty($errors)) {
69
            return;
70
        }
71
        $file = sprintf('%s:%d', $scope->getFeature()->getFile(), $scope->getStep()->getLine());
72
        $message = sprintf('Found %d javascript error%s', count($errors), count($errors) > 0 ? 's' : '');
73
        echo '-------------------------------------------------------------'.PHP_EOL;
74
        echo $file.PHP_EOL;
75
        echo $message.PHP_EOL;
76
        echo '-------------------------------------------------------------'.PHP_EOL;
77
        foreach ($errors as $index => $error) {
0 ignored issues
show
Bug introduced by
The expression $errors of type string is not traversable.
Loading history...
78
            echo sprintf('   #%d: %s', $index, $error).PHP_EOL;
79
        }
80
    }
81
82
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$email" missing
Loading history...
83
     * @Given I am logged in as :email
84
     */
85
    public function iAmLoggedInAsUser($email)
86
    {
87
        $this->minkContext->visit('/login');
88
        $this->minkContext->fillField('username', $email);
89
        $this->minkContext->fillField('password', 'test');
90
        $this->minkContext->pressButton('_submit');
91
    }
92
93
    /**
94
     * @Given I login as visitor
95
     */
96
    public function iLoginAsVisitor()
97
    {
98
        $this->getSession()->getDriver()->stop();
99
        $baseUrl = $this->minkContext->getMinkParameter('base_url');
100
        $url = str_replace('[email protected]:test', '[email protected]:test', $baseUrl);
101
        $this->minkContext->setMinkParameter('base_url', $url);
102
    }
103
104
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$domain" missing
Loading history...
105
     * @Given /^I visit homepage through domain "([^"]*)"$/
106
     */
107
    public function ivisitHomepageThroughDomain($domain)
108
    {
109
        $this->getSession()->getDriver()->stop();
110
        $url = sprintf('http://[email protected]:test@%s:8000/app_domain.php', $domain);
111
        $this->minkContext->setMinkParameter('base_url', $url);
112
        $this->minkContext->visitPath('/');
113
    }
114
115
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$arg" missing
Loading history...
116
     * @Then /^I fill in wysiwyg with "([^"]*)"$/
117
     */
118
    public function iFillInWysiwygOnFieldWith($arg)
119
    {
120
        $js = 'CKEDITOR.instances.victoire_widget_form_ckeditor_content.setData("'.$arg.'");';
121
        $this->getSession()->executeScript($js);
122
    }
123
124
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$widget" missing
Loading history...
introduced by
Doc comment for parameter "$nth" missing
Loading history...
introduced by
Doc comment for parameter "$slot" missing
Loading history...
125
     * @Then /^I select "([^"]*)" from the "([^"]*)" select of "([^"]*)" slot$/
126
     */
127
    public function iSelectFromTheSelectOfSlot($widget, $nth, $slot)
128
    {
129
        $slot = $this->getSession()->getPage()->find('xpath', 'descendant-or-self::*[@id="vic-slot-'.$slot.'"]');
130
        $selects = $slot->findAll('css', 'select[role="menu"]');
131
        $selects[$nth - 1]->selectOption(str_replace('\\"', '"', $widget));
132
    }
133
134
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$mode" missing
Loading history...
135
     * @Then /^I switch to "([^"]*)" mode$/
136
     */
137 View Code Duplication
    public function iSwitchToMode($mode)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
138
    {
139
        $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', 'descendant-or-self::*[@for="mode-switcher--'.$mode.'"]');
140
141
        if (null === $element) {
142
            $message = sprintf('Element not found in the page after 10 seconds"');
143
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
144
        }
145
        $element->click();
146
    }
147
148
    /**
149
     * @Then /^I (open|close|toggle) the hamburger menu$/
150
     */
151 View Code Duplication
    public function iOpenTheHamburgerMenu()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
152
    {
153
        $element = $this->findOrRetry(
154
            $this->getSession()->getPage(),
155
            'xpath',
156
            'descendant-or-self::*[@id="vic-menu-leftnavbar-trigger"]'
157
        );
158
159
        if (null === $element) {
160
            $message = sprintf('Element not found in the page after 10 seconds"');
161
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
162
        }
163
        $element->click();
164
    }
165
166
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$entity" missing
Loading history...
167
     * @When I open the widget mode drop for entity :entity
168
     */
169 View Code Duplication
    public function iOpenTheWidgetModeDrop($entity)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
170
    {
171
        $element = $this->findOrRetry(
172
            $this->getSession()->getPage(),
173
            'css',
174
            '[id^="picker-'.strtolower($entity).'"] .v-mode-trigger'
175
        );
176
        if (null === $element) {
177
            $message = sprintf('Element not found in the page after 10 seconds"');
178
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
179
        }
180
        $element->click();
181
    }
182
183
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$key" missing
Loading history...
184
     * @When I open the widget style tab :key
185
     */
186
    public function iOpenTheWidgetStyleTab($key)
187
    {
188
        $element = $this->findOrRetry(
189
            $this->getSession()->getPage(),
190
            'css',
191
            '[title="style-'.$key.'"]'
192
        );
193
        if (null === $element) {
194
            $message = sprintf('Element not found in the page after 10 seconds"');
195
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
196
        }
197
        $element->click();
198
    }
199
200
    /**
201
     * @When I follow the float action button
202
     */
203 View Code Duplication
    public function iFollowTheFloatAction()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
204
    {
205
        $element = $this->findOrRetry(
206
            $this->getSession()->getPage(),
207
            'css',
208
            '#v-float-container [data-flag="v-drop v-drop-fab"]'
209
        );
210
        if (null === $element) {
211
            $message = sprintf('Element not found in the page after 10 seconds"');
212
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
213
        }
214
        $element->click();
215
    }
216
217
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$entity" missing
Loading history...
218
     * @When I open the widget quantum collapse for entity :entity
219
     */
220 View Code Duplication
    public function iOpenTheWidgetQuantumCollapse($entity)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
    {
222
        $element = $this->findOrRetry(
223
            $this->getSession()->getPage(),
224
            'css',
225
            '[id^="picker-'.strtolower($entity).'"][data-state="visible"] [id^="picker-'.strtolower($entity).'"][data-state="visible"] .v-widget-form__quantum-btn'
226
        );
227
228
        if (null === $element) {
229
            $message = sprintf('Element not found in the page after 10 seconds"');
230
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
231
        }
232
        $element->click();
233
    }
234
235
    /**
236
     * @When I open the widget quantum collapse when static
237
     */
238 View Code Duplication
    public function iOpenTheWidgetQuantumCollapseWhenStatic()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
239
    {
240
        $element = $this->findOrRetry(
241
            $this->getSession()->getPage(),
242
            'css',
243
            '[data-state="visible"] [id^="picker-static"] .v-widget-form__quantum-btn'
244
        );
245
246
        if (null === $element) {
247
            $message = sprintf('Element not found in the page after 10 seconds"');
248
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
249
        }
250
        $element->click();
251
    }
252
253
    /**
254
     * @Then /^I open the settings menu$/
255
     */
256 View Code Duplication
    public function iOpenTheSettingsMenu()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
    {
258
        $element = $this->findOrRetry(
259
            $this->getSession()->getPage(),
260
            'xpath',
261
            'descendant-or-self::*[@id="v-settings-link"]'
262
        );
263
264
        if (null === $element) {
265
            $message = sprintf('Element not found in the page after 10 seconds"');
266
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
267
        }
268
        $element->click();
269
    }
270
271
    /**
272
     * @Then /^I open the additionals menu drop$/
273
     */
274 View Code Duplication
    public function iOpenTheAdditionalsMenuDrop()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
275
    {
276
        $element = $this->findOrRetry(
277
            $this->getSession()->getPage(),
278
            'xpath',
279
            'descendant-or-self::*[@id="v-additionals-drop"]'
280
        );
281
282
        if (null === $element) {
283
            $message = sprintf('Element not found in the page after 10 seconds"');
284
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
285
        }
286
        $element->click();
287
    }
288
289
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
290
     * @When I follow the tab :name
291
     */
292
    public function iFollowTheTab($name)
293
    {
294
        $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', sprintf('descendant-or-self::a[contains(@class, "v-tabs-nav__anchor") and normalize-space(text()) = "%s"]', $name));
295
296
        // @TODO When the new styleguide is completly integrated, remove.
297
        if (null === $element) {
298
            $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', sprintf('descendant-or-self::a[@data-toggle="vic-tab" and normalize-space(text()) = "%s"]', $name));
299
        }
300
301
        if (null === $element) {
302
            $message = sprintf('Element not found in the page after 10 seconds"');
303
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
304
        }
305
        $element->click();
306
    }
307
308
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
309
     * @When I follow the drop trigger :name
310
     */
311 View Code Duplication
    public function iFollowTheDropTrigger($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
312
    {
313
        $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', sprintf('descendant-or-self::a[@data-flag*="v-drop" and normalize-space(text()) = "%s"]', $name));
314
315
        if (null === $element) {
316
            $message = sprintf('Element not found in the page after 10 seconds"');
317
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
318
        }
319
        $element->click();
320
    }
321
322
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
323
     * @When I follow the drop anchor :name
324
     */
325
    public function iFollowTheDropAnchor($name)
326
    {
327
        $page = $this->getSession()->getPage();
328
        $elements = $page->findAll('xpath', sprintf('descendant-or-self::a[contains(@class, "v-drop__anchor") and normalize-space(text()) = "%s"]', $name));
329
330
        if (count($elements) < 1) {
331
            $message = sprintf('Element not found in the page after 10 seconds"');
332
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
333
        }
334
335
        foreach ($elements as $element) {
336
            if ($element->getText() === $name) {
337
                $element->click();
338
            }
339
        }
340
    }
341
342
    /**
343
     * @Then /^I submit the widget$/
344
     * @Then /^I submit the modal$/
345
     */
346
    public function iSubmitTheWidget()
347
    {
348
        $element = $this->getSession()->getPage()->find('xpath', 'descendant-or-self::a[@data-modal="create"]');
349
350
        if (!$element) {
351
            $element = $this->getSession()->getPage()->find('xpath', 'descendant-or-self::a[@data-modal="update"]');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $element is correct as $this->getSession()->get...@data-modal="update"]') (which targets Behat\Mink\Element\Element::find()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
352
        }
353
        $element->click();
354
        $this->getSession()->wait(2000);
355
    }
356
357
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$widgetType" missing
Loading history...
358
     * @Given /^I edit an "([^"]*)" widget$/
359
     * @Given /^I edit the "([^"]*)" widget$/
360
     */
361
    public function iEditTheWidget($widgetType)
362
    {
363
        $selector = sprintf('.v-widget--%s > a.v-widget__overlay', strtolower($widgetType));
364
        $session = $this->getSession(); // get the mink session
365
        $element = $this->findOrRetry($session->getPage(), 'css', $selector);
366
367
        // errors must not pass silently
368
        if (null === $element) {
369
            throw new \InvalidArgumentException(sprintf('Could not evaluate CSS selector: "%s"', $selector));
370
        }
371
372
        // ok, let's hover it
373
        $element->mouseOver();
374
        $element->click();
375
    }
376
377
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$textBefore" missing
Loading history...
introduced by
Doc comment for parameter "$textAfter" missing
Loading history...
378
     * @Then /^"([^"]*)" should precede "([^"]*)"$/
379
     */
380
    public function shouldPrecedeForTheQuery($textBefore, $textAfter)
381
    {
382
        $element = $this->getSession()->getPage()->find(
383
            'xpath',
384
            sprintf('//*[normalize-space(text()) = "%s"][preceding::*[normalize-space(text()) = "%s"]]',
385
                $textAfter,
386
                $textBefore
387
            )
388
        );
389
        if (null === $element) {
390
            $message = sprintf('"%s" does not preceed "%s"', $textBefore, $textAfter);
391
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
392
        }
393
    }
394
395
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$option" missing
Loading history...
introduced by
Doc comment for parameter "$dropdown" missing
Loading history...
396
     * @When /^I select the option "(?P<option>[^"]*)" in the dropdown "(?P<dropdown>[^"]*)"$/
397
     */
398
    public function iSelectTheOptionInTheDropdown($option, $dropdown)
399
    {
400
        $link = $this->getSession()->getPage()->find('css', sprintf('a.vic-dropdown-toggle[title="%s"]', $dropdown));
401
        $link->click();
402
        $optionButton = $this->getSession()->getPage()->find('css', sprintf('ul[aria-labelledby="%sDropdownMenu"] > li > a[title="%s"]', $dropdown, $option));
403
        $optionButton->click();
404
    }
405
406
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$imageId" missing
Loading history...
introduced by
Doc comment for parameter "$fieldId" missing
Loading history...
407
     * @Then /^I attach image with id "(\d+)" to victoire field "(.+)"$/
408
     */
409
    public function attachImageToVictoireScript($imageId, $fieldId)
410
    {
411
        $script = sprintf('$("#%s input").val(%d)', $fieldId, $imageId);
412
        $this->getSession()->executeScript($script);
413
    }
414
415
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$element" missing
Loading history...
introduced by
Doc comment for parameter "$selector" missing
Loading history...
introduced by
Doc comment for parameter "$value" missing
Loading history...
416
     * @Then I should find css element :element with selector :selector and value :value
417
     */
418
    public function iShouldFindCssWithSelectorAndValue($element, $selector, $value)
419
    {
420
        $css = sprintf('%s[%s="%s"]', $element, $selector, $value);
421
        $session = $this->getSession();
422
        $element = $this->findOrRetry($session->getPage(), 'css', $css);
423
424
        if (null === $element) {
425
            $message = sprintf('Element not found. String generate: %s[%s="%s"]', $element, $selector, $value);
426
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
427
        }
428
    }
429
430
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
431
     * @Then I should see disable drop anchor :name
432
     */
433 View Code Duplication
    public function iShouldSeeDisableDropAnchor($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
434
    {
435
        $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', sprintf('descendant-or-self::*[contains(@class, \'v-drop__anchor--disabled\') and normalize-space(.) = "%s"]', $name));
436
437
        if (null === $element) {
438
            $message = sprintf('Element not found in the page after 10 seconds"');
439
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
440
        }
441
    }
442
443
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
444
     * @Then I should see disable tab :name
445
     */
446 View Code Duplication
    public function iShouldSeeDisableTab($name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
447
    {
448
        $element = $this->findOrRetry($this->getSession()->getPage(), 'xpath', sprintf('descendant-or-self::li[@class="vic-disable" and normalize-space(.) = "%s"]', $name));
449
450
        if (null === $element) {
451
            $message = sprintf('Element not found in the page after 10 seconds"');
452
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
453
        }
454
    }
455
456
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$widgetMapMoved" missing
Loading history...
introduced by
Doc comment for parameter "$position" missing
Loading history...
introduced by
Doc comment for parameter "$widgetMapMovedTo" missing
Loading history...
457
     * @Then /^I move the widgetMap "(.+)" "(.+)" the widgetMap "(.*)"$/
458
     */
459
    public function iMoveWidgetUnder($widgetMapMoved, $position, $widgetMapMovedTo)
460
    {
461
        if (!$widgetMapMovedTo) {
462
            $widgetMapMovedTo = 'null';
463
        }
464
        $js = 'updateWidgetPosition({"parentWidgetMap": '.$widgetMapMovedTo.', "slot": "main_content", "position": "'.$position.'", "widgetMap": '.$widgetMapMoved.'})';
465
466
        $this->getSession()->executeScript($js);
467
    }
468
469
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$quantumPosition" missing
Loading history...
introduced by
Doc comment for parameter "$name" missing
Loading history...
470
     * @When /^I rename quantum "(.+)" with "(.+)"$/
471
     */
472
    public function iRenameQuantumWith($quantumPosition, $name)
473
    {
474
        $session = $this->getSession();
475
476
        $pencilSelector = sprintf('descendant-or-self::ul[contains(@class, \'vic-quantum-nav\')]/li[%s]/a/i[contains(@class, \'fa-pencil\')]', $quantumPosition);
477
        $pencil = $this->findOrRetry($session->getPage(), 'xpath', $pencilSelector);
478
        $pencil->click();
479
480
        $input = $this->findOrRetry($session->getPage(), 'css', '.quantum-edit-field');
481
        $input->setValue($name);
482
483
        //Click outside
484
        $list = $this->findOrRetry($session->getPage(), 'css', '.vic-quantum-nav');
485
        $list->click();
486
    }
487
488
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$quantumName" missing
Loading history...
489
     * @When /^I select quantum "(.+)"$/
490
     */
491
    public function iSelectQuantum($quantumName)
492
    {
493
        $session = $this->getSession();
494
495
        $quantumSelector = sprintf('descendant-or-self::a[contains(@class, \'v-btn--quantum\') and normalize-space(.) = "%s"]', $quantumName);
496
        $quantum = $this->findOrRetry($session->getPage(), 'xpath', $quantumSelector);
497
        $quantum->click();
498
    }
499
500
    /**
501
     * @When /^I create a new quantum$/
502
     */
503
    public function iCreateANewQuantum()
504
    {
505
        $session = $this->getSession();
506
507
        $element = $this->findOrRetry($session->getPage(), 'css', '#widget-new-tab');
508
        $element->click();
509
    }
510
511
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$name" missing
Loading history...
512
     * @When I select :arg1 from the collapse menu
513
     */
514
    public function iSelectFromTheCollapseMenu($name)
515
    {
516
        $page = $this->getSession()->getPage();
517
518
        $menus = $page->findAll('xpath', sprintf('descendant-or-self::a[contains(@class, "v-mode-trigger")]'));
519
        if (count($menus) < 1) {
520
            $message = sprintf('Collapse menu not found in the page after 10 seconds"');
521
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
522
        }
523
524
        foreach ($menus as $menu) {
525
            if ($menu->isVisible()) {
526
                $menu->click();
527
            }
528
        }
529
530
        $links = $menu = $page->findAll('xpath', sprintf('descendant-or-self::div[contains(@class, "v-drop__menu")]//a[contains(@class, "v-drop__anchor") and normalize-space(text()) = "%s"]', $name));
0 ignored issues
show
Unused Code introduced by
$menu is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
531
532
        if (count($links) < 1) {
533
            $message = sprintf('Menu link not found in the page after 10 seconds"');
534
            throw new \Behat\Mink\Exception\ResponseTextException($message, $this->getSession());
535
        }
536
537
        foreach ($links as $link) {
538
            if ($link->getText() === $name) {
539
                $link->click();
540
            }
541
        }
542
    }
543
544
    /**
545
     * Try to find value in element and retry for a given time.
546
     *
547
     * @param Element $element
548
     * @param string  $selectorType xpath|css
549
     * @param string  $value
550
     * @param int     $timeout
551
     *
552
     * @return \Behat\Mink\Element\NodeElement|mixed|null|void
553
     */
554
    protected function findOrRetry(Element $element, $selectorType, $value, $timeout = 10000)
555
    {
556
        if ($timeout <= 0) {
557
            return;
558
        }
559
560
        $item = $element->find($selectorType, $value);
561
562 View Code Duplication
        if ($item) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
563
            return $item;
564
        } else {
565
            $this->getSession()->wait(100);
566
567
            return $this->findOrRetry($element, $selectorType, $value, $timeout - 100);
568
        }
569
    }
570
571
    /**
0 ignored issues
show
introduced by
Doc comment for parameter "$field" missing
Loading history...
introduced by
Doc comment for parameter "$entry" missing
Loading history...
introduced by
Doc comment for parameter "$value" missing
Loading history...
572
     * Fill Select2 input field and select a value.
573
     *
574
     * @When /^(?:|I )fill in select2 input "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)" and select "(?P<entry>(?:[^"]|\\")*)"$/
575
     */
576
    public function iFillInSelect2InputWithAndSelect($field, $value, $entry)
0 ignored issues
show
introduced by
Declare public methods first,then protected ones and finally private ones
Loading history...
577
    {
578
        $page = $this->getSession()->getPage();
579
        $this->openField($page, $field);
580
        $this->fillSearchField($page, $field, $value);
581
        $this->selectValue($page, $field, $entry);
582
    }
583
584
    /**
585
     * Open Select2 choice list.
586
     *
587
     * @param DocumentElement $page
588
     * @param string          $field
589
     *
590
     * @throws \Exception
591
     */
592
    private function openField(DocumentElement $page, $field)
593
    {
594
        $fieldName = sprintf('select[name="%s"] + .select2-container', $field);
595
        $inputField = $page->find('css', $fieldName);
596
        if (!$inputField) {
597
            throw new \Exception(sprintf('No field "%s" found', $field));
598
        }
599
        $choice = $inputField->find('css', '.select2-selection');
600
        if (!$choice) {
601
            throw new \Exception(sprintf('No select2 choice found for "%s"', $field));
602
        }
603
        $choice->press();
604
    }
605
606
    /**
607
     * Fill Select2 search field.
608
     *
609
     * @param DocumentElement $page
610
     * @param string          $field
611
     * @param string          $value
612
     *
613
     * @throws \Exception
614
     */
615
    private function fillSearchField(DocumentElement $page, $field, $value)
616
    {
617
        $driver = $this->getSession()->getDriver();
618
        if ('Behat\Mink\Driver\Selenium2Driver' === get_class($driver)) {
619
            // Can't use `$this->getSession()->getPage()->find()` because of https://github.com/minkphp/MinkSelenium2Driver/issues/188
620
            $select2Input = $this->getSession()->getDriver()->getWebDriverSession()->element('xpath', "//html/descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' select2-search__field ')]");
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getWebDriverSession() does only exist in the following implementations of said interface: Behat\Mink\Driver\Selenium2Driver.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
621
            if (!$select2Input) {
622
                throw new \Exception(sprintf('No field "%s" found', $field));
623
            }
624
            $select2Input->postValue(['value' => [$value]]);
625
        } else {
626
            $select2Input = $page->find('css', '.select2-search__field');
627
            if (!$select2Input) {
628
                throw new \Exception(sprintf('No input found for "%s"', $field));
629
            }
630
            $select2Input->setValue($value);
631
        }
632
        $this->waitForLoadingResults();
633
    }
634
635
    /**
636
     * Select value in choice list.
637
     *
638
     * @param DocumentElement $page
639
     * @param string          $field
640
     * @param string          $value
641
     *
642
     * @throws \Exception
643
     */
644
    private function selectValue(DocumentElement $page, $field, $value)
645
    {
646
        $this->waitForLoadingResults();
647
        $chosenResults = $page->findAll('css', '.select2-results li');
648
        foreach ($chosenResults as $result) {
649
            if ($result->getText() == $value) {
650
                $result->click();
651
652
                return;
653
            }
654
        }
655
        throw new \Exception(sprintf('Value "%s" not found for "%s"', $value, $field));
656
    }
657
658
    /**
659
     * Wait the end of fetching Select2 results.
660
     *
661
     * @param int $time Time to wait in seconds
662
     */
663
    private function waitForLoadingResults($time = 60)
664
    {
665
        for ($i = 0; $i < $time; $i++) {
666
            if (!$this->getSession()->getPage()->find('css', '.select2-results__option.loading-results')) {
667
                return true;
668
            }
669
            sleep(1);
670
        }
671
        throw new \Exception(sprintf('Results are not load after "%d" seconds.', $time));
672
    }
673
}
674