Project

General

Profile

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

    
18
passColor = "#cfffcf";
19
failColor = "#ffcfcf";
20
errorColor = "#ffffff";
21
workingColor = "#DEE7EC";
22
doneColor = "#FFFFCC";
23

    
24
var injectedSessionId;
25
var cmd1 = document.createElement("div");
26
var cmd2 = document.createElement("div");
27
var cmd3 = document.createElement("div");
28
var cmd4 = document.createElement("div");
29

    
30
var postResult = "START";
31
var debugMode = false;
32
var relayToRC = null;
33
var proxyInjectionMode = false;
34
var uniqueId = 'sel_' + Math.round(100000 * Math.random());
35

    
36
var RemoteRunnerOptions = classCreate();
37
objectExtend(RemoteRunnerOptions.prototype, URLConfiguration.prototype);
38
objectExtend(RemoteRunnerOptions.prototype, {
39
    initialize: function() {
40
        this._acquireQueryString();
41
    },
42
    isDebugMode: function() {
43
        return this._isQueryParameterTrue("debugMode");
44
    },
45

    
46
    getContinue: function() {
47
        return this._getQueryParameter("continue");
48
    },
49

    
50
    getDriverUrl: function() {
51
        return this._getQueryParameter("driverUrl");
52
    },
53

    
54
    getSessionId: function() {
55
        return this._getQueryParameter("sessionId");
56
    },
57

    
58
    _acquireQueryString: function () {
59
        if (this.queryString) return;
60
        if (browserVersion.isHTA) {
61
            var args = this._extractArgs();
62
            if (args.length < 2) return null;
63
            this.queryString = args[1];
64
        } else if (proxyInjectionMode) {
65
            this.queryString = selenium.browserbot.getCurrentWindow().location.search.substr(1);
66
        } else {
67
            this.queryString = top.location.search.substr(1);
68
        }
69
    }
70

    
71
});
72
var runOptions;
73

    
74
function runSeleniumTest() {
75
    runOptions = new RemoteRunnerOptions();
76
    var testAppWindow;
77

    
78
    if (runOptions.isMultiWindowMode()) {
79
        testAppWindow = openSeparateApplicationWindow('Blank.html', true);
80
    } else if ($('myiframe') != null) {
81
        var myiframe = $('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.log = logToRc;
99
        selenium.browserbot._modifyWindow(testAppWindow);
100
    }
101
    else if (debugMode) {
102
        LOG.logHook = logToRc;
103
    }
104
    window.selenium = selenium;
105

    
106
    commandFactory = new CommandHandlerFactory();
107
    commandFactory.registerAll(selenium);
108

    
109
    currentTest = new RemoteRunner(commandFactory);
110

    
111
    if (document.getElementById("commandList") != null) {
112
        document.getElementById("commandList").appendChild(cmd4);
113
        document.getElementById("commandList").appendChild(cmd3);
114
        document.getElementById("commandList").appendChild(cmd2);
115
        document.getElementById("commandList").appendChild(cmd1);
116
    }
117

    
118
    var doContinue = runOptions.getContinue();
119
    if (doContinue != null) postResult = "OK";
120

    
121
    currentTest.start();
122
}
123

    
124
function buildDriverUrl() {
125
    var driverUrl = runOptions.getDriverUrl();
126
    if (driverUrl != null) {
127
        return driverUrl;
128
    }
129
    var s = window.location.href
130
    var slashPairOffset = s.indexOf("//") + "//".length
131
    var pathSlashOffset = s.substring(slashPairOffset).indexOf("/")
132
    return s.substring(0, slashPairOffset + pathSlashOffset) + "/selenium-server/driver/";
133
}
134

    
135
function logToRc(logLevel, message) {
136
    if (logLevel == null) {
137
        logLevel = "debug";
138
    }
139
    if (debugMode) {
140
        sendToRC("logLevel=" + logLevel + ":" + message.replace(/[\n\r\015]/g, " ") + "\n", "logging=true");
141
    }
142
}
143

    
144
function isArray(x) {
145
    return ((typeof x) == "object") && (x["length"] != null);
146
}
147

    
148
function serializeString(name, s) {
149
    return name + "=unescape(\"" + escape(s) + "\");";
150
}
151

    
152
function serializeObject(name, x)
153
{
154
    var s = '';
155

    
156
    if (isArray(x))
157
    {
158
        s = name + "=new Array(); ";
159
        var len = x["length"];
160
        for (var j = 0; j < len; j++)
161
        {
162
            s += serializeString(name + "[" + j + "]", x[j]);
163
        }
164
    }
165
    else if (typeof x == "string")
166
    {
167
        s = serializeString(name, x);
168
    }
169
    else
170
    {
171
        throw "unrecognized object not encoded: " + name + "(" + x + ")";
172
    }
173
    return s;
174
}
175

    
176
function relayBotToRC(s) {
177
}
178

    
179
// seems like no one uses this, but in fact it is called using eval from server-side PI mode code; however, 
180
// because multiple names can map to the same popup, assigning a single name confuses matters sometimes;
181
// thus, I'm disabling this for now.  -Nelson 10/21/06
182
function setSeleniumWindowName(seleniumWindowName) {
183
//selenium.browserbot.getCurrentWindow()['seleniumWindowName'] = seleniumWindowName;
184
}
185

    
186
RemoteRunner = classCreate();
187
objectExtend(RemoteRunner.prototype, new TestLoop());
188
objectExtend(RemoteRunner.prototype, {
189
    initialize : function(commandFactory) {
190
        this.commandFactory = commandFactory;
191
        this.requiresCallBack = true;
192
        this.commandNode = null;
193
        this.xmlHttpForCommandsAndResults = null;
194
    },
195

    
196
    nextCommand : function() {
197
        var urlParms = "";
198
        if (postResult == "START") {
199
            urlParms += "seleniumStart=true";
200
        }
201
        this.xmlHttpForCommandsAndResults = XmlHttp.create();
202
        sendToRC(postResult, urlParms, fnBind(this._HandleHttpResponse, this), this.xmlHttpForCommandsAndResults);
203
    },
204

    
205
    commandStarted : function(command) {
206
        this.commandNode = document.createElement("div");
207
        var innerHTML = command.command + '(';
208
        if (command.target != null && command.target != "") {
209
            innerHTML += command.target;
210
            if (command.value != null && command.value != "") {
211
                innerHTML += ', ' + command.value;
212
            }
213
        }
214
        innerHTML += ")";
215
        if (innerHTML.length >40) {
216
            innerHTML = innerHTML.substring(0,40);
217
            innerHTML += "...";
218
        }
219
        this.commandNode.innerHTML = innerHTML;
220
        this.commandNode.style.backgroundColor = workingColor;
221
        if (document.getElementById("commandList") != null) {
222
            document.getElementById("commandList").removeChild(cmd1);
223
            document.getElementById("commandList").removeChild(cmd2);
224
            document.getElementById("commandList").removeChild(cmd3);
225
            document.getElementById("commandList").removeChild(cmd4);
226
            cmd4 = cmd3;
227
            cmd3 = cmd2;
228
            cmd2 = cmd1;
229
            cmd1 = this.commandNode;
230
            document.getElementById("commandList").appendChild(cmd4);
231
            document.getElementById("commandList").appendChild(cmd3);
232
            document.getElementById("commandList").appendChild(cmd2);
233
            document.getElementById("commandList").appendChild(cmd1);
234
        }
235
    },
236

    
237
    commandComplete : function(result) {
238

    
239
        if (result.failed) {
240
            if (postResult == "CONTINUATION") {
241
                currentTest.aborted = true;
242
            }
243
            postResult = result.failureMessage;
244
            this.commandNode.title = result.failureMessage;
245
            this.commandNode.style.backgroundColor = failColor;
246
        } else if (result.passed) {
247
            postResult = "OK";
248
            this.commandNode.style.backgroundColor = passColor;
249
        } else {
250
            if (result.result == null) {
251
                postResult = "OK";
252
            } else {
253
                postResult = "OK," + result.result;
254
            }
255
            this.commandNode.style.backgroundColor = doneColor;
256
        }
257
    },
258

    
259
    commandError : function(message) {
260
        postResult = "ERROR: " + message;
261
        this.commandNode.style.backgroundColor = errorColor;
262
        this.commandNode.title = message;
263
    },
264

    
265
    testComplete : function() {
266
        window.status = "Selenium Tests Complete, for this Test"
267
        // Continue checking for new results
268
        this.continueTest();
269
        postResult = "START";
270
    },
271

    
272
    _HandleHttpResponse : function() {
273
        if (this.xmlHttpForCommandsAndResults.readyState == 4) {
274
            if (this.xmlHttpForCommandsAndResults.status == 200) {
275
            	if (this.xmlHttpForCommandsAndResults.responseText=="") {
276
                    LOG.error("saw blank string xmlHttpForCommandsAndResults.responseText");
277
                    return;
278
                }
279
                var command = this._extractCommand(this.xmlHttpForCommandsAndResults);
280
                this.currentCommand = command;
281
                this.continueTestAtCurrentCommand();
282
            } else {
283
                var s = 'xmlHttp returned: ' + this.xmlHttpForCommandsAndResults.status + ": " + this.xmlHttpForCommandsAndResults.statusText;
284
                LOG.error(s);
285
                this.currentCommand = null;
286
                setTimeout(fnBind(this.continueTestAtCurrentCommand, this), 2000);
287
            }
288

    
289
        }
290
    },
291

    
292
    _extractCommand : function(xmlHttp) {
293
        var command;
294
        try {
295
            var re = new RegExp("^(.*?)\n((.|[\r\n])*)");
296
            if (re.exec(xmlHttp.responseText)) {
297
                command = RegExp.$1;
298
                var rest = RegExp.$2;
299
                rest = rest.trim();
300
                if (rest) {
301
                    eval(rest);
302
                }
303
            }
304
            else {
305
                command = xmlHttp.responseText;
306
            }
307
        } catch (e) {
308
            alert('could not get responseText: ' + e.message);
309
        }
310
        if (command.substr(0, '|testComplete'.length) == '|testComplete') {
311
            return null;
312
        }
313

    
314
        return this._createCommandFromRequest(command);
315
    },
316

    
317

    
318
    _delay : function(millis) {
319
        var startMillis = new Date();
320
        while (true) {
321
            milli = new Date();
322
            if (milli - startMillis > millis) {
323
                break;
324
            }
325
        }
326
    },
327

    
328
// Parses a URI query string into a SeleniumCommand object
329
    _createCommandFromRequest : function(commandRequest) {
330
        //decodeURIComponent doesn't strip plus signs
331
        var processed = commandRequest.replace(/\+/g, "%20");
332
        // strip trailing spaces
333
        var processed = processed.replace(/\s+$/, "");
334
        var vars = processed.split("&");
335
        var cmdArgs = new Object();
336
        for (var i = 0; i < vars.length; i++) {
337
            var pair = vars[i].split("=");
338
            cmdArgs[pair[0]] = pair[1];
339
        }
340
        var cmd = cmdArgs['cmd'];
341
        var arg1 = cmdArgs['1'];
342
        if (null == arg1) arg1 = "";
343
        arg1 = decodeURIComponent(arg1);
344
        var arg2 = cmdArgs['2'];
345
        if (null == arg2) arg2 = "";
346
        arg2 = decodeURIComponent(arg2);
347
        if (cmd == null) {
348
            throw new Error("Bad command request: " + commandRequest);
349
        }
350
        return new SeleniumCommand(cmd, arg1, arg2);
351
    }
352

    
353
})
354

    
355

    
356
function sendToRC(dataToBePosted, urlParms, callback, xmlHttpObject, async) {
357
    if (async == null) {
358
        async = true;
359
    }
360
    if (xmlHttpObject == null) {
361
        xmlHttpObject = XmlHttp.create();
362
    }
363
    var url = buildDriverUrl() + "?"
364
    if (urlParms) {
365
        url += urlParms;
366
    }
367
    url += "&localFrameAddress=" + (proxyInjectionMode ? makeAddressToAUTFrame() : "top");
368
    url += getSeleniumWindowNameURLparameters();
369
    url += "&uniqueId=" + uniqueId;
370

    
371
    if (callback == null) {
372
        callback = function() {
373
        };
374
    }
375
    url += buildDriverParams() + preventBrowserCaching();
376
    xmlHttpObject.open("POST", url, async);
377
    xmlHttpObject.onreadystatechange = callback;
378
    xmlHttpObject.send(dataToBePosted);
379
    return null;
380
}
381

    
382
function buildDriverParams() {
383
    var params = "";
384

    
385
    var sessionId = runOptions.getSessionId();
386
    if (sessionId == undefined) {
387
        sessionId = injectedSessionId;
388
    }
389
    if (sessionId != undefined) {
390
        params = params + "&sessionId=" + sessionId;
391
    }
392
    return params;
393
}
394

    
395
function preventBrowserCaching() {
396
    var t = (new Date()).getTime();
397
    return "&counterToMakeURsUniqueAndSoStopPageCachingInTheBrowser=" + t;
398
}
399

    
400
//
401
// Return URL parameters pertaining to the name(s?) of the current window
402
//
403
// In selenium, the main (i.e., first) window's name is a blank string.
404
//
405
// Additional pop-ups are associated with either 1.) the name given by the 2nd parameter to window.open, or 2.) the name of a 
406
// property on the opening window which points at the window.
407
//
408
// An example of #2: if window X contains JavaScript as follows:
409
//
410
// 	var windowABC = window.open(...)
411
//
412
// Note that the example JavaScript above is equivalent to
413
//
414
// 	window["windowABC"] = window.open(...)
415
//
416
function getSeleniumWindowNameURLparameters() {
417
    var w = (proxyInjectionMode ? selenium.browserbot.getCurrentWindow() : window).top;
418
    var s = "&seleniumWindowName=";
419
    if (w.opener == null) {
420
        return s;
421
    }
422
    if (w["seleniumWindowName"] == null) {
423
    	s +=  'generatedSeleniumWindowName_' + Math.round(100000 * Math.random());
424
    }
425
    else {
426
    	s += w["seleniumWindowName"];
427
    }
428
    var windowOpener = w.opener;
429
    for (key in windowOpener) {
430
        var val = null;
431
        try {
432
    	    val = windowOpener[key];
433
        }
434
        catch(e) {
435
        }        
436
        if (val==w) {
437
	    s += "&jsWindowNameVar=" + key;			// found a js variable in the opener referring to this window
438
        }
439
    }
440
    return s;
441
}
442

    
443
// construct a JavaScript expression which leads to my frame (i.e., the frame containing the window
444
// in which this code is operating)
445
function makeAddressToAUTFrame(w, frameNavigationalJSexpression)
446
{
447
    if (w == null)
448
    {
449
        w = top;
450
        frameNavigationalJSexpression = "top";
451
    }
452

    
453
    if (w == selenium.browserbot.getCurrentWindow())
454
    {
455
        return frameNavigationalJSexpression;
456
    }
457
    for (var j = 0; j < w.frames.length; j++)
458
    {
459
        var t = makeAddressToAUTFrame(w.frames[j], frameNavigationalJSexpression + ".frames[" + j + "]");
460
        if (t != null)
461
        {
462
            return t;
463
        }
464
    }
465
    return null;
466
}
(16-16/20)