This vignette introduces two functions for generating
roxygen-style listings of your testthat
tests:
document_file(): parses a single test file and
inserts a global listing (after
#' @testsList) and per-section listings
(after each #' @testsSection). The function is
idempotent: re-running replaces only the
@testsItem blocks and leaves the rest untouched.
document(): walks a tests/testthat
directory and calls document_file() for each file,
returning per-file results and a combined table.
The listings are written as roxygen comments:
#' @testsList
#' @testsItem 1 alpha one
#' @testsItem 2 alpha two
#' @testsSection Section A
#' @testsItem 1 alpha one
#' @testsItem 2 alpha two
Why? Quick navigation and auditing of tests; machine- and human-readable structure that integrates with documentation tooling; and predictable, idempotent re-generation inside CI/CD.
Plain section markers (default prefix
"# -"), like # - My Section, are converted to
roxygen markers on-the-fly:
#' @testsSection My SectionAny text following @testsSection on the same line is
the section title.
Global marker: #' @testsList (one
per file; auto-added at top if missing).
Section marker:
#' @testsSection [Optional title] (one or many).
Items: each entry is inserted immediately after the relevant marker:
#' @testsItem <numbering> <title_expression>The first argument to test_that() is recorded as
raw code: - Literals like "alpha one" are kept
without the outer quotes → alpha one. -
Expressions like paste("a", b) or
glue::glue("{x}") are not evaluated and
are listed unchanged.
Use placeholders to control numbering in both the global and section
listings: - {g} — global index (1..N across all tests in
the file) - {s} — section index (1..S) - {i} —
local index within a section (1.. per section) - {l} —
final line number in the modified file (after
insertion) - Aliases: {local} → {i},
{line} → {l}
Two presets: - template = "simple" → "{g}"
- template = "advanced" →
"{g}.{s}.{i}.{l}"
Override with global_fmt and section_fmt
for full control.
document_file()path (character): path to the test file to
process.section_prefix (character): plain-text
section header prefix to convert (default: "# -").template ("simple"|"advanced"|"custom"):
built-in number formats.global_fmt, section_fmt
(character): custom templates using {g},
{s}, {i}, {l} and aliases.encoding (character): file encoding for
read/write (default: "UTF-8").make_backup (logical): if
TRUE, writes a timestamped backup before
overwriting.write (logical): if TRUE,
overwrites the file. Set to FALSE for a dry-run where the
function returns the would-be modified text.A list of class tests_listing_result with: -
text: final modified lines (character vector). -
listing: data frame with columns: - g,
s, i, l (final line number), -
title_raw (cleaned raw title), - section_title
(if any). - written (logical),
backup (path or NULL).
library(testthatdocs)
res <- document_file(
path = system.file("examples", "tests_sample_before.R", package="testthatdocs"),
section_prefix = "# -",
template = "advanced", # or "simple"
encoding = "UTF-8",
backup = TRUE,
write = TRUE
)
# Summary of tests
res$listing
# Modified test file
res$textdocument()Recursively processes a tree of test files (by default,
tests/testthat).
library(testthatdocs)
all_res <- document(
root = system.file("examples", package="testthatdocs"),
template = "advanced",
section_prefix = "# -",
encoding = "UTF-8",
backup = TRUE,
write = TRUE,
quiet = TRUE
)
# Combined table (with 'file' column)
all_res$listingroot (character): directory to walk.
Default "tests/testthat".pattern (character): regex to choose files
("^[Tt]est.*\\.[rR]$").recurse (logical): whether to search
subfolders.exclude (character): basenames to exclude
(default c("testthat.R")).document_file() are passed through
and applied to each file.A list of class tests_listing_dir_result with: -
files: processed file paths, - results:
per-file tests_listing_result objects, -
listing: combined table (adds a file column),
- backups: vector of backup file paths (when
write=TRUE).
@testsItem
blocks immediately following @testsList
and each @testsSection marker.{l} faithful to the ultimate
positions.#' @testsList).#' @testsItem {g=3}{s=2}{i=1}.#' @testsList
is auto-inserted at the top of the file.test_that(), the function is a no-op except ensuring the
global marker exists (if you want to avoid that, run in dry-run).{g} or placeholders: ensure
you’re using the latest version; the implementation rebuilds whole
blocks and performs a global final cleanup.encoding = "UTF-8" (default). For legacy files, pass the
correct encoding to both read & write.{g}, {s},
{i}, {l}) or the aliases
({local}, {line}).quiet = TRUE and run from CI to
avoid excessive console I/O.write = FALSE) to inspect changes before
writing.TBA
In sections # document_file() and #
document()