Testing Shiny Apps

ThinkR has some nice posts about Shiny. Here I am using tips from https://rtask.thinkr.fr/building-a-shiny-app-as-a-package. My focus here is on their neat idea about a simple way to test Shiny apps.

The Simplest Shiny Test

The idea of the test is simple: If we start a Shiny app it should still be running N seconds later for an appropriate choice of N.

We run the app in a separate process using the processx package.

p <- processx::process$new(
  file.path(Sys.getenv("R_HOME"), "bin", "R.exe"),
  c("-e", "shiny::runApp()"),
  cleanup_tree = TRUE
)
print(p)

Sys.sleep(5)

if (isFALSE(p$is_alive())) {
  stop("App not running")
}

p$kill()
print(p)

I am a little more verbose than in the ThinkR post, printing more information about the process p and explicitly writing out the path to the R executable.

All of this could be wrapped in testthat statement, but here I am keeping it simple.

Windows

At first, I did not include the cleanup_tree argument when creating the process p. But leaving it out caused some annoyances on Windows. It also turned out to be necessary when running tests on Windows through GitLab.

When R is started on Linux we have a single R process running, which can be found with this shell command:

$ ps aux | grep "R"
robert      99  4.0  0.2 426776 41944 pts/0    Sl   11:16   0:01 R 

When R is started on Windows we get two R processes and one Rterm process, which can be found with this PowerShell command:

> Get-Process -Name R,Rterm

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
     52       6     1532       4012       0,00   2416   1 R
    113       7     1924       5688       0,02   5216   1 R
    164      68    68088      47020       0,16  15484   1 Rterm

There are apparently some legacy reasons for this and usually it is not a problem – when the “main” R process (one of the two Rs above) is closed, Rterm and the other R is also closed.

However, when R is started with the processx package without cleanup_tree and later killed (with p$kill() in the R code above), only the “main” R process is closed, leaving Rterm and the other R hanging.

This can cause frustration on Windows, e.g. where the files being used by the hanging processes are not allowed to be edited because they are “in use by another program”.

On GitLab, the test runner that handles communication between GitLab and the computer running the test does not register the test as completed when there are two hanging processes.