DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
<!DOCTYPE html>
<title>Test postMessage on HTMLPortalElement</title>
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<body>
  <input id="input"/>
  <script>
    const sameOriginUrl = "resources/portal-post-message-portal.html"
    const crossOriginUrl = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-post-message-portal.html"

    async function createAndInsertPortal(portalSrc) {
      assert_implements("HTMLPortalElement" in self);
      var portal = document.createElement("portal");
      portal.src = portalSrc;
      document.body.append(portal);

      var loadPromise = new Promise((resolve, reject) => {
        portal.onload = resolve;
      });
      await loadPromise;
      return portal;
    }

    function postMessage(portal, ...postMessageArgs) {
      return new Promise((resolve, reject) => {
        portal.postMessage(...postMessageArgs);
        portal.onmessage = e => { resolve(e.data); };
      });
    }

    function postMessageWithMessagePorts(portal, message, targetOrigin) {
      return new Promise((resolve, reject) => {
        var channel = new MessageChannel();
        channel.port1.onmessage = e => {
          channel.port1.close();
          resolve(e.data);
        };
        portal.postMessage(message, targetOrigin, [channel.port2]);
      });
    }

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var message = "test message";
      var {origin, data, sourceIsPortalHost} = await postMessage(portal, message, "*");
      assert_equals(data, message);
      assert_equals(origin, window.location.origin);
      assert_true(sourceIsPortalHost);
    }, "postMessage message received by portalHost");

    promise_test(async () => {
      var portal = await createAndInsertPortal(crossOriginUrl);
      var message = "test message";
      var {origin, data, sourceIsPortalHost} = await postMessage(portal, message, "*");
      assert_equals(data, message);
      assert_equals(origin, window.location.origin);
      assert_true(sourceIsPortalHost);
    }, "postMessage message received by portalHost in cross-origin portal");

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var message = "test message";
      var {data} = await postMessage(portal, message);
      assert_equals(data, message);
      var {data} = await postMessage(portal, message, "/");
      assert_equals(data, message);
      var {data} = await postMessage(portal, message,
                                     "http://{{host}}:{{ports[http][0]}}");
      assert_equals(data, message);
    }, "postMessage received by portal host in same-origin portal for multiple valid target origins");

    promise_test(async () => {
      var portal = await createAndInsertPortal(crossOriginUrl);
      var message = "test message";
      var {data} = await postMessage(portal, message,
          "http://{{hosts[alt][www]}}:{{ports[http][0]}}");
      assert_equals(data, message);
    }, "postMessage received by portal host in cross-origin portal when target origin is specified");

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var message = {
        prop1: "value1",
        prop2: 2.5,
        prop3: [1, 2, "3"],
        prop4: {
          prop4_1: "value4_1"
        }
      }
      var {data} = await postMessage(portal, message);
      assert_object_equals(data, message);
    }, "postMessage with message object");

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var message = "test message";
      var {data} = await postMessageWithMessagePorts(portal, message, "*");
      assert_equals(data, message);
    }, "postMessage with message ports and same-origin portal");

    promise_test(async () => {
      var portal = await createAndInsertPortal(crossOriginUrl);
      var message = "test message";
      var {data} = await postMessageWithMessagePorts(portal, message, "*");
      assert_equals(data, message);
    }, "postMessage with message ports and cross-origin portal");

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var arrayBuffer = new ArrayBuffer(5);
      var int8View = new Int8Array(arrayBuffer);
      for (var i = 0; i < int8View.length; i++)
        int8View[i] = i;
      var message = {
        arrayBuffer: arrayBuffer
      };
      var {data} = await postMessage(portal, message, "*");
      assert_array_equals([0, 1, 2, 3, 4], int8View);
      assert_array_equals([0, 1, 2, 3, 4], data.array);
    }, "postMessage with array buffer without transfer");

    promise_test(async () => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      var arrayBuffer = new ArrayBuffer(5);
      var int8View = new Int8Array(arrayBuffer);
      for (var i = 0; i < int8View.length; i++)
        int8View[i] = i;
      var message = {
        arrayBuffer: arrayBuffer
      };
      var {data} = await postMessage(portal, message, "*", [arrayBuffer]);
      assert_equals(int8View.length, 0);
      assert_array_equals(data.array, [0, 1, 2, 3, 4]);
    }, "postMessage with transferred array buffer");

    promise_test(async t => {
      var portal = await createAndInsertPortal(sameOriginUrl);

      var {gotUserActivation} = await postMessage(portal, "test");
      assert_false(gotUserActivation);

      var {gotUserActivation, userActivation} = await postMessage(portal, "test", {includeUserActivation: true});
      assert_true(gotUserActivation);
      assert_false(userActivation.isActive);
      assert_false(userActivation.hasBeenActive);

      await test_driver.click(document.getElementById("input"));
      assert_true(navigator.userActivation.isActive);
      assert_true(navigator.userActivation.hasBeenActive);

      var {userActivation} = await postMessage(portal, "test", {includeUserActivation: true});
      assert_true(userActivation.isActive, "should have sent gesture");
      assert_true(userActivation.hasBeenActive);
    }, "postMessage with includeUserActivation");

    promise_test(async t => {
      var portal = document.createElement("portal");
      return promise_rejects_dom(t, "InvalidStateError",
                             postMessage(portal, "test message"));
    }, "cannot call postMessage on portal without portal browsing context");

    promise_test(async t => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      return promise_rejects_dom(t, "DataCloneError",
                             postMessage(portal, document.body));
    }, "postMessage should fail if message serialization fails");

    promise_test(async t => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      return promise_rejects_js(t, TypeError,
                             postMessage(portal, "test", "*", [null]));
    }, "postMessage should fail with invalid ports");

    async function waitForMessage(channelName) {
      var bc = new BroadcastChannel(channelName);
      return new Promise((resolve, reject) => {
        bc.onmessage = e => {
          bc.close();
          resolve(e.data);
        }
      });
    }

    promise_test(async t => {
      assert_implements("HTMLPortalElement" in self);
      window.open("resources/portal-post-message-before-activate-window.html");
      let {postMessageTS, activateTS} = await waitForMessage(
          "portals-post-message-before-activate");
      assert_less_than_equal(postMessageTS, activateTS);
    }, "postMessage before activate should work and preserve order");

    promise_test(async t => {
      assert_implements("HTMLPortalElement" in self);
      window.open("resources/portal-post-message-during-activate-window.html");
      let error = await waitForMessage("portals-post-message-during-activate");
      assert_equals(error, "InvalidStateError");
    }, "postMessage during activate throws error");

    promise_test(async t => {
      assert_implements("HTMLPortalElement" in self);
      window.open("resources/portal-post-message-after-activate-window.html");
      let error = await waitForMessage("portals-post-message-after-activate");
      assert_equals(error, "InvalidStateError");
    }, "postMessage after activate throws error");

    // TODO(adithyas): Use async_test instead of promise_test (for tests that
    // use a timeout) once we implement postMessage in the other direction and
    // no longer need to use broadcast channel.
    const TIMEOUT_DURATION_MS = 1000;

    promise_test(async t => {
      var portal = await createAndInsertPortal(crossOriginUrl);
      return new Promise((resolve, reject) => {
        postMessage(portal, "test").then(() => { reject("message delivered"); });
        t.step_timeout(resolve, TIMEOUT_DURATION_MS);
      });
    }, "message should not be delivered to cross-origin portal when targetOrigin is not specified");

    promise_test(async t => {
      var portal = await createAndInsertPortal(sameOriginUrl);
      return new Promise((resolve, reject) => {
        postMessage(portal, "test", "http://differentorigin.com:8002").then(
          () => { reject("message delivered"); });
        t.step_timeout(resolve, TIMEOUT_DURATION_MS);
      });
    }, "message should not be delivered to portal when targetOrigin does not match");
  </script>
</body>