Skip to content
Merged
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

### Added
- Display test output (stdout/stderr) on failure for runtime errors
- Shows captured output in an "Output:" section when tests fail with runtime errors
- Helps debug test failures without manually capturing output
- Enabled by default; use `--no-output-on-failure` or `BASHUNIT_SHOW_OUTPUT_ON_FAILURE=false` to disable
- New CLI options: `--show-output`, `--no-output-on-failure`

## [0.32.0](https://github.com/TypedDevs/bashunit/compare/0.31.0...0.32.0) - 2026-01-12

### Changed
Expand Down
29 changes: 29 additions & 0 deletions docs/command-line.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ bashunit test tests/ --parallel --simple
| `--debug [file]` | Enable shell debug mode |
| `--no-output` | Suppress all output |
| `--failures-only` | Only show failures |
| `--show-output` | Show test output on failure (default) |
| `--no-output-on-failure` | Hide test output on failure |
| `--strict` | Enable strict shell mode |
| `--skip-env-file` | Skip `.env` loading, use shell environment only |
| `-l, --login` | Run tests in login shell context |
Expand Down Expand Up @@ -231,6 +233,33 @@ bashunit test tests/ --report-html report.html
```
:::

### Show Output on Failure

> `bashunit test --show-output`
> `bashunit test --no-output-on-failure`

Control whether test output (stdout/stderr) is displayed when tests fail with runtime errors.

By default (`--show-output`), when a test fails due to a runtime error (command not found,
unbound variable, permission denied, etc.), bashunit displays the captured output in an
"Output:" section to help debug the failure.

Use `--no-output-on-failure` to suppress this output.

::: code-group
```bash [Example]
bashunit test tests/ --no-output-on-failure
```
```[Output with --show-output (default)]
βœ— Error: My test function
command not found
Output:
Debug: Setting up test
Running command: my_command
/path/to/test.sh: line 5: my_command: command not found
```
:::

### Strict Mode

> `bashunit test --strict`
Expand Down
24 changes: 24 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,30 @@ BASHUNIT_FAILURES_ONLY=true
```
:::

## Show output on failure

> `BASHUNIT_SHOW_OUTPUT_ON_FAILURE=true|false`

Display captured stdout/stderr output when tests fail with runtime errors. `true` by default.

When a test fails due to a runtime error (command not found, unbound variable, etc.),
bashunit displays the test's output in an "Output:" section to help debug the failure.

Similar as using `--show-output` or `--no-output-on-failure` options on the [command line](/command-line#show-output-on-failure).

::: code-group
```[Output example]
βœ— Error: My test function
command not found
Output:
Debug: Setting up test
Running command: my_command
```
```bash [.env to disable]
BASHUNIT_SHOW_OUTPUT_ON_FAILURE=false
```
:::

## Color output

> `NO_COLOR=1`
Expand Down
2 changes: 2 additions & 0 deletions src/console_header.sh
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ Options:
--debug [file] Enable shell debug mode
--no-output Suppress all output
--failures-only Only show failures (suppress passed/skipped/incomplete)
--show-output Show test output on failure (default: enabled)
--no-output-on-failure Hide test output on failure
--strict Enable strict shell mode (set -euo pipefail)
--skip-env-file Skip .env loading, use shell environment only
-l, --login Run tests in login shell context
Expand Down
8 changes: 8 additions & 0 deletions src/console_results.sh
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ function bashunit::console_results::print_snapshot_test() {
function bashunit::console_results::print_error_test() {
local function_name=$1
local error="$2"
local raw_output="${3:-}"

local test_name
test_name=$(bashunit::helper::normalize_test_function_name "$function_name")
Expand All @@ -343,6 +344,13 @@ function bashunit::console_results::print_error_test() {
line="$(printf "${_BASHUNIT_COLOR_FAILED}βœ— Error${_BASHUNIT_COLOR_DEFAULT}: %s
${_BASHUNIT_COLOR_FAINT}%s${_BASHUNIT_COLOR_DEFAULT}\n" "${test_name}" "${error}")"

if [[ -n "$raw_output" ]] && bashunit::env::is_show_output_on_failure_enabled; then
line+="$(printf " %sOutput:%s\n" "${_BASHUNIT_COLOR_FAINT}" "${_BASHUNIT_COLOR_DEFAULT}")"
while IFS= read -r output_line; do
line+="$(printf " %s\n" "$output_line")"
done <<< "$raw_output"
fi

bashunit::state::print_line "error" "$line"
}

Expand Down
6 changes: 6 additions & 0 deletions src/env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ _BASHUNIT_DEFAULT_SKIP_ENV_FILE="false"
_BASHUNIT_DEFAULT_LOGIN_SHELL="false"
_BASHUNIT_DEFAULT_FAILURES_ONLY="false"
_BASHUNIT_DEFAULT_NO_COLOR="false"
_BASHUNIT_DEFAULT_SHOW_OUTPUT_ON_FAILURE="true"

: "${BASHUNIT_PARALLEL_RUN:=${PARALLEL_RUN:=$_BASHUNIT_DEFAULT_PARALLEL_RUN}}"
: "${BASHUNIT_SHOW_HEADER:=${SHOW_HEADER:=$_BASHUNIT_DEFAULT_SHOW_HEADER}}"
Expand All @@ -80,6 +81,7 @@ _BASHUNIT_DEFAULT_NO_COLOR="false"
: "${BASHUNIT_SKIP_ENV_FILE:=${SKIP_ENV_FILE:=$_BASHUNIT_DEFAULT_SKIP_ENV_FILE}}"
: "${BASHUNIT_LOGIN_SHELL:=${LOGIN_SHELL:=$_BASHUNIT_DEFAULT_LOGIN_SHELL}}"
: "${BASHUNIT_FAILURES_ONLY:=${FAILURES_ONLY:=$_BASHUNIT_DEFAULT_FAILURES_ONLY}}"
: "${BASHUNIT_SHOW_OUTPUT_ON_FAILURE:=${SHOW_OUTPUT_ON_FAILURE:=$_BASHUNIT_DEFAULT_SHOW_OUTPUT_ON_FAILURE}}"
# Support NO_COLOR standard (https://no-color.org)
if [[ -n "${NO_COLOR:-}" ]]; then
BASHUNIT_NO_COLOR="true"
Expand Down Expand Up @@ -159,6 +161,10 @@ function bashunit::env::is_failures_only_enabled() {
[[ "$BASHUNIT_FAILURES_ONLY" == "true" ]]
}

function bashunit::env::is_show_output_on_failure_enabled() {
[[ "$BASHUNIT_SHOW_OUTPUT_ON_FAILURE" == "true" ]]
}

function bashunit::env::is_no_color_enabled() {
[[ "$BASHUNIT_NO_COLOR" == "true" ]]
}
Expand Down
6 changes: 6 additions & 0 deletions src/main.sh
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ function bashunit::main::cmd_test() {
--failures-only)
export BASHUNIT_FAILURES_ONLY=true
;;
--show-output)
export BASHUNIT_SHOW_OUTPUT_ON_FAILURE=true
;;
--no-output-on-failure)
export BASHUNIT_SHOW_OUTPUT_ON_FAILURE=false
;;
--strict)
export BASHUNIT_STRICT_MODE=true
;;
Expand Down
12 changes: 9 additions & 3 deletions src/runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -567,9 +567,9 @@ function bashunit::runner::run_test() {
elif [[ -z "$error_message" && -n "$hook_message" ]]; then
error_message="$hook_message"
fi
bashunit::console_results::print_error_test "$failure_function" "$error_message"
bashunit::console_results::print_error_test "$failure_function" "$error_message" "$runtime_output"
bashunit::reports::add_test_failed "$test_file" "$failure_label" "$duration" "$total_assertions"
bashunit::runner::write_failure_result_output "$test_file" "$failure_function" "$error_message"
bashunit::runner::write_failure_result_output "$test_file" "$failure_function" "$error_message" "$runtime_output"
bashunit::internal_log "Test error" "$failure_label" "$error_message"
return
fi
Expand Down Expand Up @@ -760,6 +760,7 @@ function bashunit::runner::write_failure_result_output() {
local test_file=$1
local fn_name=$2
local error_msg=$3
local raw_output="${4:-}"

local line_number
line_number=$(bashunit::helper::get_function_line_number "$fn_name")
Expand All @@ -769,7 +770,12 @@ function bashunit::runner::write_failure_result_output() {
test_nr=$(bashunit::state::get_tests_failed)
fi

echo -e "$test_nr) $test_file:$line_number\n$error_msg" >> "$FAILURES_OUTPUT_PATH"
local output_section=""
if [[ -n "$raw_output" ]] && bashunit::env::is_show_output_on_failure_enabled; then
output_section="\n Output:\n$raw_output"
fi

echo -e "$test_nr) $test_file:$line_number\n$error_msg$output_section" >> "$FAILURES_OUTPUT_PATH"
}

function bashunit::runner::write_skipped_result_output() {
Expand Down
53 changes: 53 additions & 0 deletions tests/acceptance/bashunit_show_output_on_failure_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
set -euo pipefail

function set_up_before_script() {
TEST_ENV_FILE="tests/acceptance/fixtures/.env.default"
}

function test_show_output_on_failure_enabled_by_default() {
local test_file=./tests/acceptance/fixtures/test_bashunit_show_output_on_failure.sh

local actual
actual="$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" 2>&1 || true)"

assert_contains "Output:" "$actual"
assert_contains "Debug: Starting test" "$actual"
assert_contains "Info: About to run command" "$actual"
}

function test_show_output_on_failure_disabled_via_flag() {
local test_file=./tests/acceptance/fixtures/test_bashunit_show_output_on_failure.sh

local actual
actual="$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --no-output-on-failure "$test_file" 2>&1 || true)"

assert_not_contains "Output:" "$actual"
assert_not_contains "Debug: Starting test" "$actual"
}

function test_show_output_on_failure_disabled_via_env() {
local test_file=./tests/acceptance/fixtures/test_bashunit_show_output_on_failure.sh

local actual
actual="$(
BASHUNIT_SHOW_OUTPUT_ON_FAILURE=false \
./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" 2>&1 || true
)"

assert_not_contains "Output:" "$actual"
assert_not_contains "Debug: Starting test" "$actual"
}

function test_show_output_flag_overrides_env() {
local test_file=./tests/acceptance/fixtures/test_bashunit_show_output_on_failure.sh

local actual
actual="$(
BASHUNIT_SHOW_OUTPUT_ON_FAILURE=false \
./bashunit --no-parallel --env "$TEST_ENV_FILE" --show-output "$test_file" 2>&1 || true
)"

assert_contains "Output:" "$actual"
assert_contains "Debug: Starting test" "$actual"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

function test_with_output_before_error() {
echo "Debug: Starting test"
echo "Info: About to run command"
nonexistent_command_xyz
}
Loading