Completed
Pull Request — master (#172)
by Gordon
03:14
created

BrowserContext::iShouldSeeNElementInTheNthParent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 7
Ratio 100 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 7
loc 7
rs 9.4285
cc 2
eloc 4
nc 2
nop 4
1
<?php
2
3
namespace Sanpi\Behatch\Context;
4
5
use Behat\Gherkin\Node\TableNode;
6
use Behat\Mink\Exception\ExpectationException;
7
use Behat\Mink\Exception\ResponseTextException;
8
use Behat\Mink\Exception\ElementNotFoundException;
9
10
class BrowserContext extends BaseContext
11
{
12
    private $timeout;
13
    private $dateFormat = 'dmYHi';
14
15
    public function __construct($timeout = 1)
16
    {
17
        $this->timeout = $timeout;
18
    }
19
20
    /**
21
     * @AfterScenario
22
     */
23
    public function closeBrowser()
24
    {
25
        $this->getSession()->stop();
26
    }
27
28
    /**
29
     * Set login / password for next HTTP authentication
30
     *
31
     * @When I set basic authentication with :user and :password
32
     */
33
    public function iSetBasicAuthenticationWithAnd($user, $password)
34
    {
35
        $this->getSession()->setBasicAuth($user, $password);
36
    }
37
38
    /**
39
     * Open url with various parameters
40
     *
41
     * @Given (I )am on url composed by:
42
     */
43
    public function iAmOnUrlComposedBy(TableNode $tableNode)
44
    {
45
        $url = '';
46
        foreach ($tableNode->getHash() as $hash) {
47
            $url .= $hash['parameters'];
48
        }
49
50
        return $this->getMinkContext()
51
            ->visit($url);
52
    }
53
54
    /**
55
     * Clicks on the nth CSS element
56
     *
57
     * @When (I )click on the :index :element element
58
     */
59
    public function iClickOnTheNthElement($index, $element)
60
    {
61
        $nodes = $this->getSession()->getPage()->findAll('css', $element);
62
63
        if (isset($nodes[$index - 1])) {
64
            $nodes[$index - 1]->click();
65
        }
66
        else {
67
            throw new \Exception("The element '$element' number $index was not found anywhere in the page");
68
        }
69
    }
70
71
    /**
72
     * Click on the nth specified link
73
     *
74
     * @When (I )follow the :index :link link
75
     */
76 View Code Duplication
    public function iFollowTheNthLink($index, $link)
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...
77
    {
78
        $page = $this->getSession()->getPage();
79
80
        $links = $page->findAll('named', [
81
            'link', $this->getSession()->getSelectorsHandler()->xpathLiteral($link)
0 ignored issues
show
Deprecated Code introduced by
The method Behat\Mink\Selector\Sele...Handler::xpathLiteral() has been deprecated with message: since Mink 1.7. Use \Behat\Mink\Selector\Xpath\Escaper::escapeLiteral when building Xpath or pass the unescaped value when using the named selector.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
82
        ]);
83
84
        if (!isset($links[$index - 1])) {
85
            throw new \Exception("The $index link '$link' was not found anywhere in the page");
86
        }
87
88
        $links[$index - 1]->click();
89
    }
90
91
    /**
92
     * Presses the nth specified button
93
     *
94
     * @When (I )press the :index :button
95
     */
96 View Code Duplication
    public function pressTheNthButton($index, $button)
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...
97
    {
98
        $page = $this->getSession()->getPage();
99
100
        $buttons = $page->findAll('named', [
101
            'button', $this->getSession()->getSelectorsHandler()->xpathLiteral($button)
0 ignored issues
show
Deprecated Code introduced by
The method Behat\Mink\Selector\Sele...Handler::xpathLiteral() has been deprecated with message: since Mink 1.7. Use \Behat\Mink\Selector\Xpath\Escaper::escapeLiteral when building Xpath or pass the unescaped value when using the named selector.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
102
        ]);
103
104
        if (!isset($buttons[$index - 1])) {
105
            throw new \Exception("The $index button '$button' was not found anywhere in the page");
106
        }
107
108
        $buttons[$index - 1]->press();
109
    }
110
111
    /**
112
     * Fills in form field with current date
113
     *
114
     * @When (I )fill in :field with the current date
115
     */
116
    public function iFillInWithTheCurrentDate($field)
117
    {
118
        return $this->iFillInWithTheCurrentDateAndModifier($field, 'now');
119
    }
120
121
    /**
122
     * Fills in form field with current date and strtotime modifier
123
     *
124
     * @When (I )fill in :field with the current date and modifier :modifier
125
     */
126
    public function iFillInWithTheCurrentDateAndModifier($field, $modifier)
127
    {
128
        return $this->getMinkContext()
129
            ->fillField($field, date($this->dateFormat, strtotime($modifier)));
130
    }
131
132
    /**
133
     * Mouse over a CSS element
134
     *
135
     * @When (I )hover :element
136
     */
137 View Code Duplication
    public function iHoverIShouldSeeIn($element)
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
        $node = $this->getSession()->getPage()->find('css', $element);
140
        if ($node === null) {
141
            throw new \Exception("The hovered element '$element' was not found anywhere in the page");
142
        }
143
        $node->mouseOver();
144
    }
145
146
    /**
147
     * Save value of the field in parameters array
148
     *
149
     * @When (I )save the value of :field in the :parameter parameter
150
     */
151
    public function iSaveTheValueOfInTheParameter($field, $parameter)
152
    {
153
        $field = str_replace('\\"', '"', $field);
154
        $node  = $this->getSession()->getPage()->findField($field);
155
        if ($node === null) {
156
            throw new \Exception("The field '$field' was not found anywhere in the page");
157
        }
158
159
        $this->setMinkParameter($parameter, $node->getValue());
160
    }
161
162
    /**
163
     * Checks, that the page should contains specified text after given timeout
164
     *
165
     * @Then (I )wait :count second(s) until I see :text
166
     */
167
    public function iWaitSecondsUntilISee($count, $text)
168
    {
169
        $this->iWaitSecondsUntilISeeInTheElement($count, $text, 'html');
170
    }
171
172
    /**
173
     * Checks, that the page should contains specified text after timeout
174
     *
175
     * @Then (I )wait until I see :text
176
     */
177
    public function iWaitUntilISee($text)
178
    {
179
        $this->iWaitSecondsUntilISee($this->timeout, $text);
180
    }
181
182
    /**
183
     * Checks, that the element contains specified text after timeout
184
     *
185
     * @Then (I )wait :count second(s) until I see :text in the :element element
186
     */
187
    public function iWaitSecondsUntilISeeInTheElement($count, $text, $element)
188
    {
189
        $this->iWaitSecondsForElement($count, $element);
190
191
        $expected = str_replace('\\"', '"', $text);
192
        $node = $this->getSession()->getPage()->find('css', $element);
193
        $message = "The text '$expected' was not found after a $count seconds timeout";
194
195
        $this->assertContains($expected, $node->getText(), $message);
196
    }
197
198
    /**
199
     * @Then (I )wait :count second(s)
200
     */
201
    public function iWaitSeconds($count)
202
    {
203
        sleep($count);
204
    }
205
206
    /**
207
     * Checks, that the element contains specified text after timeout
208
     *
209
     * @Then (I )wait until I see :text in the :element element
210
     */
211
    public function iWaitUntilISeeInTheElement($text, $element)
212
    {
213
        $this->iWaitSecondsUntilISeeInTheElement($this->timeout, $text, $element);
214
    }
215
216
    /**
217
     * Checks, that the page should contains specified element after timeout
218
     *
219
     * @Then (I )wait for :element element
220
     */
221
    public function iWaitForElement($element)
222
    {
223
        $this->iWaitSecondsForElement($this->timeout, $element);
224
    }
225
226
    /**
227
     * Wait for a element
228
     *
229
     * @Then (I )wait :count second(s) for :element element
230
     */
231
    public function iWaitSecondsForElement($count, $element)
232
    {
233
        $found = false;
234
        $startTime = time();
235
236
        do {
237
            try {
238
                $node = $this->getSession()->getPage()->findAll('css', $element);
239
                $this->assertCount(1, $node);
240
                $found = true;
241
            }
242
            catch (ExpectationException $e) {
243
                /* Intentionnaly leave blank */
244
            }
245
        }
246
        while (time() - $startTime < $count);
247
248
        if ($found === false) {
249
            $message = "The element '$element' was not found after a $count seconds timeout";
250
            throw new ResponseTextException($message, $this->getSession(), $e);
251
        }
252
    }
253
254
    /**
255
     * @Then /^(?:|I )should see (?P<count>\d+) "(?P<element>[^"]*)" in the (?P<index>\d+)(?:st|nd|rd|th) "(?P<parent>[^"]*)"$/
256
     */
257 View Code Duplication
    public function iShouldSeeNElementInTheNthParent($count, $element, $index, $parent)
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...
258
    {
259
        $actual = $this->countElements($element, $index, $parent);
260
        if ($actual !== $count) {
261
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
262
        }
263
    }
264
265
    /**
266
     * @Then (I )should see less than :count :element in the :index :parent
267
     */
268 View Code Duplication
    public function iShouldSeeLessThanNElementInTheNthParent($count, $element, $index, $parent)
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...
269
    {
270
        $actual = $this->countElements($element, $index, $parent);
271
        if ($actual > $count) {
272
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
273
        }
274
    }
275
276
    /**
277
     * @Then (I )should see more than :count :element in the :index :parent
278
     */
279 View Code Duplication
    public function iShouldSeeMoreThanNElementInTheNthParent($count, $element, $index, $parent)
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...
280
    {
281
        $actual = $this->countElements($element, $index, $parent);
282
        if ($actual < $count) {
283
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
284
        }
285
    }
286
287
    /**
288
     * Checks, that element with given CSS is enabled
289
     *
290
     * @Then the element :element should be enabled
291
     */
292 View Code Duplication
    public function theElementShouldBeEnabled($element)
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...
293
    {
294
        $node = $this->getSession()->getPage()->find('css', $element);
295
        if ($node === null) {
296
            throw new \Exception("There is no '$element' element");
297
        }
298
299
        if ($node->hasAttribute('disabled')) {
300
            throw new \Exception("The element '$element' is not enabled");
301
        }
302
    }
303
304
    /**
305
     * Checks, that element with given CSS is disabled
306
     *
307
     * @Then the element :element should be disabled
308
     */
309
    public function theElementShouldBeDisabled($element)
310
    {
311
        $this->not(function () use($element) {
312
            $this->theElementShouldBeEnabled($element);
313
        }, "The element '$element' is not disabled");
314
    }
315
316
    /**
317
     * Checks, that given select box contains the specified option
318
     *
319
     * @Then the :select select box should contain :option
320
     */
321
    public function theSelectBoxShouldContain($select, $option)
322
    {
323
        $select = str_replace('\\"', '"', $select);
324
        $option = str_replace('\\"', '"', $option);
325
326
        $obj = $this->getSession()->getPage()->findField($select);
327
        if ($obj === null) {
328
            throw new ElementNotFoundException(
329
                $this->getSession(), 'select box', 'id|name|label|value', $select
330
            );
331
        }
332
        $optionText = $obj->getText();
333
334
        $message = "The '$select' select box does not contain the '$option' option";
335
        $this->assertContains($option, $optionText, $message);
336
    }
337
338
    /**
339
     * Checks, that given select box does not contain the specified option
340
     *
341
     * @Then the :select select box should not contain :option
342
     */
343
    public function theSelectBoxShouldNotContain($select, $option)
344
    {
345
        $this->not(function () use($select, $option) {
346
            $this->theSelectBoxShouldContain($select, $option);
347
        }, "The '$select' select box does contain the '$option' option");
348
    }
349
350
    /**
351
     * Checks, that the specified CSS element is visible
352
     *
353
     * @Then the :element element should be visible
354
     */
355
    public function theElementShouldBeVisible($element)
356
    {
357
        $displayedNode = $this->getSession()->getPage()->find('css', $element);
358
        if ($displayedNode === null) {
359
            throw new \Exception("The element '$element' was not found anywhere in the page");
360
        }
361
362
363
        $message = "The element '$element' is not visible";
364
        $this->assertTrue($displayedNode->isVisible(), $message);
365
    }
366
367
    /**
368
     * Checks, that the specified CSS element is not visible
369
     *
370
     * @Then the :element element should not be visible
371
     */
372
    public function theElementShouldNotBeVisible($element)
373
    {
374
        $exception = new \Exception("The element '$element' is visible");
375
376
        $this->not(function () use($element) {
377
            $this->theElementShouldBeVisible($element);
378
        }, $exception);
379
    }
380
381
    /**
382
     * Select a frame by its name or ID.
383
     *
384
     * @When (I )switch to iframe :name
385
     * @When (I )switch to frame :name
386
     */
387
    public function switchToIFrame($name)
388
    {
389
        $this->getSession()->switchToIFrame($name);
390
    }
391
392
    /**
393
     * Go back to main document frame.
394
     *
395
     * @When (I )switch to main frame
396
     */
397
    public function switchToMainFrame()
398
    {
399
        $this->getSession()->switchToIFrame();
400
    }
401
}
402