Here are some techniques I’ve used while writing Gecko test cases. It’s quite handy for people to create complicate test cases across multiple frames or processes.

To IFrame

postMessage: You can pass the message between non-OOP iframes that not in the same origin, using postMessage and addEventListener('message', callback).

outer.html

var iframe = document.getElementById('iframe');
iframe.src = 'inner.html';

window.addEventListener('message', function(evt) { /* handle the message from inner.html */ });
iframe.onload = function() { iframe.contentWindow.postMessage('some-js-value', window.location.origin) };

inner.html

window.addEventListener('message', function(evt) {
  // handle the message from outer.html
  if (evt.data === 'some-js-value') {
    event.source.postMessage('something-else', window.location.origin);
  }
}

URL Query String: You can pass the information in URL while opening a page in iframe, using encodeURIComponent and decodeURIComponent.

outer.html

var iframe = document.getElementById('iframe');
iframe.src = 'inner.html?' + encodeURIComponent('some string or json string');

inner.html

var queryString = decodeURIComponent(window.location.search.substring(1));
// use JSON.parse(queryString) if passing a json string

To Parent Process

loadChromeScript: You can load a specified js file into B2G process and you can use sendAsyncMessage to pass information between chrome process and content process.

test.html

var script = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('chrome-script.js');
script.addMessageListener('some-command', function(data) {
  // handle the message from chrome-script.js
});
script.sendAsyncMessage('some-message', 'some js value');
script.destroy();

chrome-script.js

addMessageHandler('some-message', function(data) {
  // handle the message from test.html
  sendAsyncMessage('some-command', 'some other js value');
});

window.alert/window.prompt: If you create a content process in your testcase, you can use window.alert or window.prompt to initiate a IPC from content process to parent process by handling mozbrowsershowmodalprompt event.

outer.html

function callback() {
  var iframe = document.createElement('iframe');
  SpecialPowers.wrap(iframe).mozbrowser = true;

  iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
    // handle the message from inner.html
    var message = e.detail.message;
    var initValue = e.detail.initValue; // init value from prompt.
    e.detail.returenValue = 'some string'; // return value for prompt.

    e.preventDefault(); // cause the alert to block.
    e.detail.unblock(); // Now unblock the iframe and check that the script completed.

  });

  iframe.src = 'inner.html';
}

// necessary permission and preference for creating a remote iframe
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({
  "set": [
    ["network.disable.ipc.security", true],
    ["dom.ipc.tabs.disabled", false],
    ["dom.ipc.browser_frames.oop_by_default", true],
    ["dom.mozBrowserFramesEnabled", true],
    ["browser.pagethumbnails.capturing_disabled", true]
  ]
}, callback);

inner.html

window.alert('some string or json string');
var retValue = window.prompt('some thing need return', 'some init value');

To Child Process

hashchange: You can pass the information by changing the URL hash for the iframe, using encodeURIComponent and decodeURIComponent.

outer.html

var iframe = document.getElementById('iframe');
iframe.src = 'inner.html#' + encodeURIComponent('some string or json string');

inner.html

window.addEventListener('hashchange', function() {
  var queryString = decodeURIComponent(window.location.hash.substring(1));
  // use JSON.parse(queryString) if passing a json string
});