mirror of
https://github.com/dorny/test-reporter.git
synced 2026-02-01 02:45:22 -08:00
Create tester-junit reporter for Nette Tester tool
This commit is contained in:
15
README.md
15
README.md
@@ -20,7 +20,7 @@ This [Github Action](https://github.com/features/actions) displays test results
|
|||||||
- Java / [JUnit](https://junit.org/)
|
- Java / [JUnit](https://junit.org/)
|
||||||
- JavaScript / [JEST](https://jestjs.io/) / [Mocha](https://mochajs.org/)
|
- JavaScript / [JEST](https://jestjs.io/) / [Mocha](https://mochajs.org/)
|
||||||
- Python / [pytest](https://docs.pytest.org/en/stable/) / [unittest](https://docs.python.org/3/library/unittest.html)
|
- Python / [pytest](https://docs.pytest.org/en/stable/) / [unittest](https://docs.python.org/3/library/unittest.html)
|
||||||
- PHP / [PHPUnit](https://phpunit.de/)
|
- PHP / [PHPUnit](https://phpunit.de/) / [Nette Tester](https://tester.nette.org/)
|
||||||
- Ruby / [RSpec](https://rspec.info/)
|
- Ruby / [RSpec](https://rspec.info/)
|
||||||
- Swift / xUnit
|
- Swift / xUnit
|
||||||
|
|
||||||
@@ -324,6 +324,19 @@ Some heuristic was necessary to figure out the mapping between the line in the s
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>tester-junit</summary>
|
||||||
|
|
||||||
|
[Nette Tester](https://tester.nette.org/) can generate JUnit XML via CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tester -s -o junit tests/ > reports/tester-junit.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Nette Tester's JUnit output doesn't include test suite names. The parser will use the report file name as the suite name and automatically group tests by directory structure.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>jest-junit</summary>
|
<summary>jest-junit</summary>
|
||||||
|
|
||||||
|
|||||||
20
__tests__/__outputs__/nette-tester-bootstrap-test-results.md
Normal file
20
__tests__/__outputs__/nette-tester-bootstrap-test-results.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|

|
||||||
|
<details><summary>Expand for details</summary>
|
||||||
|
|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[fixtures/nette-tester/BootstrapFormRenderer-report.xml](#user-content-r0)|4 ✅|||300ms|
|
||||||
|
## ✅ <a id="user-content-r0" href="#user-content-r0">fixtures/nette-tester/BootstrapFormRenderer-report.xml</a>
|
||||||
|
**4** tests were completed in **300ms** with **4** passed, **0** failed and **0** skipped.
|
||||||
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[BootstrapFormRenderer-report.xml](#user-content-r0s0)|4 ✅|||300ms|
|
||||||
|
### ✅ <a id="user-content-r0s0" href="#user-content-r0s0">BootstrapFormRenderer-report.xml</a>
|
||||||
|
```
|
||||||
|
KdybyTests/BootstrapFormRenderer
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingBasics
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingIndividual
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingComponents
|
||||||
|
✅ BootstrapRendererTest.phpt::testMultipleFormsInTemplate
|
||||||
|
```
|
||||||
|
</details>
|
||||||
87
__tests__/__outputs__/nette-tester-v1.7-test-results.md
Normal file
87
__tests__/__outputs__/nette-tester-v1.7-test-results.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[fixtures/nette-tester/tester-v1.7-report.xml](#user-content-r0)|61 ✅|1 ❌|3 ⚪|2s|
|
||||||
|
## ❌ <a id="user-content-r0" href="#user-content-r0">fixtures/nette-tester/tester-v1.7-report.xml</a>
|
||||||
|
**65** tests were completed in **2s** with **61** passed, **1** failed and **3** skipped.
|
||||||
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[tester-v1.7-report.xml](#user-content-r0s0)|61 ✅|1 ❌|3 ⚪|2s|
|
||||||
|
### ❌ <a id="user-content-r0s0" href="#user-content-r0s0">tester-v1.7-report.xml</a>
|
||||||
|
```
|
||||||
|
tests/Framework
|
||||||
|
⚪ Dumper.toPhp.php7.phpt
|
||||||
|
✅ Assert.contains.phpt
|
||||||
|
✅ Assert.count.phpt
|
||||||
|
✅ Assert.equal.phpt
|
||||||
|
✅ Assert.equal.recursive.phpt::testSimple
|
||||||
|
✅ Assert.equal.recursive.phpt::testMultiple
|
||||||
|
✅ Assert.equal.recursive.phpt::testDeep
|
||||||
|
✅ Assert.equal.recursive.phpt::testCross
|
||||||
|
✅ Assert.equal.recursive.phpt::testThirdParty
|
||||||
|
✅ Assert.error.phpt
|
||||||
|
✅ Assert.exception.phpt
|
||||||
|
✅ Assert.false.phpt
|
||||||
|
✅ Assert.match.phpt
|
||||||
|
✅ Assert.match.regexp.phpt
|
||||||
|
✅ Assert.nan.phpt
|
||||||
|
✅ Assert.noError.phpt
|
||||||
|
✅ Assert.same.phpt
|
||||||
|
✅ Assert.null.phpt
|
||||||
|
✅ Assert.true.phpt
|
||||||
|
✅ Assert.truthy.phpt
|
||||||
|
✅ DataProvider.load.phpt
|
||||||
|
✅ Assert.type.phpt
|
||||||
|
✅ DataProvider.parseAnnotation.phpt
|
||||||
|
✅ DataProvider.testQuery.phpt
|
||||||
|
✅ DomQuery.css2Xpath.phpt
|
||||||
|
✅ DomQuery.fromHtml.phpt
|
||||||
|
✅ DomQuery.fromXml.phpt
|
||||||
|
✅ Dumper.dumpException.phpt
|
||||||
|
✅ Dumper.color.phpt
|
||||||
|
✅ Dumper.toLine.phpt
|
||||||
|
✅ Dumper.toPhp.recursion.phpt
|
||||||
|
✅ Dumper.toPhp.phpt
|
||||||
|
✅ FileMock.phpt
|
||||||
|
✅ Helpers.escapeArg.phpt
|
||||||
|
✅ Helpers.parseDocComment.phpt
|
||||||
|
✅ TestCase.annotationThrows.phpt
|
||||||
|
✅ TestCase.annotationThrows.setUp.tearDown.phpt
|
||||||
|
✅ TestCase.annotationThrows.syntax.phpt
|
||||||
|
✅ TestCase.basic.phpt
|
||||||
|
✅ TestCase.dataProvider.generator.phpt
|
||||||
|
✅ TestCase.dataProvider.phpt
|
||||||
|
✅ TestCase.invalidMethods.phpt
|
||||||
|
✅ TestCase.invalidProvider.phpt
|
||||||
|
✅ TestCase.order.error.phpt
|
||||||
|
✅ TestCase.order.errorMuted.phpt
|
||||||
|
✅ TestCase.order.phpt
|
||||||
|
✅ Prevent loop in error handling. The #268 regression. (TestCase.ownErrorHandler.phpt)
|
||||||
|
tests/CodeCoverage
|
||||||
|
⚪ Collector.start.phpt
|
||||||
|
✅ PhpParser.parse.lines.phpt
|
||||||
|
✅ PhpParser.parse.methods.phpt
|
||||||
|
✅ CloverXMLGenerator.phpt
|
||||||
|
✅ PhpParser.parse.edge.phpt
|
||||||
|
✅ PhpParser.parse.lines-of-code.phpt
|
||||||
|
✅ PhpParser.parse.namespaces.phpt
|
||||||
|
tests/Runner
|
||||||
|
✅ CommandLine.phpt
|
||||||
|
⚪ HhvmPhpInterpreter.phpt
|
||||||
|
✅ Runner.find-tests.phpt
|
||||||
|
✅ Job.phpt
|
||||||
|
✅ ZendPhpExecutable.phpt
|
||||||
|
✅ Runner.multiple.phpt
|
||||||
|
✅ Runner.edge.phpt
|
||||||
|
✅ Runner.stop-on-fail.phpt
|
||||||
|
❌ Runner.multiple-fails.phpt
|
||||||
|
Failed: '... in /Users/izso/Developer/nette/tester/tests/Runner/multiple-fails/...' should match
|
||||||
|
... '..., unexpected end of file in %a%testcase-syntax-error.phptx on line ...'
|
||||||
|
|
||||||
|
diff '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.expected' '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.actual'
|
||||||
|
|
||||||
|
in tests/Runner/Runner.multiple-fails.phpt(78) Tester\Assert::match()
|
||||||
|
✅ Runner.annotations.phpt
|
||||||
|
tests/RunnerOutput
|
||||||
|
✅ JUnitPrinter.phpt
|
||||||
|
```
|
||||||
20
__tests__/__outputs__/tester-bootstrap-test-results.md
Normal file
20
__tests__/__outputs__/tester-bootstrap-test-results.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|

|
||||||
|
<details><summary>Expand for details</summary>
|
||||||
|
|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[fixtures/nette-tester/BootstrapFormRenderer-report.xml](#user-content-r0)|4 ✅|||300ms|
|
||||||
|
## ✅ <a id="user-content-r0" href="#user-content-r0">fixtures/nette-tester/BootstrapFormRenderer-report.xml</a>
|
||||||
|
**4** tests were completed in **300ms** with **4** passed, **0** failed and **0** skipped.
|
||||||
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[BootstrapFormRenderer-report.xml](#user-content-r0s0)|4 ✅|||300ms|
|
||||||
|
### ✅ <a id="user-content-r0s0" href="#user-content-r0s0">BootstrapFormRenderer-report.xml</a>
|
||||||
|
```
|
||||||
|
KdybyTests/BootstrapFormRenderer
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingBasics
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingIndividual
|
||||||
|
✅ BootstrapRendererTest.phpt::testRenderingComponents
|
||||||
|
✅ BootstrapRendererTest.phpt::testMultipleFormsInTemplate
|
||||||
|
```
|
||||||
|
</details>
|
||||||
87
__tests__/__outputs__/tester-v1.7-test-results.md
Normal file
87
__tests__/__outputs__/tester-v1.7-test-results.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|

|
||||||
|
|Report|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[fixtures/nette-tester/tester-v1.7-report.xml](#user-content-r0)|61 ✅|1 ❌|3 ⚪|2s|
|
||||||
|
## ❌ <a id="user-content-r0" href="#user-content-r0">fixtures/nette-tester/tester-v1.7-report.xml</a>
|
||||||
|
**65** tests were completed in **2s** with **61** passed, **1** failed and **3** skipped.
|
||||||
|
|Test suite|Passed|Failed|Skipped|Time|
|
||||||
|
|:---|---:|---:|---:|---:|
|
||||||
|
|[tester-v1.7-report.xml](#user-content-r0s0)|61 ✅|1 ❌|3 ⚪|2s|
|
||||||
|
### ❌ <a id="user-content-r0s0" href="#user-content-r0s0">tester-v1.7-report.xml</a>
|
||||||
|
```
|
||||||
|
tests/Framework
|
||||||
|
⚪ Dumper.toPhp.php7.phpt
|
||||||
|
✅ Assert.contains.phpt
|
||||||
|
✅ Assert.count.phpt
|
||||||
|
✅ Assert.equal.phpt
|
||||||
|
✅ Assert.equal.recursive.phpt::testSimple
|
||||||
|
✅ Assert.equal.recursive.phpt::testMultiple
|
||||||
|
✅ Assert.equal.recursive.phpt::testDeep
|
||||||
|
✅ Assert.equal.recursive.phpt::testCross
|
||||||
|
✅ Assert.equal.recursive.phpt::testThirdParty
|
||||||
|
✅ Assert.error.phpt
|
||||||
|
✅ Assert.exception.phpt
|
||||||
|
✅ Assert.false.phpt
|
||||||
|
✅ Assert.match.phpt
|
||||||
|
✅ Assert.match.regexp.phpt
|
||||||
|
✅ Assert.nan.phpt
|
||||||
|
✅ Assert.noError.phpt
|
||||||
|
✅ Assert.same.phpt
|
||||||
|
✅ Assert.null.phpt
|
||||||
|
✅ Assert.true.phpt
|
||||||
|
✅ Assert.truthy.phpt
|
||||||
|
✅ DataProvider.load.phpt
|
||||||
|
✅ Assert.type.phpt
|
||||||
|
✅ DataProvider.parseAnnotation.phpt
|
||||||
|
✅ DataProvider.testQuery.phpt
|
||||||
|
✅ DomQuery.css2Xpath.phpt
|
||||||
|
✅ DomQuery.fromHtml.phpt
|
||||||
|
✅ DomQuery.fromXml.phpt
|
||||||
|
✅ Dumper.dumpException.phpt
|
||||||
|
✅ Dumper.color.phpt
|
||||||
|
✅ Dumper.toLine.phpt
|
||||||
|
✅ Dumper.toPhp.recursion.phpt
|
||||||
|
✅ Dumper.toPhp.phpt
|
||||||
|
✅ FileMock.phpt
|
||||||
|
✅ Helpers.escapeArg.phpt
|
||||||
|
✅ Helpers.parseDocComment.phpt
|
||||||
|
✅ TestCase.annotationThrows.phpt
|
||||||
|
✅ TestCase.annotationThrows.setUp.tearDown.phpt
|
||||||
|
✅ TestCase.annotationThrows.syntax.phpt
|
||||||
|
✅ TestCase.basic.phpt
|
||||||
|
✅ TestCase.dataProvider.generator.phpt
|
||||||
|
✅ TestCase.dataProvider.phpt
|
||||||
|
✅ TestCase.invalidMethods.phpt
|
||||||
|
✅ TestCase.invalidProvider.phpt
|
||||||
|
✅ TestCase.order.error.phpt
|
||||||
|
✅ TestCase.order.errorMuted.phpt
|
||||||
|
✅ TestCase.order.phpt
|
||||||
|
✅ Prevent loop in error handling. The #268 regression. (TestCase.ownErrorHandler.phpt)
|
||||||
|
tests/CodeCoverage
|
||||||
|
⚪ Collector.start.phpt
|
||||||
|
✅ PhpParser.parse.lines.phpt
|
||||||
|
✅ PhpParser.parse.methods.phpt
|
||||||
|
✅ CloverXMLGenerator.phpt
|
||||||
|
✅ PhpParser.parse.edge.phpt
|
||||||
|
✅ PhpParser.parse.lines-of-code.phpt
|
||||||
|
✅ PhpParser.parse.namespaces.phpt
|
||||||
|
tests/Runner
|
||||||
|
✅ CommandLine.phpt
|
||||||
|
⚪ HhvmPhpInterpreter.phpt
|
||||||
|
✅ Runner.find-tests.phpt
|
||||||
|
✅ Job.phpt
|
||||||
|
✅ ZendPhpExecutable.phpt
|
||||||
|
✅ Runner.multiple.phpt
|
||||||
|
✅ Runner.edge.phpt
|
||||||
|
✅ Runner.stop-on-fail.phpt
|
||||||
|
❌ Runner.multiple-fails.phpt
|
||||||
|
Failed: '... in /Users/izso/Developer/nette/tester/tests/Runner/multiple-fails/...' should match
|
||||||
|
... '..., unexpected end of file in %a%testcase-syntax-error.phptx on line ...'
|
||||||
|
|
||||||
|
diff '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.expected' '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.actual'
|
||||||
|
|
||||||
|
in tests/Runner/Runner.multiple-fails.phpt(78) Tester\Assert::match()
|
||||||
|
✅ Runner.annotations.phpt
|
||||||
|
tests/RunnerOutput
|
||||||
|
✅ JUnitPrinter.phpt
|
||||||
|
```
|
||||||
485
__tests__/__snapshots__/tester-junit.test.ts.snap
Normal file
485
__tests__/__snapshots__/tester-junit.test.ts.snap
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||||
|
|
||||||
|
exports[`tester-junit tests parses complex test names from BootstrapFormRenderer-report.xml 1`] = `
|
||||||
|
TestRunResult {
|
||||||
|
"path": "fixtures/nette-tester/BootstrapFormRenderer-report.xml",
|
||||||
|
"suites": [
|
||||||
|
TestSuiteResult {
|
||||||
|
"groups": [
|
||||||
|
TestGroupResult {
|
||||||
|
"name": "KdybyTests/BootstrapFormRenderer",
|
||||||
|
"tests": [
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "BootstrapRendererTest.phpt::testRenderingBasics",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "BootstrapRendererTest.phpt::testRenderingIndividual",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "BootstrapRendererTest.phpt::testRenderingComponents",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "BootstrapRendererTest.phpt::testMultipleFormsInTemplate",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"name": "BootstrapFormRenderer-report.xml",
|
||||||
|
"totalTime": 300,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"totalTime": undefined,
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`tester-junit tests report from tester-v1.7-report.xml matches snapshot 1`] = `
|
||||||
|
TestRunResult {
|
||||||
|
"path": "fixtures/nette-tester/tester-v1.7-report.xml",
|
||||||
|
"suites": [
|
||||||
|
TestSuiteResult {
|
||||||
|
"groups": [
|
||||||
|
TestGroupResult {
|
||||||
|
"name": "tests/Framework",
|
||||||
|
"tests": [
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.toPhp.php7.phpt",
|
||||||
|
"result": "skipped",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.contains.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.count.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.recursive.phpt::testSimple",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.recursive.phpt::testMultiple",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.recursive.phpt::testDeep",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.recursive.phpt::testCross",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.equal.recursive.phpt::testThirdParty",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.error.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.exception.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.false.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.match.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.match.regexp.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.nan.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.noError.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.same.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.null.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.true.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.truthy.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DataProvider.load.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Assert.type.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DataProvider.parseAnnotation.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DataProvider.testQuery.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DomQuery.css2Xpath.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DomQuery.fromHtml.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "DomQuery.fromXml.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.dumpException.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.color.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.toLine.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.toPhp.recursion.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Dumper.toPhp.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "FileMock.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Helpers.escapeArg.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Helpers.parseDocComment.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.annotationThrows.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.annotationThrows.setUp.tearDown.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.annotationThrows.syntax.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.basic.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.dataProvider.generator.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.dataProvider.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.invalidMethods.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.invalidProvider.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.order.error.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.order.errorMuted.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "TestCase.order.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Prevent loop in error handling. The #268 regression. (TestCase.ownErrorHandler.phpt)",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
TestGroupResult {
|
||||||
|
"name": "tests/CodeCoverage",
|
||||||
|
"tests": [
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Collector.start.phpt",
|
||||||
|
"result": "skipped",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "PhpParser.parse.lines.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "PhpParser.parse.methods.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "CloverXMLGenerator.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "PhpParser.parse.edge.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "PhpParser.parse.lines-of-code.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "PhpParser.parse.namespaces.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
TestGroupResult {
|
||||||
|
"name": "tests/Runner",
|
||||||
|
"tests": [
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "CommandLine.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "HhvmPhpInterpreter.phpt",
|
||||||
|
"result": "skipped",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Runner.find-tests.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Job.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "ZendPhpExecutable.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Runner.multiple.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Runner.edge.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Runner.stop-on-fail.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": {
|
||||||
|
"details": "Failed: '... in /Users/izso/Developer/nette/tester/tests/Runner/multiple-fails/...' should match
|
||||||
|
... '..., unexpected end of file in %a%testcase-syntax-error.phptx on line ...'
|
||||||
|
|
||||||
|
diff '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.expected' '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.actual'
|
||||||
|
|
||||||
|
in tests/Runner/Runner.multiple-fails.phpt(78) Tester\\Assert::match()",
|
||||||
|
"line": undefined,
|
||||||
|
"message": "Failed: '... in /Users/izso/Developer/nette/tester/tests/Runner/multiple-fails/...' should match
|
||||||
|
... '..., unexpected end of file in %a%testcase-syntax-error.phptx on line ...'
|
||||||
|
|
||||||
|
diff '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.expected' '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.actual'
|
||||||
|
|
||||||
|
in tests/Runner/Runner.multiple-fails.phpt(78) Tester\\Assert::match()",
|
||||||
|
"path": undefined,
|
||||||
|
},
|
||||||
|
"name": "Runner.multiple-fails.phpt",
|
||||||
|
"result": "failed",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "Runner.annotations.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
TestGroupResult {
|
||||||
|
"name": "tests/RunnerOutput",
|
||||||
|
"tests": [
|
||||||
|
TestCaseResult {
|
||||||
|
"error": undefined,
|
||||||
|
"name": "JUnitPrinter.phpt",
|
||||||
|
"result": "success",
|
||||||
|
"time": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"name": "tester-v1.7-report.xml",
|
||||||
|
"totalTime": 2100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"totalTime": undefined,
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite errors="0" skipped="0" tests="4" time="0.3" timestamp="2026-01-01T16:36:10">
|
||||||
|
<testcase classname="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingBasics]" name="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingBasics]"/>
|
||||||
|
<testcase classname="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingIndividual]" name="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingIndividual]"/>
|
||||||
|
<testcase classname="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingComponents]" name="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingComponents]"/>
|
||||||
|
<testcase classname="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testMultipleFormsInTemplate]" name="Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testMultipleFormsInTemplate]"/>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
83
__tests__/fixtures/nette-tester/tester-v1.7-report.xml
Normal file
83
__tests__/fixtures/nette-tester/tester-v1.7-report.xml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite errors="1" skipped="3" tests="65" time="2.1" timestamp="2026-01-01T16:50:52">
|
||||||
|
<testcase classname="tests/Framework/Dumper.toPhp.php7.phpt" name="tests/Framework/Dumper.toPhp.php7.phpt">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="tests/CodeCoverage/Collector.start.phpt" name="tests/CodeCoverage/Collector.start.phpt">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="tests/CodeCoverage/PhpParser.parse.lines.phpt" name="tests/CodeCoverage/PhpParser.parse.lines.phpt"/>
|
||||||
|
<testcase classname="tests/CodeCoverage/PhpParser.parse.methods.phpt" name="tests/CodeCoverage/PhpParser.parse.methods.phpt"/>
|
||||||
|
<testcase classname="tests/CodeCoverage/CloverXMLGenerator.phpt" name="tests/CodeCoverage/CloverXMLGenerator.phpt"/>
|
||||||
|
<testcase classname="tests/CodeCoverage/PhpParser.parse.edge.phpt" name="tests/CodeCoverage/PhpParser.parse.edge.phpt"/>
|
||||||
|
<testcase classname="tests/CodeCoverage/PhpParser.parse.lines-of-code.phpt" name="tests/CodeCoverage/PhpParser.parse.lines-of-code.phpt"/>
|
||||||
|
<testcase classname="tests/CodeCoverage/PhpParser.parse.namespaces.phpt" name="tests/CodeCoverage/PhpParser.parse.namespaces.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.contains.phpt" name="tests/Framework/Assert.contains.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.count.phpt" name="tests/Framework/Assert.count.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.phpt" name="tests/Framework/Assert.equal.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.recursive.phpt [method=testSimple]" name="tests/Framework/Assert.equal.recursive.phpt [method=testSimple]"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.recursive.phpt [method=testMultiple]" name="tests/Framework/Assert.equal.recursive.phpt [method=testMultiple]"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.recursive.phpt [method=testDeep]" name="tests/Framework/Assert.equal.recursive.phpt [method=testDeep]"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.recursive.phpt [method=testCross]" name="tests/Framework/Assert.equal.recursive.phpt [method=testCross]"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.equal.recursive.phpt [method=testThirdParty]" name="tests/Framework/Assert.equal.recursive.phpt [method=testThirdParty]"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.error.phpt" name="tests/Framework/Assert.error.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.exception.phpt" name="tests/Framework/Assert.exception.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.false.phpt" name="tests/Framework/Assert.false.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.match.phpt" name="tests/Framework/Assert.match.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.match.regexp.phpt" name="tests/Framework/Assert.match.regexp.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.nan.phpt" name="tests/Framework/Assert.nan.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.noError.phpt" name="tests/Framework/Assert.noError.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.same.phpt" name="tests/Framework/Assert.same.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.null.phpt" name="tests/Framework/Assert.null.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.true.phpt" name="tests/Framework/Assert.true.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.truthy.phpt" name="tests/Framework/Assert.truthy.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DataProvider.load.phpt" name="tests/Framework/DataProvider.load.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Assert.type.phpt" name="tests/Framework/Assert.type.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DataProvider.parseAnnotation.phpt" name="tests/Framework/DataProvider.parseAnnotation.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DataProvider.testQuery.phpt" name="tests/Framework/DataProvider.testQuery.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DomQuery.css2Xpath.phpt" name="tests/Framework/DomQuery.css2Xpath.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DomQuery.fromHtml.phpt" name="tests/Framework/DomQuery.fromHtml.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/DomQuery.fromXml.phpt" name="tests/Framework/DomQuery.fromXml.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Dumper.dumpException.phpt" name="tests/Framework/Dumper.dumpException.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Dumper.color.phpt" name="tests/Framework/Dumper.color.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Dumper.toLine.phpt" name="tests/Framework/Dumper.toLine.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Dumper.toPhp.recursion.phpt" name="tests/Framework/Dumper.toPhp.recursion.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Dumper.toPhp.phpt" name="tests/Framework/Dumper.toPhp.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/FileMock.phpt" name="tests/Framework/FileMock.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Helpers.escapeArg.phpt" name="tests/Framework/Helpers.escapeArg.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/Helpers.parseDocComment.phpt" name="tests/Framework/Helpers.parseDocComment.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.annotationThrows.phpt" name="tests/Framework/TestCase.annotationThrows.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.annotationThrows.setUp.tearDown.phpt" name="tests/Framework/TestCase.annotationThrows.setUp.tearDown.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.annotationThrows.syntax.phpt" name="tests/Framework/TestCase.annotationThrows.syntax.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.basic.phpt" name="tests/Framework/TestCase.basic.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.dataProvider.generator.phpt" name="tests/Framework/TestCase.dataProvider.generator.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.dataProvider.phpt" name="tests/Framework/TestCase.dataProvider.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.invalidMethods.phpt" name="tests/Framework/TestCase.invalidMethods.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.invalidProvider.phpt" name="tests/Framework/TestCase.invalidProvider.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.order.error.phpt" name="tests/Framework/TestCase.order.error.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.order.errorMuted.phpt" name="tests/Framework/TestCase.order.errorMuted.phpt"/>
|
||||||
|
<testcase classname="tests/Framework/TestCase.order.phpt" name="tests/Framework/TestCase.order.phpt"/>
|
||||||
|
<testcase classname="Prevent loop in error handling. The #268 regression. | tests/Framework/TestCase.ownErrorHandler.phpt" name="Prevent loop in error handling. The #268 regression. | tests/Framework/TestCase.ownErrorHandler.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/CommandLine.phpt" name="tests/Runner/CommandLine.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/HhvmPhpInterpreter.phpt" name="tests/Runner/HhvmPhpInterpreter.phpt">
|
||||||
|
<skipped/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="tests/Runner/Runner.find-tests.phpt" name="tests/Runner/Runner.find-tests.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Job.phpt" name="tests/Runner/Job.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/ZendPhpExecutable.phpt" name="tests/Runner/ZendPhpExecutable.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Runner.multiple.phpt" name="tests/Runner/Runner.multiple.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Runner.edge.phpt" name="tests/Runner/Runner.edge.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Runner.stop-on-fail.phpt" name="tests/Runner/Runner.stop-on-fail.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Runner.multiple-fails.phpt" name="tests/Runner/Runner.multiple-fails.phpt">
|
||||||
|
<failure message="Failed: '... in /Users/izso/Developer/nette/tester/tests/Runner/multiple-fails/...' should match
|
||||||
|
... '..., unexpected end of file in %a%testcase-syntax-error.phptx on line ...'
|
||||||
|
|
||||||
|
diff '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.expected' '/Users/izso/Developer/nette/tester/tests/Runner/output/Runner.multiple-fails.actual'
|
||||||
|
|
||||||
|
in tests/Runner/Runner.multiple-fails.phpt(78) Tester\Assert::match()"/>
|
||||||
|
</testcase>
|
||||||
|
<testcase classname="tests/RunnerOutput/JUnitPrinter.phpt" name="tests/RunnerOutput/JUnitPrinter.phpt"/>
|
||||||
|
<testcase classname="tests/Runner/Runner.annotations.phpt" name="tests/Runner/Runner.annotations.phpt"/>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
224
__tests__/tester-junit.test.ts
Normal file
224
__tests__/tester-junit.test.ts
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
import * as fs from 'fs'
|
||||||
|
import * as path from 'path'
|
||||||
|
|
||||||
|
import {NetteTesterJunitParser} from '../src/parsers/tester-junit/tester-junit-parser'
|
||||||
|
import {ParseOptions} from '../src/test-parser'
|
||||||
|
import {getReport} from '../src/report/get-report'
|
||||||
|
import {normalizeFilePath} from '../src/utils/path-utils'
|
||||||
|
|
||||||
|
describe('tester-junit tests', () => {
|
||||||
|
it('produces empty test run result when there are no test cases', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'empty', 'phpunit-empty.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
expect(result.tests).toBe(0)
|
||||||
|
expect(result.result).toBe('success')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('report from tester-v1.7-report.xml matches snapshot', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const outputPath = path.join(__dirname, '__outputs__', 'tester-v1.7-test-results.md')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
expect(result).toMatchSnapshot()
|
||||||
|
|
||||||
|
const report = getReport([result])
|
||||||
|
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
|
||||||
|
fs.writeFileSync(outputPath, report)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('parses tester-v1.7-report.xml correctly', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Verify test counts from XML: tests="65" errors="1" skipped="3"
|
||||||
|
expect(result.tests).toBe(65)
|
||||||
|
expect(result.failed).toBe(1)
|
||||||
|
expect(result.skipped).toBe(3)
|
||||||
|
expect(result.passed).toBe(61)
|
||||||
|
|
||||||
|
// Verify suite name uses file name
|
||||||
|
expect(result.suites.length).toBe(1)
|
||||||
|
expect(result.suites[0].name).toBe('tester-v1.7-report.xml')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('groups tests by directory structure', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Get all group names
|
||||||
|
const groupNames = result.suites[0].groups.map(g => g.name)
|
||||||
|
|
||||||
|
// Verify expected directory groups exist
|
||||||
|
expect(groupNames).toContain('tests/Framework')
|
||||||
|
expect(groupNames).toContain('tests/CodeCoverage')
|
||||||
|
expect(groupNames).toContain('tests/Runner')
|
||||||
|
expect(groupNames).toContain('tests/RunnerOutput')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('parses test names with method suffixes correctly', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Find the Framework group which has tests with method suffixes
|
||||||
|
const frameworkGroup = result.suites[0].groups.find(g => g.name === 'tests/Framework')
|
||||||
|
expect(frameworkGroup).toBeDefined()
|
||||||
|
|
||||||
|
// Find tests with method suffixes
|
||||||
|
const testWithMethod = frameworkGroup!.tests.find(t => t.name.includes('::testSimple'))
|
||||||
|
expect(testWithMethod).toBeDefined()
|
||||||
|
expect(testWithMethod!.name).toBe('Assert.equal.recursive.phpt::testSimple')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('parses complex test names from BootstrapFormRenderer-report.xml', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'BootstrapFormRenderer-report.xml')
|
||||||
|
const outputPath = path.join(__dirname, '__outputs__', 'tester-bootstrap-test-results.md')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Verify test counts: 4 tests, all passed
|
||||||
|
expect(result.tests).toBe(4)
|
||||||
|
expect(result.passed).toBe(4)
|
||||||
|
expect(result.failed).toBe(0)
|
||||||
|
expect(result.skipped).toBe(0)
|
||||||
|
|
||||||
|
// Verify suite name
|
||||||
|
expect(result.suites[0].name).toBe('BootstrapFormRenderer-report.xml')
|
||||||
|
|
||||||
|
// All tests should have method names
|
||||||
|
const allTests = result.suites[0].groups.flatMap(g => g.tests)
|
||||||
|
expect(allTests.every(t => t.name.includes('::'))).toBe(true)
|
||||||
|
expect(allTests.some(t => t.name.includes('::testRenderingBasics'))).toBe(true)
|
||||||
|
expect(allTests.some(t => t.name.includes('::testRenderingIndividual'))).toBe(true)
|
||||||
|
|
||||||
|
expect(result).toMatchSnapshot()
|
||||||
|
|
||||||
|
const report = getReport([result])
|
||||||
|
fs.mkdirSync(path.dirname(outputPath), {recursive: true})
|
||||||
|
fs.writeFileSync(outputPath, report)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('extracts error details from failures', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Find the failed test
|
||||||
|
const allTests = result.suites[0].groups.flatMap(g => g.tests)
|
||||||
|
const failedTests = allTests.filter(t => t.result === 'failed')
|
||||||
|
|
||||||
|
expect(failedTests.length).toBe(1)
|
||||||
|
|
||||||
|
// Verify error details are captured
|
||||||
|
const failedTest = failedTests[0]
|
||||||
|
expect(failedTest.error).toBeDefined()
|
||||||
|
expect(failedTest.error!.details).toContain('Failed:')
|
||||||
|
expect(failedTest.error!.details).toContain('multiple-fails')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('correctly identifies skipped tests', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Find skipped tests
|
||||||
|
const allTests = result.suites[0].groups.flatMap(g => g.tests)
|
||||||
|
const skippedTests = allTests.filter(t => t.result === 'skipped')
|
||||||
|
|
||||||
|
expect(skippedTests.length).toBe(3)
|
||||||
|
|
||||||
|
// Verify some known skipped tests
|
||||||
|
expect(skippedTests.some(t => t.name.includes('Dumper.toPhp.php7.phpt'))).toBe(true)
|
||||||
|
expect(skippedTests.some(t => t.name.includes('Collector.start.phpt'))).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('parses test with description prefix correctly', async () => {
|
||||||
|
const fixturePath = path.join(__dirname, 'fixtures', 'nette-tester', 'tester-v1.7-report.xml')
|
||||||
|
const filePath = normalizeFilePath(path.relative(__dirname, fixturePath))
|
||||||
|
const fileContent = fs.readFileSync(fixturePath, {encoding: 'utf8'})
|
||||||
|
|
||||||
|
const opts: ParseOptions = {
|
||||||
|
parseErrors: true,
|
||||||
|
trackedFiles: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = new NetteTesterJunitParser(opts)
|
||||||
|
const result = await parser.parse(filePath, fileContent)
|
||||||
|
|
||||||
|
// Find test with description prefix
|
||||||
|
const allTests = result.suites[0].groups.flatMap(g => g.tests)
|
||||||
|
// The test name is generated from the basename, and the description is shown in parentheses
|
||||||
|
const testWithDescription = allTests.find(t => t.name.includes('Prevent loop'))
|
||||||
|
|
||||||
|
expect(testWithDescription).toBeDefined()
|
||||||
|
expect(testWithDescription!.name).toContain('Prevent loop')
|
||||||
|
expect(testWithDescription!.name).toContain('TestCase.ownErrorHandler.phpt')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -32,6 +32,7 @@ inputs:
|
|||||||
- java-junit
|
- java-junit
|
||||||
- jest-junit
|
- jest-junit
|
||||||
- mocha-json
|
- mocha-json
|
||||||
|
- tester-junit
|
||||||
- phpunit-junit
|
- phpunit-junit
|
||||||
- python-xunit
|
- python-xunit
|
||||||
- rspec-json
|
- rspec-json
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {PhpunitJunitParser} from './parsers/phpunit-junit/phpunit-junit-parser'
|
|||||||
import {PythonXunitParser} from './parsers/python-xunit/python-xunit-parser'
|
import {PythonXunitParser} from './parsers/python-xunit/python-xunit-parser'
|
||||||
import {RspecJsonParser} from './parsers/rspec-json/rspec-json-parser'
|
import {RspecJsonParser} from './parsers/rspec-json/rspec-json-parser'
|
||||||
import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser'
|
import {SwiftXunitParser} from './parsers/swift-xunit/swift-xunit-parser'
|
||||||
|
import {NetteTesterJunitParser} from './parsers/tester-junit/tester-junit-parser'
|
||||||
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
|
import {normalizeDirPath, normalizeFilePath} from './utils/path-utils'
|
||||||
import {getCheckRunContext} from './utils/github-utils'
|
import {getCheckRunContext} from './utils/github-utils'
|
||||||
|
|
||||||
@@ -280,6 +281,8 @@ class TestReporter {
|
|||||||
return new RspecJsonParser(options)
|
return new RspecJsonParser(options)
|
||||||
case 'swift-xunit':
|
case 'swift-xunit':
|
||||||
return new SwiftXunitParser(options)
|
return new SwiftXunitParser(options)
|
||||||
|
case 'tester-junit':
|
||||||
|
return new NetteTesterJunitParser(options)
|
||||||
default:
|
default:
|
||||||
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
|
throw new Error(`Input variable 'reporter' is set to invalid value '${reporter}'`)
|
||||||
}
|
}
|
||||||
|
|||||||
260
src/parsers/tester-junit/tester-junit-parser.ts
Normal file
260
src/parsers/tester-junit/tester-junit-parser.ts
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
import * as path from 'path'
|
||||||
|
import {ParseOptions, TestParser} from '../../test-parser'
|
||||||
|
import {parseStringPromise} from 'xml2js'
|
||||||
|
|
||||||
|
import {NetteTesterReport, SingleSuiteReport, TestCase, TestSuite} from './tester-junit-types'
|
||||||
|
import {normalizeFilePath} from '../../utils/path-utils'
|
||||||
|
|
||||||
|
import {
|
||||||
|
TestExecutionResult,
|
||||||
|
TestRunResult,
|
||||||
|
TestSuiteResult,
|
||||||
|
TestGroupResult,
|
||||||
|
TestCaseResult,
|
||||||
|
TestCaseError
|
||||||
|
} from '../../test-results'
|
||||||
|
|
||||||
|
interface ParsedTestName {
|
||||||
|
filePath: string
|
||||||
|
method?: string
|
||||||
|
description?: string
|
||||||
|
className?: string
|
||||||
|
displayName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NetteTesterJunitParser implements TestParser {
|
||||||
|
readonly trackedFiles: Set<string>
|
||||||
|
readonly trackedFilesList: string[]
|
||||||
|
|
||||||
|
constructor(readonly options: ParseOptions) {
|
||||||
|
this.trackedFilesList = options.trackedFiles.map(f => normalizeFilePath(f))
|
||||||
|
this.trackedFiles = new Set(this.trackedFilesList)
|
||||||
|
}
|
||||||
|
|
||||||
|
async parse(filePath: string, content: string): Promise<TestRunResult> {
|
||||||
|
const reportOrSuite = await this.getNetteTesterReport(filePath, content)
|
||||||
|
const isReport = (reportOrSuite as NetteTesterReport).testsuites !== undefined
|
||||||
|
|
||||||
|
// XML might contain:
|
||||||
|
// - multiple suites under <testsuites> root node
|
||||||
|
// - single <testsuite> as root node
|
||||||
|
let report: NetteTesterReport
|
||||||
|
if (isReport) {
|
||||||
|
report = reportOrSuite as NetteTesterReport
|
||||||
|
} else {
|
||||||
|
// Make it behave the same way as if suite was inside <testsuites> root node
|
||||||
|
const suite = (reportOrSuite as SingleSuiteReport).testsuite
|
||||||
|
report = {
|
||||||
|
testsuites: {
|
||||||
|
$: {time: suite.$.time},
|
||||||
|
testsuite: [suite]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getTestRunResult(filePath, report)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getNetteTesterReport(
|
||||||
|
filePath: string,
|
||||||
|
content: string
|
||||||
|
): Promise<NetteTesterReport | SingleSuiteReport> {
|
||||||
|
try {
|
||||||
|
return await parseStringPromise(content)
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Invalid XML at ${filePath}\n\n${e}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTestRunResult(filePath: string, report: NetteTesterReport): TestRunResult {
|
||||||
|
const suites =
|
||||||
|
report.testsuites.testsuite === undefined
|
||||||
|
? []
|
||||||
|
: report.testsuites.testsuite.map((ts, index) => {
|
||||||
|
// Use report file name as suite name (user preference)
|
||||||
|
const fileName = path.basename(filePath)
|
||||||
|
// If there are multiple test suites, add index to distinguish them
|
||||||
|
const name =
|
||||||
|
report.testsuites.testsuite && report.testsuites.testsuite.length > 1
|
||||||
|
? `${fileName} #${index + 1}`
|
||||||
|
: fileName
|
||||||
|
const time = parseFloat(ts.$.time) * 1000
|
||||||
|
const sr = new TestSuiteResult(name, this.getGroups(ts), time)
|
||||||
|
return sr
|
||||||
|
})
|
||||||
|
|
||||||
|
const seconds = parseFloat(report.testsuites.$?.time ?? '')
|
||||||
|
const time = isNaN(seconds) ? undefined : seconds * 1000
|
||||||
|
return new TestRunResult(filePath, suites, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getGroups(suite: TestSuite): TestGroupResult[] {
|
||||||
|
if (!suite.testcase || suite.testcase.length === 0) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group tests by directory structure
|
||||||
|
const groups: Map<string, TestCase[]> = new Map()
|
||||||
|
|
||||||
|
for (const tc of suite.testcase) {
|
||||||
|
const parsed = this.parseTestCaseName(tc.$.classname)
|
||||||
|
const directory = path.dirname(parsed.filePath)
|
||||||
|
|
||||||
|
if (!groups.has(directory)) {
|
||||||
|
groups.set(directory, [])
|
||||||
|
}
|
||||||
|
groups.get(directory)!.push(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(groups.entries()).map(([dir, tests]) => {
|
||||||
|
const testResults = tests.map(tc => {
|
||||||
|
const parsed = this.parseTestCaseName(tc.$.classname)
|
||||||
|
const result = this.getTestCaseResult(tc)
|
||||||
|
const time = parseFloat(tc.$.time || '0') * 1000
|
||||||
|
const error = this.getTestCaseError(tc, parsed.filePath)
|
||||||
|
return new TestCaseResult(parsed.displayName, result, time, error)
|
||||||
|
})
|
||||||
|
return new TestGroupResult(dir, testResults)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse test case name from classname attribute.
|
||||||
|
*
|
||||||
|
* Handles multiple patterns:
|
||||||
|
* 1. Simple: "tests/Framework/Assert.equal.phpt"
|
||||||
|
* 2. With method: "tests/Framework/Assert.equal.recursive.phpt [method=testSimple]"
|
||||||
|
* 3. With description: "Prevent loop in error handling. The #268 regression. | tests/Framework/TestCase.ownErrorHandler.phpt"
|
||||||
|
* 4. With class and method: "Kdyby\BootstrapFormRenderer\BootstrapRenderer. | KdybyTests/BootstrapFormRenderer/BootstrapRendererTest.phpt [method=testRenderingBasics]"
|
||||||
|
*/
|
||||||
|
private parseTestCaseName(classname: string): ParsedTestName {
|
||||||
|
let filePath = classname
|
||||||
|
let method: string | undefined
|
||||||
|
let description: string | undefined
|
||||||
|
let className: string | undefined
|
||||||
|
|
||||||
|
// Pattern: "Description | filepath [method=methodName]"
|
||||||
|
// or "ClassName | filepath [method=methodName]"
|
||||||
|
const pipePattern = /^(.+?)\s*\|\s*(.+?)(?:\s*\[method=(.+?)\])?$/
|
||||||
|
const pipeMatch = classname.match(pipePattern)
|
||||||
|
|
||||||
|
if (pipeMatch) {
|
||||||
|
const prefix = pipeMatch[1].trim()
|
||||||
|
filePath = pipeMatch[2].trim()
|
||||||
|
method = pipeMatch[3]
|
||||||
|
|
||||||
|
// Check if prefix looks like a class name (contains backslash AND ends with dot)
|
||||||
|
// Examples: "Kdyby\BootstrapFormRenderer\BootstrapRenderer."
|
||||||
|
// vs description: "Prevent loop in error handling. The #268 regression."
|
||||||
|
if (prefix.includes('\\') && prefix.endsWith('.')) {
|
||||||
|
className = prefix
|
||||||
|
} else {
|
||||||
|
description = prefix
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pattern: "filepath [method=methodName]"
|
||||||
|
const methodPattern = /^(.+?)\s*\[method=(.+?)\]$/
|
||||||
|
const methodMatch = classname.match(methodPattern)
|
||||||
|
|
||||||
|
if (methodMatch) {
|
||||||
|
filePath = methodMatch[1].trim()
|
||||||
|
method = methodMatch[2].trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate display name
|
||||||
|
const baseName = path.basename(filePath)
|
||||||
|
let displayName = baseName
|
||||||
|
|
||||||
|
if (method) {
|
||||||
|
displayName = `${baseName}::${method}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description) {
|
||||||
|
displayName = `${description} (${baseName})`
|
||||||
|
} else if (className && method) {
|
||||||
|
// For class names, keep them but still show the file
|
||||||
|
displayName = `${baseName}::${method}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return {filePath, method, description, className, displayName}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTestCaseResult(test: TestCase): TestExecutionResult {
|
||||||
|
if (test.failure || test.error) return 'failed'
|
||||||
|
if (test.skipped) return 'skipped'
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTestCaseError(tc: TestCase, filePath: string): TestCaseError | undefined {
|
||||||
|
if (!this.options.parseErrors) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// We process <error> and <failure> the same way
|
||||||
|
const failures = tc.failure ?? tc.error
|
||||||
|
if (!failures || failures.length === 0) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const failure = failures[0]
|
||||||
|
// For Nette Tester, details are in the message attribute, not as inner text
|
||||||
|
const details = typeof failure === 'string' ? failure : failure._ ?? failure.$?.message ?? ''
|
||||||
|
|
||||||
|
// Try to extract file path and line from error details
|
||||||
|
let errorFilePath: string | undefined
|
||||||
|
let line: number | undefined
|
||||||
|
|
||||||
|
if (details) {
|
||||||
|
const extracted = this.extractFileAndLine(details)
|
||||||
|
if (extracted) {
|
||||||
|
errorFilePath = extracted.filePath
|
||||||
|
line = extracted.line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: use test file path if tracked
|
||||||
|
if (!errorFilePath) {
|
||||||
|
const normalized = normalizeFilePath(filePath)
|
||||||
|
if (this.trackedFiles.has(normalized)) {
|
||||||
|
errorFilePath = normalized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let message: string | undefined
|
||||||
|
if (typeof failure !== 'string' && failure.$) {
|
||||||
|
message = failure.$.message
|
||||||
|
if (failure.$.type) {
|
||||||
|
message = message ? `${failure.$.type}: ${message}` : failure.$.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: errorFilePath,
|
||||||
|
line,
|
||||||
|
details,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract file path and line number from error details.
|
||||||
|
* Matches patterns like: /path/to/file.phpt:123 or /path/to/file.php:456
|
||||||
|
*/
|
||||||
|
private extractFileAndLine(details: string): {filePath: string; line: number} | undefined {
|
||||||
|
const lines = details.split(/\r?\n/)
|
||||||
|
|
||||||
|
for (const str of lines) {
|
||||||
|
// Match PHP file patterns: /path/to/file.phpt:123 or /path/to/file.php:456
|
||||||
|
const match = str.match(/((?:[A-Za-z]:)?[^\s:()]+?\.(?:php|phpt)):(\d+)/)
|
||||||
|
if (match) {
|
||||||
|
const normalized = normalizeFilePath(match[1])
|
||||||
|
if (this.trackedFiles.has(normalized)) {
|
||||||
|
return {filePath: normalized, line: parseInt(match[2])}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/parsers/tester-junit/tester-junit-types.ts
Normal file
46
src/parsers/tester-junit/tester-junit-types.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
export interface NetteTesterReport {
|
||||||
|
testsuites: TestSuites
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SingleSuiteReport {
|
||||||
|
testsuite: TestSuite
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestSuites {
|
||||||
|
$?: {
|
||||||
|
time?: string
|
||||||
|
}
|
||||||
|
testsuite?: TestSuite[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestSuite {
|
||||||
|
$: {
|
||||||
|
// NOTE: name attribute is intentionally omitted - Nette Tester doesn't provide it
|
||||||
|
tests: string
|
||||||
|
errors: string
|
||||||
|
failures?: string
|
||||||
|
skipped: string
|
||||||
|
time: string
|
||||||
|
timestamp?: string
|
||||||
|
}
|
||||||
|
testcase?: TestCase[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TestCase {
|
||||||
|
$: {
|
||||||
|
classname: string // File path, possibly with method or description prefix
|
||||||
|
name: string // Usually same as classname
|
||||||
|
time: string
|
||||||
|
}
|
||||||
|
failure?: Failure[]
|
||||||
|
error?: Failure[]
|
||||||
|
skipped?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Failure {
|
||||||
|
_?: string
|
||||||
|
$?: {
|
||||||
|
type?: string
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user