Instruction file imported from y-miyazaki/arc (
.cursor/rules/bats.mdc). Copyright stays with the author.
Bats Instructions
Scope
- Scope covers authoring Bats suites and applies when editing shell scripts that require pairing a suite.
- Shell script implementation rules remain in the companion Shell Script rules (stem
shell-script); this file defines test-suite conventions only. - When adding or materially changing a shell script or sourced library, add or update the matching Bats suite in the same change (see companion Shell Script rules TEST-00).
- Bats does not mandate a global directory layout — follow the repository's established test tree (discover from existing suites, CI config, or maintainer docs).
Standards
Naming Conventions
| Component | Rule | Example |
|---|---|---|
| Suite file | snake_case; when the repo mirrors paths, match the source under test | lib/common.bats mirroring lib/common.sh |
| Support helper | snake_case .bash under the repository bats support dir when used |
common.bash, mock_cli.bash in support/ |
@test name |
Descriptive sentence (lowercase) | parse_args accepts --verbose flag |
Suite File Structure
Required order for every repository *.bats suite file:
#!/usr/bin/env bats- Optional
# shellcheck disable=…line(s) - Header comment block:
# Tests for <repo-relative path>(required)# Use cases:followed by one# - …bullet per covered scenario (required)
- Optional project support preamble (load shared support when the repository provides it)
- Target constants (
TARGET_SCRIPT,TARGET_LIB, …) when needed setup()— source script(s), export env, create temp stateteardown()— whensetup()creates temp files or dirs@testfunctions in a-z order by test description
Example header:
#!/usr/bin/env bats
# shellcheck disable=SC2030,SC2031,SC2034,SC2154
# Tests for lib/common.sh
#
# Use cases:
# - execute_command runs and logs when VERBOSE=true
# - execute_command dry-run only logs the planned command
# - is_dry_run / log behave for VERBOSE and DRY_RUN flags
When the repository provides shared support (for example support/common.bash), use a walk-up loader such as:
_bats_support="$(dirname "${BATS_TEST_FILENAME}")"
while [[ ! -f "${_bats_support}/support/common.bash" ]]; do
_bats_support="$(dirname "${_bats_support}")"
done
# shellcheck disable=SC1091
source "${_bats_support}/support/common.bash"
Support Library
| Location | Role |
|---|---|
Repository support/common.bash |
Optional shared helpers (source paths, fixtures, temp dirs) |
Repository support/*.bash |
Domain mocks; load from setup() for shared mocks or at the start of individual tests |
Prefer bats-support and bats-assert when the project adopts them.
Guidelines
File Layout (BAT)
- BAT-01 (MUST): Pair Script With Suite
- Check: When the repository pairs shell scripts with Bats suites, is a suite added or updated in the same change as the script or library?
- BAT-01b (SHOULD): Mirror Path When Repository Does
- Check: When the repository mirrors script paths under a bats root, is the suite placed with the same relative path as the script or library under test?
- BAT-02 (MUST): Header Target Path
- Check: Does the header comment name the repo-relative path of the script or library under test?
- BAT-03 (MUST): Header Use Cases
- Check: Does the header include
# Use cases:with one# - …bullet per scenario the suite is meant to guarantee (not a dump of every@testname — group related assertions)?
- Check: Does the header include
- BAT-04 (SHOULD): Shared Support Helpers
- Check: Are repeated setup paths centralized in repository support helpers instead of copied into every suite?
Setup and Teardown (SETUP)
- SETUP-01 (MUST): Source in setup()
- Check: Are targets sourced or invoked from
setup()(or a shared helper), not ad hoc per test?
- Check: Are targets sourced or invoked from
- SETUP-02 (MUST): Teardown Temp State
- Check: Does
teardown()remove files or directories created insetup()(mktemp, mock bins, fixture dirs)?
- Check: Does
- SETUP-03 (SHOULD): Export Before Source
- Check: Are environment variables exported before sourcing when the sourced script reads them at load time?
Test Design (TEST)
- TEST-01 (SHOULD): Unit vs Integration Split
- Check: Are pure functions tested after
setup()sources the script, and CLI flows tested viarun bash "${SCRIPT}" …?
- Check: Are pure functions tested after
- TEST-02 (MUST): Use run for CLI Assertions
- Check: Are CLI exit status and output asserted with Bats
runand$status/$output(or bats-assert equivalents)?
- Check: Are CLI exit status and output asserted with Bats
- TEST-03 (MUST): Subshell for cwd Changes
- Check: Are integration commands that need a different working directory wrapped in
run bash -c 'cd … && …'or an equivalent helper — never barecdimmediately beforerun?
- Check: Are integration commands that need a different working directory wrapped in
- TEST-04 (SHOULD): Test Order
- Check: Are
@testblocks ordered a-z by description (aftersetup/teardown)?
- Check: Are
- TEST-05 (SHOULD): No Duplicate Source
- Check: Is the target script sourced once in
setup()without redundantsourceinside individual tests?
- Check: Is the target script sourced once in
Mocking (MOCK)
- MOCK-01 (SHOULD): Centralize CLI Mocks
- Check: Are external CLI mocks placed under
BATS_TEST_TMPDIRor repository support helpers, withPATHprepended in the test?
- Check: Are external CLI mocks placed under
Anti-Patterns
- Bare
cdimmediately beforerun—runexecutes in a subshell that resets cwd - Mixing relative script paths in integration tests without a repository root helper
- Inconsistent headers — always use the full repo-relative path under test and a
# Use cases:block - Omitting
# Use cases:or leaving it empty when adding or expanding a suite - Real secrets or live tokens in fixtures — use placeholders and assert redaction behavior
- Skipping
teardown()whensetup()writes temp files or directories - Mandating
test/bats/when the repository uses a different bats root — discover and match existing layout
Code Modification Guidelines
- Add or update the paired Bats suite in the same change as the script; follow the repository's established bats layout.
- Reuse repository support helpers; extend shared support instead of copying preamble logic.
- Shell script DOC/header rules remain in the companion Shell Script rules (stem
shell-script); do not duplicate them here.
Testing and Validation
On-demand suite verification: see shell-script-validation skill SKILL.md, or run bats against the changed suite (use the command or path the repository documents).
References: bats-core writing tests, bats-core tutorial. Shell authoring: companion Shell Script rules (stem shell-script).
Security Guidelines
- Do not embed real API keys, tokens, or credentials in
@testfixtures — use obvious placeholders and verify sanitization/redaction where applicable. - Write temporary artifacts only under
BATS_TEST_TMPDIR,mktemp, or ignored paths; remove them inteardown(). - Do not make destructive host paths the default in examples (avoid
rm -rf /patterns); scope file operations to test fixtures.
