1 | var os = require('os');
|
2 | var path = require('path');
|
3 | var fs = require('fs');
|
4 | var builder = require('xmlbuilder');
|
5 |
|
6 |
|
7 | var JUnitReporter = function(baseReporterDecorator, config, logger, helper, formatError) {
|
8 | var log = logger.create('reporter.junit');
|
9 | var reporterConfig = config.junitReporter || {};
|
10 | var pkgName = reporterConfig.suite || '';
|
11 | var outputFile = helper.normalizeWinPath(path.resolve(config.basePath, reporterConfig.outputFile
|
12 | || 'test-results.xml'));
|
13 |
|
14 | var xml;
|
15 | var suites;
|
16 | var pendingFileWritings = 0;
|
17 | var fileWritingFinished = function() {};
|
18 | var allMessages = [];
|
19 |
|
20 | baseReporterDecorator(this);
|
21 |
|
22 | this.adapters = [function(msg) {
|
23 | allMessages.push(msg);
|
24 | }];
|
25 |
|
26 | var initliazeXmlForBrowser = function(browser) {
|
27 | var timestamp = (new Date()).toISOString().substr(0, 19);
|
28 | var suite = suites[browser.id] = xml.ele('testsuite', {
|
29 | name: browser.name, 'package': pkgName, timestamp: timestamp, id: 0, hostname: os.hostname()
|
30 | });
|
31 | suite.ele('properties').ele('property', {name: 'browser.fullName', value: browser.fullName});
|
32 | };
|
33 |
|
34 | this.onRunStart = function(browsers) {
|
35 | suites = Object.create(null);
|
36 | xml = builder.create('testsuites');
|
37 |
|
38 |
|
39 | browsers.forEach(initliazeXmlForBrowser);
|
40 | };
|
41 |
|
42 | this.onBrowserStart = function(browser) {
|
43 | initliazeXmlForBrowser(browser);
|
44 | };
|
45 |
|
46 | this.onBrowserComplete = function(browser) {
|
47 | var suite = suites[browser.id];
|
48 | var result = browser.lastResult;
|
49 |
|
50 | suite.att('tests', result.total);
|
51 | suite.att('errors', result.disconnected || result.error ? 1 : 0);
|
52 | suite.att('failures', result.failed);
|
53 | suite.att('time', (result.netTime || 0) / 1000);
|
54 |
|
55 | suite.ele('system-out').dat(allMessages.join() + '\n');
|
56 | suite.ele('system-err');
|
57 | };
|
58 |
|
59 | this.onRunComplete = function() {
|
60 | var xmlToOutput = xml;
|
61 |
|
62 | pendingFileWritings++;
|
63 | helper.mkdirIfNotExists(path.dirname(outputFile), function() {
|
64 | fs.writeFile(outputFile, xmlToOutput.end({pretty: true}), function(err) {
|
65 | if (err) {
|
66 | log.warn('Cannot write JUnit xml\n\t' + err.message);
|
67 | } else {
|
68 | log.debug('JUnit results written to "%s".', outputFile);
|
69 | }
|
70 |
|
71 | if (!--pendingFileWritings) {
|
72 | fileWritingFinished();
|
73 | }
|
74 | });
|
75 | });
|
76 |
|
77 | suites = xml = null;
|
78 | allMessages.length = 0;
|
79 | };
|
80 |
|
81 | this.specSuccess = this.specSkipped = this.specFailure = function(browser, result) {
|
82 | var spec = suites[browser.id].ele('testcase', {
|
83 | name: result.description, time: ((result.time || 0) / 1000),
|
84 | classname: (pkgName ? pkgName + ' ' : '') + browser.name + '.' + result.suite.join(' ').replace(/\./g, '_')
|
85 | });
|
86 |
|
87 | if (result.skipped) {
|
88 | spec.ele('skipped');
|
89 | }
|
90 |
|
91 | if (!result.success) {
|
92 | result.log.forEach(function(err) {
|
93 | spec.ele('failure', {type: ''}, formatError(err));
|
94 | });
|
95 | }
|
96 | };
|
97 |
|
98 |
|
99 | this.onExit = function(done) {
|
100 | if (pendingFileWritings) {
|
101 | fileWritingFinished = done;
|
102 | } else {
|
103 | done();
|
104 | }
|
105 | };
|
106 | };
|
107 |
|
108 | JUnitReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError'];
|
109 |
|
110 |
|
111 | module.exports = {
|
112 | 'reporter:junit': ['type', JUnitReporter]
|
113 | };
|