Skip to content

Commit 88915bf

Browse files
averissimogogonzo
andauthored
Fixes tests in ReporterCard feature branch (#328)
Manual CI: [![Check 🛠](https://github.com/insightsengineering/teal.reporter/actions/workflows/check.yaml/badge.svg?branch=ci%40redesign%40main)](https://github.com/insightsengineering/teal.reporter/actions/workflows/check.yaml?query=branch%3Aci%40redesign%40main) ### Changes description - Corrects failing tests - [x] `test-Reporter.R` - [x] `test-SimpleReporter.R` - [x] `test-LoadReporterModule.R` - [x] `test-DownloadReportModule.R` - [x] `test-yaml_utils.R` (`{testthat} 3e` deprecation warning) - Improvement on existing tests - No longer dependent on order of tests (each is atomic) - Generates commonly used cards (see `helper-Reporter.R`) - Uses testthat 3^rd edition (taking advantage of `waldo` for better comparisons) - See insightsengineering/NEST-roadmap#65 - Use of `describe/it` to group some tests together --------- Signed-off-by: André Veríssimo <[email protected]> Co-authored-by: Dawid Kałędkowski <[email protected]>
1 parent 43a1f13 commit 88915bf

26 files changed

+588
-342
lines changed

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ Imports:
4141
shinyjs (>= 2.1.0),
4242
shinyWidgets (>= 0.5.1),
4343
sortable (>= 0.5.0),
44-
stats,
4544
tools,
4645
utils,
4746
yaml (>= 1.1.0),
@@ -57,6 +56,7 @@ Suggests:
5756
shinytest2,
5857
testthat (>= 3.2.2),
5958
tinytex,
59+
waldo (>= 0.2.0),
6060
withr (>= 2.0.0)
6161
VignetteBuilder:
6262
knitr,
@@ -77,3 +77,4 @@ Language: en-US
7777
LazyData: true
7878
Roxygen: list(markdown = TRUE)
7979
RoxygenNote: 7.3.2
80+
Config/testthat/edition: 3

NAMESPACE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ S3method(toHTML,default)
2626
S3method(toHTML,gg)
2727
S3method(toHTML,rlisting)
2828
S3method(toHTML,rtables)
29+
S3method(tools::toHTML,ContentBlock)
2930
S3method(ui_editor_block,character)
3031
S3method(ui_editor_block,default)
3132
export("metadata<-")
@@ -53,7 +54,6 @@ export(rmd_outputs)
5354
export(simple_reporter_srv)
5455
export(simple_reporter_ui)
5556
export(srv_editor_block)
56-
export(toHTML.ContentBlock)
5757
export(ui_editor_block)
5858
importFrom(R6,R6Class)
5959
importFrom(checkmate,assert_string)

R/AddCardModule.R

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,14 +185,23 @@ add_card_button_srv <- function(id, reporter, card_fun) {
185185
type = "error"
186186
)
187187
} else {
188-
checkmate::assert_class(card, "ReportCard")
189-
if (!has_comment_arg && length(input$comment) > 0 && input$comment != "") {
190-
card$append_text("Comment", "header3")
191-
card$append_text(input$comment)
192-
}
188+
checkmate::assert_multi_class(card, c("ReportCard", "ReportDocument"))
189+
if (inherits(card, "ReportCard")) {
190+
if (!has_comment_arg && length(input$comment) > 0 && input$comment != "") {
191+
card$append_text("Comment", "header3")
192+
card$append_text(input$comment)
193+
}
193194

194-
if (!has_label_arg && length(input$label) == 1 && input$label != "") {
195-
card$set_name(input$label)
195+
if (!has_label_arg && length(input$label) == 1 && input$label != "") {
196+
card$set_name(input$label)
197+
}
198+
} else if (inherits(card, "ReportDocument")) {
199+
if (!has_comment_arg && length(input$comment) > 0 && input$comment != "") {
200+
card <- c(card, "### Comment", input$comment)
201+
}
202+
if (!has_label_arg && length(input$label) == 1 && input$label != "") {
203+
metadata(card, "title") <- input$label
204+
}
196205
}
197206

198207
reporter$append_cards(list(card))

R/DownloadModule.R

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ download_report_button_srv <- function(id,
152152
#' Render the report and zip the created directory.
153153
#'
154154
#' @param reporter (`Reporter`) instance.
155+
#' @param yaml_header (`named list`) with `Rmd` `yaml` header fields and their values.
155156
#' @param global_knitr (`list`) a global `knitr` parameters, like echo.
156157
#' But if local parameter is set it will have priority.
157158
#' @param file (`character(1)`) where to copy the returned directory.
@@ -266,7 +267,13 @@ report_render <- function(reporter, yaml_header, global_knitr = getOption("teal.
266267
args <- list(...)
267268

268269
# Create output file with report, code and outputs
269-
input_path <- to_rmd(reporter, yaml_header, global_knitr, output_dir, include_echo = TRUE)
270+
input_path <- to_rmd(
271+
reporter,
272+
output_dir,
273+
yaml_header = yaml_header,
274+
global_knitr = global_knitr,
275+
include_echo = TRUE
276+
)
270277
args <- append(args, list(
271278
input = input_path,
272279
output_dir = output_dir,
@@ -281,7 +288,13 @@ report_render <- function(reporter, yaml_header, global_knitr = getOption("teal.
281288
file.remove(input_path)
282289

283290
# Create .Rmd file
284-
to_rmd(reporter, yaml_header, global_knitr, output_dir, include_echo = FALSE) # TODO remove eval=FALSE also
291+
to_rmd(
292+
reporter,
293+
output_dir,
294+
yaml_header = yaml_header,
295+
global_knitr = global_knitr,
296+
include_echo = FALSE
297+
) # TODO remove eval=FALSE also
285298
output_dir
286299
}
287300

@@ -298,12 +311,13 @@ to_rmd.default <- function(block, output_dir, ...) {
298311

299312
#' @method to_rmd Reporter
300313
#' @keywords internal
301-
to_rmd.Reporter <- function(reporter,
314+
to_rmd.Reporter <- function(block,
315+
output_dir,
302316
yaml_header,
303317
global_knitr = getOption("teal.reporter.global_knitr"),
304-
output_dir,
305-
include_echo) {
306-
blocks <- reporter$get_blocks()
318+
include_echo,
319+
...) {
320+
blocks <- block$get_blocks()
307321

308322
checkmate::assert_list(
309323
blocks,

R/Editor.R

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
#' @rdname srv_editor_block
12
#' @export
23
ui_editor_block <- function(id, value) {
34
UseMethod("ui_editor_block", value)
45
}
56

7+
#' UI and Server functions for editing report document blocks
8+
#'
9+
#' These functions provide a user interface and server logic for editing and extending
10+
#' the editor functionality to support new data types.
11+
#' @param id (`character(1)`) A unique identifier for the module.
12+
#' @param value The content of the block to be edited. It can be a character string or other types.
13+
#' @export
614
#' @export
715
srv_editor_block <- function(id, value) {
816
UseMethod("srv_editor_block", value)
@@ -12,7 +20,7 @@ srv_editor_block <- function(id, value) {
1220
ui_editor_block.default <- function(id, value) {
1321
shiny::tags$div(
1422
shiny::tags$h6(
15-
tags$span(
23+
shiny::tags$span(
1624
class = "fa-stack small text-muted",
1725
# style = "width: 2em;", # necessary to avoid extra space after icon
1826
shiny::icon("pencil", class = "fa-stack-1x"),
@@ -40,7 +48,7 @@ ui_editor_block.character <- function(id, value) {
4048

4149
#' @export
4250
srv_editor_block.character <- function(id, value) {
43-
shiny::moduleServer(id, function(input, output, session) reactive(input$content))
51+
shiny::moduleServer(id, function(input, output, session) shiny::reactive(input$content))
4452
}
4553

4654
ui_report_document_editor <- function(id, value) {
@@ -75,7 +83,7 @@ srv_report_document_editor <- function(id, card_r) {
7583

7684
if (!block_name %in% names(card_r())) { # Only adds UI if not already rendered
7785
new_block_ui <- ui_editor_block(session$ns(new_block_id), value = block_content)
78-
insertUI(sprintf("#%s", session$ns("blocks")), where = "beforeEnd", ui = new_block_ui)
86+
shiny::insertUI(sprintf("#%s", session$ns("blocks")), where = "beforeEnd", ui = new_block_ui)
7987
}
8088
})
8189
})
@@ -109,7 +117,7 @@ ui_previewer_card_actions <- function(id) {
109117
}
110118

111119
srv_previewer_card_actions <- function(id, card_r, card_id, reporter) {
112-
moduleServer(id, function(input, output, session) {
120+
shiny::moduleServer(id, function(input, output, session) {
113121
new_card_rv <- shiny::reactiveVal()
114122

115123
shiny::observeEvent(input$edit_action, {
@@ -119,18 +127,18 @@ srv_previewer_card_actions <- function(id, card_r, card_id, reporter) {
119127
title <- metadata(template_card, "title")
120128

121129
if (isFALSE(nzchar(title))) {
122-
title <- tags$span(class = "text-muted", "(empty title)")
130+
title <- shiny::tags$span(class = "text-muted", "(empty title)")
123131
}
124132

125133
shiny::showModal(
126134
shiny::modalDialog(
127-
title = tags$span(
135+
title = shiny::tags$span(
128136
class = "edit_title_container",
129137
"Editing Card:",
130138
shiny::tags$span(id = session$ns("static_title"), title),
131139
shiny::actionButton(
132140
session$ns("edit_title"),
133-
label = tags$span(shiny::icon("pen-to-square"), "edit title"),
141+
label = shiny::tags$span(shiny::icon("pen-to-square"), "edit title"),
134142
class = "fs-6",
135143
title = "Edit title"
136144
),
@@ -157,7 +165,7 @@ srv_previewer_card_actions <- function(id, card_r, card_id, reporter) {
157165

158166
block_input_names_rvs <- srv_report_document_editor("editor", new_card_rv)
159167

160-
observeEvent(input$edit_title, {
168+
shiny::observeEvent(input$edit_title, {
161169
shinyjs::hide("edit_title")
162170
shinyjs::hide("static_title")
163171
shinyjs::show("new_title")
@@ -169,7 +177,7 @@ srv_previewer_card_actions <- function(id, card_r, card_id, reporter) {
169177
new_card <- new_card_rv()
170178
input_r <- Filter(Negate(is.null), shiny::reactiveValuesToList(block_input_names_rvs))
171179
for (name in names(input_r)) {
172-
new_card[[name]] <- isolate(input_r[[name]]())
180+
new_card[[name]] <- shiny::isolate(input_r[[name]]())
173181
}
174182
if (isFALSE(is.null(input$new_title))) {
175183
metadata(new_card, "title") <- input$new_title
@@ -202,7 +210,7 @@ srv_previewer_card_actions <- function(id, card_r, card_id, reporter) {
202210
# Handle remove button
203211
shiny::observeEvent(input$remove_action, reporter$remove_cards(ids = card_id))
204212

205-
observeEvent( # Hide button for deprecated objects
213+
shiny::observeEvent( # Hide button for deprecated objects
206214
card_r(),
207215
once = TRUE,
208216
handlerExpr = {

R/Previewer.R

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,9 @@ reporter_previewer_cards_ui <- function(id) {
135135
ns <- shiny::NS(id)
136136
shiny::tags$div(
137137
id = "reporter_previewer",
138-
tags$div(
138+
shiny::tags$div(
139139
id = ns("empty_reporters"),
140-
tags$h4(
140+
shiny::tags$h4(
141141
class = "text-muted",
142142
shiny::icon("circle-info"),
143143
"No reports have been added yet."
@@ -148,7 +148,7 @@ reporter_previewer_cards_ui <- function(id) {
148148
}
149149

150150
reporter_previewer_cards_srv <- function(id, reporter) {
151-
moduleServer(id, function(input, output, session) {
151+
shiny::moduleServer(id, function(input, output, session) {
152152
current_ids_rv <- shiny::reactiveVal()
153153
queues_rv <- list(insert = shiny::reactiveVal(), remove = shiny::reactiveVal())
154154

@@ -174,7 +174,7 @@ reporter_previewer_cards_srv <- function(id, reporter) {
174174
current_ids_rv(c(current_ids_rv(), card_id))
175175
reporter_previewer_card_srv(
176176
id = card_id,
177-
card_r = reactive(reporter$get_cards()[[card_id]]),
177+
card_r = shiny::reactive(reporter$get_cards()[[card_id]]),
178178
card_id = card_id,
179179
reporter = reporter
180180
)
@@ -192,7 +192,7 @@ reporter_previewer_card_ui <- function(id, card_id) {
192192
accordion_item <- bslib::accordion_panel(
193193
value = card_id,
194194
title = shiny::tags$label(shiny::uiOutput(ns("title"))),
195-
tags$h6(id = ns("loading_placeholder"), class = "text-muted", "Loading the report..."),
195+
shiny::tags$h6(id = ns("loading_placeholder"), class = "text-muted", "Loading the report..."),
196196
shiny::uiOutput(ns("card_content"))
197197
)
198198
accordion_item <- htmltools::tagAppendAttributes(accordion_item, "data-rank-id" = card_id)
@@ -214,14 +214,14 @@ reporter_previewer_card_srv <- function(id, card_r, card_id, reporter) {
214214
# todo: card_name should be only on the server side
215215
shiny::moduleServer(id, function(input, output, session) {
216216
output$title <- shiny::renderUI({
217-
title <- metadata(req(card_r()), "title")
217+
title <- metadata(shiny::req(card_r()), "title")
218218
if (isFALSE(nzchar(title))) {
219-
title <- tags$span("(empty title)", class = "text-muted")
219+
title <- shiny::tags$span("(empty title)", class = "text-muted")
220220
}
221221
title
222222
})
223223
output$card_content <- shiny::renderUI({
224-
result <- toHTML(req(card_r()))
224+
result <- toHTML(shiny::req(card_r()))
225225
shiny::removeUI(sprintf("#%s", session$ns("loading_placeholder")))
226226
result
227227
})
@@ -249,8 +249,10 @@ toHTML.default <- function(x, ...) {
249249
shiny::HTML(commonmark::markdown_html(x, extensions = TRUE))
250250
}
251251

252+
#' Convert a `ContentBlock` to HTML
253+
#' @inheritParams tools::toHTML
252254
#' @keywords internal
253-
#' @export
255+
#' @exportS3Method tools::toHTML
254256
toHTML.ContentBlock <- function(x, ...) {
255257
UseMethod("toHTML", x$get_content()) # Further dispatch for subclasses
256258
}

R/ReportDocument.R

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,20 @@ c.ReportDocument <- function(...) {
6565
out
6666
}
6767

68+
#' Access metadata from a `ReportDocument` or `ReportCard`
69+
#'
70+
#' This function retrieves metadata from a `ReportDocument` or `ReportCard` object.
71+
#' When `which` is `NULL`, it returns all metadata fields as a list.
72+
#' @param object (`ReportDocument` or `ReportCard`) The object from which to extract metadata.
73+
#' @param which (`character` or `NULL`) The name of the metadata field to extract.
74+
#' @return A list of metadata fields or a specific field if `which` is provided.
6875
#' @export
6976
metadata <- function(object, which = NULL) {
7077
checkmate::assert_string(which, null.ok = TRUE)
7178
UseMethod("metadata", object)
7279
}
7380

81+
#' @rdname metadata
7482
#' @export
7583
metadata.ReportDocument <- function(object, which = NULL) {
7684
metadata <- attr(object, which = "metadata", exact = TRUE)
@@ -81,6 +89,7 @@ metadata.ReportDocument <- function(object, which = NULL) {
8189
result[[which]]
8290
}
8391

92+
#' @rdname metadata
8493
#' @export
8594
metadata.ReportCard <- function(object, which = NULL) {
8695
# TODO: soft deprecate
@@ -91,20 +100,32 @@ metadata.ReportCard <- function(object, which = NULL) {
91100
result[[which]]
92101
}
93102

103+
#' Set metadata for a `ReportDocument` or `ReportCard`
104+
#'
105+
#' This function allows you to set or modify metadata fields in a `ReportDocument` or `ReportCard` object.
106+
#' It can be used to add new metadata or update existing fields.
107+
#' @param object (`ReportDocument` or `ReportCard`) The object to modify.
108+
#' @param which (`character`) The name of the metadata field to set.
109+
#' @param value The value to assign to the specified metadata field.
110+
#' @return The modified object with updated metadata.
94111
#' @export
95112
`metadata<-` <- function(object, which, value) {
96113
checkmate::assert_string(which)
97114
UseMethod("metadata<-", object)
98115
}
99116

117+
#' @rdname metadata-set
100118
#' @export
101119
`metadata<-.ReportDocument` <- function(object, which, value) {
102-
attr(object, which = "metadata") <- modifyList(
120+
attr(object, which = "metadata") <- utils::modifyList(
103121
metadata(object), structure(list(value), names = which)
104122
)
105123
object
106124
}
107125

126+
#' @rdname metadata-set
127+
#' @details
128+
#' The `ReportCard` class only supports the `title` field in metadata.
108129
#' @export
109130
`metadata<-.ReportCard` <- function(object, which, value) {
110131
if (which != "title") {

0 commit comments

Comments
 (0)