OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // This is a test harness for running javascript tests in the browser. | |
6 // The only identifier exposed by this harness is WebGLTestHarnessModule. | |
7 // | |
8 // To use it make an HTML page with an iframe. Then call the harness like this | |
9 // | |
10 // function reportResults(type, msg, success) { | |
11 // ... | |
12 // return true; | |
13 // } | |
14 // | |
15 // var fileListURL = '00_test_list.txt'; | |
16 // var testHarness = new WebGLTestHarnessModule.TestHarness( | |
17 // iframe, | |
18 // fileListURL, | |
19 // reportResults); | |
20 // | |
21 // The harness will load the fileListURL and parse it for the URLs, one URL | |
22 // per line. URLs should be on the same domain and at the same folder level | |
23 // or below the main html file. If any URL ends in .txt it will be parsed | |
24 // as well so you can nest .txt files. URLs inside a .txt file should be | |
25 // relative to that text file. | |
26 // | |
27 // During startup, for each page found the reportFunction will be called with | |
28 // WebGLTestHarnessModule.TestHarness.reportType.ADD_PAGE and msg will be | |
29 // the URL of the test. | |
30 // | |
31 // Each test is required to call testHarness.reportResults. This is most easily | |
32 // accomplished by storing that value on the main window with | |
33 // | |
34 // window.webglTestHarness = testHarness | |
35 // | |
36 // and then adding these to functions to your tests. | |
37 // | |
38 // function reportTestResultsToHarness(success, msg) { | |
39 // if (window.parent.webglTestHarness) { | |
40 // window.parent.webglTestHarness.reportResults(success, msg); | |
41 // } | |
42 // } | |
43 // | |
44 // function notifyFinishedToHarness() { | |
45 // if (window.parent.webglTestHarness) { | |
46 // window.parent.webglTestHarness.notifyFinished(); | |
47 // } | |
48 // } | |
49 // | |
50 // This way your tests will still run without the harness and you can use | |
51 // any testing framework you want. | |
52 // | |
53 // Each test should call reportTestResultsToHarness with true for success if it | |
54 // succeeded and false if it fail followed and any message it wants to | |
55 // associate with the test. If your testing framework supports checking for | |
56 // timeout you can call it with success equal to undefined in that case. | |
57 // | |
58 // To run the tests, call testHarness.runTests(); | |
59 // | |
60 // For each test run, before the page is loaded the reportFunction will be | |
61 // called with WebGLTestHarnessModule.TestHarness.reportType.START_PAGE and msg | |
62 // will be the URL of the test. You may return false if you want the test to be | |
63 // skipped. | |
64 // | |
65 // For each test completed the reportFunction will be called with | |
66 // with WebGLTestHarnessModule.TestHarness.reportType.TEST_RESULT, | |
67 // success = true on success, false on failure, undefined on timeout | |
68 // and msg is any message the test choose to pass on. | |
69 // | |
70 // When all the tests on the page have finished your page must call | |
71 // notifyFinishedToHarness. If notifyFinishedToHarness is not called | |
72 // the harness will assume the test timed out. | |
73 // | |
74 // When all the tests on a page have finished OR the page as timed out the | |
75 // reportFunction will be called with | |
76 // WebGLTestHarnessModule.TestHarness.reportType.FINISH_PAGE | |
77 // where success = true if the page has completed or undefined if the page timed | |
78 // out. | |
79 // | |
80 // Finally, when all the tests have completed the reportFunction will be called | |
81 // with WebGLTestHarnessModule.TestHarness.reportType.FINISHED_ALL_TESTS. | |
82 // | |
83 | |
84 WebGLTestHarnessModule = function() { | |
85 | |
86 /** | |
87 * Wrapped logging function. | |
88 */ | |
89 var log = function(msg) { | |
90 if (window.console && window.console.log) { | |
91 window.console.log(msg); | |
92 } | |
93 }; | |
94 | |
95 /** | |
96 * Loads text from an external file. This function is synchronous. | |
97 * @param {string} url The url of the external file. | |
98 * @return {string} the loaded text if the request is synchronous. | |
99 */ | |
100 var loadTextFileSynchronous = function(url) { | |
101 var error = 'loadTextFileSynchronous failed to load url "' + url + '"'; | |
102 var request; | |
103 if (window.XMLHttpRequest) { | |
104 request = new XMLHttpRequest(); | |
105 if (request.overrideMimeType) { | |
106 request.overrideMimeType('text/plain'); | |
107 } | |
108 } else { | |
109 throw 'XMLHttpRequest is disabled'; | |
110 } | |
111 request.open('GET', url, false); | |
112 request.send(null); | |
113 if (request.readyState != 4) { | |
114 throw error; | |
115 } | |
116 return request.responseText; | |
117 }; | |
118 | |
119 var getFileList = function(url) { | |
120 var files = []; | |
121 if (url.substr(url.length - 4) == '.txt') { | |
122 var lines = loadTextFileSynchronous(url).split('\n'); | |
123 var prefix = ''; | |
124 var lastSlash = url.lastIndexOf('/'); | |
125 if (lastSlash >= 0) { | |
126 prefix = url.substr(0, lastSlash + 1); | |
127 } | |
128 for (var ii = 0; ii < lines.length; ++ii) { | |
129 var str = lines[ii].replace(/^\s\s*/, '').replace(/\s\s*$/, ''); | |
130 if (str.length > 4 && | |
131 str[0] != '#' && | |
132 str[0] != ";" && | |
133 str.substr(0, 2) != "//") { | |
134 new_url = prefix + str; | |
135 files = files.concat(getFileList(new_url)); | |
136 } | |
137 } | |
138 } else { | |
139 files.push(url); | |
140 } | |
141 return files; | |
142 } | |
143 | |
144 var TestFile = function(url) { | |
145 this.url = url; | |
146 }; | |
147 | |
148 var TestHarness = function(iframe, filelistUrl, reportFunc) { | |
149 this.window = window; | |
150 this.iframe = iframe; | |
151 this.reportFunc = reportFunc; | |
152 var files = getFileList(filelistUrl); | |
153 this.files = []; | |
154 for (var ii = 0; ii < files.length; ++ii) { | |
155 this.files.push(new TestFile(files[ii])); | |
156 this.reportFunc(TestHarness.reportType.ADD_PAGE, files[ii], undefined); | |
157 } | |
158 this.nextFileIndex = files.length; | |
159 this.timeoutDelay = 20000; | |
160 }; | |
161 | |
162 TestHarness.reportType = { | |
163 ADD_PAGE: 1, | |
164 START_PAGE: 2, | |
165 TEST_RESULT: 3, | |
166 FINISH_PAGE: 4, | |
167 FINISHED_ALL_TESTS: 5 | |
168 }; | |
169 | |
170 TestHarness.prototype.runTests = function(files) { | |
171 this.nextFileIndex = 0; | |
172 this.startNextFile(); | |
173 }; | |
174 | |
175 TestHarness.prototype.setTimeout = function() { | |
176 var that = this; | |
177 this.timeoutId = this.window.setTimeout(function() { | |
178 that.timeout(); | |
179 }, this.timeoutDelay); | |
180 }; | |
181 | |
182 TestHarness.prototype.clearTimeout = function() { | |
183 this.window.clearTimeout(this.timeoutId); | |
184 }; | |
185 | |
186 TestHarness.prototype.startNextFile = function() { | |
187 if (this.nextFileIndex >= this.files.length) { | |
188 log("done"); | |
189 this.reportFunc(TestHarness.reportType.FINISHED_ALL_TESTS, | |
190 '', undefined); | |
191 } else { | |
192 this.currentFile = this.files[this.nextFileIndex++]; | |
193 log("loading: " + this.currentFile.url); | |
194 if (this.reportFunc(TestHarness.reportType.START_PAGE, | |
195 this.currentFile.url, undefined)) { | |
196 this.iframe.src = this.currentFile.url; | |
197 this.setTimeout(); | |
198 } else { | |
199 this.reportResults(false, "skipped"); | |
200 this.notifyFinished(); | |
201 } | |
202 } | |
203 }; | |
204 | |
205 TestHarness.prototype.reportResults = function (success, msg) { | |
206 this.clearTimeout(); | |
207 log(success ? "PASS" : "FAIL", msg); | |
208 this.reportFunc(TestHarness.reportType.TEST_RESULT, msg, success); | |
209 // For each result we get, reset the timeout | |
210 this.setTimeout(); | |
211 }; | |
212 | |
213 TestHarness.prototype.notifyFinished = function () { | |
214 this.clearTimeout(); | |
215 var url = this.currentFile ? this.currentFile.url : 'unknown'; | |
216 log(url + ": finished"); | |
217 this.reportFunc(TestHarness.reportType.FINISH_PAGE, url, true); | |
218 this.startNextFile(); | |
219 }; | |
220 | |
221 TestHarness.prototype.timeout = function() { | |
222 this.clearTimeout(); | |
223 var url = this.currentFile ? this.currentFile.url : 'unknown'; | |
224 log(url + ": timeout"); | |
225 this.reportFunc(TestHarness.reportType.FINISH_PAGE, url, undefined); | |
226 this.startNextFile(); | |
227 }; | |
228 | |
229 TestHarness.prototype.setTimeoutDelay = function(x) { | |
230 this.timeoutDelay = x; | |
231 }; | |
232 | |
233 return { | |
234 'TestHarness': TestHarness | |
235 }; | |
236 | |
237 }(); | |
238 | |
239 | |
240 | |
OLD | NEW |