Move Karma Kotlin reporter to kotlin-test-js-runner
This commit is contained in:
+6
-171
@@ -51,7 +51,7 @@ class KotlinKarma(override val compilation: KotlinJsCompilation) : KotlinJsTestF
|
|||||||
init {
|
init {
|
||||||
requiredDependencies.add(versions.karma)
|
requiredDependencies.add(versions.karma)
|
||||||
|
|
||||||
useLogReporter()
|
useKotlinReporter()
|
||||||
useMocha()
|
useMocha()
|
||||||
useWebpack()
|
useWebpack()
|
||||||
useSourceMapSupport()
|
useSourceMapSupport()
|
||||||
@@ -60,182 +60,17 @@ class KotlinKarma(override val compilation: KotlinJsCompilation) : KotlinJsTestF
|
|||||||
config.autoWatch = false
|
config.autoWatch = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// This reporter extends karma-teamcity-reporter
|
private fun useKotlinReporter() {
|
||||||
// It is necessary, because karma-teamcity-reporter can't write browser's log
|
|
||||||
// And additionally it overrides flushLogs, because flushLogs adds redundant spaces after some messages
|
|
||||||
private fun useLogReporter() {
|
|
||||||
requiredDependencies.add(versions.karmaTeamcityReporter)
|
requiredDependencies.add(versions.karmaTeamcityReporter)
|
||||||
config.reporters.add("karma-browser-log-reporter")
|
config.reporters.add("karma-kotlin-reporter")
|
||||||
|
|
||||||
confJsWriters.add {
|
confJsWriters.add {
|
||||||
//language=ES6
|
//language=ES6
|
||||||
it.appendln(
|
it.appendln(
|
||||||
"""
|
"""
|
||||||
// reporter for browser logs
|
config.plugins = config.plugins || [];
|
||||||
(function () {
|
config.plugins.push('karma-*'); // default
|
||||||
const util = require('util');
|
config.plugins.push('kotlin-test-js-runner/karma-kotlin-reporter.js');
|
||||||
const resolve = require('url').resolve;
|
|
||||||
|
|
||||||
const escapeMessage = function (message) {
|
|
||||||
if (message === null || message === undefined) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.toString()
|
|
||||||
.replace(/\|/g, '||')
|
|
||||||
.replace(/'/g, "|'")
|
|
||||||
.replace(/\n/g, '|n')
|
|
||||||
.replace(/\r/g, '|r')
|
|
||||||
.replace(/\u0085/g, '|x')
|
|
||||||
.replace(/\u2028/g, '|l')
|
|
||||||
.replace(/\u2029/g, '|p')
|
|
||||||
.replace(/\[/g, '|[')
|
|
||||||
.replace(/\]/g, '|]')
|
|
||||||
};
|
|
||||||
|
|
||||||
var formatMessage = function () {
|
|
||||||
var args = Array.prototype.slice.call(arguments);
|
|
||||||
|
|
||||||
for (var i = args.length - 1; i > 0; i--) {
|
|
||||||
args[i] = escapeMessage(args[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.format.apply(null, args) + '\n'
|
|
||||||
};
|
|
||||||
|
|
||||||
function createFormatError(config, emitter) {
|
|
||||||
const basePath = config.basePath;
|
|
||||||
const urlRoot = config.urlRoot === '/' ? '' : (config.urlRoot || '');
|
|
||||||
let lastServedFiles = [];
|
|
||||||
|
|
||||||
emitter.on('file_list_modified', (files) => {
|
|
||||||
lastServedFiles = files.served
|
|
||||||
});
|
|
||||||
const URL_REGEXP = new RegExp('(?:https?:\\/\\/' +
|
|
||||||
config.hostname + '(?:\\:' + config.port + ')?' + ')?\\/?' +
|
|
||||||
urlRoot + '\\/?' +
|
|
||||||
'(base/|absolute)' + // prefix, including slash for base/ to create relative paths.
|
|
||||||
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
|
|
||||||
'(\\?\\w*)?' + // sha
|
|
||||||
'(\\:(\\d+))?' + // line
|
|
||||||
'(\\:(\\d+))?' + // column
|
|
||||||
'', 'g');
|
|
||||||
|
|
||||||
const SourceMapConsumer = require('source-map').SourceMapConsumer;
|
|
||||||
|
|
||||||
const cache = new WeakMap();
|
|
||||||
function getSourceMapConsumer (sourceMap) {
|
|
||||||
if (!cache.has(sourceMap)) {
|
|
||||||
cache.set(sourceMap, new SourceMapConsumer(sourceMap))
|
|
||||||
}
|
|
||||||
return cache.get(sourceMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
const PathUtils = require('karma/lib/utils/path-utils.js');
|
|
||||||
|
|
||||||
return function (input) {
|
|
||||||
let msg = input.replace(URL_REGEXP, function (_, prefix, path, __, ___, line, ____, column) {
|
|
||||||
const normalizedPath = prefix === 'base/' ? `${"$"}basePath}/${"$"}{path}` : path;
|
|
||||||
const file = lastServedFiles.find((file) => file.path === normalizedPath);
|
|
||||||
|
|
||||||
if (file && file.sourceMap && line) {
|
|
||||||
line = +line;
|
|
||||||
column = +column;
|
|
||||||
const bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({ line, column: (column || 0), bias });
|
|
||||||
|
|
||||||
return `${"$"}{PathUtils.formatPathMapping(resolve(path, original.source), original.line, original.column)} <- ${"$"}{PathUtils.formatPathMapping(path, line, column)}`
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PathUtils.formatPathMapping(path, line, column) || prefix
|
|
||||||
});
|
|
||||||
|
|
||||||
return msg + '\n'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const LogReporter = function (baseReporterDecorator, config, emitter) {
|
|
||||||
const teamcityReporter = require("karma-teamcity-reporter")["reporter:teamcity"][1];
|
|
||||||
teamcityReporter.call(this, baseReporterDecorator);
|
|
||||||
|
|
||||||
const formatError = createFormatError(config, emitter);
|
|
||||||
|
|
||||||
this.TEST_STD_OUT = "##teamcity[testStdOut name='%s' out='%s' flowId='']";
|
|
||||||
|
|
||||||
const tcOnBrowserStart = this.onBrowserStart;
|
|
||||||
this.onBrowserStart = function (browser) {
|
|
||||||
tcOnBrowserStart.call(this, browser);
|
|
||||||
this.browserResults[browser.id].consoleCollector = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onBrowserLog = (browser, log, type) => {
|
|
||||||
var browserResult = this.browserResults[browser.id];
|
|
||||||
if (browserResult) {
|
|
||||||
browserResult.consoleCollector.push(`[${"$"}{type}] ${"$"}{log}\n`)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const tcSpecSuccess = this.specSuccess;
|
|
||||||
this.specSuccess = function (browser, result) {
|
|
||||||
tcSpecSuccess.call(this, browser, result);
|
|
||||||
|
|
||||||
var log = this.getLog(browser, result);
|
|
||||||
var testName = result.description;
|
|
||||||
|
|
||||||
const endMessage = log.pop();
|
|
||||||
this.browserResults[browser.id].consoleCollector.forEach(item => {
|
|
||||||
log.push(
|
|
||||||
formatMessage(this.TEST_STD_OUT, testName, item)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
log.push(endMessage);
|
|
||||||
|
|
||||||
this.browserResults[browser.id].consoleCollector = []
|
|
||||||
};
|
|
||||||
|
|
||||||
this.specFailure = function (browser, result) {
|
|
||||||
var log = this.getLog(browser, result);
|
|
||||||
var testName = result.description;
|
|
||||||
|
|
||||||
log.push(formatMessage(this.TEST_START, testName));
|
|
||||||
this.browserResults[browser.id].consoleCollector.forEach(item => {
|
|
||||||
log.push(
|
|
||||||
formatMessage(this.TEST_STD_OUT, testName, item)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
log.push(formatMessage(this.TEST_FAILED, testName,
|
|
||||||
result.log
|
|
||||||
.map(log => formatError(log))
|
|
||||||
.join('\n\n')
|
|
||||||
));
|
|
||||||
log.push(formatMessage(this.TEST_END, testName, result.time));
|
|
||||||
|
|
||||||
this.browserResults[browser.id].consoleCollector = []
|
|
||||||
};
|
|
||||||
|
|
||||||
this.flushLogs = function (browserResult) {
|
|
||||||
while (browserResult.log.length > 0) {
|
|
||||||
var line = browserResult.log.shift();
|
|
||||||
line = line.replace("flowId=''", "flowId='" + browserResult.flowId + "'");
|
|
||||||
|
|
||||||
this.write(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LogReporter.${"$"}inject = ['baseReporterDecorator', 'config', 'emitter'];
|
|
||||||
|
|
||||||
config.plugins = config.plugins || [];
|
|
||||||
config.plugins.push('karma-*'); // default
|
|
||||||
config.plugins.push({
|
|
||||||
'reporter:karma-browser-log-reporter': ['type', LogReporter]
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ tasks {
|
|||||||
inputs.files(
|
inputs.files(
|
||||||
"nodejs.ts",
|
"nodejs.ts",
|
||||||
"karma.ts",
|
"karma.ts",
|
||||||
|
"karma-kotlin-reporter.js",
|
||||||
"nodejs-source-map-support.js",
|
"nodejs-source-map-support.js",
|
||||||
"package.json",
|
"package.json",
|
||||||
"rollup.config.js",
|
"rollup.config.js",
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const util = require('util');
|
||||||
|
const resolve = require('url').resolve;
|
||||||
|
|
||||||
|
const escapeMessage = function (message) {
|
||||||
|
if (message === null || message === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return message.toString()
|
||||||
|
.replace(/\|/g, '||')
|
||||||
|
.replace(/'/g, "|'")
|
||||||
|
.replace(/\n/g, '|n')
|
||||||
|
.replace(/\r/g, '|r')
|
||||||
|
.replace(/\u0085/g, '|x')
|
||||||
|
.replace(/\u2028/g, '|l')
|
||||||
|
.replace(/\u2029/g, '|p')
|
||||||
|
.replace(/\[/g, '|[')
|
||||||
|
.replace(/]/g, '|]')
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatMessage = function () {
|
||||||
|
const args = Array.prototype.slice.call(arguments);
|
||||||
|
|
||||||
|
for (let i = args.length - 1; i > 0; i--) {
|
||||||
|
args[i] = escapeMessage(args[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.format.apply(null, args) + '\n'
|
||||||
|
};
|
||||||
|
|
||||||
|
// This ErrorFormatter is copied from standard karma's,
|
||||||
|
// but without warning in case of failed original location finding
|
||||||
|
function createFormatError(config, emitter) {
|
||||||
|
const basePath = config.basePath;
|
||||||
|
const urlRoot = config.urlRoot === '/' ? '' : (config.urlRoot || '');
|
||||||
|
let lastServedFiles = [];
|
||||||
|
|
||||||
|
emitter.on('file_list_modified', (files) => {
|
||||||
|
lastServedFiles = files.served
|
||||||
|
});
|
||||||
|
const URL_REGEXP = new RegExp('(?:https?:\\/\\/' +
|
||||||
|
config.hostname + '(?:\\:' + config.port + ')?' + ')?\\/?' +
|
||||||
|
urlRoot + '\\/?' +
|
||||||
|
'(base/|absolute)' + // prefix, including slash for base/ to create relative paths.
|
||||||
|
'((?:[A-z]\\:)?[^\\?\\s\\:]*)' + // path
|
||||||
|
'(\\?\\w*)?' + // sha
|
||||||
|
'(\\:(\\d+))?' + // line
|
||||||
|
'(\\:(\\d+))?' + // column
|
||||||
|
'', 'g');
|
||||||
|
|
||||||
|
const SourceMapConsumer = require('source-map').SourceMapConsumer;
|
||||||
|
|
||||||
|
const cache = new WeakMap();
|
||||||
|
|
||||||
|
function getSourceMapConsumer(sourceMap) {
|
||||||
|
if (!cache.has(sourceMap)) {
|
||||||
|
cache.set(sourceMap, new SourceMapConsumer(sourceMap))
|
||||||
|
}
|
||||||
|
return cache.get(sourceMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
const PathUtils = require('karma/lib/utils/path-utils.js');
|
||||||
|
|
||||||
|
return function (input) {
|
||||||
|
let msg = input.replace(URL_REGEXP, function (_, prefix, path, __, ___, line, ____, column) {
|
||||||
|
const normalizedPath = prefix === 'base/' ? `${basePath}/${path}` : path;
|
||||||
|
const file = lastServedFiles.find((file) => file.path === normalizedPath);
|
||||||
|
|
||||||
|
if (file && file.sourceMap && line) {
|
||||||
|
line = +line;
|
||||||
|
column = +column;
|
||||||
|
const bias = column ? SourceMapConsumer.GREATEST_LOWER_BOUND : SourceMapConsumer.LEAST_UPPER_BOUND;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const original = getSourceMapConsumer(file.sourceMap).originalPositionFor({line, column: (column || 0), bias});
|
||||||
|
|
||||||
|
return `${PathUtils.formatPathMapping(resolve(path, original.source), original.line,
|
||||||
|
original.column)} <- ${PathUtils.formatPathMapping(path, line, column)}`
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PathUtils.formatPathMapping(path, line, column) || prefix
|
||||||
|
});
|
||||||
|
|
||||||
|
return msg + '\n'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// This reporter extends karma-teamcity-reporter
|
||||||
|
// It is necessary, because karma-teamcity-reporter can't write browser's log
|
||||||
|
// And additionally it overrides flushLogs, because flushLogs adds redundant spaces after some messages
|
||||||
|
const KarmaKotlinReporter = function (baseReporterDecorator, config, emitter) {
|
||||||
|
const teamcityReporter = require("karma-teamcity-reporter")["reporter:teamcity"][1];
|
||||||
|
teamcityReporter.call(this, baseReporterDecorator);
|
||||||
|
|
||||||
|
const formatError = createFormatError(config, emitter);
|
||||||
|
|
||||||
|
this.TEST_STD_OUT = "##teamcity[testStdOut name='%s' out='%s' flowId='']";
|
||||||
|
|
||||||
|
const tcOnBrowserStart = this.onBrowserStart;
|
||||||
|
this.onBrowserStart = function (browser) {
|
||||||
|
tcOnBrowserStart.call(this, browser);
|
||||||
|
this.browserResults[browser.id].consoleCollector = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onBrowserLog = (browser, log, type) => {
|
||||||
|
const browserResult = this.browserResults[browser.id];
|
||||||
|
if (browserResult) {
|
||||||
|
browserResult.consoleCollector.push(`[${type}] ${log}\n`)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tcSpecSuccess = this.specSuccess;
|
||||||
|
this.specSuccess = function (browser, result) {
|
||||||
|
tcSpecSuccess.call(this, browser, result);
|
||||||
|
|
||||||
|
const log = this.getLog(browser, result);
|
||||||
|
const testName = result.description;
|
||||||
|
|
||||||
|
const endMessage = log.pop();
|
||||||
|
this.browserResults[browser.id].consoleCollector.forEach(item => {
|
||||||
|
log.push(
|
||||||
|
formatMessage(this.TEST_STD_OUT, testName, item)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
log.push(endMessage);
|
||||||
|
|
||||||
|
this.browserResults[browser.id].consoleCollector = []
|
||||||
|
};
|
||||||
|
|
||||||
|
this.specFailure = function (browser, result) {
|
||||||
|
const log = this.getLog(browser, result);
|
||||||
|
const testName = result.description;
|
||||||
|
|
||||||
|
log.push(formatMessage(this.TEST_START, testName));
|
||||||
|
this.browserResults[browser.id].consoleCollector.forEach(item => {
|
||||||
|
log.push(
|
||||||
|
formatMessage(this.TEST_STD_OUT, testName, item)
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
log.push(formatMessage(this.TEST_FAILED, testName,
|
||||||
|
result.log
|
||||||
|
.map(log => formatError(log))
|
||||||
|
.join('\n\n')
|
||||||
|
));
|
||||||
|
log.push(formatMessage(this.TEST_END, testName, result.time));
|
||||||
|
|
||||||
|
this.browserResults[browser.id].consoleCollector = []
|
||||||
|
};
|
||||||
|
|
||||||
|
this.flushLogs = function (browserResult) {
|
||||||
|
while (browserResult.log.length > 0) {
|
||||||
|
let line = browserResult.log.shift();
|
||||||
|
line = line.replace("flowId=''", "flowId='" + browserResult.flowId + "'");
|
||||||
|
|
||||||
|
this.write(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
KarmaKotlinReporter.$inject = ['baseReporterDecorator', 'config', 'emitter'];
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
'reporter:karma-kotlin-reporter': ['type', KarmaKotlinReporter]
|
||||||
|
};
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"lib/**/*"
|
"lib/**/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rimraf lib/* && rollup -c rollup.config.js"
|
"build": "rimraf lib/* && rollup -c rollup.config.js && cpx \"karma-kotlin-reporter.js\" lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^10.12.21",
|
"@types/node": "^10.12.21",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
"rollup-plugin-sourcemaps": "^0.4.2",
|
"rollup-plugin-sourcemaps": "^0.4.2",
|
||||||
"rollup-plugin-typescript2": "^0.19.2",
|
"rollup-plugin-typescript2": "^0.19.2",
|
||||||
"rollup-plugin-terser": "^5.1.2",
|
"rollup-plugin-terser": "^5.1.2",
|
||||||
"typescript": "^3.3.1"
|
"typescript": "^3.3.1",
|
||||||
|
"cpx": "^1.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user