1 | goog.require('ol.array');
|
2 | goog.require('ol.has');
|
3 |
|
4 |
|
5 |
|
6 | (function(global) {
|
7 |
|
8 |
|
9 | var showMap = (global.location.search.indexOf('generate') >= 0);
|
10 |
|
11 |
|
12 | var showDiff = (global.location.search.indexOf('showdiff') >= 0);
|
13 |
|
14 | |
15 |
|
16 |
|
17 | global.IMAGE_TOLERANCE = 1.5;
|
18 |
|
19 | function afterLoad(type, path, next) {
|
20 | var client = new XMLHttpRequest();
|
21 | client.open('GET', path, true);
|
22 | client.onload = function() {
|
23 | var data;
|
24 | if (type === 'xml') {
|
25 | data = client.responseXML;
|
26 | } else {
|
27 | data = client.responseText;
|
28 | }
|
29 | if (!data) {
|
30 | throw new Error(path + ' loading failed: ' + client.status);
|
31 | }
|
32 | next(data);
|
33 | };
|
34 | client.send();
|
35 | }
|
36 |
|
37 | |
38 |
|
39 |
|
40 |
|
41 |
|
42 | global.afterLoadJson = function(path, next) {
|
43 | afterLoad('json', path, next);
|
44 | };
|
45 |
|
46 |
|
47 | |
48 |
|
49 |
|
50 |
|
51 |
|
52 | global.afterLoadText = function(path, next) {
|
53 | afterLoad('text', path, next);
|
54 | };
|
55 |
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 | global.afterLoadXml = function(path, next) {
|
63 | afterLoad('xml', path, next);
|
64 | };
|
65 |
|
66 |
|
67 |
|
68 | var expect = global.expect;
|
69 |
|
70 |
|
71 | |
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | expect.Assertion.prototype.roughlyEqual = function(n, tol) {
|
78 | this.assert(
|
79 | Math.abs(this.obj - n) <= tol,
|
80 | function() {
|
81 | return 'expected ' + expect.stringify(this.obj) + ' to be within ' +
|
82 | tol + ' of ' + n;
|
83 | },
|
84 | function() {
|
85 | return 'expected ' + expect.stringify(this.obj) +
|
86 | ' not to be within ' + tol + ' of ' + n;
|
87 | });
|
88 | return this;
|
89 | };
|
90 |
|
91 |
|
92 | |
93 |
|
94 |
|
95 |
|
96 | expect.Assertion.prototype.called = function() {
|
97 | this.assert(
|
98 | this.obj.called,
|
99 | function() {
|
100 | return 'expected ' + expect.stringify(this.obj) + ' to be called';
|
101 | },
|
102 | function() {
|
103 | return 'expected ' + expect.stringify(this.obj) + ' not to be called';
|
104 | });
|
105 | return this;
|
106 | };
|
107 |
|
108 |
|
109 | function getChildNodes(node, options) {
|
110 |
|
111 | if (options && options.includeWhiteSpace) {
|
112 | return node.childNodes;
|
113 | } else {
|
114 | var nodes = [];
|
115 | for (var i = 0, ii = node.childNodes.length; i < ii; i++) {
|
116 | var child = node.childNodes[i];
|
117 | if (child.nodeType == 1) {
|
118 |
|
119 | nodes.push(child);
|
120 | } else if (child.nodeType == 3) {
|
121 |
|
122 | if (child.nodeValue &&
|
123 | child.nodeValue.replace(/^\s*(.*?)\s*$/, '$1') !== '') {
|
124 | nodes.push(child);
|
125 | }
|
126 | }
|
127 | }
|
128 | if (options && options.ignoreElementOrder) {
|
129 | nodes.sort(function(a, b) {
|
130 | return a.nodeName > b.nodeName ? 1 : a.nodeName < b.nodeName ? -1 : 0;
|
131 | });
|
132 | }
|
133 | return nodes;
|
134 | }
|
135 | }
|
136 |
|
137 | function assertElementNodesEqual(node1, node2, options, errors) {
|
138 | var testPrefix = (options && options.prefix === true);
|
139 | if (node1.nodeType !== node2.nodeType) {
|
140 | errors.push('nodeType test failed for: ' + node1.nodeName + ' | ' +
|
141 | node2.nodeName + ' | expected ' + node1.nodeType + ' to equal ' +
|
142 | node2.nodeType);
|
143 | }
|
144 | if (testPrefix) {
|
145 | if (node1.nodeName !== node2.nodeName) {
|
146 | errors.push('nodeName test failed for: ' + node1.nodeName + ' | ' +
|
147 | node2.nodeName + ' | expected ' + node1.nodeName + ' to equal ' +
|
148 | node2.nodeName);
|
149 | }
|
150 | } else {
|
151 | var n1 = node1.nodeName.split(':').pop();
|
152 | var n2 = node2.nodeName.split(':').pop();
|
153 | if (n1 !== n2) {
|
154 | errors.push('nodeName test failed for: ' + node1.nodeName + ' | ' +
|
155 | node2.nodeName + ' | expected ' + n1 + ' to equal ' + n2);
|
156 | }
|
157 | }
|
158 |
|
159 | if (node1.nodeType === 3) {
|
160 | var nv1 = node1.nodeValue.replace(/\s/g, '');
|
161 | var nv2 = node2.nodeValue.replace(/\s/g, '');
|
162 | if (nv1 !== nv2) {
|
163 | errors.push('nodeValue test failed | expected ' + nv1 + ' to equal ' +
|
164 | nv2);
|
165 | }
|
166 | } else if (node1.nodeType === 1) {
|
167 |
|
168 |
|
169 | if (node1.prefix || node2.prefix) {
|
170 | if (testPrefix) {
|
171 | if (node1.prefix !== node2.prefix) {
|
172 | errors.push('Prefix test failed for: ' + node1.nodeName +
|
173 | ' | expected ' + node1.prefix + ' to equal ' + node2.prefix);
|
174 | }
|
175 | }
|
176 | }
|
177 | if (node1.namespaceURI || node2.namespaceURI) {
|
178 | if (node1.namespaceURI !== node2.namespaceURI) {
|
179 | errors.push('namespaceURI test failed for: ' + node1.nodeName +
|
180 | ' | expected ' + node1.namespaceURI + ' to equal ' +
|
181 | node2.namespaceURI);
|
182 | }
|
183 | }
|
184 |
|
185 | var node1AttrLen = 0;
|
186 | var node1Attr = {};
|
187 | var node2AttrLen = 0;
|
188 | var node2Attr = {};
|
189 | var ga, ea, gn, en;
|
190 | var i, ii;
|
191 | if (node1.attributes) {
|
192 | for (i = 0, ii = node1.attributes.length; i < ii; ++i) {
|
193 | ga = node1.attributes[i];
|
194 | if (ga.specified === undefined || ga.specified === true) {
|
195 | if (ga.name.split(':').shift() != 'xmlns') {
|
196 | gn = testPrefix ? ga.name : ga.name.split(':').pop();
|
197 | node1Attr[gn] = ga;
|
198 | ++node1AttrLen;
|
199 | }
|
200 | }
|
201 | }
|
202 | }
|
203 | if (node2.attributes) {
|
204 | for (i = 0, ii = node2.attributes.length; i < ii; ++i) {
|
205 | ea = node2.attributes[i];
|
206 | if (ea.specified === undefined || ea.specified === true) {
|
207 | if (ea.name.split(':').shift() != 'xmlns') {
|
208 | en = testPrefix ? ea.name : ea.name.split(':').pop();
|
209 | node2Attr[en] = ea;
|
210 | ++node2AttrLen;
|
211 | }
|
212 | }
|
213 | }
|
214 | }
|
215 | if (node1AttrLen !== node2AttrLen) {
|
216 | errors.push('Number of attributes test failed for: ' + node1.nodeName +
|
217 | ' | expected ' + node1AttrLen + ' to equal ' + node2AttrLen);
|
218 | }
|
219 | for (var name in node1Attr) {
|
220 | if (node2Attr[name] === undefined) {
|
221 | errors.push('Attribute name ' + node1Attr[name].name +
|
222 | ' expected for element ' + node1.nodeName);
|
223 | break;
|
224 | }
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 | if ((node1Attr[name].namespaceURI || null) !==
|
231 | (node2Attr[name].namespaceURI || null)) {
|
232 | errors.push('namespaceURI attribute test failed for: ' +
|
233 | node1.nodeName + ' | expected ' + node1Attr[name].namespaceURI +
|
234 | ' to equal ' + node2Attr[name].namespaceURI);
|
235 | }
|
236 | if (node1Attr[name].value !== node2Attr[name].value) {
|
237 | errors.push('Attribute value test failed for: ' + node1.nodeName +
|
238 | ' | expected ' + node1Attr[name].value + ' to equal ' +
|
239 | node2Attr[name].value);
|
240 | }
|
241 | }
|
242 |
|
243 | var node1ChildNodes = getChildNodes(node1, options);
|
244 | var node2ChildNodes = getChildNodes(node2, options);
|
245 | if (node1ChildNodes.length !== node2ChildNodes.length) {
|
246 |
|
247 |
|
248 |
|
249 | var allText = true;
|
250 | var c, cc;
|
251 | for (c = 0, cc = node1ChildNodes.length; c < cc; ++c) {
|
252 | if (node1ChildNodes[c].nodeType !== 3) {
|
253 | allText = false;
|
254 | break;
|
255 | }
|
256 | }
|
257 | for (c = 0, cc = node2ChildNodes.length; c < cc; ++c) {
|
258 | if (node2ChildNodes[c].nodeType !== 3) {
|
259 | allText = false;
|
260 | break;
|
261 | }
|
262 | }
|
263 | if (!allText) {
|
264 | errors.push('Number of childNodes test failed for: ' +
|
265 | node1.nodeName + ' | expected ' + node1ChildNodes.length +
|
266 | ' to equal ' + node2ChildNodes.length);
|
267 | }
|
268 | }
|
269 |
|
270 | if (node1ChildNodes.length === node2ChildNodes.length) {
|
271 | for (var j = 0, jj = node1ChildNodes.length; j < jj; ++j) {
|
272 | assertElementNodesEqual(
|
273 | node1ChildNodes[j], node2ChildNodes[j], options, errors);
|
274 | }
|
275 | }
|
276 | }
|
277 | }
|
278 |
|
279 |
|
280 | |
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 | expect.Assertion.prototype.xmleql = function(obj, options) {
|
288 | if (obj && obj.nodeType == 9) {
|
289 | obj = obj.documentElement;
|
290 | }
|
291 | if (this.obj && this.obj.nodeType == 9) {
|
292 | this.obj = this.obj.documentElement;
|
293 | }
|
294 | var errors = [];
|
295 | assertElementNodesEqual(obj, this.obj, options, errors);
|
296 | var result = (errors.length === 0);
|
297 | this.assert(
|
298 | !!result,
|
299 | function() {
|
300 | return 'expected ' + expect.stringify(this.obj) +
|
301 | ' to sort of equal ' + expect.stringify(obj) + '\n' +
|
302 | errors.join('\n');
|
303 | },
|
304 | function() {
|
305 | return 'expected ' + expect.stringify(this.obj) +
|
306 | ' to sort of not equal ' + expect.stringify(obj) + '\n' +
|
307 | errors.join('\n');
|
308 | });
|
309 | return this;
|
310 | };
|
311 |
|
312 |
|
313 | |
314 |
|
315 |
|
316 |
|
317 |
|
318 | expect.Assertion.prototype.arreql = function(obj) {
|
319 | this.assert(
|
320 | ol.array.equals(this.obj, obj),
|
321 | function() {
|
322 | return 'expected ' + expect.stringify(this.obj) +
|
323 | ' to sort of equal ' + expect.stringify(obj);
|
324 | },
|
325 | function() {
|
326 | return 'expected ' + expect.stringify(this.obj) +
|
327 | ' to sort of not equal ' + expect.stringify(obj);
|
328 | });
|
329 | return this;
|
330 | };
|
331 |
|
332 |
|
333 | |
334 |
|
335 |
|
336 |
|
337 |
|
338 | expect.Assertion.prototype.arreqlNaN = function(obj) {
|
339 | function compare(a, i) {
|
340 | var b = obj[i];
|
341 | return a === b || (typeof a === 'number' && typeof b === 'number' &&
|
342 | isNaN(a) && isNaN(b));
|
343 | }
|
344 | this.assert(
|
345 | this.obj.length === obj.length && this.obj.every(compare),
|
346 | function() {
|
347 | return 'expected ' + expect.stringify(this.obj) +
|
348 | ' to sort of equal ' + expect.stringify(obj);
|
349 | },
|
350 | function() {
|
351 | return 'expected ' + expect.stringify(this.obj) +
|
352 | ' to sort of not equal ' + expect.stringify(obj);
|
353 | });
|
354 | return this;
|
355 | };
|
356 |
|
357 | global.createMapDiv = function(width, height) {
|
358 | var target = document.createElement('div');
|
359 | var style = target.style;
|
360 | style.position = 'absolute';
|
361 | style.left = '-1000px';
|
362 | style.top = '-1000px';
|
363 | style.width = width + 'px';
|
364 | style.height = height + 'px';
|
365 | document.body.appendChild(target);
|
366 |
|
367 | return target;
|
368 | };
|
369 |
|
370 | global.disposeMap = function(map) {
|
371 | var target = map.getTarget();
|
372 | map.setTarget(null);
|
373 | if (target && target.parentNode) {
|
374 | target.parentNode.removeChild(target);
|
375 | }
|
376 | map.dispose();
|
377 | };
|
378 |
|
379 | global.assertWebGL = function(map) {
|
380 | if (!ol.has.WEBGL) {
|
381 | expect().fail('No WebGL support!');
|
382 | }
|
383 | };
|
384 |
|
385 | function resembleCanvas(canvas, referenceImage, tolerance, done) {
|
386 | if (showMap) {
|
387 | var wrapper = document.createElement('div');
|
388 | wrapper.style.width = canvas.width + 'px';
|
389 | wrapper.style.height = canvas.height + 'px';
|
390 | wrapper.appendChild(canvas);
|
391 | document.body.appendChild(wrapper);
|
392 | document.body.appendChild(document.createTextNode(referenceImage));
|
393 | }
|
394 | var width = canvas.width;
|
395 | var height = canvas.height;
|
396 | var image = new Image();
|
397 | image.addEventListener('load', function() {
|
398 | expect(image.width).to.be(width);
|
399 | expect(image.height).to.be(height);
|
400 | var referenceCanvas = document.createElement('CANVAS');
|
401 | referenceCanvas.width = image.width;
|
402 | referenceCanvas.height = image.height;
|
403 | var referenceContext = referenceCanvas.getContext('2d');
|
404 | referenceContext.drawImage(image, 0, 0, image.width, image.height);
|
405 | var context = canvas.getContext('2d');
|
406 | var output = context.createImageData(canvas.width, canvas.height);
|
407 | var mismatchPx = pixelmatch(
|
408 | context.getImageData(0, 0, width, height).data,
|
409 | referenceContext.getImageData(0, 0, width, height).data,
|
410 | output.data, width, height);
|
411 | var mismatchPct = mismatchPx / (width * height) * 100;
|
412 | if (showDiff && mismatchPct > tolerance) {
|
413 | var diffCanvas = document.createElement('canvas');
|
414 | diffCanvas.width = width;
|
415 | diffCanvas.height = height;
|
416 | diffCanvas.getContext('2d').putImageData(output, 0, 0);
|
417 | document.body.appendChild(diffCanvas);
|
418 | }
|
419 | expect(mismatchPct).to.be.below(tolerance);
|
420 | done();
|
421 | });
|
422 | image.addEventListener('error', function() {
|
423 | expect().fail('Reference image could not be loaded');
|
424 | done();
|
425 | });
|
426 | image.src = referenceImage;
|
427 | }
|
428 | global.resembleCanvas = resembleCanvas;
|
429 |
|
430 | |
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 | global.expectResemble = function(map, referenceImage, tolerance, done) {
|
439 | map.render();
|
440 | map.on('postcompose', function(event) {
|
441 | if (event.frameState.animate) {
|
442 |
|
443 | return;
|
444 | }
|
445 |
|
446 | var canvas;
|
447 | if (event.glContext) {
|
448 | var webglCanvas = event.glContext.getCanvas();
|
449 | expect(webglCanvas).to.be.a(HTMLCanvasElement);
|
450 |
|
451 |
|
452 |
|
453 | canvas = document.createElement('canvas');
|
454 | canvas.width = webglCanvas.width;
|
455 | canvas.height = webglCanvas.height;
|
456 | canvas.getContext('2d').drawImage(webglCanvas, 0, 0,
|
457 | webglCanvas.width, webglCanvas.height);
|
458 | } else {
|
459 | canvas = event.context.canvas;
|
460 | }
|
461 | expect(canvas).to.be.a(HTMLCanvasElement);
|
462 |
|
463 | resembleCanvas(canvas, referenceImage, tolerance, done);
|
464 | });
|
465 | };
|
466 |
|
467 | var features = {
|
468 | ArrayBuffer: 'ArrayBuffer' in global,
|
469 | 'ArrayBuffer.isView': 'ArrayBuffer' in global && !!ArrayBuffer.isView,
|
470 | FileReader: 'FileReader' in global,
|
471 | Uint8ClampedArray: ('Uint8ClampedArray' in global),
|
472 | WebGL: false
|
473 | };
|
474 |
|
475 | |
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 | global.where = function(key) {
|
484 | if (!(key in features)) {
|
485 | throw new Error('where() called with unknown key: ' + key);
|
486 | }
|
487 | return {
|
488 | describe: features[key] ? global.describe : global.xdescribe,
|
489 | it: features[key] ? global.it : global.xit
|
490 | };
|
491 | };
|
492 |
|
493 |
|
494 | afterEach(function() {
|
495 | var garbage = document.body.getElementsByTagName('div');
|
496 | if (garbage.length) {
|
497 | throw new Error('Found extra <div> elements in the body');
|
498 | }
|
499 | });
|
500 |
|
501 | })(window);
|