/testing/selenium-core/scripts/selenium-remoterunner.js

http://datanucleus-appengine.googlecode.com/ · JavaScript · 693 lines · 473 code · 64 blank · 156 comment · 116 complexity · 78f89134c65aa67813eddc7da4300dd6 MD5 · raw file

  1. /*
  2. * Copyright 2005 ThoughtWorks, Inc
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. passColor = "#cfffcf";
  18. failColor = "#ffcfcf";
  19. errorColor = "#ffffff";
  20. workingColor = "#DEE7EC";
  21. doneColor = "#FFFFCC";
  22. var injectedSessionId;
  23. var postResult = "START";
  24. var debugMode = false;
  25. var relayToRC = null;
  26. var proxyInjectionMode = false;
  27. var uniqueId = 'sel_' + Math.round(100000 * Math.random());
  28. var seleniumSequenceNumber = 0;
  29. var cmd8 = "";
  30. var cmd7 = "";
  31. var cmd6 = "";
  32. var cmd5 = "";
  33. var cmd4 = "";
  34. var cmd3 = "";
  35. var cmd2 = "";
  36. var cmd1 = "";
  37. var lastCmd = "";
  38. var lastCmdTime = new Date();
  39. var RemoteRunnerOptions = classCreate();
  40. objectExtend(RemoteRunnerOptions.prototype, URLConfiguration.prototype);
  41. objectExtend(RemoteRunnerOptions.prototype, {
  42. initialize: function() {
  43. this._acquireQueryString();
  44. },
  45. isDebugMode: function() {
  46. return this._isQueryParameterTrue("debugMode");
  47. },
  48. getContinue: function() {
  49. return this._getQueryParameter("continue");
  50. },
  51. getDriverUrl: function() {
  52. return this._getQueryParameter("driverUrl");
  53. },
  54. // requires per-session extension Javascript as soon as this Selenium
  55. // instance becomes aware of the session identifier
  56. getSessionId: function() {
  57. var sessionId = this._getQueryParameter("sessionId");
  58. requireExtensionJs(sessionId);
  59. return sessionId;
  60. },
  61. _acquireQueryString: function () {
  62. if (this.queryString) return;
  63. if (browserVersion.isHTA) {
  64. var args = this._extractArgs();
  65. if (args.length < 2) return null;
  66. this.queryString = args[1];
  67. } else if (proxyInjectionMode) {
  68. this.queryString = window.location.search.substr(1);
  69. } else {
  70. this.queryString = top.location.search.substr(1);
  71. }
  72. }
  73. });
  74. var runOptions;
  75. function runSeleniumTest() {
  76. runOptions = new RemoteRunnerOptions();
  77. var testAppWindow;
  78. if (runOptions.isMultiWindowMode()) {
  79. testAppWindow = openSeparateApplicationWindow('Blank.html', true);
  80. } else if (sel$('selenium_myiframe') != null) {
  81. var myiframe = sel$('selenium_myiframe');
  82. if (myiframe) {
  83. testAppWindow = myiframe.contentWindow;
  84. }
  85. }
  86. else {
  87. proxyInjectionMode = true;
  88. testAppWindow = window;
  89. }
  90. selenium = Selenium.createForWindow(testAppWindow, proxyInjectionMode);
  91. if (runOptions.getBaseUrl()) {
  92. selenium.browserbot.baseUrl = runOptions.getBaseUrl();
  93. }
  94. if (!debugMode) {
  95. debugMode = runOptions.isDebugMode();
  96. }
  97. if (proxyInjectionMode) {
  98. LOG.logHook = logToRc;
  99. selenium.browserbot._modifyWindow(testAppWindow);
  100. }
  101. else if (debugMode) {
  102. LOG.logHook = logToRc;
  103. }
  104. window.selenium = selenium;
  105. commandFactory = new CommandHandlerFactory();
  106. commandFactory.registerAll(selenium);
  107. currentTest = new RemoteRunner(commandFactory);
  108. var doContinue = runOptions.getContinue();
  109. if (doContinue != null) postResult = "OK";
  110. currentTest.start();
  111. }
  112. function buildDriverUrl() {
  113. var driverUrl = runOptions.getDriverUrl();
  114. if (driverUrl != null) {
  115. return driverUrl;
  116. }
  117. var s = window.location.href
  118. var slashPairOffset = s.indexOf("//") + "//".length
  119. var pathSlashOffset = s.substring(slashPairOffset).indexOf("/")
  120. return s.substring(0, slashPairOffset + pathSlashOffset) + "/selenium-server/driver/";
  121. //return "http://localhost" + uniqueId + "/selenium-server/driver/";
  122. }
  123. function logToRc(logLevel, message) {
  124. if (debugMode) {
  125. if (logLevel == null) {
  126. logLevel = "debug";
  127. }
  128. sendToRCAndForget("logLevel=" + logLevel + ":" + message.replace(/[\n\r\015]/g, " ") + "\n", "logging=true");
  129. }
  130. }
  131. function serializeString(name, s) {
  132. return name + "=unescape(\"" + escape(s) + "\");";
  133. }
  134. function serializeObject(name, x)
  135. {
  136. var s = '';
  137. if (isArray(x))
  138. {
  139. s = name + "=new Array(); ";
  140. var len = x["length"];
  141. for (var j = 0; j < len; j++)
  142. {
  143. s += serializeString(name + "[" + j + "]", x[j]);
  144. }
  145. }
  146. else if (typeof x == "string")
  147. {
  148. s = serializeString(name, x);
  149. }
  150. else
  151. {
  152. throw "unrecognized object not encoded: " + name + "(" + x + ")";
  153. }
  154. return s;
  155. }
  156. function relayBotToRC(s) {
  157. }
  158. // seems like no one uses this, but in fact it is called using eval from server-side PI mode code; however,
  159. // because multiple names can map to the same popup, assigning a single name confuses matters sometimes;
  160. // thus, I'm disabling this for now. -Nelson 10/21/06
  161. function setSeleniumWindowName(seleniumWindowName) {
  162. //selenium.browserbot.getCurrentWindow()['seleniumWindowName'] = seleniumWindowName;
  163. }
  164. RemoteRunner = classCreate();
  165. objectExtend(RemoteRunner.prototype, new TestLoop());
  166. objectExtend(RemoteRunner.prototype, {
  167. initialize : function(commandFactory) {
  168. this.commandFactory = commandFactory;
  169. this.requiresCallBack = true;
  170. this.commandNode = null;
  171. this.xmlHttpForCommandsAndResults = null;
  172. },
  173. nextCommand : function() {
  174. var urlParms = "";
  175. if (postResult == "START") {
  176. urlParms += "seleniumStart=true";
  177. }
  178. this.xmlHttpForCommandsAndResults = XmlHttp.create();
  179. sendToRC(postResult, urlParms, fnBind(this._HandleHttpResponse, this), this.xmlHttpForCommandsAndResults);
  180. },
  181. commandStarted : function(command) {
  182. this.commandNode = document.createElement("div");
  183. var cmdText = command.command + '(';
  184. if (command.target != null && command.target != "") {
  185. cmdText += command.target;
  186. if (command.value != null && command.value != "") {
  187. cmdText += ', ' + command.value;
  188. }
  189. }
  190. if (cmdText.length > 70) {
  191. cmdText = cmdText.substring(0, 70) + "...\n";
  192. } else {
  193. cmdText += ")\n";
  194. }
  195. if (cmdText == lastCmd) {
  196. var rightNow = new Date();
  197. var msSinceStart = rightNow.getTime() - lastCmdTime.getTime();
  198. var sinceStart = msSinceStart + "ms";
  199. if (msSinceStart > 1000) {
  200. sinceStart = Math.round(msSinceStart / 1000) + "s";
  201. }
  202. cmd1 = "Same command (" + sinceStart + "): " + lastCmd;
  203. } else {
  204. lastCmdTime = new Date();
  205. cmd8 = cmd7;
  206. cmd7 = cmd6;
  207. cmd6 = cmd5;
  208. cmd5 = cmd4;
  209. cmd4 = cmd3;
  210. cmd3 = cmd2;
  211. cmd2 = cmd1;
  212. cmd1 = cmdText;
  213. }
  214. lastCmd = cmdText;
  215. var commandList = document.commands.commandList;
  216. commandList.value = cmd8 + cmd7 + cmd6 + cmd5 + cmd4 + cmd3 + cmd2 + cmd1;
  217. commandList.scrollTop = commandList.scrollHeight;
  218. },
  219. commandComplete : function(result) {
  220. if (result.failed) {
  221. if (postResult == "CONTINUATION") {
  222. currentTest.aborted = true;
  223. }
  224. postResult = result.failureMessage;
  225. this.commandNode.title = result.failureMessage;
  226. this.commandNode.style.backgroundColor = failColor;
  227. } else if (result.passed) {
  228. postResult = "OK";
  229. this.commandNode.style.backgroundColor = passColor;
  230. } else {
  231. if (result.result == null) {
  232. postResult = "OK";
  233. } else {
  234. var actualResult = result.result;
  235. actualResult = selArrayToString(actualResult);
  236. postResult = "OK," + actualResult;
  237. }
  238. this.commandNode.style.backgroundColor = doneColor;
  239. }
  240. },
  241. commandError : function(message) {
  242. postResult = "ERROR: " + message;
  243. this.commandNode.style.backgroundColor = errorColor;
  244. this.commandNode.titcle = message;
  245. },
  246. testComplete : function() {
  247. window.status = "Selenium Tests Complete, for this Test"
  248. // Continue checking for new results
  249. this.continueTest();
  250. postResult = "START";
  251. },
  252. _HandleHttpResponse : function() {
  253. // When request is completed
  254. if (this.xmlHttpForCommandsAndResults.readyState == 4) {
  255. // OK
  256. if (this.xmlHttpForCommandsAndResults.status == 200) {
  257. if (this.xmlHttpForCommandsAndResults.responseText=="") {
  258. LOG.error("saw blank string xmlHttpForCommandsAndResults.responseText");
  259. return;
  260. }
  261. var command = this._extractCommand(this.xmlHttpForCommandsAndResults);
  262. if (command.command == 'retryLast') {
  263. setTimeout(fnBind(function() {
  264. sendToRC("RETRY", "retry=true", fnBind(this._HandleHttpResponse, this), this.xmlHttpForCommandsAndResults, true);
  265. }, this), 1000);
  266. } else {
  267. this.currentCommand = command;
  268. this.continueTestAtCurrentCommand();
  269. }
  270. }
  271. // Not OK
  272. else {
  273. var s = 'xmlHttp returned: ' + this.xmlHttpForCommandsAndResults.status + ": " + this.xmlHttpForCommandsAndResults.statusText;
  274. LOG.error(s);
  275. this.currentCommand = null;
  276. setTimeout(fnBind(this.continueTestAtCurrentCommand, this), 2000);
  277. }
  278. }
  279. },
  280. _extractCommand : function(xmlHttp) {
  281. var command, text, json;
  282. text = command = xmlHttp.responseText;
  283. if (/^json=/.test(text)) {
  284. eval(text);
  285. if (json.rest) {
  286. eval(json.rest);
  287. }
  288. return json;
  289. }
  290. try {
  291. var re = new RegExp("^(.*?)\n((.|[\r\n])*)");
  292. if (re.exec(xmlHttp.responseText)) {
  293. command = RegExp.$1;
  294. var rest = RegExp.$2;
  295. rest = rest.trim();
  296. if (rest) {
  297. eval(rest);
  298. }
  299. }
  300. else {
  301. command = xmlHttp.responseText;
  302. }
  303. } catch (e) {
  304. alert('could not get responseText: ' + e.message);
  305. }
  306. if (command.substr(0, '|testComplete'.length) == '|testComplete') {
  307. return null;
  308. }
  309. return this._createCommandFromRequest(command);
  310. },
  311. _delay : function(millis) {
  312. var startMillis = new Date();
  313. while (true) {
  314. milli = new Date();
  315. if (milli - startMillis > millis) {
  316. break;
  317. }
  318. }
  319. },
  320. // Parses a URI query string into a SeleniumCommand object
  321. _createCommandFromRequest : function(commandRequest) {
  322. //decodeURIComponent doesn't strip plus signs
  323. var processed = commandRequest.replace(/\+/g, "%20");
  324. // strip trailing spaces
  325. var processed = processed.replace(/\s+$/, "");
  326. var vars = processed.split("&");
  327. var cmdArgs = new Object();
  328. for (var i = 0; i < vars.length; i++) {
  329. var pair = vars[i].split("=");
  330. cmdArgs[pair[0]] = pair[1];
  331. }
  332. var cmd = cmdArgs['cmd'];
  333. var arg1 = cmdArgs['1'];
  334. if (null == arg1) arg1 = "";
  335. arg1 = decodeURIComponent(arg1);
  336. var arg2 = cmdArgs['2'];
  337. if (null == arg2) arg2 = "";
  338. arg2 = decodeURIComponent(arg2);
  339. if (cmd == null) {
  340. throw new Error("Bad command request: " + commandRequest);
  341. }
  342. return new SeleniumCommand(cmd, arg1, arg2);
  343. }
  344. })
  345. function sendToRC(dataToBePosted, urlParms, callback, xmlHttpObject, async) {
  346. if (async == null) {
  347. async = true;
  348. }
  349. if (xmlHttpObject == null) {
  350. xmlHttpObject = XmlHttp.create();
  351. }
  352. var url = buildDriverUrl() + "?"
  353. if (urlParms) {
  354. url += urlParms;
  355. }
  356. url = addUrlParams(url);
  357. url += "&sequenceNumber=" + seleniumSequenceNumber++;
  358. var postedData = "postedData=" + encodeURIComponent(dataToBePosted);
  359. //xmlHttpObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  360. xmlHttpObject.open("POST", url, async);
  361. if (callback) xmlHttpObject.onreadystatechange = callback;
  362. xmlHttpObject.send(postedData);
  363. return null;
  364. }
  365. function addUrlParams(url) {
  366. return url + "&localFrameAddress=" + (proxyInjectionMode ? makeAddressToAUTFrame() : "top")
  367. + getSeleniumWindowNameURLparameters()
  368. + "&uniqueId=" + uniqueId
  369. + buildDriverParams() + preventBrowserCaching()
  370. }
  371. function sendToRCAndForget(dataToBePosted, urlParams) {
  372. var url;
  373. if (!(browserVersion.isChrome || browserVersion.isHTA)) {
  374. // DGF we're behind a proxy, so we can send our logging message to literally any host, to avoid 2-connection limit
  375. var protocol = "http:";
  376. if (window.location.protocol == "https:") {
  377. // DGF if we're in HTTPS, use another HTTPS url to avoid security warning
  378. protocol = "https:";
  379. }
  380. // we don't choose a super large random value, but rather 1 - 16, because this matches with the pre-computed
  381. // tunnels waiting on the Selenium Server side. This gives us higher throughput than the two-connection-per-host
  382. // limitation, but doesn't require we generate an extremely large ammount of fake SSL certs either.
  383. url = protocol + "//" + Math.floor(Math.random()* 16 + 1) + ".selenium.doesnotexist/selenium-server/driver/?" + urlParams;
  384. } else {
  385. url = buildDriverUrl() + "?" + urlParams;
  386. }
  387. url = addUrlParams(url);
  388. var method = "GET";
  389. if (method == "POST") {
  390. // DGF submit a request using an iframe; we can't see the response, but we don't need to
  391. // TODO not using this mechanism because it screws up back-button
  392. var loggingForm = document.createElement("form");
  393. loggingForm.method = "POST";
  394. loggingForm.action = url;
  395. loggingForm.target = "seleniumLoggingFrame";
  396. var postedDataInput = document.createElement("input");
  397. postedDataInput.type = "hidden";
  398. postedDataInput.name = "postedData";
  399. postedDataInput.value = dataToBePosted;
  400. loggingForm.appendChild(postedDataInput);
  401. document.body.appendChild(loggingForm);
  402. loggingForm.submit();
  403. document.body.removeChild(loggingForm);
  404. } else {
  405. var postedData = "&postedData=" + encodeURIComponent(dataToBePosted);
  406. var scriptTag = document.createElement("script");
  407. scriptTag.src = url + postedData;
  408. document.body.appendChild(scriptTag);
  409. document.body.removeChild(scriptTag);
  410. }
  411. }
  412. function buildDriverParams() {
  413. var params = "";
  414. var sessionId = runOptions.getSessionId();
  415. if (sessionId == undefined) {
  416. sessionId = injectedSessionId;
  417. }
  418. if (sessionId != undefined) {
  419. params = params + "&sessionId=" + sessionId;
  420. }
  421. return params;
  422. }
  423. function preventBrowserCaching() {
  424. var t = (new Date()).getTime();
  425. return "&counterToMakeURsUniqueAndSoStopPageCachingInTheBrowser=" + t;
  426. }
  427. //
  428. // Return URL parameters pertaining to the name(s?) of the current window
  429. //
  430. // In selenium, the main (i.e., first) window's name is a blank string.
  431. //
  432. // Additional pop-ups are associated with either 1.) the name given by the 2nd parameter to window.open, or 2.) the name of a
  433. // property on the opening window which points at the window.
  434. //
  435. // An example of #2: if window X contains JavaScript as follows:
  436. //
  437. // var windowABC = window.open(...)
  438. //
  439. // Note that the example JavaScript above is equivalent to
  440. //
  441. // window["windowABC"] = window.open(...)
  442. //
  443. function getSeleniumWindowNameURLparameters() {
  444. var w = (proxyInjectionMode ? selenium.browserbot.getCurrentWindow() : window).top;
  445. var s = "&seleniumWindowName=";
  446. if (w.opener == null) {
  447. return s;
  448. }
  449. if (w["seleniumWindowName"] == null) {
  450. if (w.name) {
  451. w["seleniumWindowName"] = w.name;
  452. } else {
  453. w["seleniumWindowName"] = 'generatedSeleniumWindowName_' + Math.round(100000 * Math.random());
  454. }
  455. }
  456. s += w["seleniumWindowName"];
  457. var windowOpener = w.opener;
  458. for (key in windowOpener) {
  459. var val = null;
  460. try {
  461. val = windowOpener[key];
  462. }
  463. catch(e) {
  464. }
  465. if (val==w) {
  466. s += "&jsWindowNameVar=" + key; // found a js variable in the opener referring to this window
  467. }
  468. }
  469. return s;
  470. }
  471. // construct a JavaScript expression which leads to my frame (i.e., the frame containing the window
  472. // in which this code is operating)
  473. function makeAddressToAUTFrame(w, frameNavigationalJSexpression)
  474. {
  475. if (w == null)
  476. {
  477. w = top;
  478. frameNavigationalJSexpression = "top";
  479. }
  480. if (w == selenium.browserbot.getCurrentWindow())
  481. {
  482. return frameNavigationalJSexpression;
  483. }
  484. for (var j = 0; j < w.frames.length; j++)
  485. {
  486. var t = makeAddressToAUTFrame(w.frames[j], frameNavigationalJSexpression + ".frames[" + j + "]");
  487. if (t != null)
  488. {
  489. return t;
  490. }
  491. }
  492. return null;
  493. }
  494. Selenium.prototype.doSetContext = function(context) {
  495. /**
  496. * Writes a message to the status bar and adds a note to the browser-side
  497. * log.
  498. *
  499. * @param context
  500. * the message to be sent to the browser
  501. */
  502. //set the current test title
  503. var ctx = document.getElementById("context");
  504. if (ctx != null) {
  505. ctx.innerHTML = context;
  506. }
  507. };
  508. /**
  509. * Adds a script tag referencing a specially-named user extensions "file". The
  510. * resource handler for this special file (which won't actually exist) will use
  511. * the session ID embedded in its name to retrieve per-session specified user
  512. * extension javascript.
  513. *
  514. * @param sessionId
  515. */
  516. function requireExtensionJs(sessionId) {
  517. var src = 'scripts/user-extensions.js[' + sessionId + ']';
  518. if (document.getElementById(src) == null) {
  519. var scriptTag = document.createElement('script');
  520. scriptTag.language = 'JavaScript';
  521. scriptTag.type = 'text/javascript';
  522. scriptTag.src = src;
  523. scriptTag.id = src;
  524. var headTag = document.getElementsByTagName('head')[0];
  525. headTag.appendChild(scriptTag);
  526. }
  527. }
  528. Selenium.prototype.doAttachFile = function(fieldLocator,fileLocator) {
  529. /**
  530. * Sets a file input (upload) field to the file listed in fileLocator
  531. *
  532. * @param fieldLocator an <a href="#locators">element locator</a>
  533. * @param fileLocator a URL pointing to the specified file. Before the file
  534. * can be set in the input field (fieldLocator), Selenium RC may need to transfer the file
  535. * to the local machine before attaching the file in a web page form. This is common in selenium
  536. * grid configurations where the RC server driving the browser is not the same
  537. * machine that started the test.
  538. *
  539. * Supported Browsers: Firefox ("*chrome") only.
  540. *
  541. */
  542. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  543. };
  544. Selenium.prototype.doCaptureScreenshot = function(filename) {
  545. /**
  546. * Captures a PNG screenshot to the specified file.
  547. *
  548. * @param filename the absolute path to the file to be written, e.g. "c:\blah\screenshot.png"
  549. */
  550. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  551. };
  552. Selenium.prototype.doCaptureScreenshotToString = function() {
  553. /**
  554. * Capture a PNG screenshot. It then returns the file as a base 64 encoded string.
  555. *
  556. * @return string The base 64 encoded string of the screen shot (PNG file)
  557. */
  558. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  559. };
  560. Selenium.prototype.doCaptureEntirePageScreenshotToString = function(kwargs) {
  561. /**
  562. * Downloads a screenshot of the browser current window canvas to a
  563. * based 64 encoded PNG file. The <em>entire</em> windows canvas is captured,
  564. * including parts rendered outside of the current view port.
  565. *
  566. * Currently this only works in Mozilla and when running in chrome mode.
  567. *
  568. * @param kwargs A kwargs string that modifies the way the screenshot is captured. Example: "background=#CCFFDD". This may be useful to set for capturing screenshots of less-than-ideal layouts, for example where absolute positioning causes the calculation of the canvas dimension to fail and a black background is exposed (possibly obscuring black text).
  569. *
  570. * @return string The base 64 encoded string of the page screenshot (PNG file)
  571. */
  572. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  573. };
  574. Selenium.prototype.doShutDownSeleniumServer = function(keycode) {
  575. /**
  576. * Kills the running Selenium Server and all browser sessions. After you run this command, you will no longer be able to send
  577. * commands to the server; you can't remotely start the server once it has been stopped. Normally
  578. * you should prefer to run the "stop" command, which terminates the current browser session, rather than
  579. * shutting down the entire server.
  580. *
  581. */
  582. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  583. };
  584. Selenium.prototype.doRetrieveLastRemoteControlLogs = function() {
  585. /**
  586. * Retrieve the last messages logged on a specific remote control. Useful for error reports, especially
  587. * when running multiple remote controls in a distributed environment. The maximum number of log messages
  588. * that can be retrieve is configured on remote control startup.
  589. *
  590. * @return string The last N log messages as a multi-line string.
  591. */
  592. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  593. };
  594. Selenium.prototype.doKeyDownNative = function(keycode) {
  595. /**
  596. * Simulates a user pressing a key (without releasing it yet) by sending a native operating system keystroke.
  597. * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing
  598. * a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and
  599. * metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular
  600. * element, focus on the element first before running this command.
  601. *
  602. * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!
  603. */
  604. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  605. };
  606. Selenium.prototype.doKeyUpNative = function(keycode) {
  607. /**
  608. * Simulates a user releasing a key by sending a native operating system keystroke.
  609. * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing
  610. * a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and
  611. * metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular
  612. * element, focus on the element first before running this command.
  613. *
  614. * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!
  615. */
  616. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  617. };
  618. Selenium.prototype.doKeyPressNative = function(keycode) {
  619. /**
  620. * Simulates a user pressing and releasing a key by sending a native operating system keystroke.
  621. * This function uses the java.awt.Robot class to send a keystroke; this more accurately simulates typing
  622. * a key on the keyboard. It does not honor settings from the shiftKeyDown, controlKeyDown, altKeyDown and
  623. * metaKeyDown commands, and does not target any particular HTML element. To send a keystroke to a particular
  624. * element, focus on the element first before running this command.
  625. *
  626. * @param keycode an integer keycode number corresponding to a java.awt.event.KeyEvent; note that Java keycodes are NOT the same thing as JavaScript keycodes!
  627. */
  628. // This doesn't really do anything on the JS side; we let the Selenium Server take care of this for us!
  629. };