Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugin-web-app] Add mobile emulation steps #4656

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions docs/modules/plugins/pages/plugin-web-app.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,51 @@ Then value `$value` is selected in slider located by `$locator`
Then value `50` is selected in slider located by `id(test_slider)`
----

=== Mobile Emulation

==== Emulate mobile device

Emulates mobile device using the provided configuration.

IMPORTANT: The step is only supported by Chrome browser.

[source,gherkin]
----
When I emulate mobile device with configuration:`$jsonConfiguration`
----

* `$jsonConfiguration` - The JSON containing https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride[device metrics] to override.

.Emulate iPhone 14 Pro Max
[source,gherkin]
----
When I emulate mobile device with configuration:`{
"width": 430,
"height": 932,
"deviceScaleFactor": 3,
"mobile": true
}`
----

==== Reset mobile device emulation

Resets the mobile device emulation returning the browser to its initial state.

IMPORTANT: The step is only supported by Chrome browser.

IMPORTANT: The step ignores the `web/desktop/chrome/mobile_emulation/phone` profile settings when returning the browser to its initial state.

[source,gherkin]
----
When I reset mobile device emulation
----

.Resets device metrics to defaults
[source,gherkin]
----
When I reset mobile device emulation
----

== Tips & Tricks

=== Validate URL host of the opened page
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.steps.ui.web.devtools;

import static org.apache.commons.lang3.Validate.isTrue;

import java.util.Map;

import org.jbehave.core.annotations.When;
import org.openqa.selenium.chromium.HasCdp;
import org.openqa.selenium.remote.Browser;
import org.vividus.selenium.IWebDriverProvider;
import org.vividus.selenium.manager.IWebDriverManager;
import org.vividus.util.json.JsonUtils;

public class MobileEmulationSteps
{
private final IWebDriverProvider webDriverProvider;
private final IWebDriverManager webDriverManager;
private final JsonUtils jsonUtils;

public MobileEmulationSteps(IWebDriverProvider webDriverProvider, IWebDriverManager webDriverManager,
JsonUtils jsonUtils)
{
this.webDriverProvider = webDriverProvider;
this.webDriverManager = webDriverManager;
this.jsonUtils = jsonUtils;
}

/**
* Emulates mobile device using the provided configuration.
*
* <p>
* <strong>The step is only supported by Chrome browser.</strong>
* </p>
*
* @param jsonConfiguration The JSON containing device metrics to override.
*/
@SuppressWarnings("unchecked")
@When("I emulate mobile device with configuration:`$jsonConfiguration`")
public void overrideDeviceMetrics(String jsonConfiguration)
{
executeCdpCommand("Emulation.setDeviceMetricsOverride", jsonUtils.toObject(jsonConfiguration, Map.class));
}

/**
* Resets the mobile device emulation returning the browser to its initial state.
*
* <p>
* <strong>The step is only supported by Chrome browser.</strong>
* </p>
*/
@When("I reset mobile device emulation")
public void clearDeviceMetrics()
{
executeCdpCommand("Emulation.clearDeviceMetricsOverride", Map.of());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the browser was started in mobile emulation mode?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will reset the mobile emulation, even if we have mobile emulation profile activated, technically the initial state of the browser doesn't include mobile emulation, its turned on after the browser is loaded

}

private void executeCdpCommand(String command, Map<String, Object> metrics)
{
isTrue(webDriverManager.isBrowserAnyOf(Browser.CHROME), "The step is only supported by Chrome browser.");
HasCdp hasCdp = webDriverProvider.getUnwrapped(HasCdp.class);
hasCdp.executeCdpCommand(command, metrics);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@
<property name="windowsStrategy" value="${selenium.windows-strategy}" />
</bean>

<bean id="mobileEmulationSteps" class="org.vividus.steps.ui.web.devtools.MobileEmulationSteps" />

<bean class="org.vividus.ui.web.monitor.PublishingWebScreenshotOnFailureMonitor"
parent="abstractPublishingScreenshotOnFailureMonitor"/>

Expand Down Expand Up @@ -302,6 +304,7 @@
<idref bean="performanceSteps" />
<idref bean="windowSteps" />
<idref bean="browserSteps" />
<idref bean="mobileEmulationSteps" />
</util:list>

<util:map id="propertyEditors-WebUi" key-type="java.lang.Class">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.steps.ui.web.devtools;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Map;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openqa.selenium.chromium.HasCdp;
import org.openqa.selenium.remote.Browser;
import org.vividus.selenium.IWebDriverProvider;
import org.vividus.selenium.manager.IWebDriverManager;
import org.vividus.util.json.JsonUtils;

@ExtendWith(MockitoExtension.class)
class MobileEmulationStepsTests
{
@Mock private IWebDriverProvider webDriverProvider;
@Mock private IWebDriverManager webDriverManager;
@Mock private HasCdp hasCdp;
private MobileEmulationSteps steps;

@BeforeEach
void init()
{
this.steps = new MobileEmulationSteps(webDriverProvider, webDriverManager, new JsonUtils());
}

@Test
void shouldOverrideDeviceMetrics()
{
when(webDriverManager.isBrowserAnyOf(Browser.CHROME)).thenReturn(true);
when(webDriverProvider.getUnwrapped(HasCdp.class)).thenReturn(hasCdp);

String metrics = """
{
"width": 430,
"height": 932,
"deviceScaleFactor": 3,
"mobile": true
}
""";

steps.overrideDeviceMetrics(metrics);

verify(hasCdp).executeCdpCommand("Emulation.setDeviceMetricsOverride", Map.of(
"width", 430,
"height", 932,
"deviceScaleFactor", 3,
"mobile", true
));
}

@Test
void shouldClearDeviceMetrics()
{
when(webDriverManager.isBrowserAnyOf(Browser.CHROME)).thenReturn(true);
when(webDriverProvider.getUnwrapped(HasCdp.class)).thenReturn(hasCdp);

steps.clearDeviceMetrics();

verify(hasCdp).executeCdpCommand("Emulation.clearDeviceMetricsOverride", Map.of());
}

@Test
void shouldFailIfBrowserIsNotChrome()
{
when(webDriverManager.isBrowserAnyOf(Browser.CHROME)).thenReturn(false);

IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, steps::clearDeviceMetrics);

assertEquals("The step is only supported by Chrome browser.", thrown.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Scenario: Validate steps: 'When I emulate mobile device with configuration:`$deviceMetrics`', 'When I reset mobile device emulation'
Given I am on page with URL `${vividus-test-site-url}`
When I execute javascript `return window.screen;` and save result to scenario variable `initialScreen`
When I emulate mobile device with configuration:`{
"width": 430,
"height": 932,
"deviceScaleFactor": 3,
"mobile": true
}`

When I execute javascript `return window.screen;` and save result to scenario variable `overridenScreen`
Then `${overridenScreen.height}` is = `932`
Then `${overridenScreen.width}` is = `430`

When I reset mobile device emulation

When I execute javascript `return window.screen;` and save result to scenario variable `clearedScreen`
Then `${initialScreen.height}` is = `${clearedScreen.height}`
Then `${initialScreen.width}` is = `${clearedScreen.width}`
Loading