chromium/chrome/test/data/extensions/api_test/protocol_handler/test_registration.js

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// browser_tests --gtest_filter=ProtocolHandlerApiTest.Registration

function registerProtocolHandlerWithUserGesture(scheme, url, title) {
  return new Promise((resolve, reject) => {
    window.addEventListener('message', function(event) {
      chrome.test.assertEq('observing_change', event.data);
      try {
        window.addEventListener('message', function(event) {
          chrome.test.assertEq('change_observed', event.data);
          resolve();
        }, {once: true});
        navigator.registerProtocolHandler(scheme, url, title);
      } catch (error) {
        reject(error);
      }
    }, {once: true});
    chrome.test.sendMessage('request_register_protocol');
  });
}

function verifyRegistration(scheme) {
  const url = `${scheme}:path`;
  const a = document.body.appendChild(document.createElement('a'));
  a.href = url;
  a.rel = 'opener';
  a.target = '_blank';
  return new Promise((resolve, reject) => {
    window.addEventListener('message', function(event) {
      chrome.test.assertEq(url, event.data.protocol);
      event.source.close();
      resolve();
    }, {once: true})
    a.click();
  });
}

async function testRegisterProtocolHandler(scheme, url, title) {
  await registerProtocolHandlerWithUserGesture(scheme, url, title);
  await verifyRegistration(scheme);
}

chrome.test.getConfig(function(config) {
  const CROSS_ORIGIN_LOCALHOST_URL =
      crossOriginLocalhostURLFromPort(config.testServer.port) +
      'handler.html?protocol=%s';

  const MESSAGE_INVALID_URI_SYNTAX =
      /The scheme name 'ext\+@' is not allowed by URI syntax \(RFC3986\)./;

  const MESSAGE_NOT_SAFELISTED = new RegExp(
      'The scheme \'unknownscheme\' doesn\'t belong to the scheme allowlist. ' +
      'Please prefix non-allowlisted schemes with the string \'web\\+\'');

  const MESSAGE_EXT_PLUS_SCHEME = new RegExp(
      'The scheme name \'ext\\+\' is not allowed. Schemes starting with ' +
      '\'ext\\+\' must be followed by one or more ASCII letters.');

  const MESSAGE_INVALID_SCHEME =
      /The scheme of the url provided must be HTTP\(S\)./;

  const MESSAGE_MISSING_PERCENT =
      /The url provided \(.+\) does not contain '%s'/;

  const MESSAGE_INVALID_URL_CREATED = new RegExp(
      'The custom handler URL created by removing \'%s\' and prepending ' +
      '\'.+\' is invalid');

  chrome.test.runTests([
    function invalidScheme() {
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['ext+@', SAME_ORIGIN_CHROME_EXTENSION_URL, TITLE],
          MESSAGE_INVALID_URI_SYNTAX);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['unknownscheme', SAME_ORIGIN_CHROME_EXTENSION_URL, TITLE],
          MESSAGE_NOT_SAFELISTED);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['ext+', SAME_ORIGIN_CHROME_EXTENSION_URL, TITLE],
          MESSAGE_EXT_PLUS_SCHEME);
      chrome.test.succeed();
    },

    function invalidURL() {
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', 'invalidurl://%s', TITLE], MESSAGE_INVALID_SCHEME);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', `blob:${SAME_ORIGIN_CHROME_EXTENSION_URL}`, TITLE],
          MESSAGE_INVALID_SCHEME);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', 'data:text/html,Hello?url=%s', TITLE],
          MESSAGE_INVALID_SCHEME);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', `filesystem:${SAME_ORIGIN_CHROME_EXTENSION_URL}`, TITLE],
          MESSAGE_INVALID_SCHEME);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', chrome.runtime.getURL('xhr.txt'), TITLE],
          MESSAGE_MISSING_PERCENT);
      chrome.test.assertThrows(
          navigator.registerProtocolHandler, navigator,
          ['mailto', 'https://%s', TITLE], MESSAGE_INVALID_URL_CREATED);
      chrome.test.succeed();
    },

    async function chromeExtensionURL() {
      chrome.test.assertTrue(
          SAME_ORIGIN_CHROME_EXTENSION_URL.startsWith('chrome-extension://'));
      await testRegisterProtocolHandler(
          'mailto', SAME_ORIGIN_CHROME_EXTENSION_URL, TITLE);
      chrome.test.succeed();
    },

    async function extPlusFooScheme() {
      await testRegisterProtocolHandler(
          'ext+foo', SAME_ORIGIN_CHROME_EXTENSION_URL, TITLE);
      chrome.test.succeed();
    },

    async function crossOriginURL() {
      chrome.test.assertFalse(
          CROSS_ORIGIN_LOCALHOST_URL.startsWith(location.origin));
      await testRegisterProtocolHandler(
          'irc', CROSS_ORIGIN_LOCALHOST_URL, TITLE);
      chrome.test.succeed();
    },

    async function finalizeTests() {
      await new Promise((resolve, reject) => {
        window.addEventListener('message', function(event) {
          chrome.test.assertEq('complete', event.data);
          chrome.test.succeed();
        }, {once: true});
        chrome.test.sendMessage('request_complete');
      });
    }
  ]);
});