1
votes

I have 15 specs in my protractor suite. I want to run these scripts in parallel and, want to generate consolidated report out of this execution.

I was able to run the scripts in parallel by adding the tag 'shardTestFiles: true" in config file. But, I could not get consolidated report (getting the result of lastly executed spec only in the report).

I am looking for solution to generate consolidated report while executing the protractor scripts in parallel.

Note: Using jasmine reporter to generate report.

3
Possible duplicate of stackoverflow.com/questions/39499847/… ??Ajitesh

3 Answers

0
votes

You can use this reporter and provide an option for consolidating your test results. For example:

 var Jasmine2HtmlReporter = require('protractor-jasmine2-html-reporter');

    jasmine.getEnv().addReporter(
        new Jasmine2HtmlReporter({
            savePath: 'testReports/',
            screenshotsFolder: 'images',
            takeScreenshotsOnlyOnFailures: true,
            consolidateAll: true,
            consolidate: true,
            cleanDestination: false
        }));
0
votes

I followed the approach mentioned below to fulfill my need.

  1. I kept below code in onPrepare section of config file. This will generate a report for every spec.

    onPrepare() {
    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); // eslint-disable-line
              jasmine.getEnv().addReporter(
                new Jasmine2HtmlReporter({
                  savePath: 'e2e/Results',
                  screenshotsFolder: 'images',
                  takeScreenshotsOnlyOnFailures: true,
                  consolidate: true,
                  consolidateAll: true,
                  cleanDestination: false,
                  fileName: "my-report.html",
                  fileName: "regression-test-report.html",
                  fileNamePrefix: reportName,
                })
              );
              fulfill();
            })
          });
        });
    },
    

    And kept following code in afterLaunch section which will consolidate all the reports generated in onPrepare section:

    afterLaunch: function afterLaunch() {
        var fs = require('fs');
        var output = '';
        fs.readdirSync('e2e/Results/').forEach(function(file){
          if(!(fs.lstatSync('e2e/Results/' + file).isDirectory()))
            output = output + fs.readFileSync('e2e/Results/' + file);
        });
        fs.writeFileSync('e2e/Results/RegressionTestReport.html', output, 'utf8');
      }
    

Challenge faced after above configuration: I was able to consolidate the report through parallel execution by writing above configuration in config file. But, If I run the script second time, the report will consolidate that as well ( which I don't want to do ). Making the tag 'cleanDestination: true' deleted each spec once its execution ends. So, it did not work.

How I resolved this challenge?: I was running the script in jenkins using shell script. So, I wrote shell command 'rm -fr e2e/Results' to delete report folder before the execution of the script. So, the report will be deleted every time and a fresh consolidated report will be generated with latest execution.

0
votes

I tried the protractor-jasmine2-html-reporter combined with suggestions in the linked answer but did not like the output. I like the output generated by protractor-html-reporter-2 which works on the xml file produced by jasmine-reporters. But that does not have any option to work with reports generated by multiple instances of browsers. After failing to find an ideal solution, I ended up doing following in the protractor config js file:

// 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,
         }));
    },
    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',
        ...
    };

    new HTMLReport().from(reportDir + path.sep + 'consolidated.xml', testConfig);
}

We use Jenkins to run the tests and the report created by above displays well in Jenkins and also shows up accurately on the report displayed by Open Blue Ocean Jenkins plugin.

See Also: