Title: | Test Shiny Apps |
---|---|
Description: | Please see the shinytest to shinytest2 migration guide at <https://rstudio.github.io/shinytest2/articles/z-migration.html>. |
Authors: | Winston Chang [aut, cre], Gábor Csárdi [aut], Hadley Wickham [aut], Posit Software, PBC [cph, fnd], Ascent Digital Services [cph, ccp] |
Maintainer: | Winston Chang <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.6.0 |
Built: | 2024-10-25 05:02:52 UTC |
Source: | https://github.com/rstudio/shinytest |
dependenciesInstalled()
that all the required system dependency,
PhantomJS, is installed, and installDependencies()
installs it if needed.
For more information about where PhantomJS will be installed
see webdriver::install_phantomjs()
.
dependenciesInstalled() installDependencies()
dependenciesInstalled() installDependencies()
TRUE
when all dependencies are fulfilled; otherwise, FALSE
.
testApp()
passes snapshot testsThis returns an testthat expectation object.
expect_pass(object, info = NULL)
expect_pass(object, info = NULL)
object |
The results returned by |
info |
Extra information to be included in the message (useful when writing tests in loops). |
## Not run: expect_pass(testApp("path/to/app/")) ## End(Not run)
## Not run: expect_pass(testApp("path/to/app/")) ## End(Not run)
This function migrates the old-style directory structure used by shinytest (versions 1.3.1 and below) to new test directory structure used in shinytest 1.4.0 and above.
migrateShinytestDir(appdir, dryrun = FALSE)
migrateShinytestDir(appdir, dryrun = FALSE)
appdir |
A directory containing a Shiny application. |
dryrun |
If |
Before shinytest 1.4.0, the shinytest scripts and results were put in a
subdirectory of the application named tests/
. As of shinytest 1.4.0,
the tests are put in tests/shinytest/
, so that it works with the
runTests()
function shiny package (added in shiny 1.5.0).
With shinytest 1.3.1 and below, the tests/ subdirectory of the application was used specifically for shinytest, and could not be used for other types of tests. So the directory structure would look like this:
appdir/ `- tests `- mytest.R
In Shiny 1.5.0, the shiny::runTests()
function was added, and it will run
test scripts tests/ subdirectory of the application. This makes it possible
to use other testing systems in addition to shinytest. shinytest 1.4.0
is designed to work with this new directory structure. The directory
structure looks something like this:
appdir/ |- R |- tests |- shinytest.R |- shinytest | `- mytest.R |- testthat.R `- testthat `- test-script.R
This allows for tests using the shinytest package as well as other
testing tools, such as the shiny::testServer()
function, which can be used
for testing module and server logic, and for unit tests of functions in an R/
subdirectory.
In shinytest 1.4.0 and above, it defaults to creating the new directory structure.
Returns the name of the current OS. This can be useful for the suffix
when
running testApp()
.
osName()
osName()
Launch test event recorder for a Shiny app
recordTest( app = ".", save_dir = NULL, load_mode = FALSE, seed = NULL, loadTimeout = 10000, debug = "shiny_console", shinyOptions = list() )
recordTest( app = ".", save_dir = NULL, load_mode = FALSE, seed = NULL, loadTimeout = 10000, debug = "shiny_console", shinyOptions = list() )
app |
A |
save_dir |
A directory to save stuff. |
load_mode |
A boolean that determines whether or not the resulting test script should be appropriate for load testing. |
seed |
A random seed to set before running the app. This seed will also be used in the test script. |
loadTimeout |
Maximum time to wait for the Shiny application to load, in milliseconds. If a value is provided, it will be saved in the test script. |
debug |
start the underlying |
shinyOptions |
A list of options to pass to |
This class starts a Shiny app in a new R session, along with a phantom.js
headless browser that can be used to simulate user actions. This provides
a full simulation of a Shiny app so that you can test user interactions
with a live app.
new()
ShinyDriver$new( path = ".", loadTimeout = NULL, checkNames = TRUE, debug = c("none", "all", shinytest::ShinyDriver$debugLogTypes), phantomTimeout = 5000, seed = NULL, cleanLogs = TRUE, shinyOptions = list(), renderArgs = NULL, options = list() )
path
Path to a directory containing a Shiny app, i.e. a
single app.R
file or a server.R
-ui.R
pair.
loadTimeout
How long to wait for the app to load, in ms. This includes the time to start R. Defaults to 5s when running locally and 10s when running on CI.
checkNames
Check if widget names are unique?
debug
Start the app in debugging mode? In debugging mode debug messages are printed to the console.
phantomTimeout
How long to wait when connecting to phantomJS process, in ms
seed
An optional random seed to use before starting the application. For apps that use R's random number generator, this can make their behavior repeatable.
cleanLogs
Whether to remove the stdout and stderr logs when the Shiny process object is garbage collected.
shinyOptions
A list of options to pass to shiny::runApp()
.
renderArgs
Passed to rmarkdown::run()
for interactive .Rmd
s.
options
A list of base::options()
to set in the driver's child
process.
finalize()
Stop app and clean up logs.
ShinyDriver$finalize()
stop()
Stop the app, the terminate external R process that runs the app and the phantomjs instance.
ShinyDriver$stop()
getValue()
Finds a widget and queries its value. See the getValue()
method of
Widget for more details.
ShinyDriver$getValue(name, iotype = c("auto", "input", "output"))
name
Name of a shiny widget.
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
setValue()
Finds a widget and sets its value. It's a shortcut for findElement()
plus setValue()
; see the Widget documentation for more details.
ShinyDriver$setValue(name, value, iotype = c("auto", "input", "output"))
name
Name of a shiny widget.
value
New value.
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
Self, invisibly.
click()
Find a widget and click it. It's a shortcut for findElement()
plus click()
; see the Widget documentation for more details.
ShinyDriver$click(name, iotype = c("auto", "input", "output"))
name
Name of a shiny widget.
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
getAllValues()
Returns a named list of all inputs, outputs, and export values.
ShinyDriver$getAllValues(input = TRUE, output = TRUE, export = TRUE)
input, output, export
Either TRUE
to return all
input/output/exported values, or a character vector of specific
controls.
sendKeys()
Sends the specified keys to specific HTML element. Shortcut for
findWidget()
plus sendKeys()
.
ShinyDriver$sendKeys(name, keys)
name
Name of a shiny widget.
keys
Keys to send to the widget or the app. See webdriver::key for how to specific special keys.
Self, invisibly.
setWindowSize()
Sets size of the browser window.
ShinyDriver$setWindowSize(width, height)
width, height
Height and width of browser, in pixels.
Self, invisibly.
getWindowSize()
Get current size of the browser window, as list of integer scalars
named width
and height
.
ShinyDriver$getWindowSize()
getDebugLog()
Query one or more of the debug logs.
ShinyDriver$getDebugLog(type = c("all", ShinyDriver$debugLogTypes))
type
Log type: "all"
, "shiny_console"
, "browser"
,
or "shinytest"
.
enableDebugLogMessages()
Enable/disable debugging messages
ShinyDriver$enableDebugLogMessages(enable = TRUE)
enable
New value.
logEvent()
Add event to log.
ShinyDriver$logEvent(event, ...)
event
Event name
...
Addition data to store for event
getEventLog()
Retrieve event log.
ShinyDriver$getEventLog()
getUrl()
Get current url
ShinyDriver$getUrl()
getTitle()
Get page title
ShinyDriver$getTitle()
getSource()
Get complete source of current page.
ShinyDriver$getSource()
goBack()
Return to previous page
ShinyDriver$goBack()
Self, invisibly.
refresh()
Refresh the browser
ShinyDriver$refresh()
Self, invisibly.
takeScreenshot()
Takes a screenshot of the current page and writes it to a PNG file or shows on current graphics device.
ShinyDriver$takeScreenshot(file = NULL, id = NULL, parent = FALSE)
file
File name to save the screenshot to. If NULL
, then
it will be shown on the R graphics device.
id
If not-NULL
, will take a screenshot of element with this id.
parent
If TRUE
, will take screenshot of parent of id
; this
is useful if you also want to capture the label attached to a Shiny
control.
Self, invisibly.
findElement()
Find an HTML element on the page, using a CSS selector, XPath expression,
or link text (for <a>
tags). If multiple elements are matched, only
the first is returned.
ShinyDriver$findElement( css = NULL, linkText = NULL, partialLinkText = NULL, xpath = NULL )
css
CSS selector to find an HTML element.
linkText
Find <a>
HTML elements based on exact innerText
partialLinkText
Find <a>
HTML elements based on partial innerText
xpath
Find HTML elements using XPath expressions.
findElements()
Find all elements matching CSS selection, xpath, or link text.
ShinyDriver$findElements( css = NULL, linkText = NULL, partialLinkText = NULL, xpath = NULL )
css
CSS selector to find an HTML element.
linkText
Find <a>
HTML elements based on exact innerText
partialLinkText
Find <a>
HTML elements based on partial innerText
xpath
Find HTML elements using XPath expressions.
A list of webdriver::Elements.
waitFor()
Waits until a JavaScript expr
ession evaluates to true
or the
timeout
is exceeded.
ShinyDriver$waitFor(expr, checkInterval = 100, timeout = 3000)
expr
A string containing JavaScript code. Will wait until the
condition returns true
.
checkInterval
How often to check for the condition, in ms.
timeout
Amount of time to wait before giving up (milliseconds).
TRUE
if expression evaluates to true
without error, before
timeout. Otherwise returns NA
.
waitForShiny()
Waits until Shiny is not busy, i.e. the reactive graph has finished
updating. This is useful, for example, if you've resized the window with
setWindowSize()
and want to make sure all plot redrawing is complete
before take a screenshot.
ShinyDriver$waitForShiny()
TRUE
if done before before timeout; NA
otherwise.
waitForValue()
Waits until the input
or output
with name name
is not one of
ignore
d values, or the timeout is reached.
This function can be useful in helping determine if an application has initialized or finished processing a complex reactive situation.
ShinyDriver$waitForValue( name, ignore = list(NULL, ""), iotype = c("input", "output", "export"), timeout = 10000, checkInterval = 400 )
name
Name of a shiny widget.
ignore
List of possible values to ignore when checking for updates.
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
timeout
Amount of time to wait before giving up (milliseconds).
checkInterval
How often to check for the condition, in ms.
listWidgets()
Lists the names of all input and output widgets
ShinyDriver$listWidgets()
A list of two character vectors, named input
and output
.
checkUniqueWidgetNames()
Check if Shiny widget names are unique.
ShinyDriver$checkUniqueWidgetNames()
executeScript()
Execute JS code
ShinyDriver$executeScript(script, ...)
script
JS to execute.
...
Additional arguments to script.
Self, invisibly.
executeScriptAsync()
Execute JS code asynchronously.
ShinyDriver$executeScriptAsync(script, ...)
script
JS to execute.
...
Additional arguments to script.
Self, invisibly.
findWidget()
Finds the a Shiny input or output control.
ShinyDriver$findWidget(name, iotype = c("auto", "input", "output"))
name
Name of a shiny widget.
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
A Widget.
expectUpdate()
It performs one or more update operations via the browser, thens
waits for the specified output(s) to update. The test succeeds if
all specified output widgets are updated before the timeout
.
For updates that involve a lot of computation, increase the timeout.
ShinyDriver$expectUpdate( output, ..., timeout = 3000, iotype = c("auto", "input", "output") )
output
Name of output control to check.
...
Name-value pairs used to update inputs.
timeout
Amount of time to wait before giving up (milliseconds).
iotype
Type of the Shiny widget. Usually shinytest finds the widgets by their name, so this is only needed if you use the same name for an input and output widget.
setInputs()
Sets input values.
ShinyDriver$setInputs( ..., wait_ = TRUE, values_ = TRUE, timeout_ = 3000, allowInputNoBinding_ = FALSE, priority_ = c("input", "event") )
...
Name-value pairs, name1 = value1, name2 = value2
etc.
Enput with name name1
will be assigned value value1
.
wait_
Wait until all reactive updates have completed?
values_
If TRUE
, will return final updated values of inputs.
timeout_
Amount of time to wait before giving up (milliseconds).
allowInputNoBinding_
When setting the value of an input, allow it to set the value of an input even if that input does not have an input binding.
priority_
Sets the event priority. For expert use only: see https://shiny.rstudio.com/articles/communicating-with-js.html#values-vs-events for details.
Returns updated values, invisibly.
uploadFile()
Uploads a file to a file input.
ShinyDriver$uploadFile(..., wait_ = TRUE, values_ = TRUE, timeout_ = 3000)
...
Name-path pairs, e.g. name1 = path1
. The file located at
path1
will be uploaded to file input with name name1
.
wait_
Wait until all reactive updates have completed?
values_
If TRUE
, will return final updated values of download
control.
timeout_
Amount of time to wait before giving up (milliseconds).
snapshotInit()
Download a snapshot. Generally, you should not call this function
yourself; it will be generated by recordTest()
as needed.
ShinyDriver$snapshotInit(path, screenshot = TRUE)
path
Directory to save snapshots.
screenshot
Take screenshots for each snapshot?
snapshot()
Take a snapshot. Generally, you should not call this function
yourself; it will be generated by recordTest()
as needed.
ShinyDriver$snapshot(items = NULL, filename = NULL, screenshot = NULL)
items
Elements to include in snapshot
filename
Filename to use. It is recommended to use a .json
file extension.
screenshot
Take a screenshot? Overrides value set by
$snapshotInit()
snapshotCompare()
Deprecated
ShinyDriver$snapshotCompare(...)
...
Ignored
snapshotDownload()
Snapshot a file download action. Generally, you should not call this
function yourself; it will be generated by recordTest()
as needed.
ShinyDriver$snapshotDownload(id, filename = NULL)
id
Output id of shiny::downloadButton()
/shiny::downloadLink()
filename
File name to save file to. The default, NULL
,
generates an ascending sequence of names: 001.download
,
002.download
, etc.
getAppDir()
Directory where app is located
ShinyDriver$getAppDir()
getAppFilename()
App file name, i.e. app.R
or server.R
. NULL
for Rmds.
ShinyDriver$getAppFilename()
getTestsDir()
Directory where tests are located
ShinyDriver$getTestsDir()
getRelativePathToApp()
Relative path to app from current directory.
ShinyDriver$getRelativePathToApp()
getSnapshotDir()
Directory where snapshots are located.
ShinyDriver$getSnapshotDir()
isRmd()
Is this app an Shiny Rmd document?
ShinyDriver$isRmd()
clone()
The objects of this class are cloneable with this method.
ShinyDriver$clone(deep = FALSE)
deep
Whether to make a deep clone.
Run tests for a Shiny application
testApp( appDir = ".", testnames = NULL, quiet = FALSE, compareImages = TRUE, interactive = is_interactive(), suffix = NULL )
testApp( appDir = ".", testnames = NULL, quiet = FALSE, compareImages = TRUE, interactive = is_interactive(), suffix = NULL )
appDir |
Path to directory containing a Shiny app (e.g. |
testnames |
Test script(s) to run. The .R extension of the filename is
optional. For example, |
quiet |
Should output be suppressed? This is useful for automated testing. |
compareImages |
Should screenshots be compared? It can be useful to set
this to |
interactive |
If there are any differences between current results and expected results, provide an interactive graphical viewer that shows the changes and allows the user to accept or reject the changes. |
suffix |
An optional suffix for the expected results directory. For
example, if the suffix is |
snapshotCompare()
and snapshotUpdate()
if
you want to compare or update snapshots after testing. In most cases, the
user is prompted to do these tasks interactively, but there are also times
where it is useful to call these functions from the console.
A Widget
object represents a Shiny input or output control, and provides
methods for finer grained interaction.
new()
Create new Widget
Widget$new(name, element, type, iotype = c("input", "output"))
name
Name of a Shiny widget.
element
type
Widget type
iotype
Input/output type.
getName()
Control id (i.e. inputId
or outputId
that control
was created with).
Widget$getName()
getElement()
Underlying webdriver::Element()
object.
Widget$getElement()
getHtml()
retrieve the underlying HTML for a widget
Widget$getHtml()
getType()
Widget type, e.g. textInput
, selectInput
.
Widget$getType()
getIoType()
Is this an input or output control?
Widget$getIoType()
isInput()
Is this an input control?
Widget$isInput()
isOutput()
Is this an output control?
Widget$isOutput()
getValue()
Get current value of control.
Widget$getValue()
setValue()
Set value of control.
Widget$setValue(value)
value
Value to set for the widget.
click()
scrolls the element into view, then clicks the in-view centre point of it.
Widget$click()
self, invisibly.
sendKeys()
Send specified key presses to control.
Widget$sendKeys(keys)
keys
Keys to send to the widget or the app. See webdriver::key for how to specific special keys.
listTabs()
Lists the tab names of a shiny::tabsetPanel()
.
It fails for other types of widgets.
Widget$listTabs()
uploadFile()
Upload a file to a shiny::fileInput()
.
It fails for other types of widgets.
Widget$uploadFile(filename)
filename
Path to file to upload
clone()
The objects of this class are cloneable with this method.
Widget$clone(deep = FALSE)
deep
Whether to make a deep clone.