forked from highcharts/highcharts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkarma-imagecapture-reporter.js
188 lines (167 loc) · 6.13 KB
/
karma-imagecapture-reporter.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* eslint-env node,es6 */
/**
* This reporter captures info from the browser tests containing image data
* and writes the image to images on the file system. The payload is passed from
* the test using __karma__.info.
*/
const fs = require('fs');
const { getLatestCommitShaSync } = require('../tools/gulptasks/lib/git');
const version = require('../package.json').version;
/* eslint-disable require-jsdoc */
function ImageCaptureReporter(baseReporterDecorator, config, logger, emitter) {
baseReporterDecorator(this);
const LOG = logger.create('reporter.imagecapture');
const gitSha = getLatestCommitShaSync();
// eslint-disable-next-line func-style
let fileWritingFinished = function () {};
let pendingFileWritings = 0;
const {
imageCapture = {
resultsOutputPath: 'test/visual-test-results.json'
},
referenceRun = false
} = config;
/**
* Create an animated gif of the reference and the candidata image, in order to
* see the differences.
* @param {String} filename
* The file name
* @param {Array} frames
* The image data of the GIF frames
* @param {number} width
* Width of the created gif
* @param {number} height
* Height of the created gif
* @return {void}
*/
function createAnimatedGif(filename, frames, width, height) {
var GIFEncoder = require('gifencoder');
var encoder = new GIFEncoder(width, height);
encoder.start();
// 0 for repeat, -1 for no-repeat
encoder.setRepeat(0);
// frame delay in ms
encoder.setDelay(500);
// image quality. 10 is default.
encoder.setQuality(10);
frames.forEach(frame => {
encoder.addFrame(frame);
});
encoder.finish();
var buf = encoder.out.getData();
pendingFileWritings++;
fs.writeFile(filename, buf, function (err) {
if (err) {
throw err;
}
if (!--pendingFileWritings) {
fileWritingFinished();
}
});
}
function readExistingResult(filePath) {
var existingFile = fs.readFileSync(filePath, { flag: 'a+' });
if (existingFile && existingFile.length !== 0) {
try {
return JSON.parse(existingFile.toString());
} catch (e) {
LOG.warn('Failed to parse existing visual test results.');
}
}
return {}; // empty object
}
// "browser_start" - a test run is beginning in _this_ browser
this.onBrowserStart = function (browser) {
const filename = imageCapture.resultsOutputPath;
LOG.info('Starting visual tests. Results stored in ' + filename);
const now = new Date();
const today = now.toISOString().slice(0, 10);
const testResults = readExistingResult(filename);
testResults.meta = Object.assign(testResults.meta || {}, {
browser: browser.name,
runId: process.env.CIRCLE_BUILD_NUM || browser.id,
runDate: today,
runDateTs: now.getTime(),
gitSha: gitSha || 'unknown',
version: version
});
fs.writeFileSync(filename, JSON.stringify(testResults, null, ' '));
};
/**
* Logs results to file specified in the config.
* @param {object} browser data
* @param {object} testResult data
* @return {void}
*/
this.specSuccess = this.specSkipped = this.specFailure = function (browser, testResult) {
if (referenceRun) {
// no need to log results test results if the test run is for references/baselines
return;
}
const { log = [], skipped, success } = testResult;
const filename = imageCapture.resultsOutputPath;
const diffResults = readExistingResult(filename);
if (skipped) {
diffResults[testResult.description] = undefined;
} else if (success) {
diffResults[testResult.description] = 0;
} else if (!success && log.length > 0) {
const matches = log[0].match(/Actual: (\d+)/);
if (matches[1]) {
LOG.info(`Test ${testResult.description} differs with ${matches[1]} pixels`);
diffResults[testResult.description] = parseInt(matches[1], 10);
} else {
LOG.warn(`Test ${testResult.description} failed, but unable to determine the diff. Has the test assert(..) changed?`);
}
}
fs.writeFileSync(filename, JSON.stringify(diffResults, null, ' '));
};
/**
* Writes image data to file
*/
emitter.on('browser_info', (browser, info) => {
let data = info.data;
const filename = info.filename;
try {
if (/\.svg$/.test(filename)) {
pendingFileWritings++;
fs.writeFile(filename, data, err => {
if (err) {
throw err;
}
if (!--pendingFileWritings) {
fileWritingFinished();
}
});
} else if (/\.png$/.test(filename)) {
data = data.replace(/^data:image\/\w+;base64,/, '');
fs.writeFileSync(filename, Buffer.from(data, 'base64'));
} else if (/\.gif$/.test(filename)) {
const canvasWidth = info.canvasWidth || 600;
const canvasHeight = info.canvasHeight || 400;
createAnimatedGif(filename, info.frames, canvasWidth, canvasHeight);
}
} catch (err) {
LOG.error(`Failed to write file ${filename}\n\n${err}`);
}
});
// wait for async file writes before exiting
this.onExit = function (done) {
if (pendingFileWritings) {
fileWritingFinished = done;
} else {
done();
}
};
}
/* eslint-enable require-jsdoc */
ImageCaptureReporter.$inject = [
'baseReporterDecorator',
'config',
'logger',
'emitter'
];
// PUBLISH DI MODULE
module.exports = {
'reporter:imagecapture': ['type', ImageCaptureReporter]
};