For R packages that have Shiny applications, there are generally two
ways that the applications will be present in the package. The first is
to have an app.R
in a subdirectory of inst/
.
The second way is to have a function which returns a Shiny app
object.
inst/
An application could live in a subdirectory of inst/
, as
shown below:
/
├── DESCRIPTION
├── NAMESPACE
├── R
├── inst
│ └── sample_app
│ ├── app.R
│ └── tests
│ ├── testthat
│ │ ├── _snaps
│ │ │ └── shinytest2
│ │ │ └── 001.json
│ │ └── test-shinytest2.R
│ └── testthat.R
└── tests
├── testthat
│ └── test-inst-apps.R
└── testthat.R
In this case, you can run record_test()
and
test_app()
as normal. After you create and run the tests,
there will be a tests/
subdirectory in the application
directory that stores the test scripts and results.
Since we are using {testthat}
for automated tests, you
would create a test driver script in tests/testthat/
. In
this example, it’s named test-inst-apps.R
and contains the
following:
# File: tests/testthat/test-inst-apps.R
library(shinytest2)
test_that("sample_app works", {
# Don't run these tests on the CRAN build servers
skip_on_cran()
appdir <- system.file(package = "exPackage", "sample_app")
test_app(appdir)
})
If the application directory is not meant to be public, it can also
be located in ./tests/testthat/apps
.
{shinytest2}
does this with many application and has
appdir
above point to the relative path to the
application.
The second way have an application in an R package is by having a
function that returns a Shiny application object. In this example,
there’s a function hello_world_app()
, which lives in
R/hello-world.R
:
/
├── .Rbuildignore
├── DESCRIPTION
├── NAMESPACE
├── R
│ └── hello-world.R
└── tests
├── testthat
│ ├── _snaps
│ │ └── app-function
│ │ └── 001.json
│ └── test-app-function.R
└── testthat.R
The function simply returns an object from
shinyApp()
:
# File: R/hello-world.R
hello_world_app <- function() {
utils::data(cars)
shinyApp(
ui = fluidPage(
sliderInput("n", "n", 1, nrow(cars), 10),
plotOutput("plot")
),
server = function(input, output) {
output$plot <- renderPlot({
plot(head(cars, input$n), xlim = range(cars[[1]]), ylim = range(cars[[2]]))
})
}
)
}
Once we have the object, it can be supplied directly to
AppDriver$new()
.
# File: tests/testthat/test-app-function.R
test_that("hello-world app initial values are consistent", {
# Don't run these tests on the CRAN build servers
skip_on_cran()
shiny_app <- hello_world_app()
app <- AppDriver$new(shiny_app, name = "hello")
app$expect_values()
})
To help create tests, you can call record_test()
on your
shiny application object directly. Unfortunately, the test file will not
be able to be saved. Instead, the test commands can be copied into a
test script manually.
There are a few steps that are needed for both types of tests.
It is recommended to call shinytest2::use_shinytest2()
to enable different test config set-ups.
You will need to add {shinytest2}
to the
Suggests
section in your DESCRIPTION
file.
Suggests:
shinytest2
When all of these items are in place, you can test your package using
devtools::install(); testthat::test_local()
or by running
R CMD check
on your package. If you are using the RStudio
IDE, you can also run Build -> Test Package or Build -> Check
Package.
{shinytest2}
requires that your package to be
installed when testing. testthat::test_local()
(and related wrappers) eventually call pkgload::load_all()
to temporarily source the local R package. You can use
test_local()
to test non-{shinytest2}
tests,
but you will need to install your R package to safely execute your
{shinytest2}
tests. If not installed, it will create a
confusing situation where your {shinytest2}
tests are
running on a different version of your R package (whichever was
last installed), than the rest of your tests (the current source).
You can call shinytest2::test_app()
multiple times
within a test script. It does not need to be wrapped within a
testthat::test_that()
call.
{shinytest2}
tests many internal apps using the code
similar to the code below:
If you would like your package to be tested with every commit, you can set it up with GitHub Actions. Please see Using shinytest2 with continuous integration for inspiration.