Completed
Pull Request — master (#344)
by
unknown
01:17
created

MinkContext::iWaitForElementToAppear()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 2
nc 1
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Behat MinkExtension.
5
 * (c) Konstantin Kudryashov <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Behat\MinkExtension\Context;
12
13
use Behat\Behat\Context\TranslatableContext;
14
use Behat\Gherkin\Node\TableNode;
15
use Behat\Mink\Exception\ElementNotFoundException;
16
17
/**
18
 * Mink context for Behat BDD tool.
19
 * Provides Mink integration and base step definitions.
20
 *
21
 * @author Konstantin Kudryashov <[email protected]>
22
 */
23
class MinkContext extends RawMinkContext implements TranslatableContext
24
{
25
    const MAXIMUM_WAIT_TIME = 60;
26
27
    /**
28
     * Opens homepage
29
     * Example: Given I am on "/"
30
     * Example: When I go to "/"
31
     * Example: And I go to "/"
32
     *
33
     * @Given /^(?:|I )am on (?:|the )homepage$/
34
     * @When /^(?:|I )go to (?:|the )homepage$/
35
     */
36
    public function iAmOnHomepage()
37
    {
38
        $this->visitPath('/');
39
    }
40
41
    /**
42
     * Opens specified page
43
     * Example: Given I am on "http://batman.com"
44
     * Example: And I am on "/articles/isBatmanBruceWayne"
45
     * Example: When I go to "/articles/isBatmanBruceWayne"
46
     *
47
     * @Given /^(?:|I )am on "(?P<page>[^"]+)"$/
48
     * @When /^(?:|I )go to "(?P<page>[^"]+)"$/
49
     */
50
    public function visit($page)
51
    {
52
        $this->visitPath($page);
53
    }
54
55
    /**
56
     * Reloads current page
57
     * Example: When I reload the page
58
     * Example: And I reload the page
59
     *
60
     * @When /^(?:|I )reload the page$/
61
     */
62
    public function reload()
63
    {
64
        $this->getSession()->reload();
65
    }
66
67
    /**
68
     * Moves backward one page in history
69
     * Example: When I move backward one page
70
     *
71
     * @When /^(?:|I )move backward one page$/
72
     */
73
    public function back()
74
    {
75
        $this->getSession()->back();
76
    }
77
78
    /**
79
     * Moves forward one page in history
80
     * Example: And I move forward one page
81
     *
82
     * @When /^(?:|I )move forward one page$/
83
     */
84
    public function forward()
85
    {
86
        $this->getSession()->forward();
87
    }
88
89
    /**
90
     * Presses button with specified id|name|title|alt|value
91
     * Example: When I press "Log In"
92
     * Example: And I press "Log In"
93
     *
94
     * @When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/
95
     */
96
    public function pressButton($button)
97
    {
98
        $button = $this->fixStepArgument($button);
99
        $this->getSession()->getPage()->pressButton($button);
100
    }
101
102
    /**
103
     * Clicks link with specified id|title|alt|text
104
     * Example: When I follow "Log In"
105
     * Example: And I follow "Log In"
106
     *
107
     * @When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/
108
     */
109
    public function clickLink($link)
110
    {
111
        $link = $this->fixStepArgument($link);
112
        $this->getSession()->getPage()->clickLink($link);
113
    }
114
115
    /**
116
     * Fills in form field with specified id|name|label|value
117
     * Example: When I fill in "username" with: "bwayne"
118
     * Example: And I fill in "bwayne" for "username"
119
     *
120
     * @When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
121
     * @When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with:$/
122
     * @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/
123
     */
124
    public function fillField($field, $value)
125
    {
126
        $field = $this->fixStepArgument($field);
127
        $value = $this->fixStepArgument($value);
128
        $this->getSession()->getPage()->fillField($field, $value);
129
    }
130
131
    /**
132
     * Fills in form fields with provided table
133
     * Example: When I fill in the following"
134
     *              | username | bruceWayne |
135
     *              | password | iLoveBats123 |
136
     * Example: And I fill in the following"
137
     *              | username | bruceWayne |
138
     *              | password | iLoveBats123 |
139
     *
140
     * @When /^(?:|I )fill in the following:$/
141
     */
142
    public function fillFields(TableNode $fields)
143
    {
144
        foreach ($fields->getRowsHash() as $field => $value) {
145
            $this->fillField($field, $value);
146
        }
147
    }
148
149
    /**
150
     * Selects option in select field with specified id|name|label|value
151
     * Example: When I select "Bats" from "user_fears"
152
     * Example: And I select "Bats" from "user_fears"
153
     *
154
     * @When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/
155
     */
156
    public function selectOption($select, $option)
157
    {
158
        $select = $this->fixStepArgument($select);
159
        $option = $this->fixStepArgument($option);
160
        $this->getSession()->getPage()->selectFieldOption($select, $option);
161
    }
162
163
    /**
164
     * Selects additional option in select field with specified id|name|label|value
165
     * Example: When I additionally select "Deceased" from "parents_alive_status"
166
     * Example: And I additionally select "Deceased" from "parents_alive_status"
167
     *
168
     * @When /^(?:|I )additionally select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/
169
     */
170
    public function additionallySelectOption($select, $option)
171
    {
172
        $select = $this->fixStepArgument($select);
173
        $option = $this->fixStepArgument($option);
174
        $this->getSession()->getPage()->selectFieldOption($select, $option, true);
175
    }
176
177
    /**
178
     * Checks checkbox with specified id|name|label|value
179
     * Example: When I check "Pearl Necklace"
180
     * Example: And I check "Pearl Necklace"
181
     *
182
     * @When /^(?:|I )check "(?P<option>(?:[^"]|\\")*)"$/
183
     */
184
    public function checkOption($option)
185
    {
186
        $option = $this->fixStepArgument($option);
187
        $this->getSession()->getPage()->checkField($option);
188
    }
189
190
    /**
191
     * Unchecks checkbox with specified id|name|label|value
192
     * Example: When I uncheck "Broadway Plays"
193
     * Example: And I uncheck "Broadway Plays"
194
     *
195
     * @When /^(?:|I )uncheck "(?P<option>(?:[^"]|\\")*)"$/
196
     */
197
    public function uncheckOption($option)
198
    {
199
        $option = $this->fixStepArgument($option);
200
        $this->getSession()->getPage()->uncheckField($option);
201
    }
202
203
    /**
204
     * Attaches file to field with specified id|name|label|value
205
     * Example: When I attach "bwayne_profile.png" to "profileImageUpload"
206
     * Example: And I attach "bwayne_profile.png" to "profileImageUpload"
207
     *
208
     * @When /^(?:|I )attach the file "(?P<path>[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/
209
     */
210
    public function attachFileToField($field, $path)
211
    {
212
        $field = $this->fixStepArgument($field);
213
214
        if ($this->getMinkParameter('files_path')) {
215
            $fullPath = rtrim(realpath($this->getMinkParameter('files_path')), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$path;
216
            if (is_file($fullPath)) {
217
                $path = $fullPath;
218
            }
219
        }
220
221
        $this->getSession()->getPage()->attachFileToField($field, $path);
222
    }
223
224
    /**
225
     * Checks, that current page PATH is equal to specified
226
     * Example: Then I should be on "/"
227
     * Example: And I should be on "/bats"
228
     * Example: And I should be on "http://google.com"
229
     *
230
     * @Then /^(?:|I )should be on "(?P<page>[^"]+)"$/
231
     */
232
    public function assertPageAddress($page)
233
    {
234
        $this->assertSession()->addressEquals($this->locatePath($page));
235
    }
236
237
    /**
238
     * Checks, that current page is the homepage
239
     * Example: Then I should be on the homepage
240
     * Example: And I should be on the homepage
241
     *
242
     * @Then /^(?:|I )should be on (?:|the )homepage$/
243
     */
244
    public function assertHomepage()
245
    {
246
        $this->assertSession()->addressEquals($this->locatePath('/'));
247
    }
248
249
    /**
250
     * Checks, that current page PATH matches regular expression
251
     * Example: Then the url should match "superman is dead"
252
     * Example: Then the uri should match "log in"
253
     * Example: And the url should match "log in"
254
     *
255
     * @Then /^the (?i)url(?-i) should match (?P<pattern>"(?:[^"]|\\")*")$/
256
     */
257
    public function assertUrlRegExp($pattern)
258
    {
259
        $this->assertSession()->addressMatches($this->fixStepArgument($pattern));
260
    }
261
262
    /**
263
     * Checks, that current page response status is equal to specified
264
     * Example: Then the response status code should be 200
265
     * Example: And the response status code should be 400
266
     *
267
     * @Then /^the response status code should be (?P<code>\d+)$/
268
     */
269
    public function assertResponseStatus($code)
270
    {
271
        $this->assertSession()->statusCodeEquals($code);
272
    }
273
274
    /**
275
     * Checks, that current page response status is not equal to specified
276
     * Example: Then the response status code should not be 501
277
     * Example: And the response status code should not be 404
278
     *
279
     * @Then /^the response status code should not be (?P<code>\d+)$/
280
     */
281
    public function assertResponseStatusIsNot($code)
282
    {
283
        $this->assertSession()->statusCodeNotEquals($code);
284
    }
285
286
    /**
287
     * Checks, that page contains specified text
288
     * Example: Then I should see "Who is the Batman?"
289
     * Example: And I should see "Who is the Batman?"
290
     *
291
     * @Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/
292
     */
293
    public function assertPageContainsText($text)
294
    {
295
        $this->assertSession()->pageTextContains($this->fixStepArgument($text));
296
    }
297
298
    /**
299
     * Checks, that page doesn't contain specified text
300
     * Example: Then I should not see "Batman is Bruce Wayne"
301
     * Example: And I should not see "Batman is Bruce Wayne"
302
     *
303
     * @Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)"$/
304
     */
305
    public function assertPageNotContainsText($text)
306
    {
307
        $this->assertSession()->pageTextNotContains($this->fixStepArgument($text));
308
    }
309
310
    /**
311
     * Checks, that page contains text matching specified pattern
312
     * Example: Then I should see text matching "Batman, the vigilante"
313
     * Example: And I should not see "Batman, the vigilante"
314
     *
315
     * @Then /^(?:|I )should see text matching (?P<pattern>"(?:[^"]|\\")*")$/
316
     */
317
    public function assertPageMatchesText($pattern)
318
    {
319
        $this->assertSession()->pageTextMatches($this->fixStepArgument($pattern));
320
    }
321
322
    /**
323
     * Checks, that page doesn't contain text matching specified pattern
324
     * Example: Then I should see text matching "Bruce Wayne, the vigilante"
325
     * Example: And I should not see "Bruce Wayne, the vigilante"
326
     *
327
     * @Then /^(?:|I )should not see text matching (?P<pattern>"(?:[^"]|\\")*")$/
328
     */
329
    public function assertPageNotMatchesText($pattern)
330
    {
331
        $this->assertSession()->pageTextNotMatches($this->fixStepArgument($pattern));
332
    }
333
334
    /**
335
     * Checks, that HTML response contains specified string
336
     * Example: Then the response should contain "Batman is the hero Gotham deserves."
337
     * Example: And the response should contain "Batman is the hero Gotham deserves."
338
     *
339
     * @Then /^the response should contain "(?P<text>(?:[^"]|\\")*)"$/
340
     */
341
    public function assertResponseContains($text)
342
    {
343
        $this->assertSession()->responseContains($this->fixStepArgument($text));
344
    }
345
346
    /**
347
     * Checks, that HTML response doesn't contain specified string
348
     * Example: Then the response should not contain "Bruce Wayne is a billionaire, play-boy, vigilante."
349
     * Example: And the response should not contain "Bruce Wayne is a billionaire, play-boy, vigilante."
350
     *
351
     * @Then /^the response should not contain "(?P<text>(?:[^"]|\\")*)"$/
352
     */
353
    public function assertResponseNotContains($text)
354
    {
355
        $this->assertSession()->responseNotContains($this->fixStepArgument($text));
356
    }
357
358
    /**
359
     * Checks, that element with specified CSS contains specified text
360
     * Example: Then I should see "Batman" in the "heroes_list" element
361
     * Example: And I should see "Batman" in the "heroes_list" element
362
     *
363
     * @Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/
364
     */
365
    public function assertElementContainsText($element, $text)
366
    {
367
        $this->assertSession()->elementTextContains('css', $element, $this->fixStepArgument($text));
368
    }
369
370
    /**
371
     * Checks, that element with specified CSS doesn't contain specified text
372
     * Example: Then I should not see "Bruce Wayne" in the "heroes_alter_egos" element
373
     * Example: And I should not see "Bruce Wayne" in the "heroes_alter_egos" element
374
     *
375
     * @Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/
376
     */
377
    public function assertElementNotContainsText($element, $text)
378
    {
379
        $this->assertSession()->elementTextNotContains('css', $element, $this->fixStepArgument($text));
380
    }
381
382
    /**
383
     * Checks, that element with specified CSS contains specified HTML
384
     * Example: Then the "body" element should contain "style=\"color:black;\""
385
     * Example: And the "body" element should contain "style=\"color:black;\""
386
     *
387
     * @Then /^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|\\")*)"$/
388
     */
389
    public function assertElementContains($element, $value)
390
    {
391
        $this->assertSession()->elementContains('css', $element, $this->fixStepArgument($value));
392
    }
393
394
    /**
395
     * Checks, that element with specified CSS doesn't contain specified HTML
396
     * Example: Then the "body" element should not contain "style=\"color:black;\""
397
     * Example: And the "body" element should not contain "style=\"color:black;\""
398
     *
399
     * @Then /^the "(?P<element>[^"]*)" element should not contain "(?P<value>(?:[^"]|\\")*)"$/
400
     */
401
    public function assertElementNotContains($element, $value)
402
    {
403
        $this->assertSession()->elementNotContains('css', $element, $this->fixStepArgument($value));
404
    }
405
406
    /**
407
     * Checks, that element with specified CSS exists on page
408
     * Example: Then I should see a "body" element
409
     * Example: And I should see a "body" element
410
     *
411
     * @Then /^(?:|I )should see an? "(?P<element>[^"]*)" element$/
412
     */
413
    public function assertElementOnPage($element)
414
    {
415
        $this->assertSession()->elementExists('css', $element);
416
    }
417
418
    /**
419
     * Checks, that element with specified CSS doesn't exist on page
420
     * Example: Then I should not see a "canvas" element
421
     * Example: And I should not see a "canvas" element
422
     *
423
     * @Then /^(?:|I )should not see an? "(?P<element>[^"]*)" element$/
424
     */
425
    public function assertElementNotOnPage($element)
426
    {
427
        $this->assertSession()->elementNotExists('css', $element);
428
    }
429
430
    /**
431
     * Checks, that form field with specified id|name|label|value has specified value
432
     * Example: Then the "username" field should contain "bwayne"
433
     * Example: And the "username" field should contain "bwayne"
434
     *
435
     * @Then /^the "(?P<field>(?:[^"]|\\")*)" field should contain "(?P<value>(?:[^"]|\\")*)"$/
436
     */
437
    public function assertFieldContains($field, $value)
438
    {
439
        $field = $this->fixStepArgument($field);
440
        $value = $this->fixStepArgument($value);
441
        $this->assertSession()->fieldValueEquals($field, $value);
442
    }
443
444
    /**
445
     * Checks, that form field with specified id|name|label|value doesn't have specified value
446
     * Example: Then the "username" field should not contain "batman"
447
     * Example: And the "username" field should not contain "batman"
448
     *
449
     * @Then /^the "(?P<field>(?:[^"]|\\")*)" field should not contain "(?P<value>(?:[^"]|\\")*)"$/
450
     */
451
    public function assertFieldNotContains($field, $value)
452
    {
453
        $field = $this->fixStepArgument($field);
454
        $value = $this->fixStepArgument($value);
455
        $this->assertSession()->fieldValueNotEquals($field, $value);
456
    }
457
458
    /**
459
     * Checks, that (?P<num>\d+) CSS elements exist on the page
460
     * Example: Then I should see 5 "div" elements
461
     * Example: And I should see 5 "div" elements
462
     *
463
     * @Then /^(?:|I )should see (?P<num>\d+) "(?P<element>[^"]*)" elements?$/
464
     */
465
    public function assertNumElements($num, $element)
466
    {
467
        $this->assertSession()->elementsCount('css', $element, intval($num));
468
    }
469
470
    /**
471
     * Checks, that checkbox with specified id|name|label|value is checked
472
     * Example: Then the "remember_me" checkbox should be checked
473
     * Example: And the "remember_me" checkbox is checked
474
     *
475
     * @Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should be checked$/
476
     * @Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox is checked$/
477
     * @Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" (?:is|should be) checked$/
478
     */
479
    public function assertCheckboxChecked($checkbox)
480
    {
481
        $this->assertSession()->checkboxChecked($this->fixStepArgument($checkbox));
482
    }
483
484
    /**
485
     * Checks, that checkbox with specified id|name|label|value is unchecked
486
     * Example: Then the "newsletter" checkbox should be unchecked
487
     * Example: Then the "newsletter" checkbox should not be checked
488
     * Example: And the "newsletter" checkbox is unchecked
489
     *
490
     * @Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should (?:be unchecked|not be checked)$/
491
     * @Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox is (?:unchecked|not checked)$/
492
     * @Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" should (?:be unchecked|not be checked)$/
493
     * @Then /^the checkbox "(?P<checkbox>(?:[^"]|\\")*)" is (?:unchecked|not checked)$/
494
     */
495
    public function assertCheckboxNotChecked($checkbox)
496
    {
497
        $this->assertSession()->checkboxNotChecked($this->fixStepArgument($checkbox));
498
    }
499
500
    /**
501
     * Prints current URL to console.
502
     * Example: Then print current URL
503
     * Example: And print current URL
504
     *
505
     * @Then /^print current URL$/
506
     */
507
    public function printCurrentUrl()
508
    {
509
        echo $this->getSession()->getCurrentUrl();
510
    }
511
512
    /**
513
     * Prints last response to console
514
     * Example: Then print last response
515
     * Example: And print last response
516
     *
517
     * @Then /^print last response$/
518
     */
519
    public function printLastResponse()
520
    {
521
        echo (
522
            $this->getSession()->getCurrentUrl()."\n\n".
523
            $this->getSession()->getPage()->getContent()
524
        );
525
    }
526
527
    /**
528
     * Opens last response content in browser
529
     * Example: Then show last response
530
     * Example: And show last response
531
     *
532
     * @Then /^show last response$/
533
     */
534
    public function showLastResponse()
535
    {
536
        if (null === $this->getMinkParameter('show_cmd')) {
537
            throw new \RuntimeException('Set "show_cmd" parameter in behat.yml to be able to open page in browser (ex.: "show_cmd: firefox %s")');
538
        }
539
540
        $filename = rtrim($this->getMinkParameter('show_tmp_dir'), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.uniqid().'.html';
541
        file_put_contents($filename, $this->getSession()->getPage()->getContent());
542
        system(sprintf($this->getMinkParameter('show_cmd'), escapeshellarg($filename)));
543
    }
544
545
    /**
546
     * Returns list of definition translation resources paths
547
     *
548
     * @return array
549
     */
550
    public static function getTranslationResources()
551
    {
552
        return self::getMinkTranslationResources();
553
    }
554
555
    /**
556
     * Returns list of definition translation resources paths for this dictionary
557
     *
558
     * @return array
559
     */
560
    public static function getMinkTranslationResources()
561
    {
562
        return glob(__DIR__.'/../../../../i18n/*.xliff');
563
    }
564
565
    /**
566
     * Returns fixed step argument (with \\" replaced back to ")
567
     *
568
     * @param string $argument
569
     *
570
     * @return string
571
     */
572
    protected function fixStepArgument($argument)
573
    {
574
        return str_replace('\\"', '"', $argument);
575
    }
576
577
    /**
578
     * Waits for an element to appear on page.
579
     * Example: Then I wait for element "#someID" to appear
580
     *
581
     * @Then I wait for element "(?P<element>[^"]*)" to appear
582
     */
583
    public function iWaitForElementToAppear($element, $secondsToWait = null)
584
    {
585
        $waitFunction = function ($context) use ($element) {
586
            try {
587
                $context->assertElementOnPage($element);
588
            } catch (ElementNotFoundException $e) {
589
                return false;
590
            }
591
592
            return true;
593
        };
594
595
        $this->spin($waitFunction, $secondsToWait);
596
    }
597
598
    /**
599
     * Executes a function and waits until the function returns true.
600
     * @see http://docs.behat.org/en/v2.5/cookbook/using_spin_functions.html#adding-a-timeout
601
     */
602
    private function spin($callback, $maxTimeToWait = null)
603
    {
604
        $waitingTime = $maxTimeToWait === null ? self::MAXIMUM_WAIT_TIME : $maxTimeToWait;
605
        $stopTime = time() + $waitingTime;
606
        while (time() < $stopTime) {
607
            if ($callback($this)) {
608
                return;
609
            }
610
611
            usleep(250000);
612
        }
613
614
        throw new \RuntimeException("Spin function timed out after {$waitingTime} seconds");
615
    }
616
}
617