addon-sdk/source/test/test-page-worker.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/test/test-page-worker.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,468 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +"use strict";
     1.8 +
     1.9 +const { Loader } = require('sdk/test/loader');
    1.10 +const { Page } = require("sdk/page-worker");
    1.11 +const { URL } = require("sdk/url");
    1.12 +const fixtures = require("./fixtures");
    1.13 +const testURI = fixtures.url("test.html");
    1.14 +
    1.15 +const ERR_DESTROYED =
    1.16 +  "Couldn't find the worker to receive this message. " +
    1.17 +  "The script may not be initialized yet, or may already have been unloaded.";
    1.18 +
    1.19 +exports.testSimplePageCreation = function(assert, done) {
    1.20 +  let page = new Page({
    1.21 +    contentScript: "self.postMessage(window.location.href)",
    1.22 +    contentScriptWhen: "end",
    1.23 +    onMessage: function (message) {
    1.24 +      assert.equal(message, "about:blank",
    1.25 +                       "Page Worker should start with a blank page by default");
    1.26 +      assert.equal(this, page, "The 'this' object is the page itself.");
    1.27 +      done();
    1.28 +    }
    1.29 +  });
    1.30 +}
    1.31 +
    1.32 +/*
    1.33 + * Tests that we can't be tricked by document overloads as we have access
    1.34 + * to wrapped nodes
    1.35 + */
    1.36 +exports.testWrappedDOM = function(assert, done) {
    1.37 +  let page = Page({
    1.38 +    allow: { script: true },
    1.39 +    contentURL: "data:text/html;charset=utf-8,<script>document.getElementById=3;window.scrollTo=3;</script>",
    1.40 +    contentScript: "window.addEventListener('load', function () " +
    1.41 +                   "self.postMessage([typeof(document.getElementById), " +
    1.42 +                   "typeof(window.scrollTo)]), true)",
    1.43 +    onMessage: function (message) {
    1.44 +      assert.equal(message[0],
    1.45 +                       "function",
    1.46 +                       "getElementById from content script is the native one");
    1.47 +
    1.48 +      assert.equal(message[1],
    1.49 +                       "function",
    1.50 +                       "scrollTo from content script is the native one");
    1.51 +
    1.52 +      done();
    1.53 +    }
    1.54 +  });
    1.55 +}
    1.56 +
    1.57 +/*
    1.58 +// We do not offer unwrapped access to DOM since bug 601295 landed
    1.59 +// See 660780 to track progress of unwrap feature
    1.60 +exports.testUnwrappedDOM = function(assert, done) {
    1.61 +  let page = Page({
    1.62 +    allow: { script: true },
    1.63 +    contentURL: "data:text/html;charset=utf-8,<script>document.getElementById=3;window.scrollTo=3;</script>",
    1.64 +    contentScript: "window.addEventListener('load', function () " +
    1.65 +                   "self.postMessage([typeof(unsafeWindow.document.getElementById), " +
    1.66 +                   "typeof(unsafeWindow.scrollTo)]), true)",
    1.67 +    onMessage: function (message) {
    1.68 +      assert.equal(message[0],
    1.69 +                       "number",
    1.70 +                       "document inside page is free to be changed");
    1.71 +
    1.72 +      assert.equal(message[1],
    1.73 +                       "number",
    1.74 +                       "window inside page is free to be changed");
    1.75 +
    1.76 +      done();
    1.77 +    }
    1.78 +  });
    1.79 +}
    1.80 +*/
    1.81 +
    1.82 +exports.testPageProperties = function(assert) {
    1.83 +  let page = new Page();
    1.84 +
    1.85 +  for each (let prop in ['contentURL', 'allow', 'contentScriptFile',
    1.86 +                         'contentScript', 'contentScriptWhen', 'on',
    1.87 +                         'postMessage', 'removeListener']) {
    1.88 +    assert.ok(prop in page, prop + " property is defined on page.");
    1.89 +  }
    1.90 +
    1.91 +  assert.ok(function () page.postMessage("foo") || true,
    1.92 +              "postMessage doesn't throw exception on page.");
    1.93 +}
    1.94 +
    1.95 +exports.testConstructorAndDestructor = function(assert, done) {
    1.96 +  let loader = Loader(module);
    1.97 +  let { Page } = loader.require("sdk/page-worker");
    1.98 +  let global = loader.sandbox("sdk/page-worker");
    1.99 +
   1.100 +  let pagesReady = 0;
   1.101 +
   1.102 +  let page1 = Page({
   1.103 +    contentScript:      "self.postMessage('')",
   1.104 +    contentScriptWhen:  "end",
   1.105 +    onMessage:          pageReady
   1.106 +  });
   1.107 +  let page2 = Page({
   1.108 +    contentScript:      "self.postMessage('')",
   1.109 +    contentScriptWhen:  "end",
   1.110 +    onMessage:          pageReady
   1.111 +  });
   1.112 +
   1.113 +  assert.notEqual(page1, page2,
   1.114 +                      "Page 1 and page 2 should be different objects.");
   1.115 +
   1.116 +  function pageReady() {
   1.117 +    if (++pagesReady == 2) {
   1.118 +      page1.destroy();
   1.119 +      page2.destroy();
   1.120 +
   1.121 +      assert.ok(isDestroyed(page1), "page1 correctly unloaded.");
   1.122 +      assert.ok(isDestroyed(page2), "page2 correctly unloaded.");
   1.123 +
   1.124 +      loader.unload();
   1.125 +      done();
   1.126 +    }
   1.127 +  }
   1.128 +}
   1.129 +
   1.130 +exports.testAutoDestructor = function(assert, done) {
   1.131 +  let loader = Loader(module);
   1.132 +  let { Page } = loader.require("sdk/page-worker");
   1.133 +
   1.134 +  let page = Page({
   1.135 +    contentScript: "self.postMessage('')",
   1.136 +    contentScriptWhen: "end",
   1.137 +    onMessage: function() {
   1.138 +      loader.unload();
   1.139 +      assert.ok(isDestroyed(page), "Page correctly unloaded.");
   1.140 +      done();
   1.141 +    }
   1.142 +  });
   1.143 +}
   1.144 +
   1.145 +exports.testValidateOptions = function(assert) {
   1.146 +  assert.throws(
   1.147 +    function () Page({ contentURL: 'home' }),
   1.148 +    /The `contentURL` option must be a valid URL\./,
   1.149 +    "Validation correctly denied a non-URL contentURL"
   1.150 +  );
   1.151 +
   1.152 +  assert.throws(
   1.153 +    function () Page({ onMessage: "This is not a function."}),
   1.154 +    /The option "onMessage" must be one of the following types: function/,
   1.155 +    "Validation correctly denied a non-function onMessage."
   1.156 +  );
   1.157 +
   1.158 +  assert.pass("Options validation is working.");
   1.159 +}
   1.160 +
   1.161 +exports.testContentAndAllowGettersAndSetters = function(assert, done) {
   1.162 +  let content = "data:text/html;charset=utf-8,<script>window.localStorage.allowScript=3;</script>";
   1.163 +
   1.164 +  // Load up the page with testURI initially for the resource:// principal,
   1.165 +  // then load the actual data:* content, as data:* URIs no longer
   1.166 +  // have localStorage
   1.167 +  let page = Page({
   1.168 +    contentURL: testURI,
   1.169 +    contentScript: "if (window.location.href==='"+testURI+"')" +
   1.170 +      "  self.postMessage('reload');" +
   1.171 +      "else " +
   1.172 +      "  self.postMessage(window.localStorage.allowScript)",
   1.173 +    contentScriptWhen: "end",
   1.174 +    onMessage: step0
   1.175 +  });
   1.176 +
   1.177 +  function step0(message) {
   1.178 +    if (message === 'reload')
   1.179 +      return page.contentURL = content;
   1.180 +    assert.equal(message, "3",
   1.181 +                     "Correct value expected for allowScript - 3");
   1.182 +    assert.equal(page.contentURL, content,
   1.183 +                     "Correct content expected");
   1.184 +    page.removeListener('message', step0);
   1.185 +    page.on('message', step1);
   1.186 +    page.allow = { script: false };
   1.187 +    page.contentURL = content =
   1.188 +      "data:text/html;charset=utf-8,<script>window.localStorage.allowScript='f'</script>";
   1.189 +  }
   1.190 +
   1.191 +  function step1(message) {
   1.192 +    assert.equal(message, "3",
   1.193 +                     "Correct value expected for allowScript - 3");
   1.194 +    assert.equal(page.contentURL, content, "Correct content expected");
   1.195 +    page.removeListener('message', step1);
   1.196 +    page.on('message', step2);
   1.197 +    page.allow = { script: true };
   1.198 +    page.contentURL = content =
   1.199 +      "data:text/html;charset=utf-8,<script>window.localStorage.allowScript='g'</script>";
   1.200 +  }
   1.201 +
   1.202 +  function step2(message) {
   1.203 +    assert.equal(message, "g",
   1.204 +                     "Correct value expected for allowScript - g");
   1.205 +    assert.equal(page.contentURL, content, "Correct content expected");
   1.206 +    page.removeListener('message', step2);
   1.207 +    page.on('message', step3);
   1.208 +    page.allow.script = false;
   1.209 +    page.contentURL = content =
   1.210 +      "data:text/html;charset=utf-8,<script>window.localStorage.allowScript=3</script>";
   1.211 +  }
   1.212 +
   1.213 +  function step3(message) {
   1.214 +    assert.equal(message, "g",
   1.215 +                     "Correct value expected for allowScript - g");
   1.216 +    assert.equal(page.contentURL, content, "Correct content expected");
   1.217 +    page.removeListener('message', step3);
   1.218 +    page.on('message', step4);
   1.219 +    page.allow.script = true;
   1.220 +    page.contentURL = content =
   1.221 +      "data:text/html;charset=utf-8,<script>window.localStorage.allowScript=4</script>";
   1.222 +  }
   1.223 +
   1.224 +  function step4(message) {
   1.225 +    assert.equal(message, "4",
   1.226 +                     "Correct value expected for allowScript - 4");
   1.227 +    assert.equal(page.contentURL, content, "Correct content expected");
   1.228 +    done();
   1.229 +  }
   1.230 +
   1.231 +}
   1.232 +
   1.233 +exports.testOnMessageCallback = function(assert, done) {
   1.234 +  Page({
   1.235 +    contentScript: "self.postMessage('')",
   1.236 +    contentScriptWhen: "end",
   1.237 +    onMessage: function() {
   1.238 +      assert.pass("onMessage callback called");
   1.239 +      done();
   1.240 +    }
   1.241 +  });
   1.242 +}
   1.243 +
   1.244 +exports.testMultipleOnMessageCallbacks = function(assert, done) {
   1.245 +  let count = 0;
   1.246 +  let page = Page({
   1.247 +    contentScript: "self.postMessage('')",
   1.248 +    contentScriptWhen: "end",
   1.249 +    onMessage: () => count += 1
   1.250 +  });
   1.251 +  page.on('message', () => count += 2);
   1.252 +  page.on('message', () => count *= 3);
   1.253 +  page.on('message', () =>
   1.254 +    assert.equal(count, 9, "All callbacks were called, in order."));
   1.255 +  page.on('message', done);
   1.256 +};
   1.257 +
   1.258 +exports.testLoadContentPage = function(assert, done) {
   1.259 +  let page = Page({
   1.260 +    onMessage: function(message) {
   1.261 +      // The message is an array whose first item is the test method to call
   1.262 +      // and the rest of whose items are arguments to pass it.
   1.263 +      let msg = message.shift();
   1.264 +      if (msg == "done")
   1.265 +        return done();
   1.266 +      assert[msg].apply(assert, message);
   1.267 +    },
   1.268 +    contentURL: fixtures.url("test-page-worker.html"),
   1.269 +    contentScriptFile: fixtures.url("test-page-worker.js"),
   1.270 +    contentScriptWhen: "ready"
   1.271 +  });
   1.272 +}
   1.273 +
   1.274 +exports.testAllowScriptDefault = function(assert, done) {
   1.275 +  let page = Page({
   1.276 +    onMessage: function(message) {
   1.277 +      assert.ok(message, "Script is allowed to run by default.");
   1.278 +      done();
   1.279 +    },
   1.280 +    contentURL: "data:text/html;charset=utf-8,<script>document.documentElement.setAttribute('foo', 3);</script>",
   1.281 +    contentScript: "self.postMessage(document.documentElement.getAttribute('foo'))",
   1.282 +    contentScriptWhen: "ready"
   1.283 +  });
   1.284 +}
   1.285 +
   1.286 +exports.testAllowScript = function(assert, done) {
   1.287 +  let page = Page({
   1.288 +    onMessage: function(message) {
   1.289 +      assert.ok(message, "Script runs when allowed to do so.");
   1.290 +      done();
   1.291 +    },
   1.292 +    allow: { script: true },
   1.293 +    contentURL: "data:text/html;charset=utf-8,<script>document.documentElement.setAttribute('foo', 3);</script>",
   1.294 +    contentScript: "self.postMessage(document.documentElement.hasAttribute('foo') && " +
   1.295 +                   "                 document.documentElement.getAttribute('foo') == 3)",
   1.296 +    contentScriptWhen: "ready"
   1.297 +  });
   1.298 +}
   1.299 +
   1.300 +exports.testPingPong = function(assert, done) {
   1.301 +  let page = Page({
   1.302 +    contentURL: 'data:text/html;charset=utf-8,ping-pong',
   1.303 +    contentScript: 'self.on("message", function(message) self.postMessage("pong"));'
   1.304 +      + 'self.postMessage("ready");',
   1.305 +    onMessage: function(message) {
   1.306 +      if ('ready' == message) {
   1.307 +        page.postMessage('ping');
   1.308 +      }
   1.309 +      else {
   1.310 +        assert.ok(message, 'pong', 'Callback from contentScript');
   1.311 +        done();
   1.312 +      }
   1.313 +    }
   1.314 +  });
   1.315 +};
   1.316 +
   1.317 +exports.testRedirect = function (assert, done) {
   1.318 +  let page = Page({
   1.319 +    contentURL: 'data:text/html;charset=utf-8,first-page',
   1.320 +    contentScriptWhen: "end",
   1.321 +    contentScript: '' +
   1.322 +      'if (/first-page/.test(document.location.href)) ' +
   1.323 +      '  document.location.href = "data:text/html;charset=utf-8,redirect";' +
   1.324 +      'else ' +
   1.325 +      '  self.port.emit("redirect", document.location.href);'
   1.326 +  });
   1.327 +
   1.328 +  page.port.on('redirect', function (url) {
   1.329 +    assert.equal(url, 'data:text/html;charset=utf-8,redirect', 'Reinjects contentScript on reload');
   1.330 +    done();
   1.331 +  });
   1.332 +};
   1.333 +
   1.334 +exports.testRedirectIncludeArrays = function (assert, done) {
   1.335 +  let firstURL = 'data:text/html;charset=utf-8,first-page';
   1.336 +  let page = Page({
   1.337 +    contentURL: firstURL,
   1.338 +    contentScript: '(function () {' +
   1.339 +      'self.port.emit("load", document.location.href);' +
   1.340 +      '  self.port.on("redirect", function (url) {' +
   1.341 +      '   document.location.href = url;' +
   1.342 +      '  })' +
   1.343 +      '})();',
   1.344 +    include: ['about:blank', 'data:*']
   1.345 +  });
   1.346 +
   1.347 +  page.port.on('load', function (url) {
   1.348 +    if (url === firstURL) {
   1.349 +      page.port.emit('redirect', 'about:blank');
   1.350 +    } else if (url === 'about:blank') {
   1.351 +      page.port.emit('redirect', 'about:mozilla');
   1.352 +      assert.ok('`include` property handles arrays');
   1.353 +      assert.equal(url, 'about:blank', 'Redirects work with accepted domains');
   1.354 +      done();
   1.355 +    } else if (url === 'about:mozilla') {
   1.356 +      assert.fail('Should not redirect to restricted domain');
   1.357 +    }
   1.358 +  });
   1.359 +};
   1.360 +
   1.361 +exports.testRedirectFromWorker = function (assert, done) {
   1.362 +  let firstURL = 'data:text/html;charset=utf-8,first-page';
   1.363 +  let secondURL = 'data:text/html;charset=utf-8,second-page';
   1.364 +  let thirdURL = 'data:text/html;charset=utf-8,third-page';
   1.365 +  let page = Page({
   1.366 +    contentURL: firstURL,
   1.367 +    contentScript: '(function () {' +
   1.368 +      'self.port.emit("load", document.location.href);' +
   1.369 +      '  self.port.on("redirect", function (url) {' +
   1.370 +      '   document.location.href = url;' +
   1.371 +      '  })' +
   1.372 +      '})();',
   1.373 +    include: 'data:*'
   1.374 +  });
   1.375 +
   1.376 +  page.port.on('load', function (url) {
   1.377 +    if (url === firstURL) {
   1.378 +      page.port.emit('redirect', secondURL);
   1.379 +    } else if (url === secondURL) {
   1.380 +      page.port.emit('redirect', thirdURL);
   1.381 +    } else if (url === thirdURL) {
   1.382 +      page.port.emit('redirect', 'about:mozilla');
   1.383 +      assert.equal(url, thirdURL, 'Redirects work with accepted domains on include strings');
   1.384 +      done();
   1.385 +    } else {
   1.386 +      assert.fail('Should not redirect to unauthorized domains');
   1.387 +    }
   1.388 +  });
   1.389 +};
   1.390 +
   1.391 +exports.testRedirectWithContentURL = function (assert, done) {
   1.392 +  let firstURL = 'data:text/html;charset=utf-8,first-page';
   1.393 +  let secondURL = 'data:text/html;charset=utf-8,second-page';
   1.394 +  let thirdURL = 'data:text/html;charset=utf-8,third-page';
   1.395 +  let page = Page({
   1.396 +    contentURL: firstURL,
   1.397 +    contentScript: '(function () {' +
   1.398 +      'self.port.emit("load", document.location.href);' +
   1.399 +      '})();',
   1.400 +    include: 'data:*'
   1.401 +  });
   1.402 +
   1.403 +  page.port.on('load', function (url) {
   1.404 +    if (url === firstURL) {
   1.405 +      page.contentURL = secondURL;
   1.406 +    } else if (url === secondURL) {
   1.407 +      page.contentURL = thirdURL;
   1.408 +    } else if (url === thirdURL) {
   1.409 +      page.contentURL = 'about:mozilla';
   1.410 +      assert.equal(url, thirdURL, 'Redirects work with accepted domains on include strings');
   1.411 +      done();
   1.412 +    } else {
   1.413 +      assert.fail('Should not redirect to unauthorized domains');
   1.414 +    }
   1.415 +  });
   1.416 +};
   1.417 +
   1.418 +
   1.419 +exports.testMultipleDestroys = function(assert) {
   1.420 +  let page = Page();
   1.421 +  page.destroy();
   1.422 +  page.destroy();
   1.423 +  assert.pass("Multiple destroys should not cause an error");
   1.424 +};
   1.425 +
   1.426 +exports.testContentScriptOptionsOption = function(assert, done) {
   1.427 +  let page = new Page({
   1.428 +    contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
   1.429 +    contentScriptWhen: "end",
   1.430 +    contentScriptOptions: {a: true, b: [1,2,3], c: "string", d: function(){ return 'test'}},
   1.431 +    onMessage: function(msg) {
   1.432 +      assert.equal(msg[0], 'undefined', 'functions are stripped from contentScriptOptions');
   1.433 +      assert.equal(typeof msg[1], 'object', 'object as contentScriptOptions');
   1.434 +      assert.equal(msg[1].a, true, 'boolean in contentScriptOptions');
   1.435 +      assert.equal(msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions');
   1.436 +      assert.equal(msg[1].c, 'string', 'string in contentScriptOptions');
   1.437 +      done();
   1.438 +    }
   1.439 +  });
   1.440 +};
   1.441 +
   1.442 +exports.testMessageQueue = function (assert, done) {
   1.443 +  let page = new Page({
   1.444 +    contentScript: 'self.on("message", function (m) {' +
   1.445 +      'self.postMessage(m);' +
   1.446 +      '});',
   1.447 +    contentURL: 'data:text/html;charset=utf-8,',
   1.448 +  });
   1.449 +  page.postMessage('ping');
   1.450 +  page.on('message', function (m) {
   1.451 +    assert.equal(m, 'ping', 'postMessage should queue messages');
   1.452 +    done();
   1.453 +  });
   1.454 +};
   1.455 +
   1.456 +function isDestroyed(page) {
   1.457 +  try {
   1.458 +    page.postMessage("foo");
   1.459 +  }
   1.460 +  catch (err) {
   1.461 +    if (err.message == ERR_DESTROYED) {
   1.462 +      return true;
   1.463 +    }
   1.464 +    else {
   1.465 +      throw err;
   1.466 +    }
   1.467 +  }
   1.468 +  return false;
   1.469 +}
   1.470 +
   1.471 +require("test").run(exports);

mercurial