blob: 897384288ecafd235770bc84220da1b494efb7f2 [file] [log] [blame]
<!DOCTYPE HTML>
<html>
<script src='test.js'></script>
<script src='call_function.js'></script>
<script>
function wrap(value) {
return jsonSerialize(value, []);
}
function unwrap(value, opt_cache) {
return jsonDeserialize(value, [], opt_cache);
}
var initialCache = getPageCache().cache_;
function clearCache() {
getPageCache().cache_ = Object.create(initialCache);
}
function isValidUUID(uuid) {
assertEquals(36, uuid.length);
var list = uuid.split("-").map(function(x) {return x.length;});
assertEquals(5, list.length);
assertEquals(8, list[0]);
assertEquals(4, list[1]);
assertEquals(4, list[2]);
assertEquals(4, list[3]);
assertEquals(12, list[4]);
assert(/[a-z0-9-]{36}/.test(uuid));
}
function testUUID() {
var uuids = {}
for (var i = 0; i < 100; i++) {
var uuid = generateUUID();
isValidUUID(uuid);
assertEquals(null, uuids[uuid]);
uuids[uuid] = 1;
}
}
function testCallFunctionNoArgs(runner) {
clearCache();
callFunction(function() { return 1; }, []).then((result) => {
assertEquals(0, result.status);
assertEquals(1, result.value);
runner.continueTesting();
});
runner.waitForAsync();
}
function testCallFunctionThrows(runner) {
clearCache();
let allComplete = 0;
callFunction(function() { throw new Error('fake error'); },
[]).then((result) => {
assertEquals(StatusCode.JAVA_SCRIPT_ERROR, result.status);
assertEquals('fake error', result.value);
if (allComplete)
runner.continueTesting();
allComplete += 1;
});
callFunction(function() {
var e = new Error('fake error');
e.code = 77;
e.message = 'CUSTOM';
throw e;
}, []).then((result) => {
assertEquals(77, result.status);
assertEquals('CUSTOM', result.value);
if (allComplete)
runner.continueTesting();
allComplete += 1;
});
runner.waitForAsync();
}
function testCallFunctionArgs(runner) {
clearCache();
function func(primitive, elem) {
return [primitive, elem.querySelector('div')];
}
callFunction(func, [1, wrap(document)]).then((result) => {
assertEquals(0, result.status);
assertEquals(1, result.value[0]);
const cache = getPageCache();
assertEquals(document.querySelector('div'), unwrap(result.value[1], cache));
runner.continueTesting();
});
runner.waitForAsync();
}
function testCallFunctionArgsUnwrappedReturn(runner) {
clearCache();
function func(elem) {
return elem.querySelector('div');
}
callFunction(func, [wrap(document)], false, true).then((result) => {
assertEquals(document.querySelector('div'), result);
runner.continueTesting();
});
runner.waitForAsync();
}
function testCacheWrap() {
clearCache();
assertEquals(1, wrap(1));
assertEquals(1, unwrap(1));
assertEquals("1", wrap("1"));
assertEquals("1", unwrap("1"));
assertEquals(false, wrap(false));
assertEquals(false, unwrap(false));
assertEquals(null, wrap(null));
assertEquals(null, unwrap(null));
assertEquals(undefined, wrap(undefined));
assertEquals(undefined, unwrap(undefined));
var cache = getPageCache();
var arr = [1, new Array(1, new Object({a: 1, b: {a: 1, b: {}, c: 3}}), 3)];
var originalJson = JSON.stringify(arr);
arr[1][1].b.b[ELEMENT_KEY] = cache.idPrefix_ + '-' + cache.nextId_;
var wrappedJson = JSON.stringify(arr);
arr[1][1].b.b = document;
assertEquals(wrappedJson, JSON.stringify(wrap(arr)));
var unwrapped = unwrap(JSON.parse(wrappedJson), cache);
assertEquals(document, unwrapped[1][1].b.b);
unwrapped[1][1].b.b = {};
assertEquals(originalJson, JSON.stringify(unwrapped));
}
function testObjectWithLengthProperty() {
clearCache();
let obj = {length: 200};
assertEquals(200, wrap({length: 200})['length'])
assertEquals(JSON.stringify(obj), JSON.stringify(wrap({length: 200})))
obj = {bar: 'foo', bazz: {length: 150}};
let wrappedObj = wrap(obj);
assertEquals('foo', wrappedObj['bar'])
assertEquals(150, wrappedObj['bazz']['length'])
assertEquals(JSON.stringify(obj), JSON.stringify(wrappedObj));
let unwrappedObj = unwrap(obj);
assertEquals('foo', unwrappedObj['bar'])
assertEquals(150, unwrappedObj['bazz']['length'])
assertEquals(JSON.stringify(obj), JSON.stringify(unwrappedObj));
}
function testCacheDoubleWrap() {
clearCache();
assertEquals(wrap(document)[ELEMENT_KEY], wrap(document)[ELEMENT_KEY]);
}
function testCacheUnwrapThrows() {
clearCache();
try {
var wrapped = {};
wrapped[ELEMENT_KEY] = '1';
unwrap(wrapped, getPageCache());
assert(false);
} catch (e) {
}
}
function testCacheQuerySelector() {
clearCache();
var cache = getPageCache();
assertEquals(document.querySelector('div'),
unwrap(wrap(document.querySelector('div')), cache));
assertEquals(document.querySelectorAll('div')[0],
unwrap(wrap(document.querySelectorAll('div')), cache)[0]);
}
function testCacheStaleRef() {
clearCache();
var cache = getPageCache();
var img = document.createElement('img');
document.body.appendChild(img);
var wrappedImg = wrap(img);
document.body.removeChild(img);
try {
unwrap(wrappedImg, cache);
assert(false);
} catch (e) {
assertEquals(StatusCode.STALE_ELEMENT_REFERENCE, e.code);
}
}
function testCallFunctionWithShadowHost(runner) {
clearCache();
// Set up something in the shadow DOM.
var host = document.body.appendChild(document.createElement('div'));
var root = host.attachShadow({ mode: 'open' });
var shadowDiv = root.appendChild(document.createElement('div'));
function func(element) {
return element;
}
var wrappedHost = wrap(host);
callFunction(func, [wrappedHost]).then((result) => {
assertEquals(0, result.status);
assertEquals(wrappedHost['ELEMENT'], result.value['ELEMENT']);
var cache = getPageCache();
assertEquals(host, unwrap(result.value, cache));
document.body.removeChild(host);
runner.continueTesting();
});
runner.waitForAsync();
}
function testCallFunctionWithShadowRoot(runner) {
clearCache();
// Set up something in the shadow DOM.
var host = document.body.appendChild(document.createElement('div'));
var root = host.attachShadow({ mode: 'open' });
var shadowDiv = root.appendChild(document.createElement('div'));
function func(element) {
return element;
}
var wrappedHost = wrap(host);
var wrappedRoot = wrap(root);
// Should handle shadow root as an argument.
callFunction(func, [wrappedRoot]).then((result) => {
assertEquals(0, result.status);
assertEquals(wrappedRoot['ELEMENT'], result.value['ELEMENT']);
var cache = getPageCache();
assertEquals(root, unwrap(result.value, cache));
document.body.removeChild(host);
runner.continueTesting();
});
runner.waitForAsync();
}
function testCacheWithShadowDomAttached() {
clearCache();
const pageCache = getPageCache();
// Set up something in the shadow DOM.
var host = document.body.appendChild(document.createElement('div'));
var root = host.attachShadow({ mode: 'open' });
var shadowDiv = root.appendChild(document.createElement('div'));
// Test with attached element in shadow DOM.
var wrappedDiv = wrap(shadowDiv);
var unwrappedDiv = unwrap(wrappedDiv, pageCache);
assertEquals(shadowDiv, unwrappedDiv);
document.body.removeChild(host);
}
function testCacheWithShadowDomDetachedChild() {
clearCache();
// Set up something in the shadow DOM.
var host = document.body.appendChild(document.createElement('div'));
var root = host.attachShadow({ mode: 'open' });
var shadowDiv = root.appendChild(document.createElement('div'));
// Test with detached element in shadow DOM.
var wrappedDiv = wrap(shadowDiv);
root.removeChild(shadowDiv);
var rootCache = getPageCache();
try {
unwrap(wrappedDiv, rootCache);
assert(false);
} catch (e) {
assertEquals(StatusCode.STALE_ELEMENT_REFERENCE, e.code);
}
document.body.removeChild(host);
}
// Verify callFunction works when Object.prototype has user-defined functions.
// (https://crbug.com/chromedriver/3074)
function testCallWithFunctionInObject(runner) {
clearCache();
Object.prototype.f = () => {};
function func(arg) {
return { bar: arg };
}
callFunction(func, [{ foo: 1 }]).then((result) => {
assertEquals(1, result.value.bar.foo);
delete Object.prototype.f;
runner.continueTesting();
});
runner.waitForAsync();
}
// Verify array serialization works when Array.prototype.toJSON is defined.
// (https://crbug.com/chromedriver/3084)
function testCallWithArrayToJSON(runner) {
clearCache();
Array.prototype.toJSON = () => '["testing"]';
function func() {
return [1, 2, 3];
}
callFunction(func, []).then((result) => {
assert(result.value instanceof Array);
assertEquals(result.value.length, 3);
assertEquals(result.value[2], 3);
delete Array.prototype.toJSON;
runner.continueTesting();
});
runner.waitForAsync();
}
function testCallWithModifiedObjectProto(runner) {
var callCount = 0;
Object.defineProperty(Object.prototype, 'f', {
enumerable: true,
configurable: true,
get: function() {
callCount += 1;
}
});
callFunction(function() {}, []).then(() => {
try {
assertEquals(callCount, 0);
runner.continueTesting();
} finally {
delete Object.prototype.f;
}
});
runner.waitForAsync();
}
</script>
<body>
<div><span></span></div>
</body>
</html>