Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7d53cdf
covr support
radbasa Jan 25, 2023
50a3ddb
removed box environment clearing
radbasa Jan 25, 2023
f25ce9d
version number change as suggested
radbasa Jan 25, 2023
fbb3d46
added filter pattern to list.files for test_files to only get test-??…
radbasa Jan 25, 2023
0134024
exposed covr::file_coverage parameters
radbasa Jan 25, 2023
ffceaf9
github spell check complained about covr
radbasa Jan 25, 2023
019be63
let covr_r search for test files recursively
radbasa Jan 27, 2023
ec28a9e
remove extra "a"
radbasa Jan 27, 2023
5a772e9
add purge_box_cache() before any tests are run to clear the environme…
radbasa Feb 3, 2023
eeb1a57
Merge branch 'fix/purge-box-cache-in-test_r' into feature/covr-support
radbasa Feb 3, 2023
a335bfa
rationalize versions
radbasa Feb 3, 2023
9f3ec62
news entry
radbasa Feb 3, 2023
d2daa72
Merge branch 'main' into feature/covr-support
radbasa Feb 3, 2023
ca72da7
Merge branch 'main' into feature/covr-support
radbasa May 11, 2026
771676c
provide covr support to Rhino apps
radbasa May 11, 2026
414a350
lint
radbasa May 11, 2026
c056da8
add covr dependency
radbasa May 11, 2026
7b14376
fix package dependency issues
radbasa May 11, 2026
829e27b
more package dependecy issues
radbasa May 11, 2026
08cb4ff
package dependency fix again
radbasa May 11, 2026
8b0c4f6
try test coverage only on ubuntu-release
radbasa May 11, 2026
bc5f6ae
fix a step conditional
radbasa May 11, 2026
e31dc54
skip covr test on covr run
radbasa May 11, 2026
d03964a
revert ci to existing. add covr minimum version
radbasa May 11, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ jobs:
Rscript -e "rhino::build_sass()"
Rscript -e "rhino::build_js()"
Rscript -e "rhino::test_r()"
Rscript -e "rhino::covr_r()"

- name: Cypress e2e tests should confirm RhinoApp works
if: runner.os != 'Windows'
Expand Down
8 changes: 5 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: rhino
Title: A Framework for Enterprise Shiny Applications
Version: 1.11.0.9000
Version: 1.11.0.9001
Authors@R:
c(
person("Kamil", "Żyła", role = c("aut", "cre"), email = "opensource+kamil@appsilon.com"),
Expand All @@ -19,7 +19,6 @@ BugReports: https://github.com/Appsilon/rhino/issues
License: LGPL-3
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.2
Depends:
R (>= 2.10)
Imports:
Expand All @@ -29,6 +28,7 @@ Imports:
callr,
cli,
config,
covr (>= 3.6.5),
fs,
glue,
lintr (>= 3.0.0),
Expand All @@ -44,7 +44,8 @@ Imports:
withr,
yaml
Suggests:
covr,
DT,
htmltools,
knitr,
lifecycle,
mockery,
Expand All @@ -58,3 +59,4 @@ LazyData: true
Config/testthat/edition: 3
Config/testthat/parallel: true
Language: en-US
Config/roxygen2/version: 8.0.0
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export(app)
export(auto_test_r)
export(build_js)
export(build_sass)
export(covr_r)
export(covr_report)
export(devmode)
export(diagnostics)
export(format_js)
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

1. Added `AGENTS.md` with repository guidance for AI coding agents.
2. Fixed: `main.R` template imports functions in alphabetical order.
3. Added `covr_r()` and `covr_report()` to execute test coverage for Rhino applications using `{covr}`.

# [rhino 1.11.0](https://github.com/Appsilon/rhino/releases/tag/v1.11.0)

Expand Down Expand Up @@ -94,6 +95,8 @@ to allow using `npm` alternatives like `bun` and `pnpm`.
This removes the need for `box::reload()` calls in tests.
2. Added support for `shinymanager`.

1. Adds `covr` support for `rhino` apps.

# [rhino 1.3.0](https://github.com/Appsilon/rhino/releases/tag/v1.3.0)

1. Rhino now works with `shinytest2` out of the box.
Expand Down
76 changes: 76 additions & 0 deletions R/tools.R
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,82 @@ test_e2e <- function(interactive = FALSE) {
}
}

#' Run a unit test coverage check
#'
#' Uses the `{covr}` package to produce unit test coverage reports.
#' Uses the `{testhat}` package to run all unit tests in `tests/testthat` directory.
#'
#' @param source_files Character vector of source files with function definitions to measure
#' coverage. Defaults to all `.R` files in the `app` tree.
#' @param test_files Character vector of test files with code to test the functions. Defaults to
#' all test files in `tests/testthat` with the `test-<name>.R` filename pattern.
#' @param line_exclusions passed to `covr::file_coverage`
#' @param function_exclusions passed to `covr::file_coverage`
#' @return A `covr` coverage dataset.
#'
#' @examples
#' if (interactive()) {
#' # Run a test coverage check for the entire rhino app
#' # using all tests in the `tests/testthat` directory.
#' covr_r()
#' }
#'
#' @export
covr_r <- function(
source_files = list.files("app",
pattern = "\\.[rR]$",
full.names = TRUE,
recursive = TRUE),
test_files = list.files("tests/testthat",
pattern = "^test-.*\\.R",
full.names = TRUE,
recursive = TRUE),
line_exclusions = NULL,
function_exclusions = NULL) {

withr::with_file("box_loader.R", {
module_list <- sub(
"__init__",
"`__init__`",
paste0(tools::file_path_sans_ext(source_files), ",")
)

loader_lines <- c("box::use(", module_list, ")")

writeLines(loader_lines, "box_loader.R")

coverage <- covr::file_coverage(
source_files = "box_loader.R",
test_files = test_files,
line_exclusions = line_exclusions,
function_exclusions = function_exclusions
)
})

coverage
}

#' Display rhino test coverage results using a standalone report
#'
#' Uses the `{covr}` package to produce unit test coverage reports.
#' Uses the `{testhat}` package to run all unit tests in `tests/testthat` directory.
#'
#' @param rhino_coverage a rhino coverage dataset, defaults to `covr_r()`.
#' @param ... additional arguments to pass to
#' [`covr::report()`](https://covr.r-lib.org/reference/report.html)
#' @return None. This function is called for side effects.
#'
#' @examples
#' if (interactive()) {
#' # Run a test coverage report on a rhino app
#' covr_report()
#' }
#'
#' @export
covr_report <- function(rhino_coverage = covr_r(), ...) {
covr::report(x = rhino_coverage, ...)
}

#' Development mode
#'
#' Run application in development mode with automatic rebuilding and reloading.
Expand Down
41 changes: 41 additions & 0 deletions man/covr_r.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions man/covr_report.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tests/e2e/app-files/main.R
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add missing line at the end.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# nolint start
box::use(
rhino[log, react_component],
shiny,
Expand All @@ -23,3 +24,4 @@ server <- function(id) {
hello$server("hello")
})
}
# nolint end
3 changes: 3 additions & 0 deletions tests/e2e/test-covr_r.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

expect_no_error(rhino::covr_r())
expect_no_error(rhino::covr_report())
4 changes: 4 additions & 0 deletions tests/testthat/helpers/hello.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#' @export
hello <- function() {
"Check out Rhino docs!"
}
34 changes: 34 additions & 0 deletions tests/testthat/helpers/main.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# nolint start
box::use(
shiny[NS, bootstrapPage, div, moduleServer, renderUI, tags, uiOutput],
)

box::use(
app/logic/hello[hello],
)

#' @export
ui <- function(id) {
ns <- NS(id)
bootstrapPage(
uiOutput(ns("message"))
)
}

#' @export
server <- function(id) {
moduleServer(id, function(input, output, session) {
output$message <- renderUI({
div(
style = "display: flex; justify-content: center; align-items: center; height: 100vh;",
tags$h1(
tags$a(
hello(),
href = "https://appsilon.github.io/rhino/"
)
)
)
})
})
}
# nolint end
8 changes: 8 additions & 0 deletions tests/testthat/helpers/test-hello.R
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to cover two additional cases:

  1. Function imported with module$function (so a more basic one).
  2. Private function (with the second pattern from box guide).
    I have run some manual tests, and it works, but it is important to have the test case to monitor it.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
box::use(testthat[describe, expect_identical, it], )
box::use(app/logic/hello[hello], )

describe("hello()", {
it("should return the welcome message", {
expect_identical(hello(), "Check out Rhino docs!")
})
})
32 changes: 32 additions & 0 deletions tests/testthat/test-tools.R
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,35 @@ test_that("build_sass_r builds a minified CSS file out of a Sass file", {
".components-container{display:inline-grid;grid-template-columns:1fr 1fr;width:100%}.components-container .component-box{padding:10px;margin:10px}" # nolint: line_length_linter
)
})

test_that("covr_r runs a coverage test on a rhino app.", {
skip_on_covr()
wd <- getwd()

withr::with_tempdir({
fs::dir_create("app")
fs::dir_create("app", "logic")
fs::dir_create("tests", "testthat")

fs::file_copy(
fs::path(wd, "helpers", "main.R"),
fs::path("app", "main.R")
)

fs::file_copy(
fs::path(wd, "helpers", "hello.R"),
fs::path("app", "logic", "hello.R")
)

fs::file_copy(
fs::path(wd, "helpers", "test-hello.R"),
fs::path("tests", "testthat", "test-hello.R")
)

box::purge_cache()
configure_box()

expect_no_error(covr_r())
expect_no_error(covr_report())
})
})
Loading