【问题标题】:protractor-jasmine2-html-reporter doesn't consolidate results for all test when tests are shared using 'shardTestFiles': true in conf file当使用 'shardTestFiles' 共享测试时,protractor-jasmine2-html-reporter 不会合并所有测试的结果:conf 文件中的 true
【发布时间】:2016-09-05 18:34:05
【问题描述】:

最近我们已经将我们的 e2e-tests 配置为在 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
  }
};

【问题讨论】:

    标签: jenkins jasmine protractor gulp-protractor jasmine-reporters


    【解决方案1】:

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

    我已经修改了上面的代码

    【讨论】:

    • 感谢您的帮助,但当我将此解决方案用于多种功能时,我仍然只能看到单个 html 报告。
    • 我终于可以根据能力生成报告了。
    • @tyaga001:你能帮我看看你是怎么做到的吗?我也遇到了同样的问题
    • @GauravLad - 我已经在这里推送了代码,请参考。 github.com/tyaga001/multi-capability-reporting-protractor-/blob/…
    • 应该是fileNamefileNamePrefix 而不是filePrefix(这是一个不再存在的选项)
    【解决方案2】:

    这是另一个解决方案,在此answer 之上构建,使用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);
    }
    

    逻辑是

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

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

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

    另见:

    【讨论】:

    • 嘿,感谢您的解决方案,这对我有用。但是,我无法显示屏幕截图,您是否实现了这一点以及如何做到这一点?
    • @SayantanGhosh 很高兴听到它有效。我不记得有截图问题。我已经用我们为屏幕截图提供的一些配置更新了答案。看看对你有没有帮助。我们实际上不再使用量角器,因为宣布对它的支持可能会停止,所以我不能说配置是否仍然有效。我们现在使用的是柏树。
    • 是的,我发现了问题,html-reporter 需要浏览器名称来检测屏幕截图,并且 afterLaunch() 挂钩中不存在浏览器对象,所以我将代码移到onComplete() 钩子(对我来说不是问题,因为我只有一种能力)。这解决了问题,因为我能够从功能中获取浏览器名称。
    【解决方案3】:

    我目前正在努力解决同样的问题,但是在我的原型设置中它正在工作,我使用的是 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 文件。

    【讨论】:

      【解决方案4】:

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

      exports.config = { 框架:'jasmine2', seleniumAddress: 'http://localhost:4444/wd/hub', /多重能力:[ { “浏览器名称”:“铬”, 'shardTestFiles':是的, “最大实例”:2, 铬选项:{ args: ['chrome.switches', '--disable-extensions'] } }, { “浏览器名称”:“火狐” } ],/ 能力: { “浏览器名称”:“铬”, 'shardTestFiles':是的, “最大实例”:2, 铬选项:{ args: ['chrome.switches', '--disable-extensions'] } }, 套房:{ 登录页面:'login.js', 添加产品:'addproduct.js' }, //规格:['addproduct.js'], 茉莉花节点选择:{ 完成:空, isVerbose:假, 包括StackTrace:真, 显示颜色:真, 默认超时间隔: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');
      }
      

      }

      【讨论】:

        【解决方案5】:

        我使用以下解决方案创建具有唯一时间戳的唯一文件夹。这会将 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,
                    })
                ); 
        

        `

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-22
          相关资源
          最近更新 更多