Use when starting a test-driven development cycle for R code. Orchestrates r-tdd and r-debugging skills with the r-code-reviewer agent through a guided Red-Green-Refactor-Review workflow. Invoke as /r-cmd-tdd-cycle. Triggers: start TDD, TDD cycle, red green refactor, new feature with tests, test-first workflow, build with tests. Do NOT use for testthat API reference without a full cycle — use r-tdd instead. Do NOT use for debugging existing code — use r-debugging instead.
Guided Red-Green-Refactor-Review workflow for R packages using testthat 3e.
Config/testthat/edition: 3 in DESCRIPTION)usethis::use_testthat(3) firstSkill: r-tdd
Action: Identify the target function name and create the test file with usethis::use_test("feature-name"). Confirm testthat 3e is active.
Gate: Test file exists at tests/testthat/test-feature-name.R.
Skill: r-tdd
Action: Write one or more test_that() blocks that define the desired behavior. Use expect_identical() (3e default), for error cases. Run .
Test runs and FAILS (function does not exist or returns wrong result). If test passes immediately, the test is wrong — rewrite it.
expect_error(class = ...)devtools::test_active_file()Skill: r-tdd
Action: Write the minimum code in R/feature-name.R to make the test pass. Do NOT add logic beyond what the test requires. Run devtools::test_active_file().
Gate: Test runs and PASSES.
Action: Improve code quality — naming, structure, duplication — while keeping tests green. Run devtools::test() to verify no regressions across the package.
Gate: All tests pass. No new warnings.
Agent: r-code-reviewer (scope: full)
Action: Review the new implementation and test files for style, correctness, and performance.
Gate: No CRITICAL findings. HIGH findings addressed.
Skill: r-tdd
Action: Run covr::package_coverage() and check function-level coverage for the new code.
Gate: Coverage >= 80% for new functions.
Prompt: "Add validate_input() that checks a data frame has required columns."
Flow: Setup (create test file) → RED (write test for valid input + missing columns) → GREEN (implement with cli::cli_abort()) → REFACTOR (clean up) → REVIEW (code reviewer) → COVERAGE (verify 80%+)
# RED — test file
test_that("validate_input errors on missing columns", {
df <- tibble::tibble(id = 1:3)
expect_error(
validate_input(df, required = c("id", "value")),
class = "pkg_missing_columns"
)
})
# GREEN — minimal implementation
validate_input <- function(df, required) {
missing <- setdiff(required, names(df))
if (length(missing) > 0) {
cli::cli_abort(
"Column{?s} {.val {missing}} not found in data.",
class = "pkg_missing_columns"
)
}
invisible(df)
}
Prompt: "Fix calc_growth() — it returns NA for single-row groups."
Flow: Setup (open existing test file) → RED (write test exposing the bug — single-row group) → GREEN (add guard for n() > 1) → REFACTOR → REVIEW → COVERAGE
# RED — expose the bug
test_that("calc_growth handles single-row groups", {
df <- tibble::tibble(group = "A", date = as.Date("2024-01-01"), value = 100)
result <- calc_growth(df)
expect_true(is.na(result$growth[1])) # expected NA, not error
})