1
0
mirror of synced 2026-08-05 23:16:54 +00:00

feat: emulate media, color scheme (#57)

This commit is contained in:
Yury Semikhatsky
2020-10-30 09:49:15 -07:00
committed by GitHub
parent 3da0ac6e85
commit 6022d47686
10 changed files with 215 additions and 55 deletions
@@ -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());
}
}