In this app the plot is only rendered when the input$n
is updated.
Good App Script
library(whereami)
# Define the UI
ui <- shiny::bootstrapPage(
shiny::uiOutput('ui_n'),
shiny::plotOutput('plot')
)
# Define the server code
server <- function(input, output) {
output$ui_n <- shiny::renderUI({
shiny::numericInput('n', 'Number of obs', 200)
})
# Run only when input$n exists and is changed
output$plot <- shiny::renderPlot({
shiny::req(input$n)
whereami::whereami(tag = 'hist')
graphics::hist(stats::runif(input$n))
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server,options = list(port=6012))
In this app the plot is rendered every time reactive elements in input
are invalidated.
Bad App Script
library(whereami)
# Define the UI
ui <- shiny::bootstrapPage(
shiny::uiOutput('ui_n'),
shiny::plotOutput('plot')
)
# Define the server code
server <- function(input, output) {
output$ui_n <- shiny::renderUI({
shiny::numericInput('n', 'Number of obs', 200)
})
shiny::observe({
# run every time any element in input is invalidated
output$plot <- shiny::renderPlot({
whereami::whereami(tag = 'hist')
graphics::hist(stats::runif(input$n))
})
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
Using reactor
we can test this expectation!
If we run the test on the good app
the test will pass and if we run it on the bad app
then it will fail signaling a problem.
To run a test you can use standard testthat
functions like testthat::test_dir()
, or you can use a reactor
function reactor::test_app()
.
To use test_app
just name the test file reactor-*.R
instead of test-*.R
this will have two benefits.
covr
will not pass the tests. This allows you to run the tests using test_dir
which does have the necessary characteristics to run the tests.covr
and testthat
to run on R CMD CHECK without needing to add skip_*
into the app test files. Reactivity Test Script for Good App
testthat::context("testing reactivity on a good app with reactor")
obj <- init_reactor()%>%
set_chrome_driver(
chromever = '88.0.4324.27'
)
# We run a test with the expectation that the hist tag
# will be triggered once at app startup and once after
# input$n is updated
testthat::describe('good reactive',{
it('reactive hits in plot reactive chunk',{
obj <- obj%>%
set_runapp_args(
appDir = system.file('examples/good_app.R',
package = 'reactor')
)%>%
start_reactor()%>%
set_id_value('n',500)%>%
expect_reactivity(tag = 'hist',count = 2)%>%
kill_app()
})
})
Reactivity Test Script for Bad App
testthat::context("testing reactivity on a bad app with reactor")
# We now run the same test but with the "bad" app
obj <- init_reactor()%>%
set_chrome_driver(
chromever = '88.0.4324.27'
)
testthat::describe('bad reactive',{
it('reactive hits in plot reactive chunk',{
obj%>%
set_runapp_args(
appDir = system.file('examples/bad_app.R',
package = 'reactor')
)%>%
start_reactor()%>%
set_id_value('n',500)%>%
expect_reactivity(tag = 'hist',count = 2)%>%
kill_app()
})
})