import events from 'events'
import junit from 'junit-report-builder'
import path from 'path'
import fs from 'fs'

/**
 * Initialize a new `Junit` test reporter.
 *
 * @param {Runner} runner
 * @api public
 */
class JunitReporter extends events.EventEmitter {
    constructor (baseReporter, config) {
        super()

        this.baseReporter = baseReporter
        this.config = config
        this.errorLogCharacterLimitation = 10000

        const { epilogue } = this.baseReporter

        this.on('end', () => {
            for (let cid of Object.keys(this.baseReporter.stats.runner)) {
                const capabilities = this.baseReporter.stats.runner[cid]
                const xml = this.prepareXml(capabilities)
                this.write(capabilities, cid, xml)
            }
            epilogue.call(baseReporter)
        })
    }

    prepareXml (capabilities) {
        const builder = junit.newBuilder()
        const packageName = capabilities.sanitizedCapabilities

        for (let specId of Object.keys(capabilities.specs)) {
            const spec = capabilities.specs[specId]

            for (let suiteName of Object.keys(spec.suites)) {
                const suite = spec.suites[suiteName]
                const testSuite = builder.testSuite()
                    .name(suiteName.toLowerCase().split(/[^a-z0-9]+/).filter((item) => item && item.length).join('_'))
                    .timestamp(spec.suites[suiteName].start)
                    .time(spec.suites[suiteName].duration / 1000)
                    .property('specId', specId)
                    .property('suiteName', suiteName)
                    .property('capabilities', capabilities.sanitizedCapabilities)

                for (let testName of Object.keys(suite.tests)) {
                    const test = suite.tests[testName]
                    const testCase = testSuite.testCase()
                        .className(`${packageName}.${suiteName}`)
                        .name(testName)
                        .time(suite.tests[testName].duration / 1000)

                    if (test.state === 'pending') {
                        testCase.skipped()
                    }

                    if (test.error) {
                        if (test.error.message) testCase.error(`\n${test.error.message}\n`)
                        if (test.error.stack) testCase.standardError(`\n${test.error.stack}\n`)
                    }

                    const output = this.getStandardOutput(test)
                    if (output) testCase.standardOutput(`\n${output}\n`)
                }
            }
        }
        return builder.build()
    }

    getStandardOutput (test) {
        let standardOutput = []
        test.output.forEach((data) => {
            switch (data.type) {
            case 'command':
                standardOutput.push(`COMMAND: ${data.command.method.toUpperCase()} ${data.command.uri.href} - ${JSON.stringify(data.command.data)}`)
                break
            case 'result':
                standardOutput.push(`RESULT: ${JSON.stringify(data.result.body).slice(0, this.errorLogCharacterLimitation)}`)
                break
            case 'screenshot':
                standardOutput.push(`[[ATTACHMENT|${data.screenshot.path}]]`)
                break
            }
        })
        return standardOutput.length ? standardOutput.join('\n') : ''
    }

    write (capabilities, cid, xml) {
        const filename = 'WDIO.xunit.' + capabilities.sanitizedCapabilities + '.' + cid + '.xml'
        const options = this.config.reporterOptions

        if (options && typeof options.outputDir === 'string') {
            const filepath = path.join(path.resolve(options.outputDir), filename)
            fs.writeFileSync(filepath, xml)
        } else {
            console.log(filename)
            console.log(xml)
        }
    }
}

export default JunitReporter

@@ -383,57 +383,8 @@
 nfig
-%0A        this.errorLogCharacterLimitation = 10000
 %0A%0A  
@@ -2857,30 +2857,27 @@
 ef%7D - $%7B
-JSON.stringify
+this.format
 (data.co
@@ -2991,22 +2991,19 @@
 : $%7B
-JSON.stringify
+this.format
 (dat
@@ -3020,51 +3020,8 @@
 ody)
-.slice(0, this.errorLogCharacterLimitation)
 %7D%60)%0A
@@ -3747,16 +3747,102 @@
  %7D%0A    %7D
+%0A%0A    format (val) %7B%0A        return JSON.stringify(this.baseReporter.limit(val))%0A    %7D
 %0A%7D%0A%0Aexpo

Use BaseReporter helper to limit log length