test: convert remaining page.evaluate tests (#62)

This commit is contained in:
Yury Semikhatsky 2020-10-30 14:33:04 -07:00 committed by GitHub
parent 4198b39b83
commit 602406b53b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 418 additions and 8 deletions

View File

@ -152,8 +152,9 @@ class Serialization {
return (T) Double.valueOf(Double.POSITIVE_INFINITY);
case "-Infinity":
return (T) Double.valueOf(Double.NEGATIVE_INFINITY);
case "-0":
return (T) Double.valueOf(-0);
case "-0": {
return (T) Double.valueOf(-0.0);
}
case "NaN":
return (T) Double.valueOf(Double.NaN);
default:

View File

@ -42,8 +42,8 @@ public class TestPageEvaluate extends TestBase {
@Test
void shouldTransfer0() {
Object result = page.evaluate("a => a", -0);
assertTrue((Integer) result == -0);
Object result = page.evaluate("a => a", -0.0);
assertEquals(Double.NEGATIVE_INFINITY, 1 / (Double) result);
}
@Test
@ -63,7 +63,7 @@ public class TestPageEvaluate extends TestBase {
Map<String, ?> value = mapOf(
"infinity", Double.POSITIVE_INFINITY,
"nInfinity", Double.NEGATIVE_INFINITY,
"nZero", -0,
"nZero", -0.0,
"nan", Double.NaN
);
Object result = page.evaluate("value => value", value);
@ -81,8 +81,8 @@ public class TestPageEvaluate extends TestBase {
assertEquals(Double.POSITIVE_INFINITY, result);
}
{
Object result = page.evaluate("value => Promise.resolve(value)", -0);
assertEquals(-0, result);
Object result = page.evaluate("value => Promise.resolve(value)", -0.0);
assertEquals(Double.NEGATIVE_INFINITY, 1 / (Double) result);
}
}
@ -91,7 +91,7 @@ public class TestPageEvaluate extends TestBase {
Map<String, ?> value = mapOf(
"infinity", Double.POSITIVE_INFINITY,
"nInfinity", Double.NEGATIVE_INFINITY,
"nZero", -0,
"nZero", -0.0,
"nan", Double.NaN
);
Object result = page.evaluate("value => Promise.resolve(value)", value);
@ -212,4 +212,413 @@ public class TestPageEvaluate extends TestBase {
assertTrue(e.getMessage().contains("not_existing_object"));
}
}
@Test
void shouldSupportThrownStringsAsErrorMessages() {
try {
page.evaluate("() => { throw 'qwerty'; }");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("qwerty"));
}
}
@Test
void shouldSupportThrownNumbersAsErrorMessages() {
try {
page.evaluate("() => { throw 100500; }");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("100500"));
}
}
@Test
void shouldReturnComplexObjects() {
Map<String, ?> object = mapOf("foo", "bar!");
Object result = page.evaluate("a => a", object);
assertFalse(object == result);
assertEquals(object, result);
}
@Test
void shouldReturnNaN() {
Object result = page.evaluate("() => NaN");
assertEquals(Double.NaN, result);
}
@Test
void shouldReturn0() {
Object result = page.evaluate("() => -0");
assertEquals(Double.NEGATIVE_INFINITY, 1 / (Double) result);
}
@Test
void shouldReturnInfinity() {
Object result = page.evaluate("() => Infinity");
assertEquals(Double.POSITIVE_INFINITY, result);
}
@Test
void shouldReturnNegativeInfinity() {
Object result = page.evaluate("() => -Infinity");
assertEquals(Double.NEGATIVE_INFINITY, result);
}
@Test
void shouldWorkWithOverwrittenPromise() {
page.evaluate("() => {\n" +
" const originalPromise = window.Promise;\n" +
" class Promise2 {\n" +
" static all(arg) {\n" +
" return wrap(originalPromise.all(arg));\n" +
" }\n" +
" static race(arg) {\n" +
" return wrap(originalPromise.race(arg));\n" +
" }\n" +
" static resolve(arg) {\n" +
" return wrap(originalPromise.resolve(arg));\n" +
" }\n" +
" constructor(f) {\n" +
" this._promise = new originalPromise(f);\n" +
" }\n" +
" then(f, r) {\n" +
" return wrap(this._promise.then(f, r));\n" +
" }\n" +
" catch(f) {\n" +
" return wrap(this._promise.catch(f));\n" +
" }\n" +
" finally(f) {\n" +
" return wrap(this._promise.finally(f));\n" +
" }\n" +
" }\n" +
" const wrap = p => {\n" +
" const result = new Promise2(() => { });\n" +
" result._promise = p;\n" +
" return result;\n" +
" };\n" +
" window.Promise = Promise2;\n" +
" window['__Promise2'] = Promise2;\n" +
" }");
// Sanity check.
assertEquals(true, page.evaluate("() => {\n" +
" const p = Promise.all([Promise.race([]), new Promise(() => { }).then(() => { })]);\n" +
" return p instanceof window['__Promise2'];\n" +
"}"));
// Now, the new promise should be awaitable.
assertEquals(42, page.evaluate("() => Promise.resolve(42)"));
}
void shouldThrowWhenPassedMoreThanOneParameter() {
// Not applicable.
}
void shouldAcceptUndefinedAsOneOfMultipleParameters() {
// Not applicable
}
@Test
void shouldProperlySerializeUndefinedArguments() {
// Not applicable
}
@Test
void shouldProperlySerializeUndefinedFields() {
assertEquals(mapOf("a", null), page.evaluate("() => ({ a: undefined })"));
}
@Test
void shouldReturnUndefinedProperties() {
Object value = page.evaluate("() => ({ a: undefined })");
assertEquals(mapOf("a", null), value);
}
@Test
void shouldProperlySerializeNullArguments() {
assertEquals(null, page.evaluate("x => x", null));
}
@Test
void shouldProperlySerializeNullFields() {
assertEquals(mapOf("a", null), page.evaluate("() => ({ a: null })"));
}
@Test
void shouldReturnUndefinedForNonSerializableObjects() {
assertEquals(null, page.evaluate("() => window"));
}
@Test
void shouldFailForCircularObject() {
Object result = page.evaluate("() => {\n" +
" const a = {};\n" +
" const b = { a };\n" +
" a.b = b;\n" +
" return a;\n" +
"}");
assertNull(result);
}
@Test
void shouldBeAbleToThrowATrickyError() {
JSHandle windowHandle = page.evaluateHandle("() => window");
String errorText = null;
try {
windowHandle.jsonValue();
fail("did not throw");
} catch (PlaywrightException e) {
errorText = e.getMessage();
}
assertNotNull(errorText);
try {
page.evaluate("errorText => {\n" +
" throw new Error(errorText);\n" +
"}", errorText);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains(errorText));
}
}
@Test
void shouldAcceptAString() {
Object result = page.evaluate("1 + 2");
assertEquals(3, result);
}
@Test
void shouldAcceptAStringWithSemiColons() {
Object result = page.evaluate("1 + 5;");
assertEquals(6, result);
}
@Test
void shouldAcceptAStringWithComments() {
Object result = page.evaluate("2 + 5;\n// do some math!");
assertEquals(7, result);
}
@Test
void shouldAcceptElementHandleAsAnArgument() {
page.setContent("<section>42</section>");
ElementHandle element = page.querySelector("section");
Object text = page.evaluate("e => e.textContent", element);
assertEquals("42", text);
}
@Test
void shouldThrowIfUnderlyingElementWasDisposed() {
page.setContent("<section>39</section>");
ElementHandle element = page.querySelector("section");
assertNotNull(element);
element.dispose();
try {
page.evaluate("e => e.textContent", element);
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("JSHandle is disposed"));
}
}
@Test
void shouldSimulateAUserGesture() {
assertEquals(true, page.evaluate("() => {\n" +
" document.body.appendChild(document.createTextNode('test'));\n" +
" document.execCommand('selectAll');\n" +
" return document.execCommand('copy');\n" +
"}"));
}
@Test
void shouldThrowANiceErrorAfterANavigation() {
try {
Deferred<Response> navigation = page.waitForNavigation();
page.evaluate("() => {\n" +
" const promise = new Promise(f => window['__resolve'] = f);\n" +
" window.location.reload();\n" +
" setTimeout(() => window['__resolve'](42), 1000);\n" +
" return promise;\n" +
"}");
navigation.get();
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("navigation"));
}
}
@Test
void shouldNotThrowAnErrorWhenEvaluationDoesANavigation() {
page.navigate(server.PREFIX + "/one-style.html");
Object result = page.evaluate("() => {\n" +
" window.location.href = '/empty.html';\n" +
" return [42];\n" +
"}");
assertEquals(asList(42), result);
}
@Test
void shouldNotThrowAnErrorWhenEvaluationDoesASynchronousNavigationAndReturnsAnObject() {
// TODO: test.fixme(browserName === "webkit");
// It is imporant to be on about:blank for sync reload.
Object result = page.evaluate("() => {\n" +
" window.location.reload();\n" +
" return { a: 42 };\n" +
"}");
assertEquals(mapOf("a", 42), result);
}
@Test
void shouldNotThrowAnErrorWhenEvaluationDoesASynchronousNavigationAndReturnsUndefined() {
// It is imporant to be on about:blank for sync reload.
Object result = page.evaluate("() => {\n" +
" window.location.reload();\n" +
" return undefined;\n" +
"}");
assertEquals(null, result);
}
@Test
void shouldTransfer100MbOfDataFromPageToNodeJs() {
// This is too slow with wire.
Object a = page.evaluate("() => Array(100 * 1024 * 1024 + 1).join('a')");
String str = (String) a;
assertEquals(100 * 1024 * 1024, str.length());
for (int i = 0; i < str.length(); i++) {
if ('a' != str.charAt(i)) {
fail("Unexpected char at position " + i);
}
}
}
@Test
void shouldThrowErrorWithDetailedInformationOnExceptionInsidePromise() {
try {
page.evaluate("() => new Promise(() => {\n" +
" throw new Error('Error in promise');\n" +
"})");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Error in promise"));
}
}
@Test
void shouldWorkEvenWhenJSONIsSetToNull() {
page.evaluate("() => { window.JSON.stringify = null; window.JSON = null; }");
Object result = page.evaluate("() => ({ abc: 123 })");
assertEquals(mapOf("abc", 123), result);
}
@Test
void shouldAwaitPromiseFromPopup() {
// Something is wrong about the way Firefox waits for the chained promise
page.navigate(server.EMPTY_PAGE);
Object result = page.evaluate("() => {\n" +
" const win = window.open('about:blank');\n" +
" return new win['Promise'](f => f(42));\n" +
"}");
assertEquals(42, result);
}
@Test
void shouldWorkWithNewFunctionAndCSP() {
server.setCSP("/empty.html", "script-src " + server.PREFIX);
page.navigate(server.PREFIX + "/empty.html");
assertEquals(true, page.evaluate("() => new Function('return true')()"));
}
@Test
void shouldWorkWithNonStrictExpressions() {
assertEquals(3.14, page.evaluate("() => {\n" +
" y = 3.14;\n" +
" return y;\n" +
"}"));
}
@Test
void shouldRespectUseStrictExpression() {
try {
page.evaluate("() => {\n" +
" 'use strict';\n" +
" // @ts-ignore\n" +
" variableY = 3.14;\n" +
" // @ts-ignore\n" +
" return variableY;\n" +
"}");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("variableY"));
}
}
@Test
void shouldNotLeakUtilityScript() {
assertEquals(true, page.evaluate("() => this === window"));
}
@Test
void shouldNotLeakHandles() {
try {
page.evaluate("handles.length");
fail("did not throw");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains(" handles"));
}
}
@Test
void shouldWorkWithCSP() {
server.setCSP("/empty.html", "script-src 'self'");
page.navigate(server.EMPTY_PAGE);
assertEquals(4, page.evaluate("() => 2 + 2"));
}
@Test
void shouldEvaluateException() {
try {
page.evaluate("() => {\n" +
" return (function functionOnStack() {\n" +
" return new Error('error message');\n" +
" })();\n" +
"}");
} catch (PlaywrightException e) {
assertTrue(e.getMessage().contains("Error: error message"));
assertTrue(e.getMessage().contains("functionOnStack"));
}
}
@Test
void shouldEvaluateException2() {
Object error = page.evaluate("new Error('error message')");
assertTrue(((String) error).contains("Error: error message"));
}
void shouldEvaluateDate() {
// TODO: Date values are not supported in java.
}
void shouldRoundtripDate() {
// TODO: Date values are not supported in java.
}
void shouldRoundtripRegex() {
// Not applicable
}
void shouldJsonValueDate() {
// TODO: Date values are not supported in java.
}
@Test
void shouldNotUseToJSONWhenEvaluating() {
Object result = page.evaluate("() => ({ toJSON: () => 'string', data: 'data' })");
assertEquals(mapOf("data", "data", "toJSON", emptyMap()), result);
}
@Test
void shouldNotUseToJSONInJsonValue() {
JSHandle resultHandle = page.evaluateHandle("() => ({ toJSON: () => 'string', data: 'data' })");
assertEquals(mapOf("data", "data", "toJSON", emptyMap()), resultHandle.jsonValue());
}
}