Skip to content

Conversation

@osenan
Copy link
Contributor

@osenan osenan commented Nov 6, 2025

Pull Request

Fixes #318

Changes

I have added checks for the ui components and modules. For the ui functions, I added input validation, component class and snapshot tests.
For the modules, I added input validation and small unit tests. All modules already have e2e tests.
The e2e tests were already existing but it seems they do not count for the coverage as they are skipped.

We have not reach 100% due to soft_deprecated functions and mainly verbatim_popup_ui which I was not able to increase that much from the previous state.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2025


🎉 Thank you for your contribution! Before this PR can be accepted, we require that you read and agree to our Contributor License Agreement.
You can digitally sign the CLA by posting a comment on this Pull Request in the format shown below. This agreement will apply to this PR as well as all future contributions on this repository.


I have read the CLA Document and I hereby sign the CLA


osenan seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@osenan
Copy link
Contributor Author

osenan commented Nov 6, 2025

I have read the CLA Document and I hereby sign the CLA

@osenan osenan added the core label Nov 6, 2025
@osenan osenan changed the title 318 coverage unit tests@main 318: Increase Coverage beyond 80% Nov 6, 2025
@osenan osenan marked this pull request as ready for review November 6, 2025 15:52
@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2025

Unit Tests Summary

  1 files   16 suites   9s ⏱️
170 tests 140 ✅ 30 💤 0 ❌
281 runs  251 ✅ 30 💤 0 ❌

Results for commit fc77004.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2025

Unit Test Performance Difference

Test Suite $Status$ Time on main $±Time$ $±Tests$ $±Skipped$ $±Failures$ $±Errors$
draggable_buckets 💚 $8.54$ $-8.18$ $+2$ $+3$ $0$ $0$
get_dt_rows_ui 💚 $2.87$ $-2.83$ $-3$ $+1$ $0$ $0$
optionalSelectInput_ui 💚 $3.04$ $-2.84$ $-6$ $+1$ $0$ $0$
optionalSliderInputValMinMax_ui 💚 $2.37$ $-2.34$ $+1$ $+2$ $0$ $0$
plot_with_settings_ui 💚 $53.80$ $-53.60$ $-30$ $+11$ $0$ $0$
table_with_settings_ui 💚 $32.74$ $-32.60$ $-47$ $+8$ $0$ $0$
verbatim_popup_ui 💚 $3.49$ $-3.39$ $-3$ $+3$ $0$ $0$
white_small_well 👶 $+0.03$ $+2$ $+1$ $0$ $0$
Additional test case details
Test Suite $Status$ Time on main $±Time$ Test Case
draggable_buckets 👶 $+0.01$ Snapshot_test_for_ui_component_draggable_buckets
draggable_buckets 💚 $2.41$ $-2.31$ e2e_teal.widgets_draggable_buckets_initializes_with_default_inputs
draggable_buckets 💚 $3.22$ $-3.11$ e2e_teal.widgets_draggable_buckets_initializes_without_input
draggable_buckets 💚 $2.90$ $-2.84$ e2e_teal.widgets_draggable_buckets_moving_elements_between_buckets_updates_input
draggable_buckets 👶 $+0.01$ fails_when_buckets_is_not_from_the_expected_type
draggable_buckets 👶 $+0.04$ fails_when_inputId_is_not_from_the_expected_type
draggable_buckets 👶 $+0.01$ fails_when_label_is_not_from_the_expected_type
get_dt_rows_ui 👶 $+0.02$ Check_class_of_get_dt_rows
get_dt_rows_ui 💚 $2.87$ $-2.84$ e2e_teal.widgets_get_dt_rows_rows_are_settable_and_visible
optionalInput 👶 $+0.01$ if_inputId_is_not_a_string_optionalSliderInputValMinMax_returns_error
optionalInput 👶 $+0.02$ if_inputId_is_not_a_string_returns_an_error
optionalInput 👶 $+0.01$ if_label_is_not_a_string_returns_an_error
optionalInput 👶 $+0.01$ if_options_is_not_a_list_returns_an_error
optionalInput 👶 $+0.01$ if_with_is_not_a_valid_css_unit_returns_an_error
optionalInput 👶 $+0.05$ optionalSelectInput_is_a_Shiny_ui_component
optionalInput 👶 $+0.00$ optionalSliderInputValMinMax_is_a_Shiny_ui_component
optionalInput 👶 $+0.12$ updateOptionalSelectInput_updates_choices_and_selected_values
optionalInput 👶 $+0.01$ value_min_max_with_invalid_length_throws_error
optionalInput 👶 $+0.01$ value_out_of_range_in_value_min_max_throws_error
optionalSelectInput_ui 👶 $+0.13$ Check_optionalSelectInput_is_created_with_different_sep
optionalSelectInput_ui 👶 $+0.01$ Check_optionalSelectInput_is_created_with_label_help
optionalSelectInput_ui 👶 $+0.01$ Check_optionalSelectInput_width_is_applied
optionalSelectInput_ui 👶 $+0.01$ Check_options_for_optionalSelectInput_are_applied
optionalSelectInput_ui 👶 $+0.01$ Check_that_choices_are_empty_if_not_introduced_by_user
optionalSelectInput_ui 💚 $3.04$ $-3.03$ e2e_teal.widgets_optionalSelectInput_initializes
optionalSelectInput_ui 👶 $+0.01$ selected_marks_the_initial_choice
optionalSelectInput_ui 👶 $+0.02$ there_is_js_show_hide_functionality_only_if_fixed_on_single_is_TRUE_and_length_is_more_than_one
optionalSliderInputValMinMax_ui 💚 $2.37$ $-2.36$ e2e_teal.widgets_optionalSliderInputValMinMax_initializes
optionalSliderInputValMinMax_ui 👶 $+0.01$ snapshot_test_for_optionalSliderInput
optionalSliderInputValMinMax_ui 👶 $+0.02$ we_create_label_help_for_optionalSliderInputValMinMax
plot_with_settings_ui 💚 $4.39$ $-4.36$ e2e_teal.widgets_plot_with_settings_buttons_have_proper_FA_icons_and_two_of_them_are_dropdowns
plot_with_settings_ui 💚 $4.22$ $-4.21$ e2e_teal.widgets_plot_with_settings_clicking_download_download_button_downloads_image_in_a_specified_format
plot_with_settings_ui 💚 $5.25$ $-5.24$ e2e_teal.widgets_plot_with_settings_expanded_image_can_be_downloaded
plot_with_settings_ui 💚 $8.57$ $-8.55$ e2e_teal.widgets_plot_with_settings_expanded_image_can_be_resized
plot_with_settings_ui 💚 $3.41$ $-3.41$ e2e_teal.widgets_plot_with_settings_initializes_with_a_plot_and_the_settings_buttons
plot_with_settings_ui 💚 $3.53$ $-3.52$ e2e_teal.widgets_plot_with_settings_it_is_possible_to_set_height_and_width_for_the_plot_on_the_third_button_dropdown_menu_without_errors
plot_with_settings_ui 💚 $4.79$ $-4.77$ e2e_teal.widgets_plot_with_settings_main_image_can_be_resized
plot_with_settings_ui 💚 $5.34$ $-5.32$ e2e_teal.widgets_plot_with_settings_scrollbar_appears_when_image_is_resized
plot_with_settings_ui 💚 $4.38$ $-4.37$ e2e_teal.widgets_plot_with_settings_the_click_on_the_download_button_in_expand_modal_opens_a_download_dropdown
plot_with_settings_ui 💚 $5.25$ $-5.23$ e2e_teal.widgets_plot_with_settings_the_click_on_the_expand_button_opens_an_overlay_plot_height_plot_width_plot_download_dropdown_and_dismiss_button
plot_with_settings_ui 💚 $4.64$ $-4.63$ e2e_teal.widgets_plot_with_settings_the_click_on_the_resize_button_opens_a_dropdown_menu_plot_height_plot_width_plot_download_dropdown_and_dismiss_button
standard_layout 👶 $+0.17$ Tests_for_standard_layout_options_checks_snapshot_with_encoding_and_null_forms
standard_layout 👶 $+0.04$ Tests_for_standard_layout_options_checks_that_the_class_is_correct
table_with_settings_ui 💚 $4.39$ $-4.38$ e2e_teal.widgets_table_with_settings_check_pagination_appearance_for_.txt_and_disappearance_for_.csv_for_the_first_button
table_with_settings_ui 💚 $4.30$ $-4.29$ e2e_teal.widgets_table_with_settings_check_pagination_appearance_for_.txt_and_disappearance_for_.csv_for_the_modal_on_the_second_button
table_with_settings_ui 💚 $3.88$ $-3.87$ e2e_teal.widgets_table_with_settings_clicking_download_download_button_downloads_table_in_a_specified_format
table_with_settings_ui 💚 $4.50$ $-4.48$ e2e_teal.widgets_table_with_settings_clicking_download_in_an_expand_modal_opens_dropdown_menu_with_dwnl_settings_such_as_file_type_file_name_pagination
table_with_settings_ui 💚 $4.34$ $-4.33$ e2e_teal.widgets_table_with_settings_expanded_table_can_be_downloaded
table_with_settings_ui 💚 $3.09$ $-3.08$ e2e_teal.widgets_table_with_settings_is_initialized_with_2_buttons_and_a_table
table_with_settings_ui 💚 $4.17$ $-4.16$ e2e_teal.widgets_table_with_settings_the_click_on_expand_button_opens_a_modal_with_a_table
table_with_settings_ui 💚 $4.04$ $-4.02$ e2e_teal.widgets_table_with_settings_the_click_on_the_download_button_opens_a_download_menu_with_file_type_file_name_and_download_button
verbatim_popup 👶 $+0.01$ button_click_observer_accepts_modal_content_as_reactive
verbatim_popup 👶 $+0.01$ format_content_handles_error_from_reactive_correctly
verbatim_popup 👶 $+0.01$ format_content_handles_reactive_throwing_error
verbatim_popup 👶 $+0.04$ format_content_styles_code_when_style_TRUE
verbatim_popup 👶 $+0.02$ format_content_validates_content_type
verbatim_popup 👶 $+0.01$ format_content_with_character_vector
verbatim_popup 👶 $+0.01$ format_content_with_non_reactive_expression
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_with_disabled_invalid_type_produces_error
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_with_id_not_a_string_produces_error
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_with_style_not_a_flag_produces_error
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_with_title_not_a_string_produces_error
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_with_verbatim_content_invalid_type_produces_error
verbatim_popup 👶 $+0.02$ verbatim_popup_srv_works_with_reactive_verbatim_content
verbatim_popup 👶 $+0.01$ verbatim_popup_srv_works_with_style_TRUE
verbatim_popup 👶 $+0.01$ verbatim_popup_ui_passes_additional_arguments_to_actionButton
verbatim_popup 👶 $+0.01$ verbatim_popup_ui_with_button_label_not_a_string_produces_error
verbatim_popup 👶 $+0.01$ verbatim_popup_ui_with_id_not_a_string_produces_error
verbatim_popup_ui 💚 $3.48$ $-3.48$ e2e_teal.widgets_verbatim_popup_is_initialized_with_a_button_that_opens_a_modal_with_a_verbatim_text
verbatim_popup_ui 👶 $+0.05$ e2e_verbatim_popup_button_can_be_disabled_and_enabled
verbatim_popup_ui 👶 $+0.04$ snapshot_test_for_verbatim_popup_ui
white_small_well 👶 $+0.02$ Check_that_the_class_for_white_small_well_is_correct
white_small_well 👶 $+0.01$ Snapshot_test_for_white_small_well

Results for commit 6c62921

♻️ This comment has been updated with latest results.

@llrs-roche llrs-roche self-assigned this Nov 7, 2025
Copy link
Contributor

@llrs-roche llrs-roche left a comment

Choose a reason for hiding this comment

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

Many new tests! Thanks!

There is no code coverage report because the CI check fails. Please fix it and report the code coverage improvement to check that we get to the 80% goal.

In order to test everything you'll need to have TESTING_DEPTH=5 on your .Renviron (usethis::edit_r_environ("user")). This is to avoid running all the tests and be faster checking the package on some environments .

Some general comments:

  • Do not add nocoverage tags.
  • I see several expect_error() that do not have the error message it expects.
    Add just a couple of key words of the expected error.
  • I see some test with local_edition(3) what does it bring that we can't test otherwise?

@osenan
Copy link
Contributor Author

osenan commented Nov 10, 2025

I have read the CLA Document and I hereby sign the CLA

@github-actions
Copy link
Contributor

github-actions bot commented Nov 10, 2025

badge

Code Coverage Summary

Filename                      Stmts    Miss  Cover    Missing
--------------------------  -------  ------  -------  ------------------------------------------------------
R/basic_table_args.R             23       0  100.00%
R/draggable_buckets.R            87      12  86.21%   116-121, 151-156
R/get_dt_rows.R                  13       0  100.00%
R/ggplot2_args.R                 49       0  100.00%
R/nested_closeable_modal.R       20      20  0.00%    83-103
R/optionalInput.R               255      79  69.02%   190, 315-389, 402-409, 411-416, 434, 436, 501, 583-596
R/panel_group.R                  39      39  0.00%    50-136
R/plot_with_settings.R          309      16  94.82%   299-305, 327, 364, 373-374, 390, 578-579, 581, 583
R/standard_layout.R              52       4  92.31%   90-93
R/table_with_settings.R         158       1  99.37%   100
R/utils.R                         7       0  100.00%
R/verbatim_popup.R              105      35  66.67%   113-114, 116, 124-155
R/white_small_well.R              7       0  100.00%
TOTAL                          1124     206  81.67%

Diff against main

Filename                 Stmts    Miss  Cover
---------------------  -------  ------  --------
R/draggable_buckets.R        0     -75  +86.21%
R/get_dt_rows.R              0     -13  +100.00%
R/optionalInput.R            0    -133  +52.16%
R/standard_layout.R          0     -16  +30.77%
R/verbatim_popup.R           0     -17  +16.19%
R/white_small_well.R         0      -7  +100.00%
TOTAL                        0    -261  +23.22%

Results for commit: fc77004

Minimum allowed coverage is 80%

♻️ This comment has been updated with latest results

@osenan
Copy link
Contributor Author

osenan commented Nov 11, 2025

Hi @llrs-roche I fixed the test. I removed the #nocov comments. The coverage changed and we were not in 80% coverage, so I had to create additional tests. It was challenging but I was able to do it.

Thank you for all your comments, I was able to do it.

I have not added expect_error messages for errors that are not generated in teal.widgets, based on this recommendation

@osenan osenan requested a review from llrs-roche November 11, 2025 18:00
Copy link
Contributor

@llrs-roche llrs-roche left a comment

Choose a reason for hiding this comment

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

Thanks for increasing the test coverage via other ways. I've left some new comments.

- Add error messages for package functions
- Skip tests if they use suggested packages
- Improve disabled button test
diff --git a/tests/testthat/test-draggable_buckets.R b/tests/testthat/test-draggable_buckets.R
index 2decf62..2fbdbc7 100644
--- a/tests/testthat/test-draggable_buckets.R
+++ b/tests/testthat/test-draggable_buckets.R
@@ -104,11 +104,17 @@ testthat::test_that(
 )

 testthat::test_that("fails when inputId is not from the expected type", {
-  expect_error(draggable_buckets(numeric(1), "test_label", "element_1", "bucket_1"))
+  expect_error(
+    draggable_buckets(numeric(1), "test_label", "element_1", "bucket_1"),
+    "Assertion on 'input_id' failed: Must be of type 'string', not 'double'."
+  )
 })

 testthat::test_that("fails when label is not from the expected type", {
-  expect_error(draggable_buckets("my_input_id", numeric(), "element_1", "bucket_1"))
+  expect_error(
+    draggable_buckets("my_input_id", numeric(), "element_1", "bucket_1"),
+    'Assertion on \'inherits(label, "character") || inherits(label, "shiny.tag")\' failed: Must be TRUE.'
+  )
 })

 testthat::test_that("fails when buckets is not from the expected type", {
diff --git a/tests/testthat/test-optionalSliderInputValMinMax_ui.R b/tests/testthat/test-optionalSliderInputValMinMax_ui.R
index b2f24c3..c9d466f 100644
--- a/tests/testthat/test-optionalSliderInputValMinMax_ui.R
+++ b/tests/testthat/test-optionalSliderInputValMinMax_ui.R
@@ -36,6 +36,7 @@ testthat::test_that("we create label help for optionalSliderInputValMinMax", {

 testthat::test_that("snapshot test for optionalSliderInput", {
   testthat::local_edition(3)
+  testthat::skip_if_not_installed("whitr")
   withr::local_seed(1)
   testthat::expect_snapshot(as.character(optionalSliderInput("my slider", "my label", 0, 10, 2)))
 })
diff --git a/tests/testthat/test-standard_layout.R b/tests/testthat/test-standard_layout.R
index 6f7b18e..9813a74 100644
--- a/tests/testthat/test-standard_layout.R
+++ b/tests/testthat/test-standard_layout.R
@@ -44,6 +44,7 @@ describe("Tests for standard_layout options", {
   it("checks snapshot with encoding and null forms", {
     # Given
     mock_layout <- standard_layout(output = mock_output, encoding = mock_form, forms = NULL)
+    testthat::skip_if_not_installed("withr")
     withr::local_seed(1)
     # Then
     testthat::local_edition(3)
diff --git a/tests/testthat/test-verbatim_popup.R b/tests/testthat/test-verbatim_popup.R
index 1d75926..70307ba 100644
--- a/tests/testthat/test-verbatim_popup.R
+++ b/tests/testthat/test-verbatim_popup.R
@@ -211,25 +211,6 @@ testthat::test_that("verbatim_popup_ui passes additional arguments to actionButt
   testthat::expect_true(grepl("custom-class", ui_char))
 })

-# Test verbatim_popup_srv with testServer
-testthat::test_that("verbatim_popup_srv creates observers correctly", {
-  shiny::testServer(
-    app = verbatim_popup_srv,
-    args = list(
-      verbatim_content = "Test content",
-      title = "Test Title",
-      style = FALSE,
-      disabled = shiny::reactiveVal(FALSE)
-    ),
-    expr = {
-      # Verify session is created
-      testthat::expect_type(session, "environment")
-      # Verify namespace function exists
-      testthat::expect_type(session$ns, "closure")
-    }
-  )
-})
-
 # Test verbatim_popup_srv with reactive content
 testthat::test_that("verbatim_popup_srv works with reactive verbatim_content", {
   test_content <- shiny::reactiveVal("Initial content")
diff --git a/tests/testthat/test-verbatim_popup_ui.R b/tests/testthat/test-verbatim_popup_ui.R
index b9ecf33..b4c37a4 100644
--- a/tests/testthat/test-verbatim_popup_ui.R
+++ b/tests/testthat/test-verbatim_popup_ui.R
@@ -86,8 +86,73 @@ testthat::test_that(
   }
 )

+testthat::test_that(
+  "e2e: verbatim_popup button can be disabled and enabled",
+  {
+    skip_if_too_deep(5)
+
+    app <- shiny::shinyApp(
+      ui = bslib::page_fluid(
+        shinyjs::useShinyjs(),
+        verbatim_popup_ui(
+          id = "verbatim_popup",
+          button_label = "Show Popup"
+        ),
+        shiny::actionButton("toggle_disable", "Toggle Disable")
+      ),
+      server = function(input, output, session) {
+        disabled_state <- shiny::reactiveVal(FALSE)
+
+        verbatim_popup_srv(
+          id = "verbatim_popup",
+          verbatim_content = "Test content",
+          title = "Test Title",
+          style = FALSE,
+          disabled = disabled_state
+        )
+
+        shiny::observeEvent(input$toggle_disable, {
+          disabled_state(!disabled_state())
+        })
+      }
+    )
+
+    app_driver <- shinytest2::AppDriver$new(
+      app,
+      name = "verbatim_popup_disabled",
+      variant = "app_driver_vpu_disabled"
+    )
+    app_driver$wait_for_idle(timeout = default_idle_timeout)
+
+    popup_button_selector <- "#verbatim_popup-button"
+
+    # Initially button should be enabled (not disabled)
+    button_html <- app_driver$get_html(popup_button_selector)
+    testthat::expect_false(grepl("disabled", button_html, ignore.case = TRUE))
+
+    # Toggle to disabled state
+    app_driver$click("toggle_disable")
+    app_driver$wait_for_idle(timeout = default_idle_timeout)
+
+    # Button should now be disabled
+    button_html <- app_driver$get_html(popup_button_selector)
+    testthat::expect_true(grepl("disabled", button_html, ignore.case = TRUE))
+
+    # Toggle back to enabled state
+    app_driver$click("toggle_disable")
+    app_driver$wait_for_idle(timeout = default_idle_timeout)
+
+    # Button should be enabled again
+    button_html <- app_driver$get_html(popup_button_selector)
+    testthat::expect_false(grepl("disabled", button_html, ignore.case = TRUE))
+
+    app_driver$stop()
+  }
+)
+
 testthat::test_that("snapshot test for verbatim_popup_ui", {
   testthat::local_edition(3)
+  testthat::skip_if_not_installed("withr")
   withr::local_seed(1)
   testthat::expect_snapshot(verbatim_popup_ui("STH", "STH2"))
 })
@osenan osenan requested a review from llrs-roche November 13, 2025 04:06
Copy link
Contributor

@llrs-roche llrs-roche left a comment

Choose a reason for hiding this comment

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

I checked with André and other packages and we could move the package to the 3rd edition adding the line on DESCRIPTION.

@osenan osenan requested a review from llrs-roche November 13, 2025 14:10
Copy link
Contributor

@llrs-roche llrs-roche left a comment

Choose a reason for hiding this comment

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

Great! Thanks!!

@osenan osenan enabled auto-merge (squash) November 17, 2025 14:01
@osenan osenan merged commit 2cd8e01 into main Nov 17, 2025
23 of 24 checks passed
@osenan osenan deleted the 318_coverage_unit_tests@main branch November 17, 2025 14:06
@github-actions github-actions bot locked and limited conversation to collaborators Nov 17, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Update unit test coverage to be at min 80% coverage

3 participants