Skip to content
32 changes: 23 additions & 9 deletions src/client/sandbox/event/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,22 +213,36 @@ export default class MessageSandbox extends SandboxBase {
}

postMessage (contentWindow: Window, args) {
const targetUrl = args[1] || destLocation.getOriginHeader();
if (!args[1] || typeof args[1] === 'string')
return MessageSandbox._postMessage(contentWindow, args);
else if (typeof args[1] === 'object')
return MessageSandbox._postMessageWithOptions(contentWindow, args);

// NOTE: We do NOT support the postMessage(message, options) overload.
// The second argument is expected to be `targetOrigin` (string).
// If an options object is provided instead, the call is considered invalid and will be aborted.
if (typeof targetUrl !== 'string') {
nativeMethods.consoleMeths.log(`testcafe-hammerhead: postMessage called with invalid targetOrigin; aborting call (type: ${typeof targetUrl})`);
return null;
}
nativeMethods.consoleMeths.log(`testcafe-hammerhead: postMessage called with invalid targetOrigin; aborting call (type: ${typeof args[1]})`);

return null;
}

private static _postMessageWithOptions (contentWindow: Window, args) {
const options = args[1];
const resolvedTargetUrl = typeof options.targetOrigin === 'string'
? options.targetOrigin
: destLocation.getOriginHeader();

args[0] = MessageSandbox._wrapMessage(MessageType.User, args[0], resolvedTargetUrl);
args[1] = nativeMethods.objectAssign({}, options, { targetOrigin: '*' });

return fastApply(contentWindow, 'postMessage', args);
}

private static _postMessage (contentWindow: Window, args) {
const targetUrl = args[1] || destLocation.getOriginHeader();

// NOTE: Here, we pass all messages as "no preference" ("*").
// We do an origin check in "_onWindowMessage" to access the target origin.
args[1] = '*';
args[0] = MessageSandbox._wrapMessage(MessageType.User, args[0], targetUrl);


return fastApply(contentWindow, 'postMessage', args);
}

Expand Down
48 changes: 37 additions & 11 deletions test/client/fixtures/sandbox/event/message-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,46 @@ asyncTest('should pass "transfer" argument for "postMessage" (GH-1535)', functio
callMethod(window, 'postMessage', ['test', '*', [channel.port1]]);
});

asyncTest('should not accept an object as "targetOrigin"', function () {
var called = false;
var handler = function () {
called = true;
asyncTest('should support postMessage(message, options) overload', function () {
var eventHandlerObject = {
handleEvent: function (e) {
strictEqual(e.data, 'options-overload-test');
window.removeEventListener('message', eventHandlerObject);
start();
},
};

window.addEventListener('message', handler);
callMethod(window, 'postMessage', ['message', { test: 1 }]);
window.addEventListener('message', eventHandlerObject);
callMethod(window, 'postMessage', ['options-overload-test', { targetOrigin: '*' }]);
});

window.setTimeout(function () {
ok(!called, 'message should not be delivered');
window.removeEventListener('message', handler);
start();
}, 100);
asyncTest('should support postMessage(message, options) overload with transfer', function () {
var channel = new MessageChannel();

var eventHandlerObject = {
handleEvent: function (e) {
strictEqual(e.data, 'options-transfer-test');
strictEqual(e.ports.length, 1);
window.removeEventListener('message', eventHandlerObject);
start();
},
};

window.addEventListener('message', eventHandlerObject);
callMethod(window, 'postMessage', ['options-transfer-test', { targetOrigin: '*', transfer: [channel.port1] }]);
});

asyncTest('should deliver message when postMessage is called with an object as second argument', function () {
var handler = function (e) {
if (e.data === 'object-arg-test') {
ok(true, 'message should be delivered via options overload');
window.removeEventListener('message', handler);
start();
}
};

window.addEventListener('message', handler);
callMethod(window, 'postMessage', ['object-arg-test', { test: 1 }]);
});

asyncTest('onmessage event', function () {
Expand Down