Skip to content
This repository has been archived by the owner on Oct 15, 2023. It is now read-only.

Commit

Permalink
Fixed viewport size not counting browser border + test. (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexSkrypnyk authored Jun 28, 2017
1 parent f6136c8 commit 5c0995a
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 45 deletions.
128 changes: 84 additions & 44 deletions src/IntegratedExperts/BehatRelativity/RelativityContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\RawMinkContext;
use Symfony\Component\Yaml\Exception\RuntimeException;

/**
* Class RelativeTrait.
Expand Down Expand Up @@ -84,30 +85,19 @@ public function __construct($parameters = [])
*/
public function iAmViewingTheSiteOnScreen($screen)
{
$errors = [];
if (!isset($this->breakpoints[$screen])) {
throw new RuntimeException(sprintf("Screen size '%s' is not defined in behat.yml", $screen));
}

try {
$this->getSession()->resizeWindow(
$this->breakpoints[$screen]['width'],
$this->breakpoints[$screen]['height'],
'current'
);
} catch (\Exception $e) {
if (!isset($this->breakpoints[$screen])) {
$errors[] = sprintf("Screen size '%s' is not defined in behat.yml", $screen);
} else {
if (!isset($this->breakpoints[$screen]['width'])) {
$errors[] = sprintf("Screen size '%s' parameter 'width' is not defined in behat.yml", $screen);
}
if (!isset($this->breakpoints[$screen]['height'])) {
$errors[] = sprintf("Screen size '%s' parameter 'height' is not defined in behat.yml", $screen);
}
}
if (!isset($this->breakpoints[$screen]['width'])) {
throw new RuntimeException(sprintf("Screen size '%s' parameter 'width' is not defined in behat.yml", $screen));
}

if (count($errors) > 0) {
throw new \Exception(implode("\n", $errors));
if (!isset($this->breakpoints[$screen]['height'])) {
throw new RuntimeException(sprintf("Screen size '%s' parameter 'height' is not defined in behat.yml", $screen));
}

$this->resizeViewport($this->breakpoints[$screen]['width'], $this->breakpoints[$screen]['height']);
}

/**
Expand Down Expand Up @@ -192,16 +182,19 @@ public function assertClick($subjects)
*/
public function init(BeforeScenarioScope $scope)
{
$defaultScreenSize = [];
foreach ($this->breakpoints as $breakpoint) {
if (isset($breakpoint['default']) && $breakpoint['default'] === true) {
$defaultScreenSize = $breakpoint;
$defaults = [];
foreach ($this->breakpoints as $name => $config) {
if (isset($config['default']) && $config['default'] === true) {
$defaults[] = $name;
}
}

if (count($defaultScreenSize) > 0) {
$this->getSession()->resizeWindow($defaultScreenSize['width'], $defaultScreenSize['height'], 'current');
if (count($defaults) != 1) {
throw new RuntimeException(sprintf('One and only one of the provided breakpoints must be configured as default'));
}

$default = reset($defaults);
$this->iAmViewingTheSiteOnScreen($default);
}

/**
Expand Down Expand Up @@ -376,10 +369,12 @@ public function iDefineComponents(TableNode $table)
*
* Note that assertions for all elements will be assessed before failing.
*
* @param string $position Position name.
* @param string $subject Subject name as a string.
* @param string $others Other names as a string.
* @param bool $scrollToOthers Optional flag to scroll to other components when performing geometry retrieval.
* @param string $position Position name.
* @param string $subject Subject name as a string.
* @param string $others Other names as a string.
* @param bool $scrollToOthers Optional flag to scroll to other
* components when performing geometry
* retrieval.
*
* @throws \Exception If at least one assertion fails.
*/
Expand Down Expand Up @@ -436,11 +431,13 @@ protected function dispatcher($position, $subject, $others, $scrollToOthers = tr
/**
* Parse component names.
*
* @param string $text Component name as a string usually taken from the test step definition.
* @param string $text Component name as a string usually taken from the
* test step definition.
*
* @return array Array of parsed components.
*
* @throws \Exception If provided components are not a part of the set of pre-configured components.
* @throws \Exception If provided components are not a part of the set of
* pre-configured components.
*/
protected function parseComponents($text)
{
Expand All @@ -460,19 +457,30 @@ protected function parseComponents($text)
* @todo Extend this to handle 'over' and 'under' absolutely positioned
* elements.
*
* @param string $position Position identifier. One of: left, right, above, below, inside, outside.
* @param string $component1 Name of the first component.
* @param string $component2 Name of the second component.
* @param bool $scrollToComponent2 Optional flag to scroll to component2 when performing geometry retrieval.
* @param string $position Position identifier. One of: left,
* right, above, below, inside, outside.
* @param string $component1 Name of the first component.
* @param string $component2 Name of the second component.
* @param bool $scrollToComponent2 Optional flag to scroll to component2
* when performing geometry retrieval.
*
* @return bool True if components are positioned relatively correct, false otherwise.
* @return bool True if components are positioned relatively correct, false
* otherwise.
*
* @throws \RuntimeException If incorrect position is provided.
* @throws \Exception If unable to retrieve component dimensions.
*/
protected function assertPosition($position, $component1, $component2, $scrollToComponent2 = true)
{
$allowed = ['left', 'right', 'above', 'below', 'inside', 'outside', 'over'];
$allowed = [
'left',
'right',
'above',
'below',
'inside',
'outside',
'over',
];
if (!in_array($position, $allowed)) {
throw new \RuntimeException(sprintf("Invalid position %s specified", $position));
}
Expand Down Expand Up @@ -560,17 +568,47 @@ protected function rectanglesIntersect($x1, $y1, $width1, $height1, $x2, $y2, $w
return !($x1 >= $x2 + $width2 || $x1 + $width1 <= $x2 || $y1 >= $y2 + $height2 || $y1 + $height1 <= $y2);
}

/**
* Resize viewport to specified size.
*
* Also handles border/chrome of the browser to make sure that viewport
* has exact size.
*
* @param int $width
* Viewport width in pixels.
* @param int $height
* Viewport height in pixels.
*/
protected function resizeViewport($width, $height)
{
$padding = $this->getSession()->getDriver()->evaluateScript("
return {
w: window.outerWidth - window.innerWidth,
h: window.outerHeight - window.innerHeight
};
");

$this->getSession()
->getDriver()
->resizeWindow(
$width + $padding['w'],
$height + $padding['h'],
'current'
);
}

/**
* Get relative component geometry data.
*
* Note that we are using oversimplified way to determine z-index of the
* element without using Stacking Contexts, but this should cover majority of
* cases.
* element without using Stacking Contexts, but this should cover majority
* of cases.
*
* @param string $selector CSS selector.
* @param bool $doScroll Whether to scroll to component.
* @param bool $doScroll Whether to scroll to component.
*
* @return array|bool Array of component geometry: width, height, top, left or false if component is not visible.
* @return array|bool Array of component geometry: width, height, top, left
* or false if component is not visible.
*/
protected function getComponentGeometry($selector, $doScroll = true)
{
Expand Down Expand Up @@ -599,7 +637,8 @@ function zIndex(el) { var z = 0; el.add(el.parents()).each(function () { if ((jQ
*
* @param string $selector CSS selector.
*
* @return bool True if element is focused, false if not focused or element is not present on the page.
* @return bool True if element is focused, false if not focused or element
* is not present on the page.
*/
protected function componentIsFocused($selector)
{
Expand All @@ -618,7 +657,8 @@ protected function componentIsFocused($selector)
*
* @param string $selector CSS selector.
*
* @return bool True if element is visible, false if not visible or element is not present on the page.
* @return bool True if element is visible, false if not visible or element
* is not present on the page.
*/
protected function componentIsVisible($selector)
{
Expand Down
17 changes: 17 additions & 0 deletions tests/behat/features/fixtures/relative.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<style>
body {
position: relative;
margin: 0;
}

#top {
Expand Down Expand Up @@ -287,6 +288,20 @@
#over-under-inner {
background: lightpink;
}

#viewport-custom {
padding: 10px;
background: orange;
display: none;
left: 50px;
top: 100px;
}

@media (min-width: 922px) {
#viewport-custom {
display: block;
}
}
</style>
</head>
<body>
Expand Down Expand Up @@ -327,6 +342,8 @@
</div>
</div>

<div id="viewport-custom">Text for custom viewport</div>

<div id="off-canvas-left">
Off-canvas left content
</div>
Expand Down
10 changes: 9 additions & 1 deletion tests/behat/features/screen_resize.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ Feature: Behat relative assertions work using breakpoints

Background:
Given I define components:
| main inner custom | #main-inner-custom |
| main inner custom | #main-inner-custom |
| viewport custom | #viewport-custom |

@javascript @phpserver
Scenario: Screen default size is used when no size is specified
Expand Down Expand Up @@ -179,3 +180,10 @@ Feature: Behat relative assertions work using breakpoints
And I see top and main above bottom
And I see top, main and left above bottom
Then I save screenshot

@javascript @phpserver
Scenario: Viewport size is calculated correctly when screen is resized.
Given I am viewing the site on a desktop device
When I am on the test page
Then I see visible viewport custom
Then I save screenshot

0 comments on commit 5c0995a

Please sign in to comment.