source: Dev/trunk/src/client/util/doh/robot.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 23.9 KB
Line 
1define([
2        "doh/_browserRunner", "require",
3        "dojo/aspect", "dojo/Deferred", "dojo/dom-class", "dojo/dom-construct", "dojo/dom-geometry", "dojo/_base/lang", "dojo/ready",
4        "dojo/_base/unload", "dojo/when", "dojo/_base/window", "dojo/sniff", "dojo/has", "dojo/has!android?doh/plugins/android-webdriver-robot"
5], function(doh, require, aspect, Deferred, domClass, construct, geom, lang, ready, unload, when, win, sniff, has, webdriver){
6
7// loading state
8var _robot = null;
9
10var isSecure = (function(){
11        var key = Math.random();
12        return function(fcn){
13                return key;
14        };
15})();
16
17var _keyPress = function(/*Number*/ charCode, /*Number*/ keyCode, /*Boolean*/ alt, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Boolean*/ meta, /*Integer?*/ delay, /*Boolean*/ async){
18        // internal function to type one non-modifier key
19
20        // typecasting Numbers helps Sun's IE plugin lookup methods that take int arguments
21
22        // otherwise JS will send a double and Sun will complain
23        _robot.typeKey(isSecure(), Number(charCode), Number(keyCode), Boolean(alt), Boolean(ctrl), Boolean(shift), Boolean(meta), Number(delay||0), Boolean(async||false));
24};
25
26// Queue of pending actions plus the currently executing action registered via sequence().
27// Each action is a function that either:
28//              1. does a setTimeout()
29//              2. calls java Robot (mouse movement, typing a single letter, etc.)
30//              3. executes user defined function (for when app called sequence() directly).
31// Each function can return a Promise, or just a plain value if it executes synchronously.
32var seqPromise;
33aspect.before(doh, "_runFixture", function(){
34        // At the start of each new test fixture, clear any leftover queued actions from the previous test fixture.
35        // This will happen when the previous test throws an error, or times out.
36        var _seqPromise = seqPromise;
37        // need setTimeout to avoid false error; seqPromise from passing test is not fulfilled until after this execution trace finishes!
38        // really we should not have both `seqPromise` here and `var d = new doh.Deferred()` in the test
39        setTimeout(function(){
40                if(_seqPromise && !_seqPromise.isFulfilled()){
41                        _seqPromise.cancel(new Error("new test starting, cancelling pending & in-progress queued events from previous test"));
42                }
43        },0);
44        seqPromise = new Deferred();
45        seqPromise.resolve(true);
46});
47
48// Previous mouse position (from most recent mouseMoveTo() command)
49var lastMouse = {x: 5, y: 5};
50
51// For 2.0, remove code to set doh.robot global.
52var robot = doh.robot = {
53        _robotLoaded: true,
54        _robotInitialized: false,
55        // prime the event pump for fast browsers like Google Chrome - it's so fast, it doesn't stop to listen for keypresses!
56        _spaceReceived: false,
57        _primePump: false,
58
59        _killApplet: function(){}, // overridden by Robot.html
60
61        killRobot: function(){
62                if(robot._robotLoaded){
63                        robot._robotLoaded = false;
64                        domClass.remove(document.documentElement, "dohRobot");
65                        robot._killApplet();
66                }
67        },
68
69        // Robot init methods
70
71        // controls access to doh.run
72        // basically, doh.run takes two calls to start the robot:
73        // one (or more after the robot loads) from the test page
74        // one from either the applet or an error condition
75        _runsemaphore: {
76                lock: ["lock"],
77                unlock: function(){
78                        try{
79                                return this.lock.shift();
80                        }catch(e){
81                                return null;
82                        }
83                }
84        },
85
86        startRobot: function(){
87                //startRobot should be called to initialize the robot (after the java applet is loaded).
88                //one good place to do this is in a dojo.addOnLoad handler. This function will be called
89                //automatically if it is not already called when doh.run() is invoked.
90                if(!this._robotInitialized){
91                        this._robotInitialized = true;
92                        // if the iframe requested the applet and got a 404, then _robot is obviously unavailable
93                        // at least run the non-robot tests!
94                        if(robot._appletDead){
95                                robot._onKeyboard();
96                        }else{
97                                _robot._callLoaded(isSecure());
98                        }
99                }
100
101                // When robot finishes initializing it types a key, firing the _onKeyboard() listener, which calls _run(),
102                // which resolves this Deferred.
103                return this._started;
104        },
105
106        // _loaded: Deferred
107        //              Deferred that resolves when the _initRobot() has been called.
108        //              Note to be confused with dojo/robotx.js, which defines initRobot() without an underscore
109        _loaded: new doh.Deferred(),
110
111        _initRobot: function(r){
112                // called from Robot
113                // Robot calls _initRobot in its startup sequence
114
115                // Prevent rerunning the whole test (see #8958 for details)
116                if(doh._initRobotCalled){ return; }
117                doh._initRobotCalled = true;
118
119                // add dohRobot class to HTML element so tests can use that in CSS rules if desired
120                domClass.add(document.documentElement, "dohRobot");
121                window.scrollTo(0, 0);
122//              document.documentElement.scrollTop = document.documentElement.scrollLeft = 0;
123                _robot = r;
124                _robot._setKey(isSecure());
125                this._loaded.resolve(true);
126        },
127
128        // _started: Deferred
129        //              Deferred that resolves when startRobot() has signaled completing by typing on the keyboard,
130        //              which in turn calls _run().
131        _started: new doh.Deferred(),
132
133        // some utility functions to help the iframe use private variables
134        _run: function(frame){
135                // called after the robot has been able to type on the keyboard, indicating that it's started
136                frame.style.visibility = "hidden";
137                this._started.resolve(true);
138        },
139
140        _initKeyboard: function(){
141                _robot._initKeyboard(isSecure());
142        },
143
144        _onKeyboard: function(){
145                // replaced by iframe when applet present.
146                // remote robots don't have frames so pass a mock frame.
147                this._run({style:{visibility:""}});
148        },
149
150        _initWheel: function(){
151                _robot._initWheel(isSecure());
152        },
153
154        _setDocumentBounds: function(docScreenX, docScreenY){
155                var robotView = document.getElementById("dohrobotview");
156                _robot.setDocumentBounds(isSecure(), Number(docScreenX), Number(docScreenY), Number(robotView.offsetLeft), Number(robotView.offsetTop));
157        },
158
159        _notified: function(keystring){
160                _robot._notified(isSecure(), keystring);
161        },
162
163        // if the applet is 404 or cert is denied, this becomes true and kills tests
164        _appletDead: false,
165
166        _assertRobot: function(){
167                // make sure the applet is there and cert accepted
168                // otherwise, skip the test requesting the robot action
169                if(robot._appletDead){ throw new Error('robot not available; skipping test.'); }
170        },
171
172        _mouseMove: function(/*Number*/ x, /*Number*/ y, /*Boolean*/ absolute, /*Integer?*/ duration){
173                // This function is no longer used, but left for back-compat
174                if(absolute){
175                        var scroll = {y: (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0),
176                        x: (window.pageXOffset || geom.fixIeBiDiScrollLeft(document.documentElement.scrollLeft) || document.body.scrollLeft || 0)};
177                        y -= scroll.y;
178                        x -= scroll.x;
179                }
180                _robot.moveMouse(isSecure(), Number(x), Number(y), Number(0), Number(duration||100));
181        },
182
183        // Main robot API
184        sequence: function(/*Function*/ f, /*Integer?*/ delay, /*Integer?*/ duration){
185                // summary:
186                //              Defer an action by adding it to the robot's incrementally delayed queue of actions to execute.
187                // f:
188                //              A function containing actions you want to defer.  It can return a Promise
189                //              to delay further actions.
190                // delay:
191                //              Delay, in milliseconds, to wait before firing.
192                //              The delay is a delta with respect to the previous automation call.
193                //              For example, the following code ends after 600ms:
194                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
195                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
196                // duration:
197                //              Delay to wait after firing.
198
199                function waitFunc(ms){
200                        // Returns a function that returns a Promise that fires after ms milliseconds.
201                        return function(){
202                                var timer, d;
203                                d = new Deferred(function(){ clearTimeout(timer); });
204                                timer = setTimeout(function(){ d.resolve(true); }, ms);
205                                return d;
206                        };
207                }
208
209                // Queue action to run specified function, plus optional "wait" actions for delay and duration.
210                if(delay){ seqPromise = seqPromise.then(waitFunc(delay)); }
211                seqPromise = seqPromise.then(f);
212                if(duration){ seqPromise = seqPromise.then(waitFunc(duration)); }
213        },
214
215        typeKeys: function(/*String|Number*/ chars, /*Integer?*/ delay, /*Integer?*/ duration){
216                // summary:
217                //              Types a string of characters in order, or types a dojo.keys.* constant.
218                // description:
219                //              Types a string of characters in order, or types a dojo.keys.* constant.
220                // example:
221                // |    robot.typeKeys("dijit.ed", 500);
222                // chars:
223                //              String of characters to type, or a dojo.keys.* constant
224                // delay:
225                //              Delay, in milliseconds, to wait before firing.
226                //              The delay is a delta with respect to the previous automation call.
227                //              For example, the following code ends after 600ms:
228                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
229                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
230                // duration:
231                //              Time, in milliseconds, to spend pressing all of the keys.
232                //              The default is (string length)*50 ms.
233
234                this._assertRobot();
235                var isNum = typeof(chars) == Number;
236                duration = duration||(isNum?50: chars.length*50);
237                if(isNum){
238                        this.sequence(lang.partial(_keyPress, chars, chars, false, false, false, false, 0, 0),
239                                delay, duration);
240                }else{
241                        for(var i = 0; i < chars.length; i++){
242                                this.sequence(lang.partial(_keyPress, chars.charCodeAt(i), 0, false, false, false, false, 0, 0),
243                                        i == 0 ? delay : 0, Math.max(Math.ceil(duration/chars.length), 0));
244                        }
245                }
246        },
247
248        keyPress: function(/*Integer*/ charOrCode, /*Integer?*/ delay, /*Object*/ modifiers, /*Boolean*/ asynchronous){
249                // summary:
250                //              Types a key combination, like SHIFT-TAB.
251                // description:
252                //              Types a key combination, like SHIFT-TAB.
253                // example:
254                //              to press shift-tab immediately, call robot.keyPress(dojo.keys.TAB, 0, {shift: true})
255                // charOrCode:
256                //              char/JS keyCode/dojo.keys.* constant for the key you want to press
257                // delay:
258                //              Delay, in milliseconds, to wait before firing.
259                //              The delay is a delta with respect to the previous automation call.
260                //              For example, the following code ends after 600ms:
261                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
262                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
263                // modifiers:
264                //              JSON object that represents all of the modifier keys being pressed.
265                //              It takes the following Boolean attributes:
266                //
267                //              - shift
268                //              - alt
269                //              - ctrl
270                //              - meta
271                // asynchronous:
272                //              If true, the delay happens asynchronously and immediately, outside of the browser's JavaScript thread and any previous calls.
273                //              This is useful for interacting with the browser's modal dialogs.
274
275                this._assertRobot();
276                if(!modifiers){
277                        modifiers = {alt:false, ctrl:false, shift:false, meta:false};
278                }else{
279                        // normalize modifiers
280                        var attrs = ["alt", "ctrl", "shift", "meta"];
281                        for(var i = 0; i<attrs.length; i++){
282                                if(!modifiers[attrs[i]]){
283                                        modifiers[attrs[i]] = false;
284                                }
285                        }
286                }
287                var isChar = typeof(charOrCode)=="string";
288                if(asynchronous){
289                        _keyPress(isChar?charOrCode.charCodeAt(0):0, isChar?0:charOrCode, modifiers.alt, modifiers.ctrl, modifiers.shift, modifiers.meta, delay, true);
290                        return;
291                }
292                this.sequence(function(){
293                        _keyPress(isChar?charOrCode.charCodeAt(0):0, isChar?0:charOrCode, modifiers.alt, modifiers.ctrl, modifiers.shift, modifiers.meta, 0);
294                }, delay);
295        },
296
297        keyDown: function(/*Integer*/ charOrCode, /*Integer?*/ delay){
298                // summary:
299                //              Holds down a single key, like SHIFT or 'a'.
300                // description:
301                //              Holds down a single key, like SHIFT or 'a'.
302                // example:
303                //              to hold down the 'a' key immediately, call robot.keyDown('a')
304                // charOrCode:
305                //              char/JS keyCode/dojo.keys.* constant for the key you want to hold down
306                //              Warning: holding down a shifted key, like 'A', can have unpredictable results.
307                // delay:
308                //              Delay, in milliseconds, to wait before firing.
309                //              The delay is a delta with respect to the previous automation call.
310                //              For example, the following code ends after 600ms:
311                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
312                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
313
314                this._assertRobot();
315                this.sequence(function(){
316                        var isChar = typeof(charOrCode)=="string";
317                        _robot.downKey(isSecure(), isChar?charOrCode:0, isChar?0:charOrCode, 0);
318                }, delay);
319        },
320
321        keyUp: function(/*Integer*/ charOrCode, /*Integer?*/ delay){
322                // summary:
323                //              Releases a single key, like SHIFT or 'a'.
324                // description:
325                //              Releases a single key, like SHIFT or 'a'.
326                // example:
327                //              to release the 'a' key immediately, call robot.keyUp('a')
328                // charOrCode:
329                //              char/JS keyCode/dojo.keys.* constant for the key you want to release
330                //              Warning: releasing a shifted key, like 'A', can have unpredictable results.
331                // delay:
332                //              Delay, in milliseconds, to wait before firing.
333                //              The delay is a delta with respect to the previous automation call.
334                //              For example, the following code ends after 600ms:
335                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
336                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
337
338                this._assertRobot();
339                this.sequence(function(){
340                        var isChar=typeof(charOrCode)=="string";
341                        _robot.upKey(isSecure(), isChar?charOrCode:0, isChar?0:charOrCode, 0);
342                }, delay);
343        },
344
345
346        mouseClick: function(/*Object*/ buttons, /*Integer?*/ delay){
347                // summary:
348                //              Convenience function to do a press/release.
349                //              See robot.mousePress for more info.
350                // description:
351                //              Convenience function to do a press/release.
352                //              See robot.mousePress for more info.
353
354                this._assertRobot();
355                robot.mousePress(buttons, delay);
356                robot.mouseRelease(buttons, 1);
357        },
358
359        mousePress: function(/*Object*/ buttons, /*Integer?*/ delay){
360                // summary:
361                //              Presses mouse buttons.
362                // description:
363                //              Presses the mouse buttons you pass as true.
364                //              Example: to press the left mouse button, pass {left: true}.
365                //              Mouse buttons you don't specify keep their previous pressed state.
366                // buttons:
367                //              JSON object that represents all of the mouse buttons being pressed.
368                //              It takes the following Boolean attributes:
369                //
370                //              - left
371                //              - middle
372                //              - right
373                // delay:
374                //              Delay, in milliseconds, to wait before firing.
375                //              The delay is a delta with respect to the previous automation call.
376                //              For example, the following code ends after 600ms:
377                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
378                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
379
380                this._assertRobot();
381                if(!buttons){ return; }
382                this.sequence(function(){
383                        var attrs = ["left", "middle", "right"];
384                        for(var i = 0; i<attrs.length; i++){
385                                if(!buttons[attrs[i]]){
386                                        buttons[attrs[i]] = false;
387                                }
388                        }
389                        _robot.pressMouse(isSecure(), Boolean(buttons.left), Boolean(buttons.middle), Boolean(buttons.right), Number(0));
390                }, delay);
391        },
392
393        mouseMoveTo: function(/*Object*/ point, /*Integer?*/ delay, /*Integer?*/ duration, /*Boolean*/ absolute){
394                // summary:
395                //              Move the mouse from the current position to the specified point.
396                //              Delays reading contents point until queued command starts running.
397                //              See mouseMove() for details.
398                // point: Object
399                //              x, y position relative to viewport, or if absolute == true, to document
400
401                this._assertRobot();
402                duration = duration||100;
403
404                // Calculate number of mouse movements we will do, based on specified duration.
405                // IE6-8 timers have a granularity of 15ms, so only do one mouse move every 15ms
406                var steps = duration<=1 ? 1 : // duration==1 -> user wants to jump the mouse
407                        (duration/15)|1; // |1 to ensure an odd # of intermediate steps for sensible interpolation
408                var stepDuration = Math.floor(duration/steps);
409
410                // Starting and ending points of the mouse movement.
411                var start, end;
412
413                this.sequence(function(){
414                        // This runs right before we start moving the mouse.   At this time (but not before), point is guaranteed
415                        // to be filled w/the correct data.   So set start and end points for the movement of the mouse.
416                        start = lastMouse;
417                        if(absolute){
418                                // Adjust end to be relative to viewport
419                                var scroll = {y: (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0),
420                                        x: (window.pageXOffset || geom.fixIeBiDiScrollLeft(document.documentElement.scrollLeft) || document.body.scrollLeft || 0)};
421                                end = { y: point.y - scroll.y, x: point.x - scroll.x };
422                        }else{
423                                end = point;
424                        }
425                        //console.log("mouseMoveTo() start, going from (", lastMouse.x, lastMouse.y, "), (", end.x, end.y, "), delay = " +
426                        //      delay + ", duration = " + duration);
427                }, delay || 0);
428
429                // Function to positions the mouse along the line from start to end at the idx'th position (from 0 .. steps)
430                function step(idx){
431                        function easeInOutQuad(/*Number*/ t, /*Number*/ b, /*Number*/ c, /*Number*/ d){
432                                t /= d / 2;
433                                if(t < 1)
434                                        return Math.round(c / 2 * t * t + b);
435                                t--;
436                                return Math.round(-c / 2 * (t * (t - 2) - 1) + b);
437                        }
438
439                        var x = idx == steps ? end.x : easeInOutQuad(idx, start.x, end.x - start.x, steps),
440                                y = idx == steps ? end.y : easeInOutQuad(idx, start.y, end.y - start.y, steps);
441
442                        // If same position as the last time, don't bother calling java robot.
443                        if(x == lastMouse.x && y == lastMouse.y){ return true; }
444
445                        _robot.moveMouse(isSecure(), Number(x), Number(y), Number(0), Number(1));
446                        lastMouse = {x: x, y: y};
447                }
448
449                // Schedule mouse moves from beginning to end of line.
450                // Start from t=1 because there's no need to move the mouse to where it already is
451                for (var t = 1; t <= steps; t++){
452                        // Use lang.partial() to lock in value of t before the t++
453                        this.sequence(lang.partial(step, t), 0, stepDuration);
454                }
455        },
456
457        mouseMove: function(/*Number*/ x, /*Number*/ y, /*Integer?*/ delay, /*Integer?*/ duration, /*Boolean*/ absolute){
458                // summary:
459                //              Moves the mouse to the specified x,y offset relative to the viewport.
460                // x:
461                //              x offset relative to the viewport, in pixels, to move the mouse.
462                // y:
463                //              y offset relative to the viewport, in pixels, to move the mouse.
464                // delay:
465                //              Delay, in milliseconds, to wait before firing.
466                //              The delay is a delta with respect to the previous automation call.
467                //              For example, the following code ends after 600ms:
468                // |            robot.mouseClick({left: true}, 100) // first call; wait 100ms
469                // |            robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
470                // duration:
471                //              Approximate time Robot will spend moving the mouse
472                //              The default is 100ms. This also affects how many mousemove events will
473                //              be generated, which is the log of the duration.
474                // absolute:
475                //              Boolean indicating whether the x and y values are absolute coordinates.
476                //              If false, then mouseMove expects that the x,y will be relative to the window. (clientX/Y)
477                //              If true, then mouseMove expects that the x,y will be absolute. (pageX/Y)
478
479                this.mouseMoveTo({x: x, y: y}, delay, duration, absolute);
480        },
481
482        mouseRelease: function(/*Object*/ buttons, /*Integer?*/ delay){
483                // summary:
484                //              Releases mouse buttons.
485                // description:
486                //              Releases the mouse buttons you pass as true.
487                //              Example: to release the left mouse button, pass {left: true}.
488                //              Mouse buttons you don't specify keep their previous pressed state.
489                //              See robot.mousePress for more info.
490
491                this._assertRobot();
492                if(!buttons){ return; }
493                this.sequence(function(){
494                        var attrs = ["left", "middle", "right"];
495                        for(var i = 0; i<attrs.length; i++){
496                                if(!buttons[attrs[i]]){
497                                        buttons[attrs[i]] = false;
498                                }
499                        }
500                        _robot.releaseMouse(isSecure(), Boolean(buttons.left), Boolean(buttons.middle), Boolean(buttons.right), Number(0));
501                }, delay);
502        },
503
504        // mouseWheelSize: Integer value that determines the amount of wheel motion per unit
505        mouseWheelSize: 1,
506
507        mouseWheel: function(/*Number*/ wheelAmt, /*Integer?*/ delay, /*Integer?*/ duration){
508                // summary:
509                //              Spins the mouse wheel.
510                // description:
511                //              Spins the wheel wheelAmt "notches."
512                //              Negative wheelAmt scrolls up/away from the user.
513                //              Positive wheelAmt scrolls down/toward the user.
514                //              Note: this will all happen in one event.
515                //              Warning: the size of one mouse wheel notch is an OS setting.
516                //              You can access this size from robot.mouseWheelSize
517                // wheelAmt:
518                //              Number of notches to spin the wheel.
519                //              Negative wheelAmt scrolls up/away from the user.
520                //              Positive wheelAmt scrolls down/toward the user.
521                // delay:
522                //              Delay, in milliseconds, to wait before firing.
523                //              The delay is a delta with respect to the previous automation call.
524                //              For example, the following code ends after 600ms:
525                //                      robot.mouseClick({left: true}, 100) // first call; wait 100ms
526                //                      robot.typeKeys("dij", 500) // 500ms AFTER previous call; 600ms in all
527                // duration:
528                //              Approximate time Robot will spend moving the mouse
529                //              By default, the Robot will wheel the mouse as fast as possible.
530
531                this._assertRobot();
532                if(!wheelAmt){ return; }
533                this.sequence(function(){
534                        _robot.wheelMouse(isSecure(), Number(wheelAmt), Number(0), Number(duration||0));
535                }, delay, duration);
536        },
537
538        setClipboard: function(/*String*/ data,/*String?*/ format){
539                // summary:
540                //              Set clipboard content.
541                // description:
542                //              Set data as clipboard content, overriding anything already there. The
543                //              data will be put to the clipboard using the given format.
544                // data:
545                //              New clipboard content to set
546                // format:
547                //              Set this to "text/html" to put richtext to the clipboard.
548                //              Otherwise, data is treated as plaintext. By default, plaintext
549                //              is used.
550                if(format==='text/html'){
551                        _robot.setClipboardHtml(isSecure(), data);
552                }else{
553                        _robot.setClipboardText(isSecure(), data);
554                }
555        }
556};
557
558// After page has finished loading, create the applet iframe.
559// Note: could eliminate dojo/ready dependency by tying this code to startRobot() call, but then users
560// are required to put doh.run() inside of a dojo/ready.   Probably they are already doing that though.
561ready(function(){
562        // console.log("creating applet iframe");
563        var iframesrc;
564        var scripts = document.getElementsByTagName("script");
565        for(var x = 0; x<scripts.length; x++){
566                var s = scripts[x].getAttribute('src');
567                if(s && (s.substr(s.length-9) == "runner.js")){
568                        iframesrc = s.substr(0, s.length-9)+'Robot.html';
569                        break;
570                }
571        }
572
573        if(!iframesrc){
574                // if user set document.domain to something else, send it to the Robot too
575                iframesrc = require.toUrl("./Robot.html") + "?domain=" + escape(document.domain);
576        }
577        construct.place('<div id="dohrobotview" style="border:0px none; margin:0px; padding:0px; position:absolute; bottom:0px; right:0px; width:1px; height:1px; overflow:hidden; visibility:hidden; background-color:red;"></div>',
578                win.body());
579
580        if(!has("doh-custom-robot")){
581                // load default robot when not custom def given
582                construct.place('<iframe application="true" style="border:0px none; z-index:32767; padding:0px; margin:0px; position:absolute; left:0px; top:0px; height:100px; width:200px; overflow:hidden; background-color:transparent;" tabIndex="-1" src="'+iframesrc+'" ALLOWTRANSPARENCY="true"></iframe>',
583                        win.body());
584        }else{
585                // custom def given
586                console.log("using custom robot");
587                _robot = webdriver;
588                // mix in exports
589                for(var i in _robot){
590                        if(robot[i]&&_robot[i]){
591                                robot[i]=_robot[i];
592                        }
593                }
594                // continue init instead of waiting on frame
595                robot._initRobot(_robot);
596        }
597});
598
599// Start the robot as the first "test" when DOH runs.
600doh.registerGroup("initialize robot", [
601        {
602                name: "load robot",
603                timeout: 20000,
604                runTest: function(){
605                        // first wait for robot to tell us it's loaded, i.e. that _initRobot() has been called
606                        return robot._loaded;
607                }
608        },
609        {
610                name: "start robot",
611                timeout: 20000,
612                runTest: function(){
613                        // then we call startRobot(), and wait it to asynchronously complete
614                        return robot.startRobot();
615                }
616        }
617]);
618
619// Register the killRobot() command as the last "test" to run.
620// There's no good API to do this, so instead call doh.registerGroup() when the app first calls doh.run(),
621// since presumably all the real tests have already been registered.   Note that doh.run() is called multiple times,
622// so make sure to only call registerGroup() once.
623var _oldRun = doh.run;
624doh.run = function(){
625        doh.registerGroup("kill robot", {
626                name: "killRobot",
627                timeout: 10000,
628                runTest: function(){
629                        robot.killRobot();
630                }
631        });
632        doh.run = _oldRun;
633        doh.run();
634};
635
636
637return robot;
638});
Note: See TracBrowser for help on using the repository browser.