test: add http server, first click test
This commit is contained in:
@@ -125,13 +125,10 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
}
|
||||
|
||||
public <T> T evalTyped(String expression) {
|
||||
JsonElement json = evaluate(expression, null, false);
|
||||
System.out.println("json = " + new Gson().toJson(json));
|
||||
SerializedValue value = new Gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
return (T) evaluate(expression, null, false);
|
||||
}
|
||||
|
||||
JsonElement evaluate(String expression, Object arg, boolean forceExpression) {
|
||||
private Object evaluate(String expression, Object arg, boolean forceExpression) {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("expression", expression);
|
||||
params.addProperty("world", "main");
|
||||
@@ -139,7 +136,10 @@ public class FrameImpl extends ChannelOwner implements Frame {
|
||||
forceExpression = true;
|
||||
params.addProperty("isFunction", !forceExpression);
|
||||
params.add("arg", new Gson().toJsonTree(serializeArgument(arg)));
|
||||
return sendMessage("evaluateExpression", params);
|
||||
JsonElement json = sendMessage("evaluateExpression", params);
|
||||
// System.out.println("json = " + new Gson().toJson(json));
|
||||
SerializedValue value = new Gson().fromJson(json.getAsJsonObject().get("value"), SerializedValue.class);
|
||||
return deserialize(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -92,10 +92,6 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
return mainFrame.evalTyped(expression);
|
||||
}
|
||||
|
||||
public JsonElement evaluate(String expression) {
|
||||
return evaluate(expression, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseOptions options) {
|
||||
|
||||
@@ -177,8 +173,8 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement evaluate(String expression, Object arg) {
|
||||
return evaluate(expression, arg, false);
|
||||
public Object evaluate(String expression, Object arg) {
|
||||
return mainFrame.evaluate(expression, arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -406,8 +402,4 @@ public class PageImpl extends ChannelOwner implements Page {
|
||||
public List<Worker> workers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JsonElement evaluate(String expression, Object arg, boolean forceExpression) {
|
||||
return mainFrame.evaluate(expression, arg, forceExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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 com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.spi.FileTypeDetector;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class Server implements HttpHandler {
|
||||
private static final int port = 8907;
|
||||
private static final int httpsPort = 8908;
|
||||
private final HttpServer server;
|
||||
|
||||
public final String PREFIX;
|
||||
public final String CROSS_PROCESS_PREFIX;
|
||||
public final int PORT;
|
||||
public final String EMPTY_PAGE;
|
||||
private final File resourcesDir;
|
||||
|
||||
Server(int port) throws IOException {
|
||||
PORT = port;
|
||||
PREFIX = "http://localhost:" + PORT;
|
||||
CROSS_PROCESS_PREFIX = "http://127.0.0.1:" + PORT;
|
||||
EMPTY_PAGE = PREFIX + "/empty.html";
|
||||
|
||||
server = HttpServer.create(new InetSocketAddress("localhost", port), 0);
|
||||
server.createContext("/", this);
|
||||
server.setExecutor(null); // creates a default executor
|
||||
|
||||
File cwd = FileSystems.getDefault().getPath(".").toFile();
|
||||
resourcesDir = new File(cwd, "src/test/resources");
|
||||
server.start();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
server.stop(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
File file = new File(resourcesDir, exchange.getRequestURI().getPath().substring(1));
|
||||
exchange.getResponseHeaders().put("Content-Type", singletonList(mimeType(file)));
|
||||
try (FileInputStream input = new FileInputStream(file)) {
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
copy(input, exchange.getResponseBody());
|
||||
} catch (IOException e) {
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody())) {
|
||||
writer.write("File not found: " + file.getCanonicalPath());
|
||||
}
|
||||
}
|
||||
exchange.getResponseBody().close();
|
||||
}
|
||||
|
||||
private static void copy(InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[8192];
|
||||
int read;
|
||||
while ((read = in.read(buffer, 0, 8192)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
}
|
||||
|
||||
private static String mimeType(File file) {
|
||||
String name = file.getName();
|
||||
int lastDotPos = name.lastIndexOf('.');
|
||||
String extension = lastDotPos == -1 ? name : name.substring(lastDotPos + 1);
|
||||
String mimeType = extensionToMime.get(extension);
|
||||
if (mimeType == null) {
|
||||
mimeType = "application/octet-stream";
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
private static Map<String, String> extensionToMime = new HashMap<>();
|
||||
static {
|
||||
extensionToMime.put("ai", "application/postscript");
|
||||
extensionToMime.put("apng", "image/apng");
|
||||
extensionToMime.put("appcache", "text/cache-manifest");
|
||||
extensionToMime.put("au", "audio/basic");
|
||||
extensionToMime.put("bmp", "image/bmp");
|
||||
extensionToMime.put("cer", "application/pkix-cert");
|
||||
extensionToMime.put("cgm", "image/cgm");
|
||||
extensionToMime.put("coffee", "text/coffeescript");
|
||||
extensionToMime.put("conf", "text/plain");
|
||||
extensionToMime.put("crl", "application/pkix-crl");
|
||||
extensionToMime.put("css", "text/css");
|
||||
extensionToMime.put("csv", "text/csv");
|
||||
extensionToMime.put("def", "text/plain");
|
||||
extensionToMime.put("doc", "application/msword");
|
||||
extensionToMime.put("dot", "application/msword");
|
||||
extensionToMime.put("drle", "image/dicom-rle");
|
||||
extensionToMime.put("dtd", "application/xml-dtd");
|
||||
extensionToMime.put("ear", "application/java-archive");
|
||||
extensionToMime.put("emf", "image/emf");
|
||||
extensionToMime.put("eps", "application/postscript");
|
||||
extensionToMime.put("exr", "image/aces");
|
||||
extensionToMime.put("fits", "image/fits");
|
||||
extensionToMime.put("g3", "image/g3fax");
|
||||
extensionToMime.put("gbr", "application/rpki-ghostbusters");
|
||||
extensionToMime.put("gif", "image/gif");
|
||||
extensionToMime.put("glb", "model/gltf-binary");
|
||||
extensionToMime.put("gltf", "model/gltf+json");
|
||||
extensionToMime.put("gz", "application/gzip");
|
||||
extensionToMime.put("h261", "video/h261");
|
||||
extensionToMime.put("h263", "video/h263");
|
||||
extensionToMime.put("h264", "video/h264");
|
||||
extensionToMime.put("heic", "image/heic");
|
||||
extensionToMime.put("heics", "image/heic-sequence");
|
||||
extensionToMime.put("heif", "image/heif");
|
||||
extensionToMime.put("heifs", "image/heif-sequence");
|
||||
extensionToMime.put("htm", "text/html");
|
||||
extensionToMime.put("html", "text/html");
|
||||
extensionToMime.put("ics", "text/calendar");
|
||||
extensionToMime.put("ief", "image/ief");
|
||||
extensionToMime.put("ifb", "text/calendar");
|
||||
extensionToMime.put("iges", "model/iges");
|
||||
extensionToMime.put("igs", "model/iges");
|
||||
extensionToMime.put("in", "text/plain");
|
||||
extensionToMime.put("ini", "text/plain");
|
||||
extensionToMime.put("jade", "text/jade");
|
||||
extensionToMime.put("jar", "application/java-archive");
|
||||
extensionToMime.put("jls", "image/jls");
|
||||
extensionToMime.put("jp2", "image/jp2");
|
||||
extensionToMime.put("jpe", "image/jpeg");
|
||||
extensionToMime.put("jpeg", "image/jpeg");
|
||||
extensionToMime.put("jpf", "image/jpx");
|
||||
extensionToMime.put("jpg", "image/jpeg");
|
||||
extensionToMime.put("jpg2", "image/jp2");
|
||||
extensionToMime.put("jpgm", "video/jpm");
|
||||
extensionToMime.put("jpgv", "video/jpeg");
|
||||
extensionToMime.put("jpm", "image/jpm");
|
||||
extensionToMime.put("jpx", "image/jpx");
|
||||
extensionToMime.put("js", "application/javascript");
|
||||
extensionToMime.put("json", "application/json");
|
||||
extensionToMime.put("json5", "application/json5");
|
||||
extensionToMime.put("jsx", "text/jsx");
|
||||
extensionToMime.put("jxr", "image/jxr");
|
||||
extensionToMime.put("kar", "audio/midi");
|
||||
extensionToMime.put("ktx", "image/ktx");
|
||||
extensionToMime.put("less", "text/less");
|
||||
extensionToMime.put("list", "text/plain");
|
||||
extensionToMime.put("litcoffee", "text/coffeescript");
|
||||
extensionToMime.put("log", "text/plain");
|
||||
extensionToMime.put("m1v", "video/mpeg");
|
||||
extensionToMime.put("m21", "application/mp21");
|
||||
extensionToMime.put("m2a", "audio/mpeg");
|
||||
extensionToMime.put("m2v", "video/mpeg");
|
||||
extensionToMime.put("m3a", "audio/mpeg");
|
||||
extensionToMime.put("m4a", "audio/mp4");
|
||||
extensionToMime.put("m4p", "application/mp4");
|
||||
extensionToMime.put("man", "text/troff");
|
||||
extensionToMime.put("manifest", "text/cache-manifest");
|
||||
extensionToMime.put("markdown", "text/markdown");
|
||||
extensionToMime.put("mathml", "application/mathml+xml");
|
||||
extensionToMime.put("md", "text/markdown");
|
||||
extensionToMime.put("mdx", "text/mdx");
|
||||
extensionToMime.put("me", "text/troff");
|
||||
extensionToMime.put("mesh", "model/mesh");
|
||||
extensionToMime.put("mft", "application/rpki-manifest");
|
||||
extensionToMime.put("mid", "audio/midi");
|
||||
extensionToMime.put("midi", "audio/midi");
|
||||
extensionToMime.put("mj2", "video/mj2");
|
||||
extensionToMime.put("mjp2", "video/mj2");
|
||||
extensionToMime.put("mjs", "application/javascript");
|
||||
extensionToMime.put("mml", "text/mathml");
|
||||
extensionToMime.put("mov", "video/quicktime");
|
||||
extensionToMime.put("mp2", "audio/mpeg");
|
||||
extensionToMime.put("mp21", "application/mp21");
|
||||
extensionToMime.put("mp2a", "audio/mpeg");
|
||||
extensionToMime.put("mp3", "audio/mpeg");
|
||||
extensionToMime.put("mp4", "video/mp4");
|
||||
extensionToMime.put("mp4a", "audio/mp4");
|
||||
extensionToMime.put("mp4s", "application/mp4");
|
||||
extensionToMime.put("mp4v", "video/mp4");
|
||||
extensionToMime.put("mpe", "video/mpeg");
|
||||
extensionToMime.put("mpeg", "video/mpeg");
|
||||
extensionToMime.put("mpg", "video/mpeg");
|
||||
extensionToMime.put("mpg4", "video/mp4");
|
||||
extensionToMime.put("mpga", "audio/mpeg");
|
||||
extensionToMime.put("mrc", "application/marc");
|
||||
extensionToMime.put("ms", "text/troff");
|
||||
extensionToMime.put("msh", "model/mesh");
|
||||
extensionToMime.put("n3", "text/n3");
|
||||
extensionToMime.put("oga", "audio/ogg");
|
||||
extensionToMime.put("ogg", "audio/ogg");
|
||||
extensionToMime.put("ogv", "video/ogg");
|
||||
extensionToMime.put("ogx", "application/ogg");
|
||||
extensionToMime.put("otf", "font/otf");
|
||||
extensionToMime.put("p10", "application/pkcs10");
|
||||
extensionToMime.put("p7c", "application/pkcs7-mime");
|
||||
extensionToMime.put("p7m", "application/pkcs7-mime");
|
||||
extensionToMime.put("p7s", "application/pkcs7-signature");
|
||||
extensionToMime.put("p8", "application/pkcs8");
|
||||
extensionToMime.put("pdf", "application/pdf");
|
||||
extensionToMime.put("pki", "application/pkixcmp");
|
||||
extensionToMime.put("pkipath", "application/pkix-pkipath");
|
||||
extensionToMime.put("png", "image/png");
|
||||
extensionToMime.put("ps", "application/postscript");
|
||||
extensionToMime.put("pskcxml", "application/pskc+xml");
|
||||
extensionToMime.put("qt", "video/quicktime");
|
||||
extensionToMime.put("rmi", "audio/midi");
|
||||
extensionToMime.put("rng", "application/xml");
|
||||
extensionToMime.put("roa", "application/rpki-roa");
|
||||
extensionToMime.put("roff", "text/troff");
|
||||
extensionToMime.put("rsd", "application/rsd+xml");
|
||||
extensionToMime.put("rss", "application/rss+xml");
|
||||
extensionToMime.put("rtf", "application/rtf");
|
||||
extensionToMime.put("rtx", "text/richtext");
|
||||
extensionToMime.put("s3m", "audio/s3m");
|
||||
extensionToMime.put("sgi", "image/sgi");
|
||||
extensionToMime.put("sgm", "text/sgml");
|
||||
extensionToMime.put("sgml", "text/sgml");
|
||||
extensionToMime.put("shex", "text/shex");
|
||||
extensionToMime.put("shtml", "text/html");
|
||||
extensionToMime.put("sil", "audio/silk");
|
||||
extensionToMime.put("silo", "model/mesh");
|
||||
extensionToMime.put("slim", "text/slim");
|
||||
extensionToMime.put("slm", "text/slim");
|
||||
extensionToMime.put("snd", "audio/basic");
|
||||
extensionToMime.put("spx", "audio/ogg");
|
||||
extensionToMime.put("stl", "model/stl");
|
||||
extensionToMime.put("styl", "text/stylus");
|
||||
extensionToMime.put("stylus", "text/stylus");
|
||||
extensionToMime.put("svg", "image/svg+xml");
|
||||
extensionToMime.put("svgz", "image/svg+xml");
|
||||
extensionToMime.put("t", "text/troff");
|
||||
extensionToMime.put("t38", "image/t38");
|
||||
extensionToMime.put("text", "text/plain");
|
||||
extensionToMime.put("tfx", "image/tiff-fx");
|
||||
extensionToMime.put("tif", "image/tiff");
|
||||
extensionToMime.put("tiff", "image/tiff");
|
||||
extensionToMime.put("tr", "text/troff");
|
||||
extensionToMime.put("ts", "video/mp2t");
|
||||
extensionToMime.put("tsv", "text/tab-separated-values");
|
||||
extensionToMime.put("ttc", "font/collection");
|
||||
extensionToMime.put("ttf", "font/ttf");
|
||||
extensionToMime.put("ttl", "text/turtle");
|
||||
extensionToMime.put("txt", "text/plain");
|
||||
extensionToMime.put("uri", "text/uri-list");
|
||||
extensionToMime.put("uris", "text/uri-list");
|
||||
extensionToMime.put("urls", "text/uri-list");
|
||||
extensionToMime.put("vcard", "text/vcard");
|
||||
extensionToMime.put("vrml", "model/vrml");
|
||||
extensionToMime.put("vtt", "text/vtt");
|
||||
extensionToMime.put("war", "application/java-archive");
|
||||
extensionToMime.put("wasm", "application/wasm");
|
||||
extensionToMime.put("wav", "audio/wav");
|
||||
extensionToMime.put("weba", "audio/webm");
|
||||
extensionToMime.put("webm", "video/webm");
|
||||
extensionToMime.put("webmanifest", "application/manifest+json");
|
||||
extensionToMime.put("webp", "image/webp");
|
||||
extensionToMime.put("wmf", "image/wmf");
|
||||
extensionToMime.put("woff", "font/woff");
|
||||
extensionToMime.put("woff2", "font/woff2");
|
||||
extensionToMime.put("wrl", "model/vrml");
|
||||
extensionToMime.put("x3d", "model/x3d+xml");
|
||||
extensionToMime.put("x3db", "model/x3d+fastinfoset");
|
||||
extensionToMime.put("x3dbz", "model/x3d+binary");
|
||||
extensionToMime.put("x3dv", "model/x3d-vrml");
|
||||
extensionToMime.put("x3dvz", "model/x3d+vrml");
|
||||
extensionToMime.put("x3dz", "model/x3d+xml");
|
||||
extensionToMime.put("xaml", "application/xaml+xml");
|
||||
extensionToMime.put("xht", "application/xhtml+xml");
|
||||
extensionToMime.put("xhtml", "application/xhtml+xml");
|
||||
extensionToMime.put("xm", "audio/xm");
|
||||
extensionToMime.put("xml", "text/xml");
|
||||
extensionToMime.put("xsd", "application/xml");
|
||||
extensionToMime.put("xsl", "application/xml");
|
||||
extensionToMime.put("xslt", "application/xslt+xml");
|
||||
extensionToMime.put("yaml", "text/yaml");
|
||||
extensionToMime.put("yml", "text/yaml");
|
||||
extensionToMime.put("zip", "application/zip");
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class TestBrowser {
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_click_the_button() {
|
||||
void version_should_work() {
|
||||
if (isChromium)
|
||||
assertTrue(Pattern.matches("^\\d+\\.\\d+\\.\\d+\\.\\d+$", browser.version()));
|
||||
else
|
||||
|
||||
@@ -16,26 +16,40 @@
|
||||
|
||||
package com.microsoft.playwright;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestClick {
|
||||
private static Playwright playwright;
|
||||
private static Server server;
|
||||
private Browser browser;
|
||||
private boolean isChromium;
|
||||
private BrowserContext context;
|
||||
private Page page;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
static void createPlaywright() {
|
||||
playwright = Playwright.create();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void startServer() throws IOException {
|
||||
server = new Server(8907);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void stopServer() throws IOException {
|
||||
server.stop();
|
||||
server = null;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
browser = playwright.chromium().launch();
|
||||
BrowserType.LaunchOptions options = new BrowserType.LaunchOptions().withHeadless(false);
|
||||
browser = playwright.chromium().launch(options);
|
||||
isChromium = true;
|
||||
context = browser.newContext();
|
||||
page = context.newPage();
|
||||
@@ -47,9 +61,9 @@ public class TestClick {
|
||||
}
|
||||
|
||||
@Test
|
||||
void version_should_work() {
|
||||
// page.navigate(server.PREFIX + "/input/button.html");
|
||||
// page.click("button");
|
||||
// assertEquals("Clicked", page.evaluate("result"));
|
||||
void should_click_the_button() {
|
||||
page.navigate(server.PREFIX + "/input/button.html");
|
||||
page.click("button");
|
||||
assertEquals("Clicked", page.evaluate("result"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<style>
|
||||
body, html { margin: 0; padding: 0; }
|
||||
@keyframes move {
|
||||
from { marign-left: 0; }
|
||||
to { margin-left: 100px; }
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function addButton() {
|
||||
const button = document.createElement('button');
|
||||
button.textContent = 'Click me';
|
||||
button.style.animation = '3s linear move';
|
||||
button.style.animationIterationCount = 'infinite';
|
||||
button.addEventListener('click', () => window.clicked = true);
|
||||
document.body.appendChild(button);
|
||||
}
|
||||
|
||||
function stopButton(remove) {
|
||||
const button = document.querySelector('button');
|
||||
button.style.marginLeft = button.getBoundingClientRect().left + 'px';
|
||||
button.style.animation = '';
|
||||
if (remove)
|
||||
button.remove();
|
||||
}
|
||||
|
||||
let x = 0;
|
||||
function jump() {
|
||||
x += 300;
|
||||
const button = document.querySelector('button');
|
||||
button.style.marginLeft = x + 'px';
|
||||
}
|
||||
|
||||
function startJumping() {
|
||||
x = 0;
|
||||
const moveIt = () => {
|
||||
jump();
|
||||
requestAnimationFrame(moveIt);
|
||||
};
|
||||
setInterval(jump, 0);
|
||||
moveIt();
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Button test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="mouse-helper.js"></script>
|
||||
<button>Click target</button>
|
||||
<script>
|
||||
window.result = 'Was not clicked';
|
||||
window.offsetX = undefined;
|
||||
window.offsetY = undefined;
|
||||
window.pageX = undefined;
|
||||
window.pageY = undefined;
|
||||
window.shiftKey = undefined;
|
||||
window.pageX = undefined;
|
||||
window.pageY = undefined;
|
||||
window.bubbles = undefined;
|
||||
document.querySelector('button').addEventListener('click', e => {
|
||||
result = 'Clicked';
|
||||
offsetX = e.offsetX;
|
||||
offsetY = e.offsetY;
|
||||
pageX = e.pageX;
|
||||
pageY = e.pageY;
|
||||
shiftKey = e.shiftKey;
|
||||
bubbles = e.bubbles;
|
||||
cancelable = e.cancelable;
|
||||
composed = e.composed;
|
||||
}, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Selection Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<label for="agree">Remember Me</label>
|
||||
<input id="agree" type="checkbox">
|
||||
<script>
|
||||
window.result = {
|
||||
check: null,
|
||||
events: [],
|
||||
};
|
||||
|
||||
let checkbox = document.querySelector('input');
|
||||
|
||||
const events = [
|
||||
'change',
|
||||
'click',
|
||||
'dblclick',
|
||||
'input',
|
||||
'mousedown',
|
||||
'mouseenter',
|
||||
'mouseleave',
|
||||
'mousemove',
|
||||
'mouseout',
|
||||
'mouseover',
|
||||
'mouseup',
|
||||
];
|
||||
|
||||
for (let event of events) {
|
||||
checkbox.addEventListener(event, () => {
|
||||
if (['change', 'click', 'dblclick', 'input'].includes(event) === true) {
|
||||
result.check = checkbox.checked;
|
||||
}
|
||||
|
||||
result.events.push(event);
|
||||
}, false);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>File upload test</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/input/fileupload.html">
|
||||
<input type="file">
|
||||
<input type="submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Keyboard test</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea></textarea>
|
||||
<script>
|
||||
window.result = "";
|
||||
let textarea = document.querySelector('textarea');
|
||||
textarea.focus();
|
||||
textarea.addEventListener('keydown', event => {
|
||||
log('Keydown:', event.key, event.code, event.which, modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keypress', event => {
|
||||
log('Keypress:', event.key, event.code, event.which, event.charCode, modifiers(event));
|
||||
});
|
||||
textarea.addEventListener('keyup', event => {
|
||||
log('Keyup:', event.key, event.code, event.which, modifiers(event));
|
||||
});
|
||||
function modifiers(event) {
|
||||
let m = [];
|
||||
if (event.altKey)
|
||||
m.push('Alt')
|
||||
if (event.ctrlKey)
|
||||
m.push('Control');
|
||||
if (event.shiftKey)
|
||||
m.push('Shift')
|
||||
return '[' + m.join(' ') + ']';
|
||||
}
|
||||
function log(...args) {
|
||||
console.log.apply(console, args);
|
||||
result += args.join(' ') + '\n';
|
||||
}
|
||||
function getResult() {
|
||||
let temp = result.trim();
|
||||
result = "";
|
||||
return temp;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,62 @@
|
||||
// This injects a box into the page that moves with the mouse;
|
||||
// Useful for debugging
|
||||
(function(){
|
||||
const box = document.createElement('div');
|
||||
box.classList.add('mouse-helper');
|
||||
const styleElement = document.createElement('style');
|
||||
styleElement.innerHTML = `
|
||||
.mouse-helper {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(0,0,0,.4);
|
||||
border: 1px solid white;
|
||||
border-radius: 10px;
|
||||
margin-left: -10px;
|
||||
margin-top: -10px;
|
||||
transition: background .2s, border-radius .2s, border-color .2s;
|
||||
}
|
||||
.mouse-helper.button-1 {
|
||||
transition: none;
|
||||
background: rgba(0,0,0,0.9);
|
||||
}
|
||||
.mouse-helper.button-2 {
|
||||
transition: none;
|
||||
border-color: rgba(0,0,255,0.9);
|
||||
}
|
||||
.mouse-helper.button-3 {
|
||||
transition: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.mouse-helper.button-4 {
|
||||
transition: none;
|
||||
border-color: rgba(255,0,0,0.9);
|
||||
}
|
||||
.mouse-helper.button-5 {
|
||||
transition: none;
|
||||
border-color: rgba(0,255,0,0.9);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(styleElement);
|
||||
document.body.appendChild(box);
|
||||
document.addEventListener('mousemove', event => {
|
||||
box.style.left = event.pageX + 'px';
|
||||
box.style.top = event.pageY + 'px';
|
||||
updateButtons(event.buttons);
|
||||
}, true);
|
||||
document.addEventListener('mousedown', event => {
|
||||
updateButtons(event.buttons);
|
||||
box.classList.add('button-' + event.which);
|
||||
}, true);
|
||||
document.addEventListener('mouseup', event => {
|
||||
updateButtons(event.buttons);
|
||||
box.classList.remove('button-' + event.which);
|
||||
}, true);
|
||||
function updateButtons(buttons) {
|
||||
for (let i = 0; i < 5; i++)
|
||||
box.classList.toggle('button-' + i, buttons & (1 << i));
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rotated button test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="mouse-helper.js"></script>
|
||||
<button onclick="clicked();">Click target</button>
|
||||
<style>
|
||||
button {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
window.result = 'Was not clicked';
|
||||
function clicked() {
|
||||
result = 'Clicked';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Scrollable test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src='mouse-helper.js'></script>
|
||||
<script>
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let button = document.createElement('button');
|
||||
button.textContent = i + ': not clicked';
|
||||
button.id = 'button-' + i;
|
||||
button.onclick = () => button.textContent = 'clicked';
|
||||
button.oncontextmenu = event => {
|
||||
event.preventDefault();
|
||||
button.textContent = 'context menu';
|
||||
}
|
||||
document.body.appendChild(button);
|
||||
document.body.appendChild(document.createElement('br'));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Selection Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<select>
|
||||
<option value="black">Black</option>
|
||||
<option value="blue">Blue</option>
|
||||
<option value="brown">Brown</option>
|
||||
<option value="cyan">Cyan</option>
|
||||
<option value="gray">Gray</option>
|
||||
<option value="green">Green</option>
|
||||
<option value="indigo">Indigo</option>
|
||||
<option value="magenta">Magenta</option>
|
||||
<option value="orange">Orange</option>
|
||||
<option value="pink">Pink</option>
|
||||
<option value="purple">Purple</option>
|
||||
<option value="red">Red</option>
|
||||
<option value="violet">Violet</option>
|
||||
<option value="white" id="whiteOption">White</option>
|
||||
<option value="yellow">Yellow</option>
|
||||
</select>
|
||||
<script>
|
||||
window.result = {
|
||||
onInput: null,
|
||||
onChange: null,
|
||||
onBubblingChange: null,
|
||||
onBubblingInput: null,
|
||||
};
|
||||
|
||||
let select = document.querySelector('select');
|
||||
|
||||
function makeEmpty() {
|
||||
for (let i = select.options.length - 1; i >= 0; --i) {
|
||||
select.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
function makeMultiple() {
|
||||
select.setAttribute('multiple', true);
|
||||
}
|
||||
|
||||
select.addEventListener('input', () => {
|
||||
result.onInput = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
select.addEventListener('change', () => {
|
||||
result.onChange = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
document.body.addEventListener('input', () => {
|
||||
result.onBubblingInput = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
|
||||
document.body.addEventListener('change', () => {
|
||||
result.onBubblingChange = Array.from(select.querySelectorAll('option:checked')).map((option) => {
|
||||
return option.value;
|
||||
});
|
||||
}, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Textarea test</title>
|
||||
</head>
|
||||
<body>
|
||||
<textarea spellcheck="false"></textarea>
|
||||
<input></input>
|
||||
<div contenteditable="true"></div>
|
||||
<div class="plain">Plain div</div>
|
||||
<script src='mouse-helper.js'></script>
|
||||
<script>
|
||||
window.result = '';
|
||||
let textarea = document.querySelector('textarea');
|
||||
textarea.addEventListener('input', () => result = textarea.value, false);
|
||||
let input = document.querySelector('input');
|
||||
input.addEventListener('input', () => result = input.value, false);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Touch test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="mouse-helper.js"></script>
|
||||
<button onclick="clicked();">Click target</button>
|
||||
<script>
|
||||
window.result = [];
|
||||
const button = document.querySelector('button');
|
||||
button.style.height = '200px';
|
||||
button.style.width = '200px';
|
||||
button.focus();
|
||||
button.addEventListener('touchstart', event => {
|
||||
log('Touchstart:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
|
||||
});
|
||||
button.addEventListener('touchend', event => {
|
||||
log('Touchend:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
|
||||
});
|
||||
button.addEventListener('touchmove', event => {
|
||||
log('Touchmove:', ...Array.from(event.changedTouches).map(touch => touch.identifier));
|
||||
});
|
||||
function log(...args) {
|
||||
console.log.apply(console, args);
|
||||
result.push(args.join(' '));
|
||||
}
|
||||
function getResult() {
|
||||
let temp = result;
|
||||
result = [];
|
||||
return temp;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user