Browse Source

Test Custom junjt plugin

sebavan 6 năm trước cách đây
mục cha
commit
56aecb6925
3 tập tin đã thay đổi với 276 bổ sung2 xóa
  1. 265 0
      Tools/Gulp/helpers/gulp-karmaJunitPlugin.js
  2. 2 2
      package.json
  3. 9 0
      tests/unit/karma.conf.js

+ 265 - 0
Tools/Gulp/helpers/gulp-karmaJunitPlugin.js

@@ -0,0 +1,265 @@
+var os = require('os')
+var path = require('path')
+var fs = require('fs')
+var builder = require('xmlbuilder')
+
+/* XML schemas supported by the reporter: 'xmlVersion' in karma.conf.js,
+   'XMLconfigValue' as variable here.
+   0 = "old", original XML format. For example, SonarQube versions prior to 6.2
+   1 = first amended version. Compatible with SonarQube starting from 6.2
+*/
+
+// concatenate test suite(s) and test description by default
+function defaultNameFormatter (browser, result) {
+  return result.suite.join(' ') + ' ' + result.description
+}
+
+var JUnitReporter = function (baseReporterDecorator, config, logger, helper, formatError) {
+  var log = logger.create('reporter.junit')
+  var reporterConfig = config.junitReporter || {}
+  // All reporterConfig.something are for reading flags from the Karma config file
+  var pkgName = reporterConfig.suite || ''
+  var outputDir = reporterConfig.outputDir
+  var outputFile = reporterConfig.outputFile
+  var useBrowserName = reporterConfig.useBrowserName
+  var nameFormatter = reporterConfig.nameFormatter || defaultNameFormatter
+  var classNameFormatter = reporterConfig.classNameFormatter
+  var properties = reporterConfig.properties
+  // The below two variables have to do with adding support for new SonarQube XML format
+  var XMLconfigValue = reporterConfig.xmlVersion
+  var NEWXML
+  // We need one global variable for the tag <file> to be visible to functions
+  var exposee
+  var suites = []
+  var pendingFileWritings = 0
+  var fileWritingFinished = function () {}
+  var allMessages = []
+
+  // The NEWXML is just sugar, a flag. Remove it when there are more than 2
+  // supported XML output formats.
+  if (!XMLconfigValue) {
+    XMLconfigValue = 0
+    NEWXML = false
+  } else {
+    // Slack behavior: "If defined, assume to be 1" since we have only two formats now
+    XMLconfigValue = 1
+    NEWXML = true
+  }
+
+  if (outputDir == null) {
+    outputDir = '.'
+  }
+
+  outputDir = helper.normalizeWinPath(path.resolve(config.basePath, outputDir)) + path.sep
+
+  if (typeof useBrowserName === 'undefined') {
+    useBrowserName = true
+  }
+
+  baseReporterDecorator(this)
+
+  this.adapters = [
+    function (msg) {
+      allMessages.push(msg)
+    }
+  ]
+
+  // Creates the outermost XML element: <unitTest>
+  var initializeXmlForBrowser = function (browser) {
+    var timestamp = (new Date()).toISOString().substr(0, 19)
+    var suite
+    if (NEWXML) {
+      suite = suites[browser.id] = builder.create('unitTest')
+      suite.att('version', '1')
+      exposee = suite.ele('file', {'path': 'fixedString'})
+    } else {
+      suite = suites[browser.id] = builder.create('testsuite')
+      suite.att('name', pkgName)
+      .att('package', pkgName)
+      .att('timestamp', timestamp)
+      .att('id', 'MYTESTMYTEST')
+      .att('hostname', os.hostname())
+      var propertiesElement = suite.ele('properties')
+      propertiesElement.ele('property', {name: 'browser.fullName', value: browser.fullName})
+
+      // add additional properties passed in through the config
+      for (var property in properties) {
+        if (properties.hasOwnProperty(property)) {
+          propertiesElement.ele('property', {name: property, value: properties[property]})
+        }
+      }
+    }
+  }
+
+  // This function takes care of writing the XML into a file
+  var writeXmlForBrowser = function (browser) {
+    // Define the file name using rules
+    var safeBrowserName = browser.name.replace(/ /g, '_')
+    var newOutputFile
+    if (outputFile && path.isAbsolute(outputFile)) {
+      newOutputFile = outputFile
+    } else if (outputFile != null) {
+      var dir = useBrowserName ? path.join(outputDir, safeBrowserName)
+                               : outputDir
+      newOutputFile = path.join(dir, outputFile)
+    } else if (useBrowserName) {
+      newOutputFile = path.join(outputDir, 'TESTS-' + safeBrowserName + '.xml')
+    } else {
+      newOutputFile = path.join(outputDir, 'TESTS.xml')
+    }
+
+    var xmlToOutput = suites[browser.id]
+
+    if (!xmlToOutput) {
+      return // don't die if browser didn't start
+    }
+
+    pendingFileWritings++
+    helper.mkdirIfNotExists(path.dirname(newOutputFile), function () {
+      fs.writeFile(newOutputFile, xmlToOutput.end({pretty: true}), function (err) {
+        if (err) {
+          log.warn('Cannot write JUnit xml\n\t' + err.message)
+        } else {
+          log.debug('JUnit results written to "%s".', newOutputFile)
+        }
+
+        if (!--pendingFileWritings) {
+          fileWritingFinished()
+        }
+      })
+    })
+  }
+
+  // Return a 'safe' name for test. This will be the name="..." content in XML.
+  var getClassName = function (browser, result) {
+    var name = ''
+    // configuration tells whether to use browser name at all
+    if (useBrowserName) {
+      name += browser.name
+        .replace(/ /g, '_')
+        .replace(/\./g, '_') + '.'
+    }
+    if (pkgName) {
+      name += '.'
+    }
+    if (result.suite && result.suite.length > 0) {
+      name += result.suite.join(' ')
+    }
+    return name
+  }
+
+  // "run_start" - a test run is beginning for all browsers
+  this.onRunStart = function (browsers) {
+    // TODO(vojta): remove once we don't care about Karma 0.10
+    browsers.forEach(initializeXmlForBrowser)
+  }
+
+  // "browser_start" - a test run is beginning in _this_ browser
+  this.onBrowserStart = function (browser) {
+    initializeXmlForBrowser(browser)
+  }
+
+  // "browser_complete" - a test run has completed in _this_ browser
+  // writes the XML to file and releases memory
+  this.onBrowserComplete = function (browser) {
+    var suite = suites[browser.id]
+    var result = browser.lastResult
+    if (!suite || !result) {
+      return // don't die if browser didn't start
+    }
+
+    if (!NEWXML) {
+      suite.att('tests', result.total ? result.total : 0)
+      suite.att('errors', result.disconnected || result.error ? 1 : 0)
+      suite.att('failures', result.failed ? result.failed : 0)
+      suite.att('time', (result.netTime || 0) / 1000)
+      suite.ele('system-out').dat(allMessages.join() + '\n')
+      suite.ele('system-err')
+    }
+
+    writeXmlForBrowser(browser)
+
+    // Release memory held by the test suite.
+    suites[browser.id] = null
+  }
+
+  // "run_complete" - a test run has completed on all browsers
+  this.onRunComplete = function () {
+    allMessages.length = 0
+  }
+
+  // --------------------------------------------
+  // | Producing XML for individual testCase    |
+  // --------------------------------------------
+  this.specSuccess = this.specSkipped = this.specFailure = function (browser, result) {
+    var testsuite = suites[browser.id]
+    var validMilliTime
+    var spec
+
+    if (!testsuite) {
+      return
+    }
+
+    // New in the XSD schema: only name and duration. classname is obsoleted
+    if (NEWXML) {
+      if (!result.time || result.time === 0) {
+        validMilliTime = 1
+      } else {
+        validMilliTime = result.time
+      }
+    }
+
+    // create the tag for a new test case
+    /*
+    if (NEWXML) {
+      spec = testsuite.ele('testCase', {
+      name: nameFormatter(browser, result),
+      duration: validMilliTime })
+    }
+    */
+
+    if (NEWXML) {
+      spec = exposee.ele('testCase', {
+        name: nameFormatter(browser, result),
+        duration: validMilliTime })
+    } else {
+      // old XML format. Code as-was
+      spec = testsuite.ele('testcase', {
+        name: nameFormatter(browser, result),
+        time: ((result.time || 0) / 1000),
+        classname: (typeof classNameFormatter === 'function' ? classNameFormatter : getClassName)(browser, result)
+      })
+    }
+
+    if (result.skipped) {
+      spec.ele('skipped')
+    }
+
+    if (!result.success) {
+      result.log.forEach(function (err) {
+        if (!NEWXML) {
+          spec.ele('failure', {type: ''}, formatError(err))
+        } else {
+        // In new XML format, an obligatory 'message' attribute in failure
+          spec.ele('failure', {message: formatError(err)})
+        }
+      })
+    }
+  }
+
+  // wait for writing all the xml files, before exiting
+  this.onExit = function (done) {
+    if (pendingFileWritings) {
+      fileWritingFinished = done
+    } else {
+      done()
+    }
+  }
+}
+
+JUnitReporter.$inject = ['baseReporterDecorator', 'config', 'logger', 'helper', 'formatError']
+
+// PUBLISH DI MODULE
+module.exports = {
+  'reporter:junit': ['type', JUnitReporter]
+}

+ 2 - 2
package.json

@@ -75,7 +75,6 @@
         "karma-chai": "^0.1.0",
         "karma-chrome-launcher": "^2.2.0",
         "karma-firefox-launcher": "^1.1.0",
-        "karma-junit-reporter": "^1.2.0",
         "karma-mocha": "^1.3.0",
         "karma-sinon": "^1.0.5",
         "merge2": "~1.2.2",
@@ -104,6 +103,7 @@
         "webpack-cli": "^3.1.2",
         "webpack-dev-server": "^3.1.14",
         "webpack-stream": "5.0.0",
-        "xhr2": "^0.1.4"
+        "xhr2": "^0.1.4",
+        "xmlbuilder": "8.2.2"
     }
 }

+ 9 - 0
tests/unit/karma.conf.js

@@ -50,6 +50,15 @@ module.exports = function (config) {
 
         reporters: ['progress', 'junit'],
 
+        plugins: [
+            // Karma will require() these plugins
+            'karma-mocha',
+            'karma-chai',
+            'karma-sinon',
+            'karma-chrome-launcher',
+            require('../../Tools/Gulp/helpers/gulp-karmaJunitPlugin')
+        ],
+
         junitReporter: {
             outputDir: '.temp/testResults', // results will be saved as $outputDir/$browserName.xml
             outputFile: 'UnitTests.xml', // if included, results will be saved as $outputDir/$browserName/$outputFile