diff --git a/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java b/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java index a70ba0fb..46fc179d 100644 --- a/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java +++ b/api-generator/src/main/java/com/microsoft/playwright/tools/Types.java @@ -259,7 +259,10 @@ class Types { add("BrowserType.launchPersistentContext.options.geolocation.longitude", "number", "double"); add("BrowserType.launchPersistentContext.options.geolocation.accuracy", "number", "double"); - add("BrowserContext.setGeolocation.geolocation", "null|Object", "Geolocation"); + add("BrowserContext.setGeolocation.geolocation", "null|Object", "Geolocation", new Empty()); + add("Browser.newContext.options.geolocation", "Object", "Geolocation", new Empty()); + add("Browser.newPage.options.geolocation", "Object", "Geolocation", new Empty()); + add("BrowserType.launchPersistentContext.options.geolocation", "Object", "Geolocation", new Empty()); // Single field options add("Keyboard.type.options", "Object", "int", new Empty()); diff --git a/playwright/src/main/java/com/microsoft/playwright/Browser.java b/playwright/src/main/java/com/microsoft/playwright/Browser.java index 780ad5da..3a422ba0 100644 --- a/playwright/src/main/java/com/microsoft/playwright/Browser.java +++ b/playwright/src/main/java/com/microsoft/playwright/Browser.java @@ -27,30 +27,6 @@ public interface Browser { void removeListener(EventType type, Listener listener); class NewContextOptions { public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE } - public class Geolocation { - public double latitude; - public double longitude; - public double accuracy; - - Geolocation() { - } - public NewContextOptions done() { - return NewContextOptions.this; - } - - public Geolocation withLatitude(double latitude) { - this.latitude = latitude; - return this; - } - public Geolocation withLongitude(double longitude) { - this.longitude = longitude; - return this; - } - public Geolocation withAccuracy(double accuracy) { - this.accuracy = accuracy; - return this; - } - } public class VideoSize { public int width; public int height; @@ -131,9 +107,9 @@ public interface Browser { this.timezoneId = timezoneId; return this; } - public Geolocation setGeolocation() { - this.geolocation = new Geolocation(); - return this.geolocation; + public NewContextOptions withGeolocation(Geolocation geolocation) { + this.geolocation = geolocation; + return this; } public NewContextOptions withLocale(String locale) { this.locale = locale; @@ -174,30 +150,6 @@ public interface Browser { } class NewPageOptions { public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE } - public class Geolocation { - public double latitude; - public double longitude; - public double accuracy; - - Geolocation() { - } - public NewPageOptions done() { - return NewPageOptions.this; - } - - public Geolocation withLatitude(double latitude) { - this.latitude = latitude; - return this; - } - public Geolocation withLongitude(double longitude) { - this.longitude = longitude; - return this; - } - public Geolocation withAccuracy(double accuracy) { - this.accuracy = accuracy; - return this; - } - } public class VideoSize { public int width; public int height; @@ -278,9 +230,9 @@ public interface Browser { this.timezoneId = timezoneId; return this; } - public Geolocation setGeolocation() { - this.geolocation = new Geolocation(); - return this.geolocation; + public NewPageOptions withGeolocation(Geolocation geolocation) { + this.geolocation = geolocation; + return this; } public NewPageOptions withLocale(String locale) { this.locale = locale; diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java index 10b22983..d1716fc1 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserContext.java @@ -160,24 +160,6 @@ public interface BrowserContext { return this; } } - class Geolocation { - public int latitude; - public int longitude; - public Integer accuracy; - - public Geolocation withLatitude(int latitude) { - this.latitude = latitude; - return this; - } - public Geolocation withLongitude(int longitude) { - this.longitude = longitude; - return this; - } - public Geolocation withAccuracy(Integer accuracy) { - this.accuracy = accuracy; - return this; - } - } void close(); void addCookies(List cookies); default void addInitScript(String script) { diff --git a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java index e0b3b2c6..788dbbaa 100644 --- a/playwright/src/main/java/com/microsoft/playwright/BrowserType.java +++ b/playwright/src/main/java/com/microsoft/playwright/BrowserType.java @@ -185,30 +185,6 @@ public interface BrowserType { return this; } } - public class Geolocation { - public double latitude; - public double longitude; - public double accuracy; - - Geolocation() { - } - public LaunchPersistentContextOptions done() { - return LaunchPersistentContextOptions.this; - } - - public Geolocation withLatitude(double latitude) { - this.latitude = latitude; - return this; - } - public Geolocation withLongitude(double longitude) { - this.longitude = longitude; - return this; - } - public Geolocation withAccuracy(double accuracy) { - this.accuracy = accuracy; - return this; - } - } public class VideoSize { public int width; public int height; @@ -363,9 +339,9 @@ public interface BrowserType { this.timezoneId = timezoneId; return this; } - public Geolocation setGeolocation() { - this.geolocation = new Geolocation(); - return this.geolocation; + public LaunchPersistentContextOptions withGeolocation(Geolocation geolocation) { + this.geolocation = geolocation; + return this; } public LaunchPersistentContextOptions withLocale(String locale) { this.locale = locale; diff --git a/playwright/src/main/java/com/microsoft/playwright/Geolocation.java b/playwright/src/main/java/com/microsoft/playwright/Geolocation.java new file mode 100644 index 00000000..80eb2ae7 --- /dev/null +++ b/playwright/src/main/java/com/microsoft/playwright/Geolocation.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * 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 + * + * 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 com.microsoft.playwright; + +public class Geolocation { + public double latitude; + public double longitude; + public Double accuracy; + + public Geolocation() { + } + + public Geolocation(double latitude, double longitude) { + this(latitude, longitude, null); + } + + public Geolocation(double latitude, double longitude, Double accuracy) { + this.latitude = latitude; + this.longitude = longitude; + this.accuracy = accuracy; + } + + public Geolocation withLatitude(double latitude) { + this.latitude = latitude; + return this; + } + public Geolocation withLongitude(double longitude) { + this.longitude = longitude; + return this; + } + public Geolocation withAccuracy(double accuracy) { + this.accuracy = accuracy; + return this; + } +} diff --git a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java index f2dfab7b..7a854c53 100644 --- a/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java +++ b/playwright/src/main/java/com/microsoft/playwright/impl/BrowserContextImpl.java @@ -17,9 +17,7 @@ package com.microsoft.playwright.impl; import com.google.gson.*; -import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.microsoft.playwright.*; @@ -36,7 +34,7 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { final List pages = new ArrayList<>(); final Router routes = new Router(); private boolean isClosedOrClosing; - final Map bindings = new HashMap(); + final Map bindings = new HashMap<>(); PageImpl ownerPage; private final ListenerCollection listeners = new ListenerCollection<>(); final TimeoutSettings timeoutSettings = new TimeoutSettings(); @@ -166,7 +164,15 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { @Override public void grantPermissions(List permissions, GrantPermissionsOptions options) { - + if (options == null) { + options = new GrantPermissionsOptions(); + } + if (permissions == null) { + permissions = Collections.emptyList(); + } + JsonObject params = new Gson().toJsonTree(options).getAsJsonObject(); + params.add("permissions", new Gson().toJsonTree(permissions)); + sendMessage("grantPermissions", params); } @Override @@ -239,7 +245,11 @@ class BrowserContextImpl extends ChannelOwner implements BrowserContext { @Override public void setGeolocation(Geolocation geolocation) { - + JsonObject params = new JsonObject(); + if (geolocation != null) { + params.add("geolocation", new Gson().toJsonTree(geolocation)); + } + sendMessage("setGeolocation", params); } @Override diff --git a/playwright/src/test/java/com/microsoft/playwright/TestGeolocation.java b/playwright/src/test/java/com/microsoft/playwright/TestGeolocation.java new file mode 100644 index 00000000..931a5d19 --- /dev/null +++ b/playwright/src/test/java/com/microsoft/playwright/TestGeolocation.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) Microsoft Corporation. + * + * 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 + * + * 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 com.microsoft.playwright; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.microsoft.playwright.Page.EventType.CONSOLE; +import static com.microsoft.playwright.Page.EventType.POPUP; +import static com.microsoft.playwright.Utils.mapOf; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class TestGeolocation extends TestBase { + @Test + void shouldWork() { + context.grantPermissions(asList("geolocation")); + page.navigate(server.EMPTY_PAGE); + context.setGeolocation(new Geolocation(10, 10)); + Object geolocation = page.evaluate("() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => {\n" + + " resolve({latitude: position.coords.latitude, longitude: position.coords.longitude});\n" + + "}))"); + assertEquals(mapOf("latitude", 10, "longitude", 10), geolocation); + } + + @Test + void shouldThrowWhenInvalidLongitude() { + try { + context.setGeolocation(new Geolocation(10, 200)); + } catch (PlaywrightException e) { + assertTrue(e.getMessage().contains("geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed.")); + } + } + + @Test + void shouldIsolateContexts() { + context.grantPermissions(asList("geolocation")); + context.setGeolocation(new Geolocation(10, 10)); + page.navigate(server.EMPTY_PAGE); + + BrowserContext context2 = browser.newContext(new Browser.NewContextOptions() + .withPermissions(asList("geolocation")) + .withGeolocation(new Geolocation(20, 20))); + Page page2 = context2.newPage(); + page2.navigate(server.EMPTY_PAGE); + + Object geolocation = page.evaluate("() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => {\n" + + " resolve({latitude: position.coords.latitude, longitude: position.coords.longitude});\n" + + "}))"); + assertEquals(mapOf("latitude", 10, "longitude", 10), geolocation); + + Object geolocation2 = page2.evaluate("() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => {\n" + + " resolve({latitude: position.coords.latitude, longitude: position.coords.longitude});\n" + + "}))"); + assertEquals(mapOf("latitude", 20, "longitude", 20), geolocation2); + context2.close(); + } + + void shouldThrowWithMissingLatitude() { + // Not applicable in Java. + } + + @Test + void shouldNotModifyPassedDefaultOptionsObject() { + Geolocation geolocation = new Geolocation(10, 10); + Browser.NewContextOptions options = new Browser.NewContextOptions().withGeolocation(geolocation); + BrowserContext context = browser.newContext(options); + context.setGeolocation(new Geolocation(20, 20)); + assertEquals(geolocation, options.geolocation); + context.close(); + } + + void shouldThrowWithMissingLongitudeInDefaultOptions() { + // Not applicable in Java. + } + + @Test + void shouldUseContextOptions() { + Browser.NewContextOptions options = new Browser.NewContextOptions() + .withGeolocation(new Geolocation(10, 10)) + .withPermissions(asList("geolocation")); + BrowserContext context = browser.newContext(options); + Page page = context.newPage(); + page.navigate(server.EMPTY_PAGE); + Object geolocation = page.evaluate("() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => {\n" + + " resolve({latitude: position.coords.latitude, longitude: position.coords.longitude});\n" + + "}))"); + assertEquals(mapOf("latitude", 10, "longitude", 10), geolocation); + context.close(); + } + + @Test + void watchPositionShouldBeNotified() { + context.grantPermissions(asList("geolocation")); + page.navigate(server.EMPTY_PAGE); + List messages = new ArrayList<>(); + page.addListener(CONSOLE, event -> messages.add(((ConsoleMessage) event.data()).text())); + context.setGeolocation(new Geolocation()); + page.evaluate("() => {\n" + + " navigator.geolocation.watchPosition(pos => {\n" + + " const coords = pos.coords;\n" + + " console.log(`lat=${coords.latitude} lng=${coords.longitude}`);\n" + + " }, err => {});\n" + + "}"); + { + Deferred> deferred = page.waitForEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=0 lng=10")); + context.setGeolocation(new Geolocation(0, 10)); + deferred.get(); + } + { + Deferred> deferred = page.waitForEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=20 lng=30")); + context.setGeolocation(new Geolocation(20, 30)); + deferred.get(); + } + { + Deferred> deferred = page.waitForEvent(CONSOLE, event -> ((ConsoleMessage) event.data()).text().contains("lat=40 lng=50")); + context.setGeolocation(new Geolocation(40, 50)); + deferred.get(); + } + assertTrue(messages.contains("lat=0 lng=10")); + assertTrue(messages.contains("lat=20 lng=30")); + assertTrue(messages.contains("lat=40 lng=50")); + } + + @Test + void shouldUseContextOptionsForPopup() { + context.grantPermissions(asList("geolocation")); + context.setGeolocation(new Geolocation(10, 10)); + Deferred> popupEvent = page.waitForEvent(POPUP); + page.evaluate("url => window['_popup'] = window.open(url)", server.PREFIX + "/geolocation.html"); + Page popup = (Page) popupEvent.get().data(); + popup.waitForLoadState(); + Object geolocation = popup.evaluate("window['geolocationPromise']"); + assertEquals(mapOf("longitude", 10, "latitude", 10), geolocation); + } +}