diff --git a/java/src/org/openqa/selenium/bidi/module/BUILD.bazel b/java/src/org/openqa/selenium/bidi/module/BUILD.bazel index 59676269b2733..13bd4b6452418 100644 --- a/java/src/org/openqa/selenium/bidi/module/BUILD.bazel +++ b/java/src/org/openqa/selenium/bidi/module/BUILD.bazel @@ -22,6 +22,7 @@ java_library( "//java/src/org/openqa/selenium/bidi/browsingcontext", "//java/src/org/openqa/selenium/bidi/log", "//java/src/org/openqa/selenium/bidi/network", + "//java/src/org/openqa/selenium/bidi/permissions", "//java/src/org/openqa/selenium/bidi/script", "//java/src/org/openqa/selenium/bidi/storage", "//java/src/org/openqa/selenium/json", diff --git a/java/src/org/openqa/selenium/bidi/module/Permission.java b/java/src/org/openqa/selenium/bidi/module/Permission.java new file mode 100644 index 0000000000000..1edc5c5628fd8 --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/module/Permission.java @@ -0,0 +1,70 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you 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 +// +// http://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.openqa.selenium.bidi.module; + +import java.util.HashMap; +import java.util.Map; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.bidi.BiDi; +import org.openqa.selenium.bidi.Command; +import org.openqa.selenium.bidi.HasBiDi; +import org.openqa.selenium.bidi.permissions.PermissionState; +import org.openqa.selenium.internal.Require; + +public class Permission { + + private final BiDi bidi; + + public Permission(WebDriver driver) { + Require.nonNull("WebDriver", driver); + + if (!(driver instanceof HasBiDi)) { + throw new IllegalArgumentException("WebDriver instance must support BiDi protocol"); + } + + this.bidi = ((HasBiDi) driver).getBiDi(); + } + + public void setPermission( + Map permissionDescriptor, PermissionState state, String origin) { + this.setPermission(permissionDescriptor, state, origin, null); + } + + public void setPermission( + Map permissionDescriptor, + PermissionState state, + String origin, + String userContext) { + Require.nonNull("Permission descriptor", permissionDescriptor); + Require.nonNull("Permission state", state); + Require.nonNull("Origin", origin); + + Map params = + new HashMap<>( + Map.of( + "descriptor", permissionDescriptor, + "state", state.toString(), + "origin", origin)); + + if (userContext != null) { + params.put("userContext", userContext); + } + + this.bidi.send(new Command<>("permissions.setPermission", params)); + } +} diff --git a/java/src/org/openqa/selenium/bidi/permissions/BUILD.bazel b/java/src/org/openqa/selenium/bidi/permissions/BUILD.bazel new file mode 100644 index 0000000000000..46df58008f913 --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/permissions/BUILD.bazel @@ -0,0 +1,17 @@ +load("//java:defs.bzl", "java_library") + +java_library( + name = "permissions", + srcs = glob( + [ + "*.java", + ], + ), + visibility = [ + "//java/src/org/openqa/selenium/bidi:__subpackages__", + "//java/src/org/openqa/selenium/firefox:__subpackages__", + "//java/src/org/openqa/selenium/remote:__pkg__", + "//java/test/org/openqa/selenium/bidi:__subpackages__", + "//java/test/org/openqa/selenium/grid:__subpackages__", + ], +) diff --git a/java/src/org/openqa/selenium/bidi/permissions/PermissionState.java b/java/src/org/openqa/selenium/bidi/permissions/PermissionState.java new file mode 100644 index 0000000000000..e4b3ab62c1c18 --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/permissions/PermissionState.java @@ -0,0 +1,46 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you 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 +// +// http://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.openqa.selenium.bidi.permissions; + +public enum PermissionState { + GRANTED("granted"), + DENIED("denied"), + PROMPT("prompt"); + + private final String state; + + PermissionState(String state) { + this.state = state; + } + + @Override + public String toString() { + return state; + } + + public static PermissionState findByName(String name) { + PermissionState result = null; + for (PermissionState state : values()) { + if (state.toString().equalsIgnoreCase(name)) { + result = state; + break; + } + } + return result; + } +} diff --git a/java/src/org/openqa/selenium/remote/BUILD.bazel b/java/src/org/openqa/selenium/remote/BUILD.bazel index 1f4dee171f251..0834343da717f 100644 --- a/java/src/org/openqa/selenium/remote/BUILD.bazel +++ b/java/src/org/openqa/selenium/remote/BUILD.bazel @@ -31,6 +31,7 @@ java_export( "//java/src/org/openqa/selenium/bidi/log", "//java/src/org/openqa/selenium/bidi/module", "//java/src/org/openqa/selenium/bidi/network", + "//java/src/org/openqa/selenium/bidi/permissions", "//java/src/org/openqa/selenium/bidi/script", "//java/src/org/openqa/selenium/bidi/storage", "//java/src/org/openqa/selenium/devtools", diff --git a/java/test/org/openqa/selenium/bidi/input/BUILD.bazel b/java/test/org/openqa/selenium/bidi/input/BUILD.bazel index 9ae9147c3b872..690d36b9a0de4 100644 --- a/java/test/org/openqa/selenium/bidi/input/BUILD.bazel +++ b/java/test/org/openqa/selenium/bidi/input/BUILD.bazel @@ -22,6 +22,7 @@ java_selenium_test_suite( "//java/src/org/openqa/selenium/bidi/log", "//java/src/org/openqa/selenium/bidi/module", "//java/src/org/openqa/selenium/bidi/network", + "//java/src/org/openqa/selenium/bidi/permissions", "//java/src/org/openqa/selenium/bidi/script", "//java/src/org/openqa/selenium/chrome", "//java/src/org/openqa/selenium/firefox", diff --git a/java/test/org/openqa/selenium/bidi/permissions/BUILD.bazel b/java/test/org/openqa/selenium/bidi/permissions/BUILD.bazel new file mode 100644 index 0000000000000..33e1bdfd8451e --- /dev/null +++ b/java/test/org/openqa/selenium/bidi/permissions/BUILD.bazel @@ -0,0 +1,39 @@ +load("@rules_jvm_external//:defs.bzl", "artifact") +load("//java:defs.bzl", "JUNIT5_DEPS", "java_selenium_test_suite") + +java_selenium_test_suite( + name = "large-tests", + size = "large", + srcs = glob(["*Test.java"]), + browsers = [ + "firefox", + ], + data = [ + "//third_party/chrome_ext:backspace.crx", + ], + tags = [ + "selenium-remote", + ], + deps = [ + "//java/src/org/openqa/selenium/bidi", + "//java/src/org/openqa/selenium/bidi/browsingcontext", + "//java/src/org/openqa/selenium/bidi/log", + "//java/src/org/openqa/selenium/bidi/module", + "//java/src/org/openqa/selenium/bidi/network", + "//java/src/org/openqa/selenium/bidi/script", + "//java/src/org/openqa/selenium/chrome", + "//java/src/org/openqa/selenium/firefox", + "//java/src/org/openqa/selenium/json", + "//java/src/org/openqa/selenium/remote", + "//java/src/org/openqa/selenium/support", + "//java/test/org/openqa/selenium:helpers", + "//java/test/org/openqa/selenium/build", + "//java/test/org/openqa/selenium/environment", + "//java/test/org/openqa/selenium/testing:annotations", + "//java/test/org/openqa/selenium/testing:test-base", + "//java/test/org/openqa/selenium/testing/drivers", + artifact("org.junit.jupiter:junit-jupiter-api"), + artifact("org.assertj:assertj-core"), + artifact("org.mockito:mockito-core"), + ] + JUNIT5_DEPS, +) diff --git a/java/test/org/openqa/selenium/bidi/permissions/PermissionsTest.java b/java/test/org/openqa/selenium/bidi/permissions/PermissionsTest.java new file mode 100644 index 0000000000000..0b3185ead41e3 --- /dev/null +++ b/java/test/org/openqa/selenium/bidi/permissions/PermissionsTest.java @@ -0,0 +1,174 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you 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 +// +// http://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.openqa.selenium.bidi.permissions; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.WindowType; +import org.openqa.selenium.bidi.browsingcontext.BrowsingContext; +import org.openqa.selenium.bidi.browsingcontext.CreateContextParameters; +import org.openqa.selenium.bidi.browsingcontext.ReadinessState; +import org.openqa.selenium.bidi.module.Browser; +import org.openqa.selenium.bidi.module.Permission; +import org.openqa.selenium.bidi.module.Script; +import org.openqa.selenium.bidi.script.EvaluateResult; +import org.openqa.selenium.bidi.script.EvaluateResultSuccess; +import org.openqa.selenium.testing.JupiterTestBase; +import org.openqa.selenium.testing.NeedsFreshDriver; +import org.openqa.selenium.testing.Pages; + +public class PermissionsTest extends JupiterTestBase { + private Permission permission; + private Script script; + + private static final String GET_GEOLOCATION_PERMISSION = + "() => {return navigator.permissions.query({ name: 'geolocation' })" + + ".then(val => val.state, err => err.message)}"; + private static final String GET_ORIGIN = "() => {return window.location.origin;}"; + + @BeforeEach + public void setUp() { + permission = new Permission(driver); + script = new Script(driver); + } + + @Test + @NeedsFreshDriver + public void canSetPermission() { + BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle()); + + context.navigate(new Pages(appServer).blankPage, ReadinessState.COMPLETE); + + String contextId = context.getId(); + + EvaluateResult origin = + script.callFunctionInBrowsingContext( + contextId, GET_ORIGIN, true, Optional.empty(), Optional.empty(), Optional.empty()); + + String originValue = (String) ((EvaluateResultSuccess) origin).getResult().getValue().get(); + + permission.setPermission(Map.of("name", "geolocation"), PermissionState.GRANTED, originValue); + + EvaluateResult result = + script.callFunctionInBrowsingContext( + contextId, + GET_GEOLOCATION_PERMISSION, + true, + Optional.empty(), + Optional.empty(), + Optional.empty()); + + String resultValue = (String) ((EvaluateResultSuccess) result).getResult().getValue().get(); + assertThat(resultValue).isEqualTo("granted"); + + permission.setPermission(Map.of("name", "geolocation"), PermissionState.DENIED, originValue); + + result = + script.callFunctionInBrowsingContext( + contextId, + GET_GEOLOCATION_PERMISSION, + true, + Optional.empty(), + Optional.empty(), + Optional.empty()); + + resultValue = (String) ((EvaluateResultSuccess) result).getResult().getValue().get(); + assertThat(resultValue).isEqualTo("denied"); + + permission.setPermission(Map.of("name", "geolocation"), PermissionState.PROMPT, originValue); + + result = + script.callFunctionInBrowsingContext( + contextId, + GET_GEOLOCATION_PERMISSION, + true, + Optional.empty(), + Optional.empty(), + Optional.empty()); + + resultValue = (String) ((EvaluateResultSuccess) result).getResult().getValue().get(); + assertThat(resultValue).isEqualTo("prompt"); + } + + @Test + @NeedsFreshDriver + public void canSetPermissionForAUserContext() { + Browser browser = new Browser(driver); + + String url = new Pages(appServer).blankPage; + + String userContext = browser.createUserContext(); + + String originalTab = driver.getWindowHandle(); + + BrowsingContext context1 = new BrowsingContext(this.driver, driver.getWindowHandle()); + BrowsingContext context2 = + new BrowsingContext( + this.driver, new CreateContextParameters(WindowType.TAB).userContext(userContext)); + + String newTab = context2.getId(); + + context1.navigate(url, ReadinessState.COMPLETE); + context2.navigate(url, ReadinessState.COMPLETE); + + EvaluateResult origin = + script.callFunctionInBrowsingContext( + originalTab, GET_ORIGIN, true, Optional.empty(), Optional.empty(), Optional.empty()); + + String originValue = (String) ((EvaluateResultSuccess) origin).getResult().getValue().get(); + + permission.setPermission( + Map.of("name", "geolocation"), PermissionState.GRANTED, originValue, userContext); + + EvaluateResult newTabUpdatedPermission = + script.callFunctionInBrowsingContext( + newTab, + GET_GEOLOCATION_PERMISSION, + true, + Optional.empty(), + Optional.empty(), + Optional.empty()); + + String newTabUpdatedPermissionValue = + (String) ((EvaluateResultSuccess) newTabUpdatedPermission).getResult().getValue().get(); + assertThat(newTabUpdatedPermissionValue).isEqualTo("granted"); + + BrowsingContext context3 = + new BrowsingContext( + this.driver, new CreateContextParameters(WindowType.TAB).userContext(userContext)); + + context3.navigate(url, ReadinessState.COMPLETE); + + newTabUpdatedPermission = + script.callFunctionInBrowsingContext( + context3.getId(), + GET_GEOLOCATION_PERMISSION, + true, + Optional.empty(), + Optional.empty(), + Optional.empty()); + + newTabUpdatedPermissionValue = + (String) ((EvaluateResultSuccess) newTabUpdatedPermission).getResult().getValue().get(); + assertThat(newTabUpdatedPermissionValue).isEqualTo("granted"); + } +}