hjg
2024-10-30 8cf23534166c07e711aac2a25911ada317ba01f0
提交 | 用户 | 时间
58d006 1 var system = require('system');
A 2
3 /**
4  * Wait until the test condition is true or a timeout occurs. Useful for waiting
5  * on a server response or for a ui change (fadeIn, etc.) to occur.
6  *
7  * @param testFx javascript condition that evaluates to a boolean,
8  * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
9  * as a callback function.
10  * @param onReady what to do when testFx condition is fulfilled,
11  * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
12  * as a callback function.
13  * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
14  */
15 function waitFor(testFx, onReady, timeOutMillis) {
16     var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 10001, //< Default Max Timout is 3s
17         start = new Date().getTime(),
18         condition = false,
19         interval = setInterval(function() {
20             if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
21                 // If not time-out yet and condition not yet fulfilled
22                 condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
23             } else {
24                 if(!condition) {
25                     // If condition still not fulfilled (timeout but condition is 'false')
26                     console.log("'waitFor()' timeout");
27                     phantom.exit(1);
28                 } else {
29                     // Condition fulfilled (timeout and/or condition is 'true')
30                     //console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
31                     typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
32                     clearInterval(interval); //< Stop this interval
33                 }
34             }
35         }, 100); //< repeat check every 100ms
36 };
37
38 if (system.args.length !== 2) {
39     console.log('Usage: run-qunit.js URL');
40     phantom.exit(1);
41 }
42
43 var fs = require('fs');
44 var page = require('webpage').create();
45
46 // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
47 page.onConsoleMessage = function(msg) {
48     console.log(msg);
49 };
50 page.onError = function (msg, trace) {
51     console.log(msg);
52     trace.forEach(function(item) {
53         console.log('  ', item.file, ':', item.line);
54     })
55 }
56
57 var _openPath = phantom.args[0].replace(/^.*(\\|\/)/, '');
58 var openPath = _openPath;
59 var origdir = '../js/';
60 var basedir = '../instrumented/';
61 var coverageBase = fs.read('_coverage.html');
62
63 if (fs.exists(basedir)){
64     var script = /<script.*><\/script>/g,
65         src = /src=(["'])(.*?)\1/,
66         contents = fs.read(openPath),
67         _contents = contents,
68         srcs = [],
69         s;
70     while (script.exec(contents)){
71         s = src.exec(RegExp.lastMatch)[2];
72         if (s && s.indexOf(origdir) != -1)
73             _contents = _contents.replace(s, s.replace(origdir, basedir))
74     }
75     if (_contents != contents){
76         openPath += '.cov.html';
77         fs.write(openPath, _contents);
78     }
79 }
80
81 page.open(openPath, function(status){
82     if (status !== "success") {
83         console.log("Unable to access network");
84         phantom.exit(1);
85     } else {
86         // Inject instrumented sources if they exist
87         if (fs.exists(basedir))
88             for (var i=0; i<srcs.length; i++)
89                 page.includeJs(srcs[i]);
90         waitFor(function(){
91             return page.evaluate(function(){
92                 var el = document.getElementById('qunit-testresult');
93                 if (el && el.innerText.match('completed')) {
94                     return true;
95                 }
96                 return false;
97             });
98         }, function(){
99             // output colorized code coverage
100             // reach into page context and pull out coverage info. stringify to pass context boundaries.
101             var coverageInfo = JSON.parse(page.evaluate(function() { return JSON.stringify(getCoverageByLine()); }));
102             if (coverageInfo.key){
103                 var lineCoverage = coverageInfo.lines;
104                 var originalFile = origdir + fs.separator + coverageInfo.key;
105                 var source = coverageInfo.source;
106                 var fileLines = readFileLines(originalFile);
107
108                 var colorized = '';
109
110                 for (var idx=0; idx < lineCoverage.length; idx++) {
111                     //+1: coverage lines count from 1.
112                     var cvg = lineCoverage[idx + 1];
113                     var hitmiss = '';
114                     if (typeof cvg === 'number') {
115                         hitmiss = ' ' + (cvg>0 ? 'hit' : 'miss');
116                     } else {
117                         hitmiss = ' ' + 'undef';
118                     }
119                     var htmlLine = fileLines[idx]
120                     if (!source)
121                         htmlLine = htmlLine.replace('<', '&lt;').replace('>', '&gt;');
122                     colorized += '<div class="code' + hitmiss + '">' + htmlLine + '</div>\n';
123                 };
124                 colorized = coverageBase.replace('COLORIZED_LINE_HTML', colorized);
125
126                 fs.write('coverage.html', colorized, 'w');
127
128                 console.log('Coverage for ' + coverageInfo.key + ' in coverage.html');
129             }
130             if (_openPath != openPath)
131                 fs.remove(openPath);
132
133             var failedNum = page.evaluate(function(){
134                 var el = document.getElementById('qunit-testresult');
135                 console.log(el.innerText);
136                 try {
137                     return el.getElementsByClassName('failed')[0].innerHTML;
138                 } catch (e) { }
139                 return 10000;
140             });
141             phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0);
142         });
143     }
144 });
145
146 function readFileLines(filename) {
147     var stream = fs.open(filename, 'r');
148     var lines = [];
149     var line;
150     while (!stream.atEnd()) {
151         lines.push(stream.readLine());
152     }
153     stream.close();
154
155     return lines;
156 }
157