2

最近我们已经将我们的 e2e 测试配置为在 Jenkins 上,很快我们意识到我们必须使用共享测试文件:真正的选项,因为完整的套件运行需要很长时间,我们每天要花 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
  }
};
4

5 回答 5

3

限制在于“Jasmine2HtmlReporter”,因为当测试并行运行时,它会覆盖 html 报告文件。但避免这种情况绝对是可能的,并且有几种方法可以做到这一点。根据您的方便选择正确的方式

1) 修补 Jasmine2HtmlReporter 的“index.js”以附加文件而不是 PhantomJs 覆盖其使用

2) 通过 onPrepare() 函数配置 Jasmine2HTML 报告器生成唯一的 HTML 报告,并在以后合并所有报告

解决方案 1:Jasmine2HtmlReporter 的当前代码库 -index.js使用两个函数 - phantomWrite()&nodeWrite()来写入数据。参考这里

我创建了一个新函数 -appendwrite()追加而不是覆盖,并修改了代码来获取这个函数查看我的 github 代码分叉出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;
        }

并修改self.writeFile“node_modules/protractor-jasmine2-html-reporter/index.js”中的函数以获取新函数

        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 报告生成一个随机数并稍后合并

我修改了上面的代码

于 2016-09-06T10:58:36.637 回答
1

这是另一种解决方案,建立在这个答案之上,使用protractor-html-reporter-2它适用于 .xml 生成的 xml 文件jasmine-reporters。但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);
}

逻辑是

  1. 确保所有 xml 文件的名称都是唯一的。
  2. 将所有 xml 文件合并为 .xml 文件中的一个有效 xml afterLaunch
  3. 使用任何使用该 xml 文件的包在afterLaunch.

Open Blue Ocean Jenkins我们使用 Jenkins 运行测试,上面创建的报告在 Jenkins 中很好地显示,并且在插件显示的报告中也准确显示。

注意:我已经使用 shardTestFiles 而不是 multiCapabilities 进行了测试,但我认为它也应该可以使用。

也可以看看:

于 2020-11-25T01:17:44.167 回答
0

我目前正在努力解决同样的问题,但是在我的原型设置中它正在工作,并且我使用的是 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 可能会在您不想要的时候覆盖/清理。

编辑 2:如果您选择我下面的解决方案,请确保您启动了足够多的浏览器,因为您有规格 - 如果您拆分规格,我下面的解决方案会根据浏览器 ID 生成报告:

capabilities: {
    browserName: 'chrome',                                                      
    shardTestFiles: true,                                                       
    maxInstances: **2**                                                             
},

如果您想要超过 2 个,它仍然会覆盖您的记者 HTML。它会根据用于测试它的浏览器/会话 ID 创建一个 HTML 文件 - 如果您使用 2 个浏览器实例,您将获得 2 个 HTML 文件,不多不少。

编辑3:一个快速的解决方法是不要让茉莉花清理......

cleanDestination: false,

但这似乎没有任何作用,所以在搜索和搜索之后 - 我认为 jasmine html 报告器不会让我们整合比我们拥有的碎片更多的规范。github 上的问题跟踪器没有显示任何进展。

所以我能想到的唯一解决方案是使用我下面的解决方案,有足够的分片来支持你的规格数量,然后在你完成后将其解析回一个文件。

编辑 4:您总是可以滥用 Jenkins 在实际测试运行之间连接 HTML 文件。

于 2016-09-06T07:12:55.337 回答
0

Aditya 的解决方案对我来说很好用。我的示例配置文件: var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');

export.config = { framework: 'jasmine2', seleniumAddress: ' http://localhost:4444/wd/hub ', / multiCapabilities: [ { 'browserName': 'chrome', 'shardTestFiles': true, 'maxInstances': 2、chromeOptions: { args: ['chrome.switches', '--disable-extensions'] } }, { 'browserName': 'firefox' } ],/能力:{'browserName':'chrome','shardTestFiles':true,'maxInstances':2,chromeOptions:{args:['chrome.switches','--disable-extensions']}},套件:{ loginpage: 'login.js', addproduct: 'addproduct.js' }, //specs: ['addproduct.js'], jasmineNodeOpts: { onComplete: null, isVerbose: false, includeStackTrace: true, showColors: true, defaultTimeoutInterval: 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');
}

}

于 2016-09-19T13:40:52.077 回答
0

我使用以下解决方案创建具有唯一时间戳的唯一文件夹。这会将 HTML 报告保存在 date-timestamp 文件夹中,而不是 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,
            })
        ); 

`

于 2016-10-03T15:57:09.690 回答