const xulApp = require("xul-app");
const proxy = require("content/content-proxy");
const hiddenFrames = require("hidden-frame");
exports.testProxy = function (test) {
let html = '' +
'' +
'' +
'';
let url = 'data:text/html,' + encodeURI(html);
test.waitUntilDone();
let hiddenFrame = hiddenFrames.add(hiddenFrames.HiddenFrame({
onReady: function () {
function onDOMReady() {
hiddenFrame.element.removeEventListener("DOMContentLoaded", onDOMReady,
false);
let win = hiddenFrame.element.contentWindow.wrappedJSObject;
test.assert(win.documentGlobal, "`win` object is unwrapped");
let wrapped = proxy.create(win);
let document = wrapped.document;
let body = document.body;
// Ensure that postMessage is working correctly.
// 1/ Check across documents with an iframe
let ifWindow = win.document.getElementById("iframe").contentWindow;
// Listen without proxies, to check that it will work in regular case
// simulate listening from a web document.
ifWindow.addEventListener("message", function listener(event) {
ifWindow.removeEventListener("message", listener, false);
// As we are in system principal, event is an XrayWrapper
test.assertEqual(event.source.wrappedJSObject, ifWindow,
"event.source is the iframe window");
test.assertEqual(event.origin, "null", "origin is null");
test.assertEqual(event.data, "ok", "message data is correct");
}, false);
// Dispatch a message from the content script proxy
document.getElementById("iframe").contentWindow.postMessage("ok", "*");
test.assertEqual(wrapped.postMessage, wrapped.postMessage,
"verify that we doesn't generate multiple functions for the same method");
// Test objects being given as event listener
let input = document.getElementById("input2");
let myClickListener = {
called: false,
handleEvent: function(event) {
test.assertEqual(this, myClickListener, "`this` is the original object");
test.assert(!this.called, "called only once");
this.called = true;
test.assertNotEqual(event.valueOf(), event.valueOf(proxy.UNWRAP_ACCESS_KEY), "event is wrapped");
test.assertEqual(event.target, input, "event.target is the wrapped window");
}
};
wrapped.addEventListener("click", myClickListener, true);
input.click();
wrapped.removeEventListener("click", myClickListener, true);
// Verify object as DOM event listener
let myMessageListener = {
called: false,
handleEvent: function(event) {
wrapped.removeEventListener("message", myMessageListener, true);
test.assertEqual(this, myMessageListener, "`this` is the original object");
test.assert(!this.called, "called only once");
this.called = true;
test.assertNotEqual(event.valueOf(), event.valueOf(proxy.UNWRAP_ACCESS_KEY), "event is wrapped");
test.assertEqual(event.target, wrapped, "event.target is the wrapped window");
test.assertEqual(event.source, wrapped, "event.source is the wrapped window");
test.assertEqual(event.origin, "null", "origin is null");
test.assertEqual(event.data, "ok", "message data is correct");
}
};
wrapped.addEventListener("message", myMessageListener, true);
wrapped.postMessage("ok", '*');
// RightJS is hacking around String.prototype, and do similar thing:
// Pass `this` from a String prototype method.
// It is funny because typeof this == "object"!
// So that when we pass `this` to a native method,
// our proxy code can fail on another even more crazy thing.
// See following test to see what fails around proxies.
String.prototype.update = function () {
test.assertEqual(typeof this, "object");
test.assertEqual(this.toString(), "input");
return document.querySelectorAll(this);
};
test.assertEqual("input".update().length, 3, "String.prototype overload works");
// Proxy - toString error
let originalString = "string";
let p = Proxy.create({
get: function(receiver, name) {
if (name == "binded")
return originalString.toString.bind(originalString);
return originalString[name];
}
});
test.assertRaises(function () {
p.toString();
},
/String.prototype.toString called on incompatible Proxy/,
"toString can't be called with this being the proxy");
test.assertEqual(p.binded(), "string", "but it works if we bind this to the original string");
// Check mozMatchesSelector XrayWrappers bug:
// mozMatchesSelector returns bad results when we are not calling it from the node itself
// SEE BUG 658909: mozMatchesSelector returns incorrect results with XrayWrappers
test.assert(document.createElement( "div" ).mozMatchesSelector("div"),
"mozMatchesSelector works while being called from the node");
test.assert(document.documentElement.mozMatchesSelector.call(
document.createElement( "div" ),
"div"
),
"mozMatchesSelector works while being called from a " +
"function reference to " +
"document.documentElement.mozMatchesSelector.call");
// If we add a "____proxy" attribute on XrayWrappers in order to store
// the related proxy to create an unique proxy for each wrapper;
// we end up setting this attribute to prototype objects :x
// And so, instances created with such prototype will be considered
// as equal to the prototype ...
// // Internal method that return the proxy for a given XrayWrapper
// function proxify(obj) {
// if (obj._proxy) return obj._proxy;
// return obj._proxy = Proxy.create(...);
// }
//
// // Get a proxy of a XrayWrapper prototype object
// let proto = proxify(xpcProto);
//
// // Use this proxy as a prototype
// function Constr() {}
// Constr.proto = proto;
//
// // Try to create an instance using this prototype
// let xpcInstance = new Constr();
// let wrapper = proxify(xpcInstance)
//
// xpcProto._proxy = proto and as xpcInstance.__proto__ = xpcProto,
// xpcInstance._proxy = proto ... and profixy(xpcInstance) = proto :(
//
let proto = wrapped.document.createEvent('HTMLEvents').__proto__;
wrapped.Event.prototype = proto;
let event = document.createEvent('HTMLEvents');
test.assertNotEqual(event, proto, "Event should not be equal to its prototype");
event.initEvent('dataavailable', true, true);
test.assertEqual(event.type, 'dataavailable', "Events are working fine");
// XrayWrappers has a bug when you set an attribute on it,
// in some cases, it creates an unnecessary wrapper that introduces
// a different object that refers to the same original object
// Check that our wrappers don't reproduce this bug
// SEE BUG 658560: Fix identity problem with CrossOriginWrappers
let o = {sandboxObject:true};
wrapped.nested = o;
o.foo = true;
test.assertEqual(o, wrapped.nested, "Nested attribute to sandbox object should not be proxified");
wrapped.nested = document;
test.assertEqual(wrapped.nested, document, "Nested attribute to proxy should not be double proxified");
// Check form[nodeName]
let form = document.createElement("form");
let input = document.createElement("input");
input.setAttribute("name", "test");
form.appendChild(input);
body.appendChild(form);
test.assertEqual(form.test, input, "form[nodeName] is valid");
body.removeChild(form);
// Check localStorage:
test.assert(wrapped.localStorage, "has access to localStorage");
wrapped.localStorage.name = 1;
test.assertEqual(wrapped.localStorage.name, 1, "localStorage appears to work");
test.assertEqual(win.localStorage.name, 1, "localStorage really works");
wrapped.localStorage.clear();
test.assertEqual(wrapped.localStorage.name, undefined, "localStorage really, really works");
// Check sessionStorage:
/*
// Does not work on data: uri
console.log(wrapped.sessionStorage);
//test.assert(wrapped.sessionStorage, "has access to localStorage");
wrapped.sessionStorage.setItem('name', 1);
test.assertEqual(wrapped.sessionStorage.getItem('name'), 1, "localStorage appears to work");
test.assertEqual(win.sessionStorage.getItem('name'), 1, "localStorage really work");
wrapped.sessionStorage.clear();
test.assert(!wrapped.sessionStorage.hasItem('name'), "localStorage really,really work");
*/
// Setting a custom object to a proxy attribute is not wrapped when we get it afterward
let object = {custom: true, enumerable: false};
body.customAttribute = object;
test.assertEqual(body.customAttribute.valueOf(), body.customAttribute.valueOf(proxy.UNWRAP_ACCESS_KEY), "custom JS attributes are not wrapped");
test.assertEqual(object, body.customAttribute, "custom JS attributes are not wrapped");
/*
let originalToString = win.Object.prototype.toString;
win.Object.prototype.toString = function overloadedToString() {
return originalToString.apply(this.valueOf(proxy.UNWRAP_ACCESS_KEY));
};
*/
//