| /** |
| * Supports pseudo-"namespacing" for window-posted messages for a given test |
| * by generating and using a unique prefix that gets wrapped into message |
| * objects. This makes it more feasible to have multiple tests that use |
| * `window.postMessage` in a single test file. Basically, make it possible |
| * for the each test to listen for only the messages that are pertinent to it. |
| * |
| * 'Prefix' not an elegant term to use here but this models itself after |
| * PrefixedLocalStorage. |
| * |
| * PrefixedMessageTest: Instantiate in testharness.js tests to generate |
| * a new unique-ish prefix that can be used by other test support files |
| * PrefixedMessageResource: Instantiate in supporting test resource |
| * files to use/share a prefix generated by a test. |
| */ |
| var PrefixedMessage = function () { |
| this.prefix = ''; |
| this.param = 'prefixedMessage'; // Param to use in querystrings |
| }; |
| |
| /** |
| * Generate a URL that adds/replaces param with this object's prefix |
| * Use to link to test support files that make use of |
| * PrefixedMessageResource. |
| */ |
| PrefixedMessage.prototype.url = function (uri) { |
| function updateUrlParameter (uri, key, value) { |
| var i = uri.indexOf('#'); |
| var hash = (i === -1) ? '' : uri.substr(i); |
| uri = (i === -1) ? uri : uri.substr(0, i); |
| var re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i'); |
| var separator = uri.indexOf('?') !== -1 ? '&' : '?'; |
| uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) : |
| `${uri}${separator}${key}=${value}`; |
| return uri + hash; |
| } |
| return updateUrlParameter(uri, this.param, this.prefix); |
| }; |
| |
| /** |
| * Add an eventListener on `message` but only invoke the given callback |
| * for messages whose object contains this object's prefix. Remove the |
| * event listener once the anticipated message has been received. |
| */ |
| PrefixedMessage.prototype.onMessage = function (fn) { |
| window.addEventListener('message', e => { |
| if (typeof e.data === 'object' && e.data.hasOwnProperty('prefix')) { |
| if (e.data.prefix === this.prefix) { |
| // Only invoke callback when `data` is an object containing |
| // a `prefix` key with this object's prefix value |
| // Note fn is invoked with "unwrapped" data first, then the event `e` |
| // (which contains the full, wrapped e.data should it be needed) |
| fn.call(this, e.data.data, e); |
| window.removeEventListener('message', fn); |
| } |
| } |
| }); |
| }; |
| |
| /** |
| * Instantiate in a test file (e.g. during `setup`) to create a unique-ish |
| * prefix that can be shared by support files |
| */ |
| var PrefixedMessageTest = function () { |
| PrefixedMessage.call(this); |
| this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`; |
| }; |
| PrefixedMessageTest.prototype = Object.create(PrefixedMessage.prototype); |
| PrefixedMessageTest.prototype.constructor = PrefixedMessageTest; |
| |
| /** |
| * Instantiate in a test support script to use a "prefix" generated by a |
| * PrefixedMessageTest in a controlling test file. It will look for |
| * the prefix in a URL param (see also PrefixedMessage#url) |
| */ |
| var PrefixedMessageResource = function () { |
| PrefixedMessage.call(this); |
| // Check URL querystring for prefix to use |
| var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`), |
| results = regex.exec(document.location.href); |
| if (results && results[2]) { |
| this.prefix = results[2]; |
| } |
| }; |
| PrefixedMessageResource.prototype = Object.create(PrefixedMessage.prototype); |
| PrefixedMessageResource.prototype.constructor = PrefixedMessageResource; |
| |
| /** |
| * This is how a test resource document can "send info" to its |
| * opener context. It will whatever message is being sent (`data`) in |
| * an object that injects the prefix. |
| */ |
| PrefixedMessageResource.prototype.postToOpener = function (data) { |
| if (window.opener) { |
| window.opener.postMessage({ |
| prefix: this.prefix, |
| data: data |
| }, '*'); |
| } |
| }; |