Skip to content

Commit 2e937cb

Browse files
ilslvtyranron
andauthored
Implement outputting JUnit XML report (#147, #50)
- impl `writer::JUnit` behind `output-junit` Cargo feature - make `writer::Basic` generic over `io::Write` implementor Co-authored-by: Kai Ren <[email protected]>
1 parent a153215 commit 2e937cb

File tree

16 files changed

+868
-130
lines changed

16 files changed

+868
-130
lines changed

.clippy.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,15 @@
22
# See full lints list at:
33
# https://rust-lang.github.io/rust-clippy/master/index.html
44

5+
doc-valid-idents = ["JUnit"]
6+
57
standard-macro-braces = [
8+
{ name = "assert", brace = "(" },
9+
{ name = "assert_eq", brace = "(" },
10+
{ name = "assert_ne", brace = "(" },
611
{ name = "format", brace = "(" },
712
{ name = "format_ident", brace = "(" },
13+
{ name = "panic", brace = "(" },
814
{ name = "quote", brace = "{" },
915
{ name = "vec", brace = "[" },
1016
]

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
strategy:
6262
fail-fast: false
6363
matrix:
64-
feature: ['<none>', 'macros', 'timestamps']
64+
feature: ["<none>", "macros", "timestamps", "output-junit"]
6565
runs-on: ubuntu-latest
6666
steps:
6767
- uses: actions/checkout@v2

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ All user visible changes to `cucumber` crate will be documented in this file. Th
1414
### Added
1515

1616
- Ability for step functions to return `Result`. ([#151])
17+
- Arbitrary output for `writer::Basic` ([#147])
18+
- `writer::JUnit` ([JUnit XML report][0110-1]) behind the `output-junit` feature flag ([#147])
1719

20+
[#147]: /../../pull/147
1821
[#151]: /../../pull/151
22+
[0110-1]: https://llg.cubic.org/docs/junit
1923

2024

2125

Cargo.toml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ repository = "https://github.com/cucumber-rs/cucumber"
1919
readme = "README.md"
2020
categories = ["asynchronous", "development-tools::testing"]
2121
keywords = ["cucumber", "testing", "bdd", "atdd", "async"]
22-
include = ["/src/", "/tests/wait.rs", "/LICENSE-*", "/README.md", "/CHANGELOG.md"]
22+
include = ["/src/", "/tests/junit.rs", "/tests/wait.rs", "/LICENSE-*", "/README.md", "/CHANGELOG.md"]
2323

2424
[package.metadata.docs.rs]
2525
all-features = true
@@ -29,14 +29,16 @@ rustdoc-args = ["--cfg", "docsrs"]
2929
default = ["macros"]
3030
# Enables step attributes and auto-wiring.
3131
macros = ["cucumber-codegen", "inventory"]
32+
# Enables support for outputting JUnit XML report.
33+
output-junit = ["junit-report", "timestamps"]
3234
# Enables timestamps collecting for all events.
3335
timestamps = []
3436

3537
[dependencies]
3638
async-trait = "0.1.40"
3739
atty = "0.2.14"
3840
console = "0.15"
39-
derive_more = { version = "0.99.16", features = ["as_ref", "deref", "deref_mut", "display", "error", "from"], default_features = false }
41+
derive_more = { version = "0.99.16", features = ["as_ref", "deref", "deref_mut", "display", "error", "from", "into"], default_features = false }
4042
either = "1.6"
4143
futures = "0.3.17"
4244
gherkin = { package = "gherkin_rust", version = "0.10" }
@@ -52,10 +54,19 @@ structopt = "0.3.25"
5254
cucumber-codegen = { version = "0.11.0-dev", path = "./codegen", optional = true }
5355
inventory = { version = "0.1.10", optional = true }
5456

57+
# "output-junit" feature dependencies
58+
junit-report = { version = "0.7", optional = true }
59+
5560
[dev-dependencies]
5661
humantime = "2.1"
62+
tempfile = "3.2"
5763
tokio = { version = "1.12", features = ["macros", "rt-multi-thread", "time"] }
5864

65+
[[test]]
66+
name = "junit"
67+
required-features = ["output-junit"]
68+
harness = false
69+
5970
[[test]]
6071
name = "wait"
6172
harness = false

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ For more examples check out the Book ([current][1] | [edge][2]).
100100

101101
- `macros` (default): Enables step attributes and auto-wiring.
102102
- `timestamps`: Enables timestamps collecting for all [Cucumber] events.
103+
- `output-junit` (implies `timestamps`): Enables support for outputting [JUnit XML report].
103104

104105

105106

@@ -131,7 +132,8 @@ at your option.
131132

132133

133134
[Cucumber]: https://cucumber.io
134-
[Gherkin]: https://cucumber.io/docs/gherkin/reference
135+
[Gherkin]: https://cucumber.io/docs/gherkin/reference
136+
[JUnit XML report]: https://llg.cubic.org/docs/junit
135137

136138
[1]: https://cucumber-rs.github.io/cucumber/current
137139
[2]: https://cucumber-rs.github.io/cucumber/main

book/src/Features.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,5 +431,49 @@ You may also extend CLI options with custom ones, if you have such a need for ru
431431

432432

433433

434+
## JUnit XML report
435+
436+
Library provides an ability to output tests result in as [JUnit XML report].
437+
438+
Just enable `output-junit` library feature in your `Cargo.toml`:
439+
```toml
440+
cucumber = { version = "0.11", features = ["output-junit"] }
441+
```
442+
443+
And configure [Cucumber]'s output to `writer::JUnit`:
444+
```rust
445+
# use std::{convert::Infallible, fs, io};
446+
#
447+
# use async_trait::async_trait;
448+
# use cucumber::WorldInit;
449+
use cucumber::writer;
450+
451+
# #[derive(Debug, WorldInit)]
452+
# struct World;
453+
#
454+
# #[async_trait(?Send)]
455+
# impl cucumber::World for World {
456+
# type Error = Infallible;
457+
#
458+
# async fn new() -> Result<Self, Self::Error> {
459+
# Ok(World)
460+
# }
461+
# }
462+
#
463+
# #[tokio::main]
464+
# async fn main() -> io::Result<()> {
465+
let file = fs::File::create(dbg!(format!("{}/target/junit.xml", env!("CARGO_MANIFEST_DIR"))))?;
466+
World::cucumber()
467+
.with_writer(writer::JUnit::new(file))
468+
.run("tests/features/book")
469+
.await;
470+
# Ok(())
471+
# }
472+
```
473+
474+
475+
476+
434477
[Cucumber]: https://cucumber.io
435478
[Gherkin]: https://cucumber.io/docs/gherkin
479+
[JUnit XML report]: https://llg.cubic.org/docs/junit

book/tests/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ publish = false
1111

1212
[dependencies]
1313
async-trait = "0.1"
14-
cucumber = { version = "0.11.0-dev", path = "../.." }
14+
cucumber = { version = "0.11.0-dev", path = "../..", features = ["output-junit"] }
1515
futures = "0.3"
1616
skeptic = "0.13"
1717
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }

src/cucumber.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -922,10 +922,10 @@ where
922922
I: AsRef<Path>,
923923
{
924924
fn default() -> Self {
925-
Cucumber::custom(
925+
Self::custom(
926926
parser::Basic::new(),
927927
runner::Basic::default(),
928-
writer::Basic::new().normalized().summarized(),
928+
writer::Basic::default().normalized().summarized(),
929929
)
930930
}
931931
}
@@ -957,7 +957,7 @@ where
957957
/// [tag]: https://cucumber.io/docs/cucumber/api/#tags
958958
#[must_use]
959959
pub fn new() -> Self {
960-
Cucumber::default()
960+
Self::default()
961961
}
962962
}
963963

src/parser/basic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use derive_more::{Display, Error};
2222
use futures::stream;
2323
use gherkin::GherkinEnv;
2424
use globwalk::{GlobWalker, GlobWalkerBuilder};
25+
use itertools::Itertools as _;
2526
use structopt::StructOpt;
2627

2728
use crate::feature::Ext as _;
@@ -65,6 +66,7 @@ impl<I: AsRef<Path>> Parser<I> for Basic {
6566
let walk = |walker: GlobWalker| {
6667
walker
6768
.filter_map(Result::ok)
69+
.sorted_by(|l, r| Ord::cmp(l.path(), r.path()))
6870
.filter(|file| {
6971
file.path()
7072
.extension()

0 commit comments

Comments
 (0)