diff --git a/src/escape_html.ts b/src/escape_html.ts
index 1f8955e..97959f3 100644
--- a/src/escape_html.ts
+++ b/src/escape_html.ts
@@ -6,6 +6,6 @@ const lookup: Record = {
">": ">"
}
-export default function escapeHTML(s: string): string {
- return s.replace(/[&"'<>]/g, c => lookup[c])
+export default function escapeHTML(s: any): string {
+ return String(s).replace(/[&"'<>]/g, c => lookup[c] || c)
}
diff --git a/src/test_parser.ts b/src/test_parser.ts
index 9798822..82ae1d2 100644
--- a/src/test_parser.ts
+++ b/src/test_parser.ts
@@ -199,6 +199,11 @@ export async function parseTap(data: string): Promise {
}
}
+export async function parseTapFile(filename: string): Promise {
+ const readfile = util.promisify(fs.readFile)
+ return await parseTap(await readfile(filename, "utf8"))
+}
+
async function parseJunitXml(xml: any): Promise {
let testsuites
@@ -292,16 +297,78 @@ export async function parseJunit(data: string): Promise {
return await parseJunitXml(xml)
}
-export async function parseTapFile(filename: string): Promise {
- const readfile = util.promisify(fs.readFile)
- return await parseTap(await readfile(filename, "utf8"))
-}
-
export async function parseJunitFile(filename: string): Promise {
const readfile = util.promisify(fs.readFile)
return await parseJunit(await readfile(filename, "utf8"))
}
+export async function parseTrx(xml: any): Promise {
+ if (xml.TestRun.$.xmlns != "http://microsoft.com/schemas/VisualStudio/TeamTest/2010"
+ || !Array.isArray(xml.TestRun.Results)) {
+ throw new Error("Not a valid .trx file.")
+ }
+
+ const suites: TestSuite[] = [ ]
+ const counts = {
+ passed: 0,
+ failed: 0,
+ skipped: 0
+ }
+
+ for (const result of xml.TestRun.Results) {
+ const cases: TestCase[] = [ ]
+
+ if (!Array.isArray(result.UnitTestResult)) {
+ continue
+ }
+
+ for (const item of result.UnitTestResult) {
+ let status = TestStatus.Pass
+
+ const id = item.$.testId
+ const name = item.$.testName
+ const duration = item.$.duration
+ const outcome = item.$.outcome
+
+ let message: string | undefined = undefined
+ let details: string = ""
+
+ const output = item?.Output?.[0]
+ details = "StdOut:" + output?.StdOut?.[0]
+
+ if (outcome == "Passed") {
+ counts.passed++
+ } else if (outcome == "Failed") {
+ status = TestStatus.Fail
+ counts.failed++
+
+ message = output?.ErrorInfo?.[0]?.Message
+ details = "StackTrace:" + output?.ErrorInfo?.[0]?.StackTrace + '\n' + details
+ } else {
+ status = TestStatus.Pass
+ counts.skipped++
+ }
+
+ cases.push({
+ status: status,
+ name: name,
+ message: message,
+ details: details,
+ duration: duration
+ })
+ }
+
+ suites.push({
+ cases: cases
+ })
+ }
+
+ return {
+ counts: counts,
+ suites: suites
+ }
+}
+
export async function parseFile(filename: string): Promise {
const readfile = util.promisify(fs.readFile)
const parser = util.promisify(xml2js.parseString)
diff --git a/test/resources/trx/example.trx b/test/resources/trx/example.trx
new file mode 100644
index 0000000..dc1ece9
--- /dev/null
+++ b/test/resources/trx/example.trx
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fail to add two numbers
+
+
+
+ FeatureTitle
+ Addition
+
+
+
+
+
+ Add two numbers
+
+
+
+ FeatureTitle
+ Addition
+
+
+
+
+
+ Adding several numbers
+
+
+
+ FeatureTitle
+ Addition
+
+
+ VariantName
+ 40
+
+
+ Parameter:Second Number
+ 50
+
+
+ Parameter:Result
+ 90
+
+
+ Parameter:First Number
+ 40
+
+
+
+
+
+ Adding several numbers
+
+
+
+ FeatureTitle
+ Addition
+
+
+ VariantName
+ 60
+
+
+ Parameter:Second Number
+ 70
+
+
+ Parameter:Result
+ 130
+
+
+ Parameter:First Number
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/trx.ts b/test/trx.ts
new file mode 100644
index 0000000..dfe75cd
--- /dev/null
+++ b/test/trx.ts
@@ -0,0 +1,103 @@
+import * as chai from "chai"
+import { expect } from "chai"
+
+import * as fs from "fs"
+import * as util from "util"
+
+import xml2js from "xml2js"
+
+import { TestStatus, parseTrx } from "../src/test_parser"
+
+const resourcePath = `${__dirname}/resources/trx`
+
+async function parseTrxFile(filename: string) {
+ const readfile = util.promisify(fs.readFile)
+ const parser = util.promisify(xml2js.parseString)
+ const xml: any = await parser(await readfile(filename, "utf8"))
+ return await parseTrx(xml)
+}
+
+describe("trx", async () => {
+ it("parses common", async () => {
+ const result = await parseTrxFile(`${resourcePath}/example.trx`)
+
+ expect(result.counts.passed).to.eql(3)
+ expect(result.counts.failed).to.eql(1)
+ expect(result.counts.skipped).to.eql(0)
+
+ expect(result.suites.length).to.eql(1)
+ expect(result.suites[0].cases.length).to.eql(4)
+ })
+
+ it("parses example", async () => {
+ const result = await parseTrxFile(`${resourcePath}/example.trx`)
+
+ expect(result.counts.passed).to.eql(3)
+ expect(result.counts.failed).to.eql(1)
+ expect(result.counts.skipped).to.eql(0)
+
+ expect(result.suites.length).to.eql(1)
+ expect(result.suites[0].cases.length).to.eql(4)
+
+ expect(result.suites[0].cases[0].status).to.eql(TestStatus.Pass)
+ expect(result.suites[0].cases[0].name).to.eql("AddingSeveralNumbers_40")
+ expect(result.suites[0].cases[0].details).to.eql(`StdOut:
+ Given I have entered 40 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(40) (0.0s)
+ And I have entered 50 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(50) (0.0s)
+ When I press add
+ -> done: Steps.WhenIPressAdd() (0.0s)
+ Then the result should be 90 on the screen
+ -> done: Steps.ThenTheResultShouldBePass(90) (0.0s)
+ `)
+ expect(result.suites[0].cases[1].status).to.eql(TestStatus.Pass)
+ expect(result.suites[0].cases[1].name).to.eql("AddingSeveralNumbers_60")
+ expect(result.suites[0].cases[1].details).to.eql(`StdOut:
+ Given I have entered 60 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(60) (0.0s)
+ And I have entered 70 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(70) (0.0s)
+ When I press add
+ -> done: Steps.WhenIPressAdd() (0.0s)
+ Then the result should be 130 on the screen
+ -> done: Steps.ThenTheResultShouldBePass(130) (0.0s)
+ `)
+ expect(result.suites[0].cases[2].status).to.eql(TestStatus.Pass)
+ expect(result.suites[0].cases[2].name).to.eql("AddTwoNumbers")
+ expect(result.suites[0].cases[2].details).to.eql(`StdOut:
+ Given I have entered 50 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(50) (0.0s)
+ And I have entered 70 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(70) (0.0s)
+ When I press add
+ -> done: Steps.WhenIPressAdd() (0.0s)
+ Then the result should be 120 on the screen
+ -> done: Steps.ThenTheResultShouldBePass(120) (0.0s)
+ `)
+ expect(result.suites[0].cases[3].status).to.eql(TestStatus.Fail)
+ expect(result.suites[0].cases[3].name).to.eql("FailToAddTwoNumbers")
+ expect(result.suites[0].cases[3].details).to.eql(`StackTrace:
+ at Pickles.TestHarness.MSTest.Steps.ThenTheResultShouldBePass(Int32 result) in C:\\dev\\pickles-results-harness\\Pickles.TestHarness\\Pickles.TestHarness.MSTest\\Steps.cs:line 28
+ at lambda_method(Closure , IContextManager , Int32 )
+ at TechTalk.SpecFlow.Bindings.MethodBinding.InvokeAction(IContextManager contextManager, Object[] arguments, ITestTracer testTracer, TimeSpan& duration)
+ at TechTalk.SpecFlow.Bindings.StepDefinitionBinding.Invoke(IContextManager contextManager, ITestTracer testTracer, Object[] arguments, TimeSpan& duration)
+ at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStepMatch(BindingMatch match, Object[] arguments)
+ at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStep(StepArgs stepArgs)
+ at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.OnAfterLastStep()
+ at TechTalk.SpecFlow.TestRunner.CollectScenarioErrors()
+ at Pickles.TestHarness.MSTest.AdditionFeature.ScenarioCleanup() in C:\\dev\\pickles-results-harness\\Pickles.TestHarness\\Pickles.TestHarness.MSTest\\Addition.feature.cs:line 0
+ at Pickles.TestHarness.MSTest.AdditionFeature.FailToAddTwoNumbers() in c:\\dev\\pickles-results-harness\\Pickles.TestHarness\\Pickles.TestHarness.MSTest\\Addition.feature:line 18
+
+StdOut:
+ Given I have entered 50 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(50) (0.0s)
+ And I have entered -1 into the calculator
+ -> done: Steps.GivenIHaveEnteredSomethingIntoTheCalculator(-1) (0.0s)
+ When I press add
+ -> done: Steps.WhenIPressAdd() (0.0s)
+ Then the result should be -50 on the screen
+ -> error: Assert.NotEqual() Failure
+ `)
+ })
+})