Completed
Pull Request — master (#183)
by Will
09:22
created

BrowserContext::theSelectBoxShouldNotContain()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 4
nc 1
nop 2
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
use WebDriver\Exception\StaleElementReference;
10
use Behat\Behat\Tester\Exception\PendingException;
11
12
class BrowserContext extends BaseContext
13
{
14
    private $timeout;
15
    private $dateFormat = 'dmYHi';
16
    private $timerStartedAt;
17
18
    public function __construct($timeout = 1)
19
    {
20
        $this->timeout = $timeout;
21
    }
22
23
    /**
24
     * @AfterScenario
25
     */
26
    public function closeBrowser()
27
    {
28
        $this->getSession()->stop();
29
    }
30
31
    /**
32
     * @BeforeScenario
33
     *
34
     * @When (I )start timing now
35
     */
36
    public function startTimer()
37
    {
38
        $this->timerStartedAt = time();
39
    }
40
41
    /**
42
     * Set login / password for next HTTP authentication
43
     *
44
     * @When I set basic authentication with :user and :password
45
     */
46
    public function iSetBasicAuthenticationWithAnd($user, $password)
47
    {
48
        $this->getSession()->setBasicAuth($user, $password);
49
    }
50
51
    /**
52
     * Open url with various parameters
53
     *
54
     * @Given (I )am on url composed by:
55
     */
56
    public function iAmOnUrlComposedBy(TableNode $tableNode)
57
    {
58
        $url = '';
59
        foreach ($tableNode->getHash() as $hash) {
60
            $url .= $hash['parameters'];
61
        }
62
63
        return $this->getMinkContext()
64
            ->visit($url);
65
    }
66
67
    /**
68
     * Clicks on the nth CSS element
69
     *
70
     * @When (I )click on the :index :element element
71
     */
72
    public function iClickOnTheNthElement($index, $element)
73
    {
74
        $node = $this->findElement('css', $element, $index);
75
        $node->click();
76
    }
77
78
    /**
79
     * Click on the nth specified link
80
     *
81
     * @When (I )follow the :index :link link
82
     */
83
    public function iFollowTheNthLink($index, $link)
84
    {
85
        $element = ['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...
86
        $node = $this->findElement('named', $element, $index);
87
        $node->click();
88
    }
89
90
    /**
91
     * Presses the nth specified button
92
     *
93
     * @When (I )press the :index :button button
94
     */
95
    public function pressTheNthButton($index, $button)
96
    {
97
        $element = ['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...
98
        $node = $this->findElement('named', $element, $index);
99
        $node->click();
100
    }
101
102
    /**
103
     * Fills in form field with current date
104
     *
105
     * @When (I )fill in :field with the current date
106
     */
107
    public function iFillInWithTheCurrentDate($field)
108
    {
109
        return $this->iFillInWithTheCurrentDateAndModifier($field, 'now');
110
    }
111
112
    /**
113
     * Fills in form field with current date and strtotime modifier
114
     *
115
     * @When (I )fill in :field with the current date and modifier :modifier
116
     */
117
    public function iFillInWithTheCurrentDateAndModifier($field, $modifier)
118
    {
119
        return $this->getMinkContext()
120
            ->fillField($field, date($this->dateFormat, strtotime($modifier)));
121
    }
122
123
    /**
124
     * Mouse over a CSS element
125
     *
126
     * @When (I )hover :element
127
     */
128 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...
129
    {
130
        $node = $this->getSession()->getPage()->find('css', $element);
131
        if ($node === null) {
132
            throw new \Exception("The hovered element '$element' was not found anywhere in the page");
133
        }
134
        $node->mouseOver();
135
    }
136
137
    /**
138
     * Save value of the field in parameters array
139
     *
140
     * @When (I )save the value of :field in the :parameter parameter
141
     */
142
    public function iSaveTheValueOfInTheParameter($field, $parameter)
143
    {
144
        $field = str_replace('\\"', '"', $field);
145
        $node  = $this->getSession()->getPage()->findField($field);
146
        if ($node === null) {
147
            throw new \Exception("The field '$field' was not found anywhere in the page");
148
        }
149
150
        $this->setMinkParameter($parameter, $node->getValue());
151
    }
152
153
    /**
154
     * Checks, that the page should contains specified text after given timeout
155
     *
156
     * @Then (I )wait :count second(s) until I see :text
157
     */
158
    public function iWaitSecondsUntilISee($count, $text)
159
    {
160
        $this->iWaitSecondsUntilISeeInTheElement($count, $text, 'html');
161
    }
162
163
    /**
164
     * Checks, that the page should contains specified text after timeout
165
     *
166
     * @Then (I )wait until I see :text
167
     */
168
    public function iWaitUntilISee($text)
169
    {
170
        $this->iWaitSecondsUntilISee($this->timeout, $text);
171
    }
172
173
    /**
174
     * Checks, that the element contains specified text after timeout
175
     *
176
     * @Then (I )wait :count second(s) until I see :text in the :element element
177
     */
178
    public function iWaitSecondsUntilISeeInTheElement($count, $text, $element)
179
    {
180
        $startTime = time();
181
        $this->iWaitSecondsForElement($count, $element);
182
183
        $expected = str_replace('\\"', '"', $text);
184
        $message = "The text '$expected' was not found after a $count seconds timeout";
185
186
        $found = false;
187 View Code Duplication
        do {
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...
188
            try {
189
                usleep(1000);
190
                $node = $this->getSession()->getPage()->find('css', $element);
191
                $this->assertContains($expected, $node->getText(), $message);
192
                return;
193
            }
194
            catch (ExpectationException $e) {
195
                /* Intentionaly leave blank */
196
            }
197
            catch (StaleElementReference $e) {
198
                // assume page reloaded whilst we were still waiting
199
            }
200
        } while (!$found && (time() - $startTime < $count));
201
    }
202
203
    /**
204
     * @Then (I )wait :count second(s)
205
     */
206
    public function iWaitSeconds($count)
207
    {
208
        usleep($count * 1000000);
209
    }
210
211
    /**
212
     * Checks, that the element contains specified text after timeout
213
     *
214
     * @Then (I )wait until I see :text in the :element element
215
     */
216
    public function iWaitUntilISeeInTheElement($text, $element)
217
    {
218
        $this->iWaitSecondsUntilISeeInTheElement($this->timeout, $text, $element);
219
    }
220
221
    /**
222
     * Checks, that the page should contains specified element after timeout
223
     *
224
     * @Then (I )wait for :element element
225
     */
226
    public function iWaitForElement($element)
227
    {
228
        $this->iWaitSecondsForElement($this->timeout, $element);
229
    }
230
231
    /**
232
     * Wait for a element
233
     *
234
     * @Then (I )wait :count second(s) for :element element
235
     */
236
    public function iWaitSecondsForElement($count, $element)
237
    {
238
        $found = false;
239
        $startTime = time();
240
241 View Code Duplication
        do {
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...
242
            try {
243
                usleep(1000);
244
                $node = $this->getSession()->getPage()->findAll('css', $element);
245
                $this->assertCount(1, $node);
246
                $found = true;
247
            }
248
            catch (ExpectationException $e) {
249
                /* Intentionnaly leave blank */
250
            }
251
        }
252
        while (!$found && (time() - $startTime < $count));
253
254
        if ($found === false) {
255
            $message = "The element '$element' was not found after a $count seconds timeout";
256
            throw new ResponseTextException($message, $this->getSession(), $e);
257
        }
258
    }
259
260
    /**
261
     * @Then /^(?:|I )should see (?P<count>\d+) "(?P<element>[^"]*)" in the (?P<index>\d+)(?:st|nd|rd|th) "(?P<parent>[^"]*)"$/
262
     */
263 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...
264
    {
265
        $actual = $this->countElements($element, $index, $parent);
266
        if ($actual !== $count) {
267
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
268
        }
269
    }
270
271
    /**
272
     * @Then (I )should see less than :count :element in the :index :parent
273
     */
274 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...
275
    {
276
        $actual = $this->countElements($element, $index, $parent);
277
        if ($actual > $count) {
278
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
279
        }
280
    }
281
282
    /**
283
     * @Then (I )should see more than :count :element in the :index :parent
284
     */
285 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...
286
    {
287
        $actual = $this->countElements($element, $index, $parent);
288
        if ($actual < $count) {
289
            throw new \Exception("$actual occurrences of the '$element' element in '$parent' found");
290
        }
291
    }
292
293
    /**
294
     * Checks, that element with given CSS is enabled
295
     *
296
     * @Then the element :element should be enabled
297
     */
298 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...
299
    {
300
        $node = $this->getSession()->getPage()->find('css', $element);
301
        if ($node === null) {
302
            throw new \Exception("There is no '$element' element");
303
        }
304
305
        if ($node->hasAttribute('disabled')) {
306
            throw new \Exception("The element '$element' is not enabled");
307
        }
308
    }
309
310
    /**
311
     * Checks, that element with given CSS is disabled
312
     *
313
     * @Then the element :element should be disabled
314
     */
315
    public function theElementShouldBeDisabled($element)
316
    {
317
        $this->not(function () use($element) {
318
            $this->theElementShouldBeEnabled($element);
319
        }, "The element '$element' is not disabled");
320
    }
321
322
    /**
323
     * Checks, that given select box contains the specified option
324
     *
325
     * @Then the :select select box should contain :option
326
     */
327
    public function theSelectBoxShouldContain($select, $option)
328
    {
329
        $select = str_replace('\\"', '"', $select);
330
        $option = str_replace('\\"', '"', $option);
331
332
        $obj = $this->getSession()->getPage()->findField($select);
333
        if ($obj === null) {
334
            throw new ElementNotFoundException(
335
                $this->getSession(), 'select box', 'id|name|label|value', $select
336
            );
337
        }
338
        $optionText = $obj->getText();
339
340
        $message = "The '$select' select box does not contain the '$option' option";
341
        $this->assertContains($option, $optionText, $message);
342
    }
343
344
    /**
345
     * Checks, that given select box does not contain the specified option
346
     *
347
     * @Then the :select select box should not contain :option
348
     */
349
    public function theSelectBoxShouldNotContain($select, $option)
350
    {
351
        $this->not(function () use($select, $option) {
352
            $this->theSelectBoxShouldContain($select, $option);
353
        }, "The '$select' select box does contain the '$option' option");
354
    }
355
356
    /**
357
     * Checks, that the specified CSS element is visible
358
     *
359
     * @Then the :element element should be visible
360
     */
361
    public function theElementShouldBeVisible($element)
362
    {
363
        $displayedNode = $this->getSession()->getPage()->find('css', $element);
364
        if ($displayedNode === null) {
365
            throw new \Exception("The element '$element' was not found anywhere in the page");
366
        }
367
368
369
        $message = "The element '$element' is not visible";
370
        $this->assertTrue($displayedNode->isVisible(), $message);
371
    }
372
373
    /**
374
     * Checks, that the specified CSS element is not visible
375
     *
376
     * @Then the :element element should not be visible
377
     */
378
    public function theElementShouldNotBeVisible($element)
379
    {
380
        $exception = new \Exception("The element '$element' is visible");
381
382
        $this->not(function () use($element) {
383
            $this->theElementShouldBeVisible($element);
384
        }, $exception);
385
    }
386
387
    /**
388
     * Select a frame by its name or ID.
389
     *
390
     * @When (I )switch to iframe :name
391
     * @When (I )switch to frame :name
392
     */
393
    public function switchToIFrame($name)
394
    {
395
        $this->getSession()->switchToIFrame($name);
396
    }
397
398
    /**
399
     * Go back to main document frame.
400
     *
401
     * @When (I )switch to main frame
402
     */
403
    public function switchToMainFrame()
404
    {
405
        $this->getSession()->switchToIFrame();
406
    }
407
408
    /**
409
     * test time from when the scenario started
410
     *
411
     * @Then (the )total elapsed time should be :comparison than :expected seconds
412
     * @Then (the )total elapsed time should be :comparison to :expected seconds
413
     */
414
    public function elapsedTime($comparison, $expected)
415
    {
416
        $elapsed = time() - $this->timerStartedAt;
417
418
        switch ($comparison) {
419
            case 'less':
420
                $this->assertTrue($elapsed < $expected, "Elapsed time '$elapsed' is not less than '$expected' seconds.");
421
                break;
422
423
            case 'more':
424
                $this->assertTrue($elapsed > $expected, "Elapsed time '$elapsed' is not more than '$expected' seconds.");
425
                break;
426
427
            case 'equal':
428
                $this->assertTrue($elapsed === $expected, "Elapsed time '$elapsed' is not '$expected' seconds.");
429
                break;
430
431
            default:
432
                throw new PendingException("Unknown comparison '$comparison'. Use 'less', 'more' or 'equal'");
433
        }
434
    }
435
}
436