2016-07-07 09:44:38 -07:00
< ? php
namespace Drupal\FunctionalJavascriptTests ;
2017-01-04 16:50:53 -08:00
use Behat\Mink\Element\NodeElement ;
use Behat\Mink\Exception\ElementHtmlException ;
use Behat\Mink\Exception\ElementNotFoundException ;
use Behat\Mink\Exception\UnsupportedDriverActionException ;
2016-07-07 09:44:38 -07:00
use Drupal\Tests\WebAssert ;
/**
* Defines a class with methods for asserting presence of elements during tests .
*/
class JSWebAssert extends WebAssert {
/**
* Waits for AJAX request to be completed .
*
* @ param int $timeout
* ( Optional ) Timeout in milliseconds , defaults to 10000.
* @ param string $message
* ( optional ) A message for exception .
*
* @ throws \RuntimeException
* When the request is not completed . If left blank , a default message will
* be displayed .
*/
public function assertWaitOnAjaxRequest ( $timeout = 10000 , $message = 'Unable to complete AJAX request.' ) {
$result = $this -> session -> wait ( $timeout , '(typeof(jQuery)=="undefined" || (0 === jQuery.active && 0 === jQuery(\':animated\').length))' );
if ( ! $result ) {
throw new \RuntimeException ( $message );
}
}
2016-11-02 11:43:31 -07:00
/**
* Waits for the jQuery autocomplete delay duration .
*
* @ see https :// api . jqueryui . com / autocomplete / #option-delay
*/
public function waitOnAutocomplete () {
// Drupal is using the default delay value of 300 milliseconds.
$this -> session -> wait ( 300 );
$this -> assertWaitOnAjaxRequest ();
}
2017-01-04 16:50:53 -08:00
/**
* Test that a node , or it ' s specific corner , is visible in the viewport .
*
* Note : Always set the viewport size . This can be done with a PhantomJS
* startup parameter or in your test with \Behat\Mink\Session -> resizeWindow () .
* Drupal CI Javascript tests by default use a viewport of 1024 x768px .
*
* @ param string $selector_type
* The element selector type ( CSS , XPath ) .
* @ param string | array $selector
* The element selector . Note : the first found element is used .
* @ param bool | string $corner
* ( Optional ) The corner to test :
* topLeft , topRight , bottomRight , bottomLeft .
* Or FALSE to check the complete element ( default ) .
* @ param string $message
* ( optional ) A message for the exception .
*
* @ throws \Behat\Mink\Exception\ElementHtmlException
* When the element doesn ' t exist .
* @ throws \Behat\Mink\Exception\ElementNotFoundException
* When the element is not visible in the viewport .
*/
public function assertVisibleInViewport ( $selector_type , $selector , $corner = FALSE , $message = 'Element is not visible in the viewport.' ) {
$node = $this -> session -> getPage () -> find ( $selector_type , $selector );
if ( $node === NULL ) {
if ( is_array ( $selector )) {
$selector = implode ( ' ' , $selector );
}
throw new ElementNotFoundException ( $this -> session -> getDriver (), 'element' , $selector_type , $selector );
}
// Check if the node is visible on the page, which is a prerequisite of
// being visible in the viewport.
if ( ! $node -> isVisible ()) {
throw new ElementHtmlException ( $message , $this -> session -> getDriver (), $node );
}
$result = $this -> checkNodeVisibilityInViewport ( $node , $corner );
if ( ! $result ) {
throw new ElementHtmlException ( $message , $this -> session -> getDriver (), $node );
}
}
/**
* Test that a node , or its specific corner , is not visible in the viewport .
*
* Note : the node should exist in the page , otherwise this assertion fails .
*
* @ param string $selector_type
* The element selector type ( CSS , XPath ) .
* @ param string | array $selector
* The element selector . Note : the first found element is used .
* @ param bool | string $corner
* ( Optional ) Corner to test : topLeft , topRight , bottomRight , bottomLeft .
* Or FALSE to check the complete element ( default ) .
* @ param string $message
* ( optional ) A message for the exception .
*
* @ throws \Behat\Mink\Exception\ElementHtmlException
* When the element doesn ' t exist .
* @ throws \Behat\Mink\Exception\ElementNotFoundException
* When the element is not visible in the viewport .
*
* @ see \Drupal\FunctionalJavascriptTests\JSWebAssert :: assertVisibleInViewport ()
*/
public function assertNotVisibleInViewport ( $selector_type , $selector , $corner = FALSE , $message = 'Element is visible in the viewport.' ) {
$node = $this -> session -> getPage () -> find ( $selector_type , $selector );
if ( $node === NULL ) {
if ( is_array ( $selector )) {
$selector = implode ( ' ' , $selector );
}
throw new ElementNotFoundException ( $this -> session -> getDriver (), 'element' , $selector_type , $selector );
}
$result = $this -> checkNodeVisibilityInViewport ( $node , $corner );
if ( $result ) {
throw new ElementHtmlException ( $message , $this -> session -> getDriver (), $node );
}
}
/**
* Check the visibility of a node , or it ' s specific corner .
*
* @ param \Behat\Mink\Element\NodeElement $node
* A valid node .
* @ param bool | string $corner
* ( Optional ) Corner to test : topLeft , topRight , bottomRight , bottomLeft .
* Or FALSE to check the complete element ( default ) .
*
* @ return bool
* Returns TRUE if the node is visible in the viewport , FALSE otherwise .
*
* @ throws \Behat\Mink\Exception\UnsupportedDriverActionException
* When an invalid corner specification is given .
*/
private function checkNodeVisibilityInViewport ( NodeElement $node , $corner = FALSE ) {
$xpath = $node -> getXpath ();
// Build the Javascript to test if the complete element or a specific corner
// is in the viewport.
switch ( $corner ) {
case 'topLeft' :
$test_javascript_function = <<< JS
function t ( r , lx , ly ) {
return (
r . top >= 0 &&
r . top <= ly &&
r . left >= 0 &&
r . left <= lx
)
}
JS ;
break ;
case 'topRight' :
$test_javascript_function = <<< JS
function t ( r , lx , ly ) {
return (
r . top >= 0 &&
r . top <= ly &&
r . right >= 0 &&
r . right <= lx
);
}
JS ;
break ;
case 'bottomRight' :
$test_javascript_function = <<< JS
function t ( r , lx , ly ) {
return (
r . bottom >= 0 &&
r . bottom <= ly &&
r . right >= 0 &&
r . right <= lx
);
}
JS ;
break ;
case 'bottomLeft' :
$test_javascript_function = <<< JS
function t ( r , lx , ly ) {
return (
r . bottom >= 0 &&
r . bottom <= ly &&
r . left >= 0 &&
r . left <= lx
);
}
JS ;
break ;
case FALSE :
$test_javascript_function = <<< JS
function t ( r , lx , ly ) {
return (
r . top >= 0 &&
r . left >= 0 &&
r . bottom <= ly &&
r . right <= lx
);
}
JS ;
break ;
// Throw an exception if an invalid corner parameter is given.
default :
throw new UnsupportedDriverActionException ( $corner , $this -> session -> getDriver ());
}
// Build the full Javascript test. The shared logic gets the corner
// specific test logic injected.
$full_javascript_visibility_test = <<< JS
( function ( t ){
var w = window ,
d = document ,
e = d . documentElement ,
n = d . evaluate ( " $xpath " , d , null , XPathResult . FIRST_ORDERED_NODE_TYPE , null ) . singleNodeValue ,
r = n . getBoundingClientRect (),
lx = ( w . innerWidth || e . clientWidth ),
ly = ( w . innerHeight || e . clientHeight );
return t ( r , lx , ly );
}( $test_javascript_function ));
JS ;
// Check the visibility by injecting and executing the full Javascript test
// script in the page.
return $this -> session -> evaluateScript ( $full_javascript_visibility_test );
}
2016-07-07 09:44:38 -07:00
}