protractor-jasmine2-html-reporter 在 conf 文件中使用 'shardTestFiles': true 共享测试时不会合并所有测试的结果
protractor-jasmine2-html-reporter doesn't consolidate results for all test when tests are shared using 'shardTestFiles': true in conf file
最近我们将 e2e-tests 配置为在 Jenkins 上进行,很快我们意识到我们必须使用共享测试文件:作为完整套件的 true 选项 运行 需要很长时间才能查看 9-每天10小时。但是当我们在 conf 文件中配置以下两个选项时。测试 运行 正常,但最终报告仅显示保存路径中的最后规格 运行 结果。合并所有选项未提供完整报告。
请查找我们的 conf 文件详细信息。任何帮助将不胜感激。
根据 Aditya 提供的解决方案编辑 conf 文件。请帮忙
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
var log4js = require('log4js');
var params = process.argv;
var args = process.argv.slice(3);
exports.config = {
//seleniumServerJar: './node_modules/gulp-protractor/node_modules/protractor/selenium/selenium-server-standalone-2.48.2.jar',
seleniumAddress: 'http://localhost:4444/wd/hub',
allScriptsTimeout: 100000,
framework: 'jasmine2',
onPrepare: function () {
return new Promise(function(fulfill, reject) {
browser.getCapabilities().then(function(value) {
reportName = value.get(Math.random(8,2)) + '_' + value.get('browserName') + '_' + Math.floor(Math.random() * 1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
//cleanDestination: false,
savePath: __dirname+'/target',
//docTitle: 'Web UI Test Report',
screenshotsFolder: 'image',
//takeScreenshots: true,
takeScreenshotsOnlyOnFailures: true,
consolidate: true,
consolidateAll: true,
preserveDirectory: true,
//fixedScreenshotName: true,
filePrefix: reportName + ".html"
})
);
fulfill();
});
});
// browser.manage().timeouts().implicitlyWait(11000);
var width = 768;
var height = 1366;
browser.driver.manage().window().setSize(768, 1366);
browser.ignoreSynchronization = false;
},
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function (file) {
if (!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
},
suites:{
example:['./test/e2e/specs/**/*Spec.js',]
},
/* capabilities: {
'browserName': 'chrome'
},*/
multiCapabilities: [
{
'browserName': 'chrome'
},
{
'browserName': 'firefox'
}
],
resultJsonOutputFile:'./results.json',
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 100000
}
};
我目前正在努力解决同样的问题,但是在我的原型设置中它可以正常工作,而且我使用的是 BASE 配置,仅此而已。
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['**-spec**.js'],
capabilities: {
browserName: 'chrome',
shardTestFiles: true,
maxInstances: 2
},
onPrepare: function() {
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: 'target/',
screenshotsFolder: 'images',
consolidate: true,
consolidateAll: false // false in my saved config - true in tut.
})
);
}
}
你能看看你是否可以让分片报告只用最低限度的工作吗?
编辑:还要注意目标文件夹中发生的情况,Jasmine 可能会在您不想要的时候 overwriting/cleaning。
编辑 2:如果您选择我下面的解决方案,请确保您启动了足够的浏览器,因为您有规格 - 如果您拆分规格,我下面的解决方案会根据浏览器 ID 生成报告:
capabilities: {
browserName: 'chrome',
shardTestFiles: true,
maxInstances: **2**
},
它会仍然覆盖你的记者HTML如果你想要超过2个。它会根据browser/session创建一个HTML文件用于测试它的 ID - 如果您使用 2 个浏览器实例,您将获得 2 个 HTML 个文件,不多也不少。
编辑 3:快速解决方法是不让 jasmine 清理...
cleanDestination: false,
但这似乎没有任何作用,所以在搜索和搜索之后 - 我认为 jasmine html 记者不会让我们整合比我们拥有的碎片更多的规范。 github 上的问题跟踪器没有显示任何进展。
所以我能想到的唯一解决方案是使用我下面的解决方案,使用足够的分片来支持您的大量规格,然后在完成后将其解析回一个文件。
编辑 4:您总是可以滥用 Jenkins 在实际测试运行之间连接 HTML 文件。
限制在于 'Jasmine2HtmlReporter',因为它会在并行测试 运行 时覆盖 html 报告文件。但是避免这种情况绝对是可能的,并且有几种方法可以做到这一点。根据您的方便选择正确的方式
1) 修改 Jasmine2HtmlReporter 的 'index.js' 以附加文件而不是 PhantomJs 使用
覆盖它
2) 通过从 onPrepare() 函数配置 Jasmine2HTML 报告器生成独特的 HTML 报告,并稍后合并所有报告
解决方案 1:Jasmine2HtmlReporter 的当前代码库 - index.js
使用两个函数 - phantomWrite()
和 nodeWrite()
来写入数据。参考 here
我创建了一个新函数 - appendwrite()
用于追加而不是覆盖,并且修改了代码以获取此函数
查看我从 protractor-jasmine2-html-reporter
中分叉出来的 github 代码
function appendwrite(path, filename, text){
var fs = require("fs");
var nodejs_path = require("path");
require("mkdirp").sync(path); // make sure the path exists
var filepath = nodejs_path.join(path, filename);
fs.appendFileSync(filepath,text)
return;
}
并修改'node_modules/protractor-jasmine2-html-reporter/index.js'中的self.writeFile
函数以获取新函数
try {
appendwrite(path, filename, text);
//phantomWrite(path, filename, text);
return;
} catch (e) { errors.push(' PhantomJs attempt: ' + e.message); }
try {
nodeWrite(path, filename, text);
return;
} catch (f) { errors.push(' NodeJS attempt: ' + f.message); }
并注释以下清理新 运行 报告的代码,这样您就不会看到任何错误清理错误 - CleanUpCode
rmdir(self.savePath);
解决方案 2:通过在 OnPrepare 函数中配置 Jasmine 报告器,为并行实例生成基于 sessionID 的单独报告
onPrepare: function() {
return new Promise(function (fulfill, reject) {
browser.getCapabilities().then(function (value) {
reportName = value.get('webdriver.remote.sessionid') + '_' + value.get('browserName') + '_' + Math.floor(Math.random()*1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: 'target/',
screenshotsFolder: 'images',
consolidate: true,
consolidateAll: true,
filePrefix: reportName + ".html"
})
);
fulfill();
})
});
},
第 2 步:在完成完整测试并关闭所有 webdriver 会话后,在 afterLaunch() 方法中合并跨并行实例生成的报告
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function(file){
if(!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
},
您还会看到使用一个 ConsolidatedReport 生成的报告如下所示
PS: 请忽略任何拼写错误和语法错误。这只是作为一个例子,可以定制
EDIT1:我们用来命名 HTML 报告的 'sessionID' 是 webdriver 远程 sessionID,如果您怀疑它可能无法通过多个会话保持唯一性,只需生成一个随机数用于个人 HTML 报告并稍后合并
我修改了上面的代码
Aditya 的解决方案对我来说效果很好。
我的示例配置文件:
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
exports.config = {
框架:'jasmine2',
seleniumAddress: 'http://localhost:4444/wd/hub',
/多重能力:[
{
'browserName': 'chrome',
'shardTestFiles':是的,
'maxInstances': 2,
铬选项:{
args: ['chrome.switches', '--disable-extensions']
}
},
{
'browserName': 'firefox'
}
],/
能力:
{
'browserName': 'chrome',
'shardTestFiles':是的,
'maxInstances': 2,
铬选项:{
args: ['chrome.switches', '--disable-extensions']
}
},
套房:{
登录页面:'login.js',
添加产品:'addproduct.js'
},
//规格:['addproduct.js'],
茉莉花节点选项:{
onComplete:空,
isVerbose: false,
includeStackTrace:真,
显示颜色:真实,
默认超时间隔:30000
},
onPrepare: function() {
return new Promise(function(fulfill, reject) {
browser.getCapabilities().then(function(value) {
reportName = value.get(Math.random(8,2)) + '_' + value.get('browserName') + '_' + Math.floor(Math.random() * 1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
//cleanDestination: false,
savePath: 'target/',
//docTitle: 'Web UI Test Report',
screenshotsFolder: 'image',
//takeScreenshots: true,
//takeScreenshotsOnlyOnFailures: true,
consolidate: true,
consolidateAll: true,
// preserveDirectory: true,
//fixedScreenshotName: true,
filePrefix: reportName + ".html"
})
);
fulfill();
});
});
},
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function(file) {
if (!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
}
}
我使用以下解决方案创建了具有唯一时间戳的唯一文件夹。这会将 HTML 报告保存在日期时间戳文件夹中,而不是 Jasmin-2-html-reporter 将其删除。
var today = new Date();
var timeStamp = today.getMonth() + 1 + '-' + today.getDate() + '-' + today.getFullYear() + '-' +
today.getHours() + 'h-' + today.getMinutes() + 'm-' +today.getSeconds()+'s';
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: './Reports/testResultsReport '+timeStamp,
screenshotsFolder: 'screenPrints',
takeScreenshots: true,
takeScreenshotsOnlyOnFailures: true,
})
);
`
这是另一个解决方案,建立在 之上,使用 protractor-html-reporter-2
,它适用于 jasmine-reporters
生成的 xml 文件。但是 jasmine-reporters
没有任何选项可以处理由多个浏览器实例生成的报告。在找不到理想的解决方案后,我最终在量角器配置 js 文件中执行了以下操作:
// add relevant packages in package.json
'use strict';
const HTMLReport = require('protractor-html-reporter-2');
const jasmineReporters = require('jasmine-reporters');
const moment = require('moment');
const os = require('os');
const xmldoc = require('xmldoc');
...
const DATE_FORMAT = 'YYYYMMDD-HHmmss-SSS'; // use any other format that gives unique timestamp
const reportDir = path.join(__dirname, '../report');
...
exports.config = {
...
framework: 'jasmine',
capabilities: {
browserName: 'chrome',
maxInstances: 2,
shardTestFiles: true,
},
beforeLaunch: async function () {
// clean up report directory
fs.emptyDirSync(reportDir);
},
onPrepare: async function () {
const NOW = moment().format(DATE_FORMAT);
const reportName = 'index-' + NOW;
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: reportDir,
filePrefix: reportName,
}));
// for screenshots
jasmine.getEnv().addReporter({
specDone: function (result) {
if (result.status === 'failed') {
browser.getCapabilities().then(function (caps) {
const browserName = caps.get('browserName');
browser.takeScreenshot().then(function (png) {
const stream = fs.createWriteStream(reportDir + '/screenshots/' + browserName + '-' + result.fullName.replace(/[.:]/g, ' ') + '.png');
stream.write(Buffer.from(png, 'base64'));
stream.end();
});
});
}
}
});
},
onComplete: async function () {
// do something after each instance of browser is closed
},
afterLaunch: async function (exitCode) {
// do something after ALL instances of browser are closed
await consolidateJasmineXmlReports();
},
...
},
...
async function consolidateJasmineXmlReports() {
// there may be better ways to write xml out but this works for me
const files = fs.readdirSync(reportDir).filter(fn => fn.endsWith('.xml'));
let disabledSum = 0;
let errorsSum = 0;
let failuresSum = 0;
let testsSum = 0;
let timeSum = 0;
const allTestSuiteNodes = [];
for (const file of files) {
const pathToXml = reportDir + path.sep + file;
console.log('Reading xml report file: ' + pathToXml);
const xml = fs.readFileSync(pathToXml);
const xmlDoc = new xmldoc.XmlDocument(xml);
const disabled = parseInt(xmlDoc.attr.disabled);
const errors = parseInt(xmlDoc.attr.errors);
const failures = parseInt(xmlDoc.attr.failures);
const tests = parseInt(xmlDoc.attr.tests);
const time = parseFloat(xmlDoc.attr.time);
disabledSum += disabled;
errorsSum += errors;
failuresSum += failures;
testsSum += tests;
timeSum += time;
const testSuiteNodes = xmlDoc.childrenNamed('testsuite');
allTestSuiteNodes.push(testSuiteNodes);
}
let startXml = `<?xml version="1.0" encoding="UTF-8" ?>`;
startXml += `<testsuites disabled="` + disabledSum + `" errors="` + errorsSum + `" failures="` + failuresSum + `" tests="` + testsSum + `" time="` + timeSum + `">`;
const endXml = '</testsuites>';
allTestSuiteNodes.push(endXml);
const finalXml = startXml + allTestSuiteNodes.join('\n');
fs.writeFileSync(reportDir + path.sep + 'consolidated.xml', finalXml, 'utf8');
const testConfig = {
outputPath: reportDir,
outputFilename: 'consolidated',
screenshotPath: './screenshots',
screenshotsOnlyOnFailure: true,
...
};
new HTMLReport().from(reportDir + path.sep + 'consolidated.xml', testConfig);
}
逻辑是
- 确保所有 xml 个文件的唯一名称。
- 将所有 xml 文件合并为
afterLaunch
. 中的一个有效 xml
- 使用任何使用该 xml 文件的包在
afterLaunch
. 中生成 html
我们使用 Jenkins 运行 上面创建的测试和报告在 Jenkins 中显示良好,并且在 Open Blue Ocean Jenkins
插件显示的报告中也准确显示。
注意:我已经使用 shardTestFiles 进行了测试,但没有使用 multiCapabilities 进行测试,但我认为它也应该适用。
另请参阅:
最近我们将 e2e-tests 配置为在 Jenkins 上进行,很快我们意识到我们必须使用共享测试文件:作为完整套件的 true 选项 运行 需要很长时间才能查看 9-每天10小时。但是当我们在 conf 文件中配置以下两个选项时。测试 运行 正常,但最终报告仅显示保存路径中的最后规格 运行 结果。合并所有选项未提供完整报告。
请查找我们的 conf 文件详细信息。任何帮助将不胜感激。
根据 Aditya 提供的解决方案编辑 conf 文件。请帮忙
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
var log4js = require('log4js');
var params = process.argv;
var args = process.argv.slice(3);
exports.config = {
//seleniumServerJar: './node_modules/gulp-protractor/node_modules/protractor/selenium/selenium-server-standalone-2.48.2.jar',
seleniumAddress: 'http://localhost:4444/wd/hub',
allScriptsTimeout: 100000,
framework: 'jasmine2',
onPrepare: function () {
return new Promise(function(fulfill, reject) {
browser.getCapabilities().then(function(value) {
reportName = value.get(Math.random(8,2)) + '_' + value.get('browserName') + '_' + Math.floor(Math.random() * 1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
//cleanDestination: false,
savePath: __dirname+'/target',
//docTitle: 'Web UI Test Report',
screenshotsFolder: 'image',
//takeScreenshots: true,
takeScreenshotsOnlyOnFailures: true,
consolidate: true,
consolidateAll: true,
preserveDirectory: true,
//fixedScreenshotName: true,
filePrefix: reportName + ".html"
})
);
fulfill();
});
});
// browser.manage().timeouts().implicitlyWait(11000);
var width = 768;
var height = 1366;
browser.driver.manage().window().setSize(768, 1366);
browser.ignoreSynchronization = false;
},
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function (file) {
if (!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
},
suites:{
example:['./test/e2e/specs/**/*Spec.js',]
},
/* capabilities: {
'browserName': 'chrome'
},*/
multiCapabilities: [
{
'browserName': 'chrome'
},
{
'browserName': 'firefox'
}
],
resultJsonOutputFile:'./results.json',
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 100000
}
};
我目前正在努力解决同样的问题,但是在我的原型设置中它可以正常工作,而且我使用的是 BASE 配置,仅此而已。
var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['**-spec**.js'],
capabilities: {
browserName: 'chrome',
shardTestFiles: true,
maxInstances: 2
},
onPrepare: function() {
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: 'target/',
screenshotsFolder: 'images',
consolidate: true,
consolidateAll: false // false in my saved config - true in tut.
})
);
}
}
你能看看你是否可以让分片报告只用最低限度的工作吗?
编辑:还要注意目标文件夹中发生的情况,Jasmine 可能会在您不想要的时候 overwriting/cleaning。
编辑 2:如果您选择我下面的解决方案,请确保您启动了足够的浏览器,因为您有规格 - 如果您拆分规格,我下面的解决方案会根据浏览器 ID 生成报告:
capabilities: {
browserName: 'chrome',
shardTestFiles: true,
maxInstances: **2**
},
它会仍然覆盖你的记者HTML如果你想要超过2个。它会根据browser/session创建一个HTML文件用于测试它的 ID - 如果您使用 2 个浏览器实例,您将获得 2 个 HTML 个文件,不多也不少。
编辑 3:快速解决方法是不让 jasmine 清理...
cleanDestination: false,
但这似乎没有任何作用,所以在搜索和搜索之后 - 我认为 jasmine html 记者不会让我们整合比我们拥有的碎片更多的规范。 github 上的问题跟踪器没有显示任何进展。
所以我能想到的唯一解决方案是使用我下面的解决方案,使用足够的分片来支持您的大量规格,然后在完成后将其解析回一个文件。
编辑 4:您总是可以滥用 Jenkins 在实际测试运行之间连接 HTML 文件。
限制在于 'Jasmine2HtmlReporter',因为它会在并行测试 运行 时覆盖 html 报告文件。但是避免这种情况绝对是可能的,并且有几种方法可以做到这一点。根据您的方便选择正确的方式
1) 修改 Jasmine2HtmlReporter 的 'index.js' 以附加文件而不是 PhantomJs 使用
覆盖它2) 通过从 onPrepare() 函数配置 Jasmine2HTML 报告器生成独特的 HTML 报告,并稍后合并所有报告
解决方案 1:Jasmine2HtmlReporter 的当前代码库 - index.js
使用两个函数 - phantomWrite()
和 nodeWrite()
来写入数据。参考 here
我创建了一个新函数 - appendwrite()
用于追加而不是覆盖,并且修改了代码以获取此函数
查看我从 protractor-jasmine2-html-reporter
function appendwrite(path, filename, text){
var fs = require("fs");
var nodejs_path = require("path");
require("mkdirp").sync(path); // make sure the path exists
var filepath = nodejs_path.join(path, filename);
fs.appendFileSync(filepath,text)
return;
}
并修改'node_modules/protractor-jasmine2-html-reporter/index.js'中的self.writeFile
函数以获取新函数
try {
appendwrite(path, filename, text);
//phantomWrite(path, filename, text);
return;
} catch (e) { errors.push(' PhantomJs attempt: ' + e.message); }
try {
nodeWrite(path, filename, text);
return;
} catch (f) { errors.push(' NodeJS attempt: ' + f.message); }
并注释以下清理新 运行 报告的代码,这样您就不会看到任何错误清理错误 - CleanUpCode
rmdir(self.savePath);
解决方案 2:通过在 OnPrepare 函数中配置 Jasmine 报告器,为并行实例生成基于 sessionID 的单独报告
onPrepare: function() {
return new Promise(function (fulfill, reject) {
browser.getCapabilities().then(function (value) {
reportName = value.get('webdriver.remote.sessionid') + '_' + value.get('browserName') + '_' + Math.floor(Math.random()*1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: 'target/',
screenshotsFolder: 'images',
consolidate: true,
consolidateAll: true,
filePrefix: reportName + ".html"
})
);
fulfill();
})
});
},
第 2 步:在完成完整测试并关闭所有 webdriver 会话后,在 afterLaunch() 方法中合并跨并行实例生成的报告
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function(file){
if(!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
},
您还会看到使用一个 ConsolidatedReport 生成的报告如下所示 PS: 请忽略任何拼写错误和语法错误。这只是作为一个例子,可以定制
EDIT1:我们用来命名 HTML 报告的 'sessionID' 是 webdriver 远程 sessionID,如果您怀疑它可能无法通过多个会话保持唯一性,只需生成一个随机数用于个人 HTML 报告并稍后合并
我修改了上面的代码
Aditya 的解决方案对我来说效果很好。 我的示例配置文件: var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');
exports.config = { 框架:'jasmine2', seleniumAddress: 'http://localhost:4444/wd/hub', /多重能力:[ { 'browserName': 'chrome', 'shardTestFiles':是的, 'maxInstances': 2, 铬选项:{ args: ['chrome.switches', '--disable-extensions'] } }, { 'browserName': 'firefox' } ],/ 能力: { 'browserName': 'chrome', 'shardTestFiles':是的, 'maxInstances': 2, 铬选项:{ args: ['chrome.switches', '--disable-extensions'] } }, 套房:{ 登录页面:'login.js', 添加产品:'addproduct.js' }, //规格:['addproduct.js'], 茉莉花节点选项:{ onComplete:空, isVerbose: false, includeStackTrace:真, 显示颜色:真实, 默认超时间隔:30000 },
onPrepare: function() {
return new Promise(function(fulfill, reject) {
browser.getCapabilities().then(function(value) {
reportName = value.get(Math.random(8,2)) + '_' + value.get('browserName') + '_' + Math.floor(Math.random() * 1E16);
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
//cleanDestination: false,
savePath: 'target/',
//docTitle: 'Web UI Test Report',
screenshotsFolder: 'image',
//takeScreenshots: true,
//takeScreenshotsOnlyOnFailures: true,
consolidate: true,
consolidateAll: true,
// preserveDirectory: true,
//fixedScreenshotName: true,
filePrefix: reportName + ".html"
})
);
fulfill();
});
});
},
afterLaunch: function afterLaunch() {
var fs = require('fs');
var output = '';
fs.readdirSync('target/').forEach(function(file) {
if (!(fs.lstatSync('target/' + file).isDirectory()))
output = output + fs.readFileSync('target/' + file);
});
fs.writeFileSync('target/ConsolidatedReport.html', output, 'utf8');
}
}
我使用以下解决方案创建了具有唯一时间戳的唯一文件夹。这会将 HTML 报告保存在日期时间戳文件夹中,而不是 Jasmin-2-html-reporter 将其删除。
var today = new Date();
var timeStamp = today.getMonth() + 1 + '-' + today.getDate() + '-' + today.getFullYear() + '-' +
today.getHours() + 'h-' + today.getMinutes() + 'm-' +today.getSeconds()+'s';
jasmine.getEnv().addReporter(
new Jasmine2HtmlReporter({
savePath: './Reports/testResultsReport '+timeStamp,
screenshotsFolder: 'screenPrints',
takeScreenshots: true,
takeScreenshotsOnlyOnFailures: true,
})
);
`
这是另一个解决方案,建立在 protractor-html-reporter-2
,它适用于 jasmine-reporters
生成的 xml 文件。但是 jasmine-reporters
没有任何选项可以处理由多个浏览器实例生成的报告。在找不到理想的解决方案后,我最终在量角器配置 js 文件中执行了以下操作:
// add relevant packages in package.json
'use strict';
const HTMLReport = require('protractor-html-reporter-2');
const jasmineReporters = require('jasmine-reporters');
const moment = require('moment');
const os = require('os');
const xmldoc = require('xmldoc');
...
const DATE_FORMAT = 'YYYYMMDD-HHmmss-SSS'; // use any other format that gives unique timestamp
const reportDir = path.join(__dirname, '../report');
...
exports.config = {
...
framework: 'jasmine',
capabilities: {
browserName: 'chrome',
maxInstances: 2,
shardTestFiles: true,
},
beforeLaunch: async function () {
// clean up report directory
fs.emptyDirSync(reportDir);
},
onPrepare: async function () {
const NOW = moment().format(DATE_FORMAT);
const reportName = 'index-' + NOW;
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: reportDir,
filePrefix: reportName,
}));
// for screenshots
jasmine.getEnv().addReporter({
specDone: function (result) {
if (result.status === 'failed') {
browser.getCapabilities().then(function (caps) {
const browserName = caps.get('browserName');
browser.takeScreenshot().then(function (png) {
const stream = fs.createWriteStream(reportDir + '/screenshots/' + browserName + '-' + result.fullName.replace(/[.:]/g, ' ') + '.png');
stream.write(Buffer.from(png, 'base64'));
stream.end();
});
});
}
}
});
},
onComplete: async function () {
// do something after each instance of browser is closed
},
afterLaunch: async function (exitCode) {
// do something after ALL instances of browser are closed
await consolidateJasmineXmlReports();
},
...
},
...
async function consolidateJasmineXmlReports() {
// there may be better ways to write xml out but this works for me
const files = fs.readdirSync(reportDir).filter(fn => fn.endsWith('.xml'));
let disabledSum = 0;
let errorsSum = 0;
let failuresSum = 0;
let testsSum = 0;
let timeSum = 0;
const allTestSuiteNodes = [];
for (const file of files) {
const pathToXml = reportDir + path.sep + file;
console.log('Reading xml report file: ' + pathToXml);
const xml = fs.readFileSync(pathToXml);
const xmlDoc = new xmldoc.XmlDocument(xml);
const disabled = parseInt(xmlDoc.attr.disabled);
const errors = parseInt(xmlDoc.attr.errors);
const failures = parseInt(xmlDoc.attr.failures);
const tests = parseInt(xmlDoc.attr.tests);
const time = parseFloat(xmlDoc.attr.time);
disabledSum += disabled;
errorsSum += errors;
failuresSum += failures;
testsSum += tests;
timeSum += time;
const testSuiteNodes = xmlDoc.childrenNamed('testsuite');
allTestSuiteNodes.push(testSuiteNodes);
}
let startXml = `<?xml version="1.0" encoding="UTF-8" ?>`;
startXml += `<testsuites disabled="` + disabledSum + `" errors="` + errorsSum + `" failures="` + failuresSum + `" tests="` + testsSum + `" time="` + timeSum + `">`;
const endXml = '</testsuites>';
allTestSuiteNodes.push(endXml);
const finalXml = startXml + allTestSuiteNodes.join('\n');
fs.writeFileSync(reportDir + path.sep + 'consolidated.xml', finalXml, 'utf8');
const testConfig = {
outputPath: reportDir,
outputFilename: 'consolidated',
screenshotPath: './screenshots',
screenshotsOnlyOnFailure: true,
...
};
new HTMLReport().from(reportDir + path.sep + 'consolidated.xml', testConfig);
}
逻辑是
- 确保所有 xml 个文件的唯一名称。
- 将所有 xml 文件合并为
afterLaunch
. 中的一个有效 xml
- 使用任何使用该 xml 文件的包在
afterLaunch
. 中生成 html
我们使用 Jenkins 运行 上面创建的测试和报告在 Jenkins 中显示良好,并且在 Open Blue Ocean Jenkins
插件显示的报告中也准确显示。
注意:我已经使用 shardTestFiles 进行了测试,但没有使用 multiCapabilities 进行测试,但我认为它也应该适用。
另请参阅: