Completed
Push — master ( 92b26f...232625 )
by Albin
06:25 queued 03:33
created

MinkContext::searchElement()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 15
rs 9.2
cc 4
eloc 8
nc 4
nop 4
1
<?php
2
3
namespace Knp\FriendlyContexts\Context;
4
5
use Behat\MinkExtension\Context\MinkContext as BaseMinkContext;
6
use Behat\Mink\Element\TraversableElement;
7
use Behat\Mink\Exception\ElementNotFoundException;
8
use Knp\FriendlyContexts\Utils\Asserter;
9
use Knp\FriendlyContexts\Utils\TextFormater;
10
11
class MinkContext extends BaseMinkContext
12
{
13
    /**
14
     * @When /^(?:|I )(follow|press) the "(?P<name>[^"]*)" (?P<element>[^"]*)$/
15
     * @When /^(?:|I )(follow|press) the first "(?P<name>[^"]*)" (?P<element>[^"]*)$/
16
     * @When /^(?:|I )(follow|press) the (?P<nbr>\d*)(st|nd|rd|th) "(?P<name>[^"]*)" (?P<element>[^"]*)$/
17
     **/
18
    public function clickElement($name, $element, $nbr = 1, $filterCallback = null)
19
    {
20
        $this->elementAction($name, $element, $nbr, function ($e) { $e->click(); }, $filterCallback);
21
    }
22
23
    /**
24
     * @When /^(?:|I )(?P<state>check|uncheck) the "(?P<name>[^"]*)" checkbox$/
25
     * @When /^(?:|I )(?P<state>check|uncheck) the first "(?P<name>[^"]*)" checkbox$/
26
     * @When /^(?:|I )(?P<state>check|uncheck) the (?P<nbr>\d*)(st|nd|rd|th) "(?P<name>[^"]*)" checkbox$/
27
     **/
28
    public function checkCheckbox($state, $name, $nbr = 1)
29
    {
30
        $this->elementAction(
31
            $name,
32
            'field',
33
            $nbr,
34
            function ($e) use ($state) { if ('check' === $state) { $e->check(); } else { $e->uncheck(); } },
35
            function ($e) { return 'checkbox' === $e->getAttribute('type'); }
36
        );
37
    }
38
39
    /**
40
     * @When /^(?:|I )check the "(?P<name>[^"]*)" radio$/
41
     * @When /^(?:|I )check the first "(?P<name>[^"]*)" radio$/
42
     * @When /^(?:|I )check the (?P<nbr>\d*)(st|nd|rd|th) "(?P<name>[^"]*)" radio$/
43
     **/
44
    public function checkRadio($name, $nbr = 1)
45
    {
46
        $this->elementAction(
47
            $name,
48
            'field',
49
            $nbr,
50
            function ($e) { $this->getSession()->getDriver()->click($e->getXPath()); },
51
            function ($e) { return 'radio' === $e->getAttribute('type'); }
52
        );
53
    }
54
55
56
    /**
57
     * @Then /^(?:|I )should(?P<should>| not) see (?P<nbr>\d*) "(?P<name>[^"]*)" (?P<element>link|button|radio|checkbox)$/
58
     **/
59
    public function nbrElement($should, $nbr, $name, $element)
60
    {
61
        $type = in_array($element, [ 'checkbox', 'radio' ]) ? 'field' : $element;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
62
        $filterCallback = null;
63
64
        if ('field' === $type) {
65
            $filterCallback = function ($e) use ($element) { return $element === $e->getAttribute('type'); };
66
        }
67
68
        $elements = $this->searchElement($name, $type, $filterCallback);
69
70
        $message = sprintf('%s %s found', $nbr, $element);
71
72
        if (' not' === $should) {
73
            $this->getAsserter()->assertEquals($nbr, count($elements), $message);
74
        } else {
75
            $this->getAsserter()->assertNotEquals($nbr, count($elements), $message);
76
        }
77
    }
78
79
    /**
80
     * @Then /^(?:|I )should(?P<should>| not) see a "(?P<name>[^"]*)" (?P<element>link|button|radio|checkbox)$/
81
     **/
82
    public function seeElement($should, $name, $element)
83
    {
84
        $type = in_array($element, [ 'checkbox', 'radio' ]) ? 'field' : $element;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 11 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
85
        $filterCallback = null;
86
87
        if ('field' === $type) {
88
            $filterCallback = function ($e) use ($element) { return $element === $e->getAttribute('type'); };
89
        }
90
91
        $elements = $this->searchElement($name, $type, $filterCallback);
92
93
        $message = sprintf('%s %s%s found', $name, $element, ' not' === $should ? '' : ' not');
94
95
        if (' not' === $should) {
96
            $this->getAsserter()->assert(0 == count($elements), $message);
97
        } else {
98
            $this->getAsserter()->assert(0 < count($elements), $message);
99
        }
100
    }
101
102
    /**
103
     * @When /^(?:|I )(follow|press) the last "(?P<name>[^"]*)" (?P<element>[^"]*)$/
104
     **/
105
    public function clicklastElement($name, $element)
106
    {
107
        $this->clickElement($name, $element, -1);
108
    }
109
110
    /**
111
     * @When /^(?:|I )follow the link containing "(?P<link>(?:[^"]|\\")*)"$/
112
     */
113
    public function clickLinkContaining($link)
114
    {
115
        parent::clickLink($link);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (clickLink() instead of clickLinkContaining()). Are you sure this is correct? If so, you might want to change this to $this->clickLink().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
116
    }
117
118
    public function clickLink($link)
119
    {
120
        $this->clickElement($link, 'link', 1, function ($e) use ($link) { return $link === $e->getText(); });
121
    }
122
123
    /**
124
     * @When /^(?:|I )fill in the first "(?P<field>(?:[^"]|\\")*)" field with "(?P<value>(?:[^"]|\\")*)"$/
125
     * @When /^(?:|I )fill in the (?P<nbr>\d*)(st|nd|rd|th) "(?P<field>(?:[^"]|\\")*)" field with "(?P<value>(?:[^"]|\\")*)"$/
126
     **/
127
    public function fillTheNthField($field, $value, $nbr = 1)
128
    {
129
        $field = $this->fixStepArgument($field);
130
        $value = $this->fixStepArgument($value);
131
132
        $this->elementAction(
133
            $field,
134
            'field',
135
            $nbr,
136
            function ($e) use ($value) { $e->setValue($value); },
137
            function ($e) {
138
                return in_array($e->getAttribute('type'), array(
139
                    'text', 'password', 'color', 'date', 'datetime',
140
                    'datetime-local', 'email', 'month', 'number', 'range',
141
                    'search', 'tel', 'time', 'url', 'week',
142
                ));
143
            }
144
        );
145
    }
146
147
    protected function searchElement($locator, $element, $filterCallback = null, TraversableElement $parent = null)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
148
    {
149
        $parent  = $parent ?: $this->getSession()->getPage();
150
        $locator = $this->fixStepArgument($locator);
151
152
        $elements = $parent->findAll('named', array(
153
            $element, $locator
154
        ));
155
156
        if (null !== $filterCallback && is_callable($filterCallback)) {
157
            $elements = array_values(array_filter($elements, $filterCallback));
158
        }
159
160
        return $elements;
161
    }
162
163
    protected function elementAction($locator, $element, $nbr = 1, $actionCallback, $filterCallback = null)
0 ignored issues
show
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
164
    {
165
        $elements = $this->searchElement($locator, $element, $filterCallback);
166
167
        $nbr = is_numeric($nbr) ? intval($nbr) : $nbr;
168
        $nbr = is_string($nbr) ? 1 : (-1 === $nbr ? count($elements) : $nbr);
169
170
        if ($nbr > count($elements)) {
171
            throw new ElementNotFoundException($this->getSession(), $element, null, $locator);
172
        }
173
174
        $e = $elements[$nbr - 1];
175
176
        $actionCallback($e);
177
    }
178
179
    protected function getAsserter()
180
    {
181
        return new Asserter(new TextFormater);
182
    }
183
}
184