chromium/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js

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

var defaultUrl = 'http://www.google.com';

// Utility function to open a URL in a new tab.  If the useIncognito global is
// true, the URL is opened in a new incognito window, otherwise it is opened in
// a new tab in the current window.  Alternatively, whether to use incognito
// can be specified as a second argument which overrides the global setting.
var useIncognito = false;

// For the automated tests a port needs to be specified for the URLs in order to
// contact the embedded test server. The manual tests do not use an embedded
// test server so the port will remain undefined for manual testing and no
// modifications will be made to the URLs.
var testServerPort = undefined;

chrome.test.getConfig(function(config) {
  // config is undefined in manual mode, this check required to stop crashes in
  // manual mode.
  if (config != undefined)
    testServerPort = config.testServer.port;
});

function getURLWithPort(url) {
  if (testServerPort == undefined || url.substring(0, 4) != 'http')
    return url;
  return url + ':' + testServerPort;
}

function openTab(url, incognito) {
  var testUrl = getURLWithPort(url);
  if (incognito == undefined ? useIncognito : incognito) {
    chrome.windows.create({'url': testUrl, 'incognito': true});
  } else {
    window.open(testUrl);
  }
}

// CHROME API TEST METHODS -- PUT YOUR TESTS BELOW HERE
////////////////////////////////////////////////////////////////////////////////

// Makes an API call.
function makeApiCall() {
  resetStatus();
  chrome.cookies.set({
    'url': 'https://www.cnn.com',
    'name': 'activity_log_test_cookie',
    'value': 'abcdefg'
  });
  appendCompleted('makeApiCall');
}

// Makes an API call that has a custom binding.
function makeSpecialApiCalls() {
  resetStatus();
  var url = chrome.runtime.getURL('image/cat.jpg');
  var noparam = chrome.extension.getViews();
  appendCompleted('makeSpecialApiCalls');
}

// Checks that we don't double-log calls that go through setHandleRequest
// *and* the ExtensionFunction machinery.
function checkNoDoubleLogging() {
  resetStatus();
  chrome.omnibox.setDefaultSuggestion({description: 'hello world'});
  appendCompleted('checkNoDoubleLogging');
}

// Check whether we log calls to chrome.app.*;
function checkAppCalls() {
  resetStatus();
  var callback = function() {};
  chrome.app.getDetails();
  var b = chrome.app.isInstalled;
  var c = chrome.app.installState(callback);
  appendCompleted('checkAppCalls');
}

function callObjectMethod() {
  resetStatus();
  var storageArea = chrome.storage.sync;
  storageArea.clear();
  appendCompleted('callObjectMethod');
}

// Modifies the headers sent and received in an HTTP request using the
// webRequest API.
function doWebRequestModifications() {
  resetStatus();
  // Install a webRequest handler that will add an HTTP header to the outgoing
  // request for the main page.
  function doModifyRequestHeaders(details) {
    var response = {};

    var headers = details.requestHeaders;
    if (headers === undefined) {
      headers = [];
    }
    headers.push({'name': 'X-Test-Activity-Log-Send',
                  'value': 'Present'});
    response['requestHeaders'] = headers;

    return response;
  }
  function doModifyResponseHeaders(details) {
    var response = {};

    headers = details.responseHeaders;
    if (headers === undefined) {
      headers = [];
    }
    headers = headers.filter(
        function(x) {return x['name'] != 'Cache-Control';});
    headers.push({'name': 'X-Test-Response-Header',
                  'value': 'Inserted'});
    headers.push({'name': 'Set-Cookie',
                  'value': 'ActivityLog=InsertedCookie'});
    response['responseHeaders'] = headers;

    return response;
  }
  chrome.webRequest.onBeforeSendHeaders.addListener(
      doModifyRequestHeaders,
      {'urls': ['http://*/*'], 'types': ['main_frame']},
      ['blocking', 'requestHeaders']);
  chrome.webRequest.onHeadersReceived.addListener(
      doModifyResponseHeaders,
      {'urls': ['http://*/*'], 'types': ['main_frame']},
      ['blocking', 'responseHeaders']);

  // Open a tab, then close it when it has finished loading--this should give
  // the webRequest handler a chance to run.
  chrome.tabs.onUpdated.addListener(
    function closeTab(tabId, changeInfo, tab) {
      if (changeInfo['status'] === 'complete' &&
          tab.url.match(/google\.com/g)) {
        chrome.webRequest.onBeforeSendHeaders.removeListener(
            doModifyRequestHeaders);
        chrome.webRequest.onHeadersReceived.removeListener(
            doModifyResponseHeaders);
        chrome.tabs.onUpdated.removeListener(closeTab);
        chrome.tabs.remove(tabId);
        appendCompleted('doWebRequestModifications');
      }
    }
  );
  openTab(defaultUrl);
}

function sendMessageToSelf() {
  resetStatus();
  try {
    chrome.runtime.sendMessage('hello hello');
    appendCompleted('sendMessageToSelf');
  } catch (err) {
    setError(err + ' in function: sendMessageToSelf');
  }
}

function sendMessageToOther() {
  resetStatus();
  try {
    chrome.runtime.sendMessage('ocacnieaapoflmkebkeaidpgfngocapl',
        'knock knock',
        function response() {
          appendCompleted('sendMessageToOther');
        });
  } catch (err) {
    setError(err + ' in function: sendMessageToOther');
  }
}

function connectToOther() {
  resetStatus();
  try {
    chrome.runtime.connect('ocacnieaapoflmkebkeaidpgfngocapl');
    appendCompleted('connectToOther');
  } catch (err) {
    setError(err + ' in function:connectToOther');
  }
}

function tabIdTranslation() {
  resetStatus();
  var tabIds = [-1, -1];

  // Test the case of a single int
  chrome.tabs.onUpdated.addListener(
    function testSingleInt(tabId, changeInfo, tab) {
      if (changeInfo['status'] === 'complete' &&
          tab.url.match(/google\.com/g)) {
        chrome.tabs.executeScript(
            tabId,
            {'file': 'google_cs.js'},
            function() {
              chrome.tabs.onUpdated.removeListener(testSingleInt);
              tabIds[0] = tabId;
              openTab('http://www.google.be');
            });
      }
    }
  );

  // Test the case of arrays
  chrome.tabs.onUpdated.addListener(
    function testArray(tabId, changeInfo, tab) {
      if (changeInfo['status'] === 'complete' && tab.url.match(/google\.be/g)) {
        chrome.tabs.move(tabId, {'index': -1});
        tabIds[1] = tabId;
        chrome.tabs.onUpdated.removeListener(testArray);
        chrome.tabs.remove(tabIds);
        appendCompleted('tabIdTranslation');
      }
    }
  );

  openTab(defaultUrl);
}

function executeApiCallsOnTabUpdated() {
  resetStatus();
  chrome.tabs.onUpdated.addListener(
    function callback(tabId, changeInfo, tab) {
      if (changeInfo['status'] === 'complete' &&
          tab.url.match(/google\.com/g)) {
        chrome.tabs.onUpdated.removeListener(callback);

        // Send a message.
        chrome.tabs.sendMessage(tabId, 'hellooooo!');
        appendCompleted('sendMessageToCS');

        // Inject a content script
        chrome.tabs.executeScript(
            tab.id,
            {'file': 'google_cs.js'},
            function() {
              appendCompleted('injectContentScript');
            });

        // Injects a blob of script into a page and cleans up the tab when
        // finished.
        chrome.tabs.executeScript(
            tab.id,
            {'code': 'document.write("g o o g l e");'},
            function() {
              appendCompleted('injectScriptBlob');
              chrome.tabs.remove(tabId);
            });
      }
    }
  );
  openTab(defaultUrl);
}


// DOM API TEST METHODS -- PUT YOUR TESTS BELOW HERE
////////////////////////////////////////////////////////////////////////////////

// Does an XHR from this [privileged] context.
function doBackgroundXHR() {
  resetStatus();
  var request = new XMLHttpRequest();
  request.open('POST', defaultUrl, false);
  request.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
  try {
    request.send();
  } catch (err) {
    // doesn't matter if it works or not; should be recorded either way
  }
  appendCompleted('doBackgroundXHR');
}

function executeDOMChangesOnTabUpdated() {
  resetStatus();
  code = '';

  // Accesses the Location object from inside a content script.
  code = 'window.location = "http://www.google.com/#foo"; ' +
          'document.location = "http://www.google.com/#bar"; ' +
          'var loc = window.location; ' +
          'loc.assign("http://www.google.com/#fo"); ' +
          'loc.replace("http://www.google.com/#bar");';

  // Mutates the DOM tree from inside a content script.
  code += 'var d1 = document.createElement("div"); ' +
          'var d2 = document.createElement("div"); ' +
          'document.body.appendChild(d1); ' +
          'document.body.insertBefore(d2, d1); ' +
          'document.body.replaceChild(d1, d2);';

  code += 'document.write("Hello using document.write"); ' +
          'document.writeln("Hello using document.writeln"); ' +
          'document.body.innerHTML = "Hello using innerHTML";';

  // Accesses the HTML5 Navigator API from inside a content script.
  code += 'var geo = navigator.geolocation; ' +
          'var successCallback = function(x) { }; ' +
          'var errorCallback = function(x) { }; ' +
          'geo.getCurrentPosition(successCallback, errorCallback); ' +
          'var id = geo.watchPosition(successCallback, errorCallback);';

  // Accesses the HTML5 WebStorage API from inside a content script.
  code += 'var store = window.sessionStorage; ' +
          'store.setItem("foo", 42); ' +
          'var val = store.getItem("foo"); ' +
          'store.removeItem("foo"); ' +
          'store.clear();';

  // Same but for localStorage.
  code += 'var store = window.localStorage; ' +
          'store.setItem("foo", 42); ' +
          'var val = store.getItem("foo"); ' +
          'store.removeItem("foo"); ' +
          'store.clear();';

  // Accesses the HTML5 Canvas API from inside a content script.
  code += 'var testCanvas = document.createElement("canvas"); ' +
          'var testContext = testCanvas.getContext("2d");';

  // Does an XHR from inside a content script.
  var xhrUrl = getURLWithPort(defaultUrl);
  code += 'var request = new XMLHttpRequest(); ' +
          'request.open("POST", "' + xhrUrl + '", false); ' +
          'request.setRequestHeader("Content-type", ' +
          '                         "text/plain;charset=UTF-8"); ' +
          'request.send(); ' +
          'document.write("sent an XHR");';

  // This function is used as a handler for hooking mouse and keyboard events.
  code += 'function handlerHook(event) { };';

  hookNames = ['onclick', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter',
               'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'oninput',
               'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown',
               'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout',
               'onmouseover', 'onmouseup', 'onmousewheel'];

  // Access to each hook can be monitored for Element, Document, and Window.
  for (var i = 0; i < hookNames.length; i++) {
    // handler on Element
    code += 'document.body.' + hookNames[i] + ' = handlerHook;';

    // handler on a Document
    code += 'document.' + hookNames[i] + ' = handlerHook;';

    // handler on a Window
    code += 'window.' + hookNames[i] + ' = handlerHook;';
  }

  chrome.tabs.onUpdated.addListener(
    function callback(tabId, changeInfo, tab) {
      if (changeInfo['status'] === 'complete' &&
          tab.url.match(/google\.com/g)) {
        chrome.tabs.onUpdated.removeListener(callback);
        chrome.tabs.executeScript(
             tabId, {'code': code},
             function() {
               chrome.tabs.remove(tabId);
               appendCompleted('executeDOMChangesOnTabUpdated');
             });
      }
    }
  );
  openTab(defaultUrl);
}

function executeDOMFullscreen() {
  resetStatus();
  appendCompleted('Switching to fullscreen...');
  $('status').webkitRequestFullscreen();
  setTimeout(
      function() {document.webkitExitFullscreen(); window.close();}, 100);
}

// Opens the extensions options page and then runs the executeDOMFullscreen
// test.
function launchDOMFullscreenTest() {
  openTab(chrome.runtime.getURL('/options.html#dom_fullscreen'));
}

// ADD TESTS CASES TO THE MAP HERE.
var fnMap = {};
fnMap['api_call'] = makeApiCall;
fnMap['special_call'] = makeSpecialApiCalls;
fnMap['double'] = checkNoDoubleLogging;
fnMap['app_bindings'] = checkAppCalls;
fnMap['object_methods'] = callObjectMethod;
fnMap['message_self'] = sendMessageToSelf;
fnMap['message_other'] = sendMessageToOther;
fnMap['connect_other'] = connectToOther;
fnMap['background_xhr'] = doBackgroundXHR;
fnMap['webrequest'] = doWebRequestModifications;
fnMap['tab_ids'] = tabIdTranslation;
fnMap['dom_tab_updated'] = executeDOMChangesOnTabUpdated;
fnMap['api_tab_updated'] = executeApiCallsOnTabUpdated;
fnMap['dom_fullscreen'] = executeDOMFullscreen;
fnMap['launch_dom_fullscreen'] = launchDOMFullscreenTest;

// Setup function mapping for the automated tests, except when running on the
// options page.
if (window.location.pathname !== '/options.html') {
  try {
    chrome.runtime.onMessageExternal.addListener(
        function(message, sender, response) {
          useIncognito = false;
          if (message.match(/_incognito$/)) {
            // Enable incognito windows for this test, then strip the
            // _incognito suffix for the lookup below.
            useIncognito = true;
            message = message.slice(0, -10);
          }
          if (fnMap.hasOwnProperty(message)) {
            fnMap[message]();
          } else {
            console.log('UNKNOWN METHOD: ' + message);
          }
        }
        );
  } catch (err) {
    console.log('Error while adding listeners: ' + err);
  }
} else {
  console.log('Not installing extension message listener on options.html');
}

// Convenience functions for the manual run mode.
function $(o) {
  return document.querySelector('#' + o);
}

var completed = 0;
function resetStatus(str) {
  completed = 0;
  if ($('status') != null) {
    $('status').innerText = '';
  }
}

function appendCompleted(str) {
  if ($('status') != null) {
    if (completed > 0) {
      $('status').innerText += ', ' + str;
    } else {
      $('status').innerText = 'Completed: ' + str;
    }
  }
  completed += 1;
}

function appendError(str) {
  if ($('status') != null) {
    $('status').innerText += 'Error: ' + str;
  }
}

// Set up the event listeners for use in manual run mode.  Then, if the URL
// contains a test name in the URL fragment
// (chrome-extension://pkn.../options.html#dom_fullscreen), launch that test
// automatically.
function setupEvents() {
  for (var key in fnMap) {
    if (fnMap.hasOwnProperty(key) && key != '' && $(key) != null) {
      $(key).addEventListener('click', fnMap[key]);
    }
  }
  if ($('incognito_checkbox') != null) {
    $('incognito_checkbox').addEventListener(
        'click',
        function() { useIncognito = $('incognito_checkbox').checked; });
  }
  completed = 0;
  appendCompleted('setup events');

  // Automatically launch a requested test if specified in the URL.
  if (window.location.hash) {
    var requestedTest = window.location.hash.substr(1);
    if (fnMap.hasOwnProperty(requestedTest)) {
      fnMap[requestedTest]();
    }
  }
}
document.addEventListener('DOMContentLoaded', setupEvents);