12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Enum for WebDriver status codes.
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @enum {number}
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var StatusCode = {
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  OK: 0,
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UNKNOWN_ERROR: 13,
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  JAVASCRIPT_ERROR: 17,
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SCRIPT_TIMEOUT: 28,
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Dictionary key for asynchronous script info.
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @const
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)var ASYNC_INFO_KEY = '$chrome_asyncScriptInfo';
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)* Return the information of asynchronous script execution.
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)*
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)* @return {Object.<string, ?>} Information of asynchronous script execution.
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)*/
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function getAsyncScriptInfo() {
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!(ASYNC_INFO_KEY in document))
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    document[ASYNC_INFO_KEY] = {'id': 0};
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return document[ASYNC_INFO_KEY];
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)* Execute the given script and save its asynchronous result.
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)*
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)* If script1 finishes after script2 is executed, then script1's result will be
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)* discarded while script2's will be saved.
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)*
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)* @param {string} script The asynchronous script to be executed. The script
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     should be a proper function body. It will be wrapped in a function and
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     invoked with the given arguments and, as the final argument, a callback
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     function to invoke to report the asynchronous result.
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)* @param {!Array.<*>} args Arguments to be passed to the script.
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)* @param {boolean} isUserSupplied Whether the script is supplied by the user.
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     If not, UnknownError will be used instead of JavaScriptError if an
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     exception occurs during the script, and an additional error callback will
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     be supplied to the script.
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)* @param {?number} opt_timeoutMillis The timeout, in milliseconds, to use.
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     If the timeout is exceeded and the callback has not been invoked, a error
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     result will be saved and future invocation of the callback will be
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)*     ignored.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)*/
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function executeAsyncScript(script, args, isUserSupplied, opt_timeoutMillis) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var info = getAsyncScriptInfo();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  info.id++;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete info.result;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var id = info.id;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  function report(status, value) {
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (id != info.id)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    info.id++;
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    info.result = {status: status, value: value};
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  function reportValue(value) {
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    report(StatusCode.OK, value);
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  function reportScriptError(error) {
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    var code = isUserSupplied ? StatusCode.JAVASCRIPT_ERROR :
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                (error.code || StatusCode.UNKNOWN_ERROR);
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    report(code, error.message);
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  args.push(reportValue);
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!isUserSupplied)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    args.push(reportScriptError);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  try {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    new Function(script).apply(null, args);
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } catch (error) {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    reportScriptError(error);
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (typeof(opt_timeoutMillis) != 'undefined') {
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    window.setTimeout(function() {
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      var code = isUserSupplied ? StatusCode.SCRIPT_TIMEOUT :
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                  StatusCode.UNKNOWN_ERROR;
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      var errorMsg = 'result was not received in ' + opt_timeoutMillis / 1000 +
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     ' seconds';
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      report(code, errorMsg);
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }, opt_timeoutMillis);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
94