Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/guides/test/coverage-threshold.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ bun test --coverage

```txt
test.test.ts:
✓ math > add [0.71ms]
✓ math > multiply [0.03ms]
math
✓ add [0.71ms]
✓ multiply [0.03ms]
✓ random [0.13ms]
-------------|---------|---------|-------------------
File | % Funcs | % Lines | Uncovered Line #s
Expand Down
5 changes: 3 additions & 2 deletions docs/guides/test/coverage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ bun test --coverage
```txt

test.test.ts:
✓ math > add [0.71ms]
✓ math > multiply [0.03ms]
math
✓ add [0.71ms]
✓ multiply [0.03ms]
✓ random [0.13ms]
-------------|---------|---------|-------------------
File | % Funcs | % Lines | Uncovered Line #s
Expand Down
16 changes: 16 additions & 0 deletions docs/test/reporters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ test/package-json-lint.test.ts:
Ran 4 tests across 1 file. [9.00ms]
```

Tests inside a `describe` block are nested beneath their scope. The scope header appears before its first displayed result and may appear again if results from another scope or file intervene:

```sh terminal icon="terminal"
test/math.test.ts:
math
arithmetic
✓ add [0.12ms]
✓ subtract [0.04ms]
✓ is a module [0.03ms]
✓ top-level test [0.02ms]

4 pass
0 fail
Ran 4 tests across 1 file. [0.31ms]
```

### Dots Reporter

The dots reporter shows `.` for passing tests and prints full error details for failures, useful for large test suites.
Expand Down
15 changes: 15 additions & 0 deletions src/runtime/cli/test/parallel/Coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use super::file_range::FileRange;
use super::frame::{self, Frame};
use super::parts::{self, Part, PartBuilder, PartState, Parts};
use super::reservation::{Reservation, Room, own_kilobytes_in};
use super::runner;
use super::worker::{SpawnContext, Worker, WorkerPipe};
use crate::cli::command::TestOptions;
use crate::cli::run_compiled::{
Expand Down Expand Up @@ -63,6 +64,9 @@ pub(crate) struct Coordinator<'a> {
/// from concurrent workers interleave; whenever the source file changes the
/// header is re-emitted so every line has visible context. None at start.
pub(crate) last_header_idx: Option<u32>,
/// Ids of describe scopes whose headers have already been printed under
/// `last_header_idx`. Cleared whenever the file header is re-emitted.
pub(crate) printed_scopes: Vec<u64>,
/// Where the run ends as in one process: the file that the worker has begun. It has printed the header itself.
pub(crate) header_printed_by_worker: Option<u32>,
pub frame: Frame,
Expand Down Expand Up @@ -850,6 +854,7 @@ impl<'a> Coordinator<'a> {
}
self.end_group();
self.last_header_idx = Some(file_idx);
self.printed_scopes.clear();
let file_prefix: &[u8] = if Output::is_github_action() {
b"::group::"
} else {
Expand Down Expand Up @@ -932,6 +937,16 @@ impl<'a> Coordinator<'a> {
if !is_dot {
self.break_dots();
self.ensure_header(idx);
if !self.dots
&& let Some(test) =
runner::decode_test_case(&mut frame::Reader { p: rd.p }, b"")
{
CommandLineReporter::emit_scope_headers(
&mut self.printed_scopes,
test.scopes.iter().map(|s| (s.name, s.id)),
Output::error_writer(),
);
}
}
let _ = Output::error_writer().write_all(formatted);
self.last_printed_dot = is_dot;
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/cli/test/parallel/Frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ pub(crate) enum Kind {
/// u32 file_idx
FileStart,
/// u32 file_idx, str formatted_line (ANSI included; printed verbatim);
/// then, only when the worker runs with `--reporter`, the structured
/// then, only when the worker runs with `--reporter` or the line is
/// nested under describe headers the coordinator prints, the structured
/// result (`runner::encode_test_case`): u32 status, u32 assertions,
/// u64 elapsed_ns, u32 line, str name, u32 n × {str scope_name,
/// u32 scope_line}, u32 has_failure [, str name, str message, str body, u32 uncaught]
Expand Down
20 changes: 13 additions & 7 deletions src/runtime/cli/test/parallel/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ pub(crate) fn run_as_coordinator(
},
coverage_files: Default::default(),
last_header_idx: None,
printed_scopes: Vec::new(),
header_printed_by_worker: None,
frame: Frame::default(),
files_done: 0,
Expand Down Expand Up @@ -1171,10 +1172,10 @@ static WORKER_CMDS: bun_core::RacyCell<Option<*mut WorkerCommands>> = bun_core::
// pointee outlives all callers (process exits before it's dropped).

/// Called from `CommandLineReporter.handleTestCompleted` in the worker with the
/// fully-formatted status line (✓/✗ + scopes + name + duration, including ANSI
/// fully-formatted status line (✓/✗ + indent + name + duration, including ANSI
/// codes), which the coordinator prints verbatim so output matches serial, and,
/// when the coordinator asked for it (`--reporter`), the structured result it
/// replays into its own reporters.
/// when the coordinator asked for it (`--reporter`) or needs the describe scopes
/// to print headers above a nested line, the structured result.
#[optimize(size)]
pub(crate) fn worker_emit_test_done(
file_idx: u32,
Expand Down Expand Up @@ -1204,9 +1205,10 @@ fn encode_test_case(wf: &mut Frame, t: &test_command::TestCaseReport<'_>) {
wf.u32(t.line_number);
wf.str(t.name);
wf.u32(u32::try_from(t.scopes.len()).expect("int cast"));
for &(name, line) in &t.scopes {
wf.str(name);
wf.u32(line);
for s in &t.scopes {
wf.str(s.name);
wf.u32(s.line);
wf.u64(s.id);
}
// Earlier attempts' failures first, then the last attempt's if it failed.
wf.u32(u32::from(t.failure.is_some()));
Expand Down Expand Up @@ -1238,7 +1240,11 @@ pub(crate) fn decode_test_case<'a>(
}
let mut scopes = Vec::with_capacity(n);
for _ in 0..n {
scopes.push((rd.str(), rd.u32()));
scopes.push(test_command::ReportScope {
name: rd.str(),
line: rd.u32(),
id: rd.u64(),
});
}
let has_failure = rd.u32() != 0;
let earlier = rd.u32() as usize;
Expand Down
Loading