feat: emulate media, color scheme (#57)
This commit is contained in:
@@ -23,8 +23,6 @@ import com.google.gson.JsonObject;
|
||||
import java.io.*;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
@@ -501,6 +499,11 @@ class Field extends Element {
|
||||
output.add(offset + "public byte[] bodyBytes;");
|
||||
return;
|
||||
}
|
||||
if (asList("Page.emulateMedia.options.media",
|
||||
"Page.emulateMedia.options.colorScheme").contains(jsonPath)) {
|
||||
output.add(offset + access + "Optional<" + type.toJava() + "> " + name + ";");
|
||||
return;
|
||||
}
|
||||
output.add(offset + access + type.toJava() + " " + name + ";");
|
||||
}
|
||||
|
||||
@@ -557,7 +560,14 @@ class Field extends Element {
|
||||
output.add(offset + "}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (asList("Page.emulateMedia.options.media",
|
||||
"Page.emulateMedia.options.colorScheme").contains(jsonPath)) {
|
||||
output.add(offset + "public " + parentClass + " with" + toTitle(name) + "(" + type.toJava() + " " + name + ") {");
|
||||
output.add(offset + " this." + name + " = Optional.ofNullable(" + name + ");");
|
||||
output.add(offset + " return this;");
|
||||
output.add(offset + "}");
|
||||
return;
|
||||
}
|
||||
if ("Route.continue.overrides.postData".equals(jsonPath)) {
|
||||
output.add(offset + "public ContinueOverrides withPostData(String postData) {");
|
||||
output.add(offset + " this.postData = postData.getBytes(StandardCharsets.UTF_8);");
|
||||
|
||||
@@ -53,14 +53,14 @@ class Types {
|
||||
add("Logger.log.severity", "\"error\"|\"info\"|\"verbose\"|\"warning\"", "Severity");
|
||||
|
||||
// Option enums
|
||||
add("Browser.newContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("Browser.newPage.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("Browser.newContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme", new Empty());
|
||||
add("Browser.newPage.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme", new Empty());
|
||||
add("Page.click.options.button", "\"left\"|\"middle\"|\"right\"", "Mouse.Button", new Empty());
|
||||
add("Page.click.options.modifiers", "Array<\"Alt\"|\"Control\"|\"Meta\"|\"Shift\">", "Set<Keyboard.Modifier>", new Empty());
|
||||
add("Page.dblclick.options.button", "\"left\"|\"middle\"|\"right\"", "Mouse.Button", new Empty());
|
||||
add("Page.dblclick.options.modifiers", "Array<\"Alt\"|\"Control\"|\"Meta\"|\"Shift\">", "Set<Keyboard.Modifier>", new Empty());
|
||||
add("Page.emulateMedia.options.media", "null|\"print\"|\"screen\"", "Media");
|
||||
add("Page.emulateMedia.options.colorScheme", "null|\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("Page.emulateMedia.options.colorScheme", "null|\"dark\"|\"light\"|\"no-preference\"", "ColorScheme", new Empty());
|
||||
add("Page.goBack.options.waitUntil", "\"domcontentloaded\"|\"load\"|\"networkidle\"", "Frame.LoadState", new Empty());
|
||||
add("Page.goForward.options.waitUntil", "\"domcontentloaded\"|\"load\"|\"networkidle\"", "Frame.LoadState", new Empty());
|
||||
add("Page.goto.options.waitUntil", "\"domcontentloaded\"|\"load\"|\"networkidle\"", "Frame.LoadState", new Empty());
|
||||
@@ -92,7 +92,7 @@ class Types {
|
||||
add("Mouse.dblclick.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
|
||||
add("Mouse.down.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
|
||||
add("Mouse.up.options.button", "\"left\"|\"middle\"|\"right\"", "Button", new Empty());
|
||||
add("BrowserType.launchPersistentContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme");
|
||||
add("BrowserType.launchPersistentContext.options.colorScheme", "\"dark\"|\"light\"|\"no-preference\"", "ColorScheme", new Empty());
|
||||
|
||||
// File
|
||||
add("Page.addScriptTag.options.path", "string", "Path");
|
||||
|
||||
@@ -26,7 +26,6 @@ public interface Browser {
|
||||
void addListener(EventType type, Listener<EventType> listener);
|
||||
void removeListener(EventType type, Listener<EventType> listener);
|
||||
class NewContextOptions {
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
public class VideoSize {
|
||||
public int width;
|
||||
public int height;
|
||||
@@ -149,7 +148,6 @@ public interface Browser {
|
||||
}
|
||||
}
|
||||
class NewPageOptions {
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
public class VideoSize {
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
@@ -155,7 +155,6 @@ public interface BrowserType {
|
||||
}
|
||||
}
|
||||
class LaunchPersistentContextOptions {
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
public class Proxy {
|
||||
public String server;
|
||||
public String bypass;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.microsoft.playwright;
|
||||
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
@@ -262,16 +262,15 @@ public interface Page {
|
||||
}
|
||||
class EmulateMediaOptions {
|
||||
public enum Media { PRINT, SCREEN }
|
||||
public enum ColorScheme { DARK, LIGHT, NO_PREFERENCE }
|
||||
public Media media;
|
||||
public ColorScheme colorScheme;
|
||||
public Optional<Media> media;
|
||||
public Optional<ColorScheme> colorScheme;
|
||||
|
||||
public EmulateMediaOptions withMedia(Media media) {
|
||||
this.media = media;
|
||||
this.media = Optional.ofNullable(media);
|
||||
return this;
|
||||
}
|
||||
public EmulateMediaOptions withColorScheme(ColorScheme colorScheme) {
|
||||
this.colorScheme = colorScheme;
|
||||
this.colorScheme = Optional.ofNullable(colorScheme);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package com.microsoft.playwright.impl;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.microsoft.playwright.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -295,34 +293,12 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
mainFrame.dispatchEvent(selector, type, eventInit, convertViaJson(options, Frame.DispatchEventOptions.class));
|
||||
}
|
||||
|
||||
private static String toProtocol(EmulateMediaOptions.Media media) {
|
||||
if (media == null) {
|
||||
return "null";
|
||||
}
|
||||
return media.toString().toLowerCase();
|
||||
}
|
||||
|
||||
private static String toProtocol(EmulateMediaOptions.ColorScheme colorScheme) {
|
||||
if (colorScheme == null) {
|
||||
return "null";
|
||||
}
|
||||
switch (colorScheme) {
|
||||
case DARK:
|
||||
return "dark";
|
||||
case LIGHT:
|
||||
return "light";
|
||||
case NO_PREFERENCE:
|
||||
return "no-preference";
|
||||
default:
|
||||
throw new PlaywrightException("Unknown option: " + colorScheme);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emulateMedia(EmulateMediaOptions options) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("media", toProtocol(options.media));
|
||||
params.addProperty("colorScheme", toProtocol(options.colorScheme));
|
||||
if (options == null) {
|
||||
options = new EmulateMediaOptions();
|
||||
}
|
||||
JsonObject params = gson().toJsonTree(options).getAsJsonObject();
|
||||
sendMessage("emulateMedia", params);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +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.JsonWriter;
|
||||
import com.microsoft.playwright.*;
|
||||
@@ -36,7 +37,9 @@ class Serialization {
|
||||
if (gson == null) {
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(BrowserContext.SameSite.class, new SameSiteAdapter().nullSafe())
|
||||
.registerTypeAdapter(BrowserType.LaunchPersistentContextOptions.ColorScheme.class, new ColorSchemeAdapter().nullSafe())
|
||||
.registerTypeAdapter(ColorScheme.class, new ColorSchemeAdapter().nullSafe())
|
||||
.registerTypeAdapter(Page.EmulateMediaOptions.Media.class, new MediaSerializer())
|
||||
.registerTypeAdapter(Optional.class, new OptionalSerializer())
|
||||
.registerTypeAdapter(Path.class, new PathSerializer()).create();
|
||||
}
|
||||
return gson;
|
||||
@@ -87,7 +90,7 @@ class Serialization {
|
||||
result.s = (String) value;
|
||||
} else if (value instanceof List) {
|
||||
List<SerializedValue> list = new ArrayList<>();
|
||||
for (Object o : (List) value) {
|
||||
for (Object o : (List<Object>) value) {
|
||||
list.add(serializeValue(o, handles, depth + 1));
|
||||
}
|
||||
result.a = list.toArray(new SerializedValue[0]);
|
||||
@@ -245,6 +248,29 @@ class Serialization {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class OptionalSerializer implements JsonSerializer<Optional<?>> {
|
||||
private static boolean isSupported(Type type) {
|
||||
return new TypeToken<Optional<Page.EmulateMediaOptions.Media>>() {}.getType().getTypeName().equals(type.getTypeName()) ||
|
||||
new TypeToken<Optional<ColorScheme>>() {}.getType().getTypeName().equals(type.getTypeName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(Optional<?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
assert isSupported(typeOfSrc);
|
||||
if (!src.isPresent()) {
|
||||
return new JsonPrimitive("null");
|
||||
}
|
||||
return context.serialize(src.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static class MediaSerializer implements JsonSerializer<Page.EmulateMediaOptions.Media> {
|
||||
@Override
|
||||
public JsonElement serialize(Page.EmulateMediaOptions.Media src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toString().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
private static class PathSerializer implements JsonSerializer<Path> {
|
||||
@Override
|
||||
public JsonElement serialize(Path src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
@@ -279,9 +305,9 @@ class Serialization {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ColorSchemeAdapter extends TypeAdapter<BrowserType.LaunchPersistentContextOptions.ColorScheme> {
|
||||
private static class ColorSchemeAdapter extends TypeAdapter<ColorScheme> {
|
||||
@Override
|
||||
public void write(JsonWriter out, BrowserType.LaunchPersistentContextOptions.ColorScheme value) throws IOException {
|
||||
public void write(JsonWriter out, ColorScheme value) throws IOException {
|
||||
String stringValue;
|
||||
switch (value) {
|
||||
case DARK:
|
||||
@@ -300,12 +326,12 @@ class Serialization {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrowserType.LaunchPersistentContextOptions.ColorScheme read(JsonReader in) throws IOException {
|
||||
public ColorScheme read(JsonReader in) throws IOException {
|
||||
String value = in.nextString();
|
||||
switch (value) {
|
||||
case "dark": return BrowserType.LaunchPersistentContextOptions.ColorScheme.DARK;
|
||||
case "light": return BrowserType.LaunchPersistentContextOptions.ColorScheme.LIGHT;
|
||||
case "no-preference": return BrowserType.LaunchPersistentContextOptions.ColorScheme.NO_PREFERENCE;
|
||||
case "dark": return ColorScheme.DARK;
|
||||
case "light": return ColorScheme.LIGHT;
|
||||
case "no-preference": return ColorScheme.NO_PREFERENCE;
|
||||
default: throw new PlaywrightException("Unexpected value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import java.nio.file.Path;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static com.microsoft.playwright.BrowserType.LaunchPersistentContextOptions.ColorScheme.DARK;
|
||||
import static com.microsoft.playwright.ColorScheme.DARK;
|
||||
import static com.microsoft.playwright.Utils.mapOf;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.function.Supplier;
|
||||
|
||||
import static com.microsoft.playwright.ColorScheme.DARK;
|
||||
import static com.microsoft.playwright.ColorScheme.LIGHT;
|
||||
import static com.microsoft.playwright.Page.EmulateMediaOptions.Media.PRINT;
|
||||
import static com.microsoft.playwright.Page.EventType.POPUP;
|
||||
import static com.microsoft.playwright.Utils.attachFrame;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestPageEmulateMedia extends TestBase {
|
||||
@Test
|
||||
void shouldEmulateType() {
|
||||
assertEquals(true, page.evaluate("() => matchMedia('screen').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('print').matches"));
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withMedia(PRINT));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('screen').matches"));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('print').matches"));
|
||||
page.emulateMedia(new Page.EmulateMediaOptions());
|
||||
assertEquals(false, page.evaluate("() => matchMedia('screen').matches"));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('print').matches"));
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withMedia(null));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('screen').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('print').matches"));
|
||||
}
|
||||
|
||||
void shouldThrowInCaseOfBadTypeArgument() {
|
||||
// Impossible in Java.
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldEmulateSchemeWork() {
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(LIGHT));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(DARK));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDefaultToLight() {
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(DARK));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(null));
|
||||
assertEquals(false, page.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
assertEquals(true, page.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
}
|
||||
|
||||
void shouldThrowInCaseOfBadArgument() {
|
||||
// Impossible in Java.
|
||||
}
|
||||
|
||||
// @Test
|
||||
void shouldWorkDuringNavigation() {
|
||||
// TODO: requires async API
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkInPopup() {
|
||||
{
|
||||
BrowserContext context = browser.newContext(new Browser.NewContextOptions().withColorScheme(DARK));
|
||||
Page page = context.newPage();
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE);
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
assertEquals(false, popup.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(true, popup.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
context.close();
|
||||
}
|
||||
{
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withColorScheme(LIGHT));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
Deferred<Event<Page.EventType>> popupEvent = page.waitForEvent(POPUP);
|
||||
page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE);
|
||||
Page popup = (Page) popupEvent.get().data();
|
||||
assertEquals(true, popup.evaluate("() => matchMedia('(prefers-color-scheme: light)').matches"));
|
||||
assertEquals(false, popup.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
page.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWorkInCrossProcessIframe() {
|
||||
Page page = browser.newPage(new Browser.NewPageOptions().withColorScheme(DARK));
|
||||
page.navigate(server.EMPTY_PAGE);
|
||||
attachFrame(page, "frame1", server.CROSS_PROCESS_PREFIX + "/empty.html");
|
||||
Frame frame = page.frames().get(1);
|
||||
assertEquals(true, frame.evaluate("() => matchMedia('(prefers-color-scheme: dark)').matches"));
|
||||
page.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldChangeTheActualColorsInCss() {
|
||||
page.setContent("<style>\n" +
|
||||
"@media (prefers-color-scheme: dark) {\n" +
|
||||
" div {\n" +
|
||||
" background: black;\n" +
|
||||
" color: white;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"@media (prefers-color-scheme: light) {\n" +
|
||||
" div {\n" +
|
||||
" background: white;\n" +
|
||||
" color: black;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"</style>\n" +
|
||||
"<div>Hello</div>");
|
||||
|
||||
Supplier<Object> backgroundColor = () -> {
|
||||
return page.evalOnSelector("div", "div => window.getComputedStyle(div).backgroundColor");
|
||||
};
|
||||
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(LIGHT));
|
||||
assertEquals("rgb(255, 255, 255)", backgroundColor.get());
|
||||
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(DARK));
|
||||
assertEquals("rgb(0, 0, 0)", backgroundColor.get());
|
||||
|
||||
page.emulateMedia(new Page.EmulateMediaOptions().withColorScheme(LIGHT));
|
||||
assertEquals("rgb(255, 255, 255)", backgroundColor.get());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user