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