comparison core/tests/Drupal/Tests/WebAssert.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children a9cd425dd02b
comparison
equal deleted inserted replaced
-1:000000000000 0:c75dbcec494b
1 <?php
2
3 namespace Drupal\Tests;
4
5 use Behat\Mink\Exception\ExpectationException;
6 use Behat\Mink\WebAssert as MinkWebAssert;
7 use Behat\Mink\Element\TraversableElement;
8 use Behat\Mink\Exception\ElementNotFoundException;
9 use Behat\Mink\Session;
10 use Drupal\Component\Utility\Html;
11 use Drupal\Core\Url;
12
13 /**
14 * Defines a class with methods for asserting presence of elements during tests.
15 */
16 class WebAssert extends MinkWebAssert {
17
18 /**
19 * The absolute URL of the site under test.
20 *
21 * @var string
22 */
23 protected $baseUrl = '';
24
25 /**
26 * Constructor.
27 *
28 * @param \Behat\Mink\Session $session
29 * The Behat session object;
30 * @param string $base_url
31 * The base URL of the site under test.
32 */
33 public function __construct(Session $session, $base_url = '') {
34 parent::__construct($session);
35 $this->baseUrl = $base_url;
36 }
37
38 /**
39 * {@inheritdoc}
40 */
41 protected function cleanUrl($url) {
42 if ($url instanceof Url) {
43 $url = $url->setAbsolute()->toString();
44 }
45 // Strip the base URL from the beginning for absolute URLs.
46 if ($this->baseUrl !== '' && strpos($url, $this->baseUrl) === 0) {
47 $url = substr($url, strlen($this->baseUrl));
48 }
49 // Make sure there is a forward slash at the beginning of relative URLs for
50 // consistency.
51 if (parse_url($url, PHP_URL_HOST) === NULL && strpos($url, '/') !== 0) {
52 $url = "/$url";
53 }
54 return parent::cleanUrl($url);
55 }
56
57 /**
58 * Checks that specific button exists on the current page.
59 *
60 * @param string $button
61 * One of id|name|label|value for the button.
62 * @param \Behat\Mink\Element\TraversableElement $container
63 * (optional) The document to check against. Defaults to the current page.
64 *
65 * @return \Behat\Mink\Element\NodeElement
66 * The matching element.
67 *
68 * @throws \Behat\Mink\Exception\ElementNotFoundException
69 * When the element doesn't exist.
70 */
71 public function buttonExists($button, TraversableElement $container = NULL) {
72 $container = $container ?: $this->session->getPage();
73 $node = $container->findButton($button);
74
75 if ($node === NULL) {
76 throw new ElementNotFoundException($this->session, 'button', 'id|name|label|value', $button);
77 }
78
79 return $node;
80 }
81
82 /**
83 * Checks that the specific button does NOT exist on the current page.
84 *
85 * @param string $button
86 * One of id|name|label|value for the button.
87 * @param \Behat\Mink\Element\TraversableElement $container
88 * (optional) The document to check against. Defaults to the current page.
89 *
90 * @throws \Behat\Mink\Exception\ExpectationException
91 * When the button exists.
92 */
93 public function buttonNotExists($button, TraversableElement $container = NULL) {
94 $container = $container ?: $this->session->getPage();
95 $node = $container->findButton($button);
96
97 $this->assert(NULL === $node, sprintf('A button "%s" appears on this page, but it should not.', $button));
98 }
99
100 /**
101 * Checks that specific select field exists on the current page.
102 *
103 * @param string $select
104 * One of id|name|label|value for the select field.
105 * @param \Behat\Mink\Element\TraversableElement $container
106 * (optional) The document to check against. Defaults to the current page.
107 *
108 * @return \Behat\Mink\Element\NodeElement
109 * The matching element
110 *
111 * @throws \Behat\Mink\Exception\ElementNotFoundException
112 * When the element doesn't exist.
113 */
114 public function selectExists($select, TraversableElement $container = NULL) {
115 $container = $container ?: $this->session->getPage();
116 $node = $container->find('named', [
117 'select',
118 $this->session->getSelectorsHandler()->xpathLiteral($select),
119 ]);
120
121 if ($node === NULL) {
122 throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $select);
123 }
124
125 return $node;
126 }
127
128 /**
129 * Checks that specific option in a select field exists on the current page.
130 *
131 * @param string $select
132 * One of id|name|label|value for the select field.
133 * @param string $option
134 * The option value.
135 * @param \Behat\Mink\Element\TraversableElement $container
136 * (optional) The document to check against. Defaults to the current page.
137 *
138 * @return \Behat\Mink\Element\NodeElement
139 * The matching option element
140 *
141 * @throws \Behat\Mink\Exception\ElementNotFoundException
142 * When the element doesn't exist.
143 */
144 public function optionExists($select, $option, TraversableElement $container = NULL) {
145 $container = $container ?: $this->session->getPage();
146 $select_field = $container->find('named', [
147 'select',
148 $this->session->getSelectorsHandler()->xpathLiteral($select),
149 ]);
150
151 if ($select_field === NULL) {
152 throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $select);
153 }
154
155 $option_field = $select_field->find('named', ['option', $option]);
156
157 if ($option_field === NULL) {
158 throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $option);
159 }
160
161 return $option_field;
162 }
163
164 /**
165 * Checks that an option in a select field does NOT exist on the current page.
166 *
167 * @param string $select
168 * One of id|name|label|value for the select field.
169 * @param string $option
170 * The option value that shoulkd not exist.
171 * @param \Behat\Mink\Element\TraversableElement $container
172 * (optional) The document to check against. Defaults to the current page.
173 *
174 * @throws \Behat\Mink\Exception\ElementNotFoundException
175 * When the select element doesn't exist.
176 */
177 public function optionNotExists($select, $option, TraversableElement $container = NULL) {
178 $container = $container ?: $this->session->getPage();
179 $select_field = $container->find('named', [
180 'select',
181 $this->session->getSelectorsHandler()->xpathLiteral($select),
182 ]);
183
184 if ($select_field === NULL) {
185 throw new ElementNotFoundException($this->session, 'select', 'id|name|label|value', $select);
186 }
187
188 $option_field = $select_field->find('named', ['option', $option]);
189
190 $this->assert($option_field === NULL, sprintf('An option "%s" exists in select "%s", but it should not.', $option, $select));
191 }
192
193 /**
194 * Pass if the page title is the given string.
195 *
196 * @param string $expected_title
197 * The string the page title should be.
198 *
199 * @throws \Behat\Mink\Exception\ExpectationException
200 * Thrown when element doesn't exist, or the title is a different one.
201 */
202 public function titleEquals($expected_title) {
203 $title_element = $this->session->getPage()->find('css', 'title');
204 if (!$title_element) {
205 throw new ExpectationException('No title element found on the page', $this->session->getDriver());
206 }
207 $actual_title = $title_element->getText();
208 $this->assert($expected_title === $actual_title, 'Title found');
209 }
210
211 /**
212 * Passes if a link with the specified label is found.
213 *
214 * An optional link index may be passed.
215 *
216 * @param string $label
217 * Text between the anchor tags.
218 * @param int $index
219 * Link position counting from zero.
220 * @param string $message
221 * (optional) A message to display with the assertion. Do not translate
222 * messages: use strtr() to embed variables in the message text, not
223 * t(). If left blank, a default message will be displayed.
224 *
225 * @throws \Behat\Mink\Exception\ExpectationException
226 * Thrown when element doesn't exist, or the link label is a different one.
227 */
228 public function linkExists($label, $index = 0, $message = '') {
229 $message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
230 $links = $this->session->getPage()->findAll('named', ['link', $label]);
231 $this->assert(!empty($links[$index]), $message);
232 }
233
234 /**
235 * Passes if a link with the exactly specified label is found.
236 *
237 * An optional link index may be passed.
238 *
239 * @param string $label
240 * Text between the anchor tags.
241 * @param int $index
242 * Link position counting from zero.
243 * @param string $message
244 * (optional) A message to display with the assertion. Do not translate
245 * messages: use strtr() to embed variables in the message text, not
246 * t(). If left blank, a default message will be displayed.
247 *
248 * @throws \Behat\Mink\Exception\ExpectationException
249 * Thrown when element doesn't exist, or the link label is a different one.
250 */
251 public function linkExistsExact($label, $index = 0, $message = '') {
252 $message = ($message ? $message : strtr('Link with label %label found.', ['%label' => $label]));
253 $links = $this->session->getPage()->findAll('named_exact', ['link', $label]);
254 $this->assert(!empty($links[$index]), $message);
255 }
256
257 /**
258 * Passes if a link with the specified label is not found.
259 *
260 * An optional link index may be passed.
261 *
262 * @param string $label
263 * Text between the anchor tags.
264 * @param string $message
265 * (optional) A message to display with the assertion. Do not translate
266 * messages: use strtr() to embed variables in the message text, not
267 * t(). If left blank, a default message will be displayed.
268 *
269 * @throws \Behat\Mink\Exception\ExpectationException
270 * Thrown when element doesn't exist, or the link label is a different one.
271 */
272 public function linkNotExists($label, $message = '') {
273 $message = ($message ? $message : strtr('Link with label %label not found.', ['%label' => $label]));
274 $links = $this->session->getPage()->findAll('named', ['link', $label]);
275 $this->assert(empty($links), $message);
276 }
277
278 /**
279 * Passes if a link with the exactly specified label is not found.
280 *
281 * An optional link index may be passed.
282 *
283 * @param string $label
284 * Text between the anchor tags.
285 * @param string $message
286 * (optional) A message to display with the assertion. Do not translate
287 * messages: use strtr() to embed variables in the message text, not
288 * t(). If left blank, a default message will be displayed.
289 *
290 * @throws \Behat\Mink\Exception\ExpectationException
291 * Thrown when element doesn't exist, or the link label is a different one.
292 */
293 public function linkNotExistsExact($label, $message = '') {
294 $message = ($message ? $message : strtr('Link with label %label not found.', ['%label' => $label]));
295 $links = $this->session->getPage()->findAll('named_exact', ['link', $label]);
296 $this->assert(empty($links), $message);
297 }
298
299 /**
300 * Passes if a link containing a given href (part) is found.
301 *
302 * @param string $href
303 * The full or partial value of the 'href' attribute of the anchor tag.
304 * @param int $index
305 * Link position counting from zero.
306 * @param string $message
307 * (optional) A message to display with the assertion. Do not translate
308 * messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
309 * variables in the message text, not t(). If left blank, a default message
310 * will be displayed.
311 *
312 * @throws \Behat\Mink\Exception\ExpectationException
313 * Thrown when element doesn't exist, or the link label is a different one.
314 */
315 public function linkByHrefExists($href, $index = 0, $message = '') {
316 $xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
317 $message = ($message ? $message : strtr('Link containing href %href found.', ['%href' => $href]));
318 $links = $this->session->getPage()->findAll('xpath', $xpath);
319 $this->assert(!empty($links[$index]), $message);
320 }
321
322 /**
323 * Passes if a link containing a given href (part) is not found.
324 *
325 * @param string $href
326 * The full or partial value of the 'href' attribute of the anchor tag.
327 * @param string $message
328 * (optional) A message to display with the assertion. Do not translate
329 * messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
330 * variables in the message text, not t(). If left blank, a default message
331 * will be displayed.
332 *
333 * @throws \Behat\Mink\Exception\ExpectationException
334 * Thrown when element doesn't exist, or the link label is a different one.
335 */
336 public function linkByHrefNotExists($href, $message = '') {
337 $xpath = $this->buildXPathQuery('//a[contains(@href, :href)]', [':href' => $href]);
338 $message = ($message ? $message : strtr('No link containing href %href found.', ['%href' => $href]));
339 $links = $this->session->getPage()->findAll('xpath', $xpath);
340 $this->assert(empty($links), $message);
341 }
342
343 /**
344 * Builds an XPath query.
345 *
346 * Builds an XPath query by replacing placeholders in the query by the value
347 * of the arguments.
348 *
349 * XPath 1.0 (the version supported by libxml2, the underlying XML library
350 * used by PHP) doesn't support any form of quotation. This function
351 * simplifies the building of XPath expression.
352 *
353 * @param string $xpath
354 * An XPath query, possibly with placeholders in the form ':name'.
355 * @param array $args
356 * An array of arguments with keys in the form ':name' matching the
357 * placeholders in the query. The values may be either strings or numeric
358 * values.
359 *
360 * @return string
361 * An XPath query with arguments replaced.
362 */
363 public function buildXPathQuery($xpath, array $args = []) {
364 // Replace placeholders.
365 foreach ($args as $placeholder => $value) {
366 if (is_object($value)) {
367 throw new \InvalidArgumentException('Just pass in scalar values for $args and remove all t() calls from your test.');
368 }
369 // XPath 1.0 doesn't support a way to escape single or double quotes in a
370 // string literal. We split double quotes out of the string, and encode
371 // them separately.
372 if (is_string($value)) {
373 // Explode the text at the quote characters.
374 $parts = explode('"', $value);
375
376 // Quote the parts.
377 foreach ($parts as &$part) {
378 $part = '"' . $part . '"';
379 }
380
381 // Return the string.
382 $value = count($parts) > 1 ? 'concat(' . implode(', \'"\', ', $parts) . ')' : $parts[0];
383 }
384
385 // Use preg_replace_callback() instead of preg_replace() to prevent the
386 // regular expression engine from trying to substitute backreferences.
387 $replacement = function ($matches) use ($value) {
388 return $value;
389 };
390 $xpath = preg_replace_callback('/' . preg_quote($placeholder) . '\b/', $replacement, $xpath);
391 }
392 return $xpath;
393 }
394
395 /**
396 * Passes if the raw text IS NOT found escaped on the loaded page.
397 *
398 * Raw text refers to the raw HTML that the page generated.
399 *
400 * @param string $raw
401 * Raw (HTML) string to look for.
402 */
403 public function assertNoEscaped($raw) {
404 $this->responseNotContains(Html::escape($raw));
405 }
406
407 /**
408 * Passes if the raw text IS found escaped on the loaded page.
409 *
410 * Raw text refers to the raw HTML that the page generated.
411 *
412 * @param string $raw
413 * Raw (HTML) string to look for.
414 */
415 public function assertEscaped($raw) {
416 $this->responseContains(Html::escape($raw));
417 }
418
419 /**
420 * Asserts a condition.
421 *
422 * The parent method is overridden because it is a private method.
423 *
424 * @param bool $condition
425 * The condition.
426 * @param string $message
427 * The success message.
428 *
429 * @throws \Behat\Mink\Exception\ExpectationException
430 * When the condition is not fulfilled.
431 */
432 public function assert($condition, $message) {
433 if ($condition) {
434 return;
435 }
436
437 throw new ExpectationException($message, $this->session->getDriver());
438 }
439
440 /**
441 * Checks that a given form field element is disabled.
442 *
443 * @param string $field
444 * One of id|name|label|value for the field.
445 * @param \Behat\Mink\Element\TraversableElement $container
446 * (optional) The document to check against. Defaults to the current page.
447 *
448 * @return \Behat\Mink\Element\NodeElement
449 * The matching element.
450 *
451 * @throws \Behat\Mink\Exception\ElementNotFoundException
452 * @throws \Behat\Mink\Exception\ExpectationException
453 */
454 public function fieldDisabled($field, TraversableElement $container = NULL) {
455 $container = $container ?: $this->session->getPage();
456 $node = $container->findField($field);
457
458 if ($node === NULL) {
459 throw new ElementNotFoundException($this->session->getDriver(), 'field', 'id|name|label|value', $field);
460 }
461
462 if (!$node->hasAttribute('disabled')) {
463 throw new ExpectationException("Field $field is disabled", $this->session->getDriver());
464 }
465
466 return $node;
467 }
468
469 /**
470 * Checks that specific hidden field exists.
471 *
472 * @param string $field
473 * One of id|name|value for the hidden field.
474 * @param \Behat\Mink\Element\TraversableElement $container
475 * (optional) The document to check against. Defaults to the current page.
476 *
477 * @return \Behat\Mink\Element\NodeElement
478 * The matching element.
479 *
480 * @throws \Behat\Mink\Exception\ElementNotFoundException
481 */
482 public function hiddenFieldExists($field, TraversableElement $container = NULL) {
483 $container = $container ?: $this->session->getPage();
484 if ($node = $container->find('hidden_field_selector', ['hidden_field', $field])) {
485 return $node;
486 }
487 throw new ElementNotFoundException($this->session->getDriver(), 'form hidden field', 'id|name|value', $field);
488 }
489
490 /**
491 * Checks that specific hidden field does not exists.
492 *
493 * @param string $field
494 * One of id|name|value for the hidden field.
495 * @param \Behat\Mink\Element\TraversableElement $container
496 * (optional) The document to check against. Defaults to the current page.
497 *
498 * @throws \Behat\Mink\Exception\ExpectationException
499 */
500 public function hiddenFieldNotExists($field, TraversableElement $container = NULL) {
501 $container = $container ?: $this->session->getPage();
502 $node = $container->find('hidden_field_selector', ['hidden_field', $field]);
503 $this->assert($node === NULL, "A hidden field '$field' exists on this page, but it should not.");
504 }
505
506 /**
507 * Checks that specific hidden field have provided value.
508 *
509 * @param string $field
510 * One of id|name|value for the hidden field.
511 * @param string $value
512 * The hidden field value that needs to be checked.
513 * @param \Behat\Mink\Element\TraversableElement $container
514 * (optional) The document to check against. Defaults to the current page.
515 *
516 * @throws \Behat\Mink\Exception\ElementNotFoundException
517 * @throws \Behat\Mink\Exception\ExpectationException
518 */
519 public function hiddenFieldValueEquals($field, $value, TraversableElement $container = NULL) {
520 $node = $this->hiddenFieldExists($field, $container);
521 $actual = $node->getValue();
522 $regex = '/^' . preg_quote($value, '/') . '$/ui';
523 $message = "The hidden field '$field' value is '$actual', but '$value' expected.";
524 $this->assert((bool) preg_match($regex, $actual), $message);
525 }
526
527 /**
528 * Checks that specific hidden field doesn't have the provided value.
529 *
530 * @param string $field
531 * One of id|name|value for the hidden field.
532 * @param string $value
533 * The hidden field value that needs to be checked.
534 * @param \Behat\Mink\Element\TraversableElement $container
535 * (optional) The document to check against. Defaults to the current page.
536 *
537 * @throws \Behat\Mink\Exception\ElementNotFoundException
538 * @throws \Behat\Mink\Exception\ExpectationException
539 */
540 public function hiddenFieldValueNotEquals($field, $value, TraversableElement $container = NULL) {
541 $node = $this->hiddenFieldExists($field, $container);
542 $actual = $node->getValue();
543 $regex = '/^' . preg_quote($value, '/') . '$/ui';
544 $message = "The hidden field '$field' value is '$actual', but it should not be.";
545 $this->assert(!preg_match($regex, $actual), $message);
546 }
547
548 }