diff --git a/R/module_init_data.R b/R/module_init_data.R index 8c09936a7..f2a39ce6e 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -126,11 +126,18 @@ srv_init_data <- function(id, data) { vapply( datanames, function(dataname, datasets) { - hash <- rlang::hash(data[[dataname]]) + x <- data[[dataname]] + + code <- if (is.function(x) && !is.primitive(x)) { + x <- deparse1(x) + bquote(rlang::hash(deparse1(.(as.name(dataname))))) + } else { + bquote(rlang::hash(.(as.name(dataname)))) + } sprintf( "stopifnot(%s == %s) # @linksto %s", - deparse1(bquote(rlang::hash(.(as.name(dataname))))), - deparse1(hash), + deparse1(code), + deparse1(rlang::hash(x)), dataname ) }, diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index b8878e566..ed01caaef 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -70,6 +70,8 @@ testthat::describe("srv_teal lockfile", { "creation process is invoked for teal.lockfile.mode = \"enabled\" ", "and snapshot is copied to teal_app.lock and removed after session ended" ), { + testthat::skip_if_not_installed("mirai") + testthat::skip_if_not_installed("renv") withr::with_options( list(teal.lockfile.mode = "enabled"), { @@ -95,6 +97,8 @@ testthat::describe("srv_teal lockfile", { ) }) testthat::it("creation process is not invoked for teal.lockfile.mode = \"disabled\"", { + testthat::skip_if_not_installed("mirai") + testthat::skip_if_not_installed("renv") withr::with_options( list(teal.lockfile.mode = "disabled"), { @@ -2280,44 +2284,127 @@ testthat::describe("Datanames with special symbols", { }) testthat::it("(when used as non-native pipe) are present in datanames in the pre-processing code", { - testthat::expect_warning( - shiny::testServer( - app = srv_teal, - args = list( - id = "test", - data = within( - teal.data::teal_data(), - { - iris <- iris - mtcars <- mtcars - `%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) - iris <- iris %cbind% data.frame("new_column") - } - ), - modules = modules( - module("module_1", server = function(id, data) data, , datanames = c("iris")) - ), - filter = teal_slices( - module_specific = TRUE - ) + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = within( + teal.data::teal_data(), + { + iris <- iris + mtcars <- mtcars + `%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) + iris <- iris %cbind% data.frame("new_column") + } ), - expr = { - session$setInputs("teal_modules-active_tab" = "module_1") - session$flushReact() + modules = modules( + module("module_1", server = function(id, data) data, , datanames = c("iris")) + ), + filter = teal_slices( + module_specific = TRUE + ) + ), + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() - testthat::expect_contains( - strsplit( - x = teal.code::get_code(modules_output$module_1()()), - split = "\n" - )[[1]], - c( - "`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)", - ".raw_data <- list2env(list(iris = iris))" + testthat::expect_contains( + strsplit( + x = teal.code::get_code(modules_output$module_1()()), + split = "\n" + )[[1]], + c( + "`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)", + ".raw_data <- list2env(list(iris = iris))" + ) + ) + } + ) + }) +}) + +testthat::describe("teal.data code with a function defined", { + testthat::it("is fully reproducible", { + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = reactive(within(teal.data::teal_data(), { + fun <- function(x) { + y <- x + 1 + y + 3 + } + })), + modules = modules(module("module_1", server = function(id, data) data)) + ), , + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() + + # Need to evaluate characters to preserve indentation + local_env <- new.env(parent = .GlobalEnv) + dat <- modules_output$module_1()() + + eval( + parse(text = teal.code::get_code(dat)), + envir = local_env + ) + + testthat::expect_identical(local_env$fun(1), 5) + testthat::expect_identical(local_env$fun(1), dat[["fun"]](1)) + } + ) + }) + + testthat::it("has the correct code (with hash)", { + shiny::testServer( + app = srv_teal, + args = list( + id = "test", + data = reactive(within(teal.data::teal_data(), { + fun <- function(x) { + y <- x + 1 + y + 3 + } + })), + modules = modules(module("module_1", server = function(id, data) data)) + ), , + expr = { + session$setInputs("teal_modules-active_tab" = "module_1") + session$flushReact() + + # Need to evaluate characters to preserve indentation + local_env <- new.env(parent = .GlobalEnv) + eval( + parse( + text = paste( + sep = "\n", + "fun <- function(x) {", + " y <- x + 1", + " y + 3", + "}" ) + ), + envir = local_env + ) + local(hash <- rlang::hash(deparse1(fun)), envir = local_env) + + testthat::expect_setequal( + trimws(strsplit( + x = teal.code::get_code(modules_output$module_1()()), + split = "\n" + )[[1]]), + c( + "fun <- function(x) {", + "y <- x + 1", + "y + 3", + "}", + sprintf("stopifnot(rlang::hash(deparse1(fun)) == \"%s\")", local_env$hash), + ".raw_data <- list2env(list(fun = fun))", + "lockEnvironment(.raw_data)" ) - } - ), - "'package:teal' may not be available when loading" + ) + } ) }) }) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 4904c4646..41c06581b 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,4 +1,5 @@ testthat::test_that("get_teal_bs_theme", { + testthat::skip_if_not_installed("bslib") testthat::expect_true(is.null(get_teal_bs_theme())) withr::with_options(list("teal.bs_theme" = bslib::bs_theme(version = "5")), { testthat::expect_s3_class(get_teal_bs_theme(), "bs_theme")