-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathREADME.Rmd
182 lines (133 loc) · 5.22 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
library(details)
```
# reactor <img src="https://github.com/yonicd/hex/raw/master/images/logos/reactor.png" align="right" class="logo"/>
<!-- badges: start -->
[![Lifecycle: maturing](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://www.tidyverse.org/lifecycle/#maturing)
[![R-CMD-check](https://github.com/yonicd/reactor/workflows/R-CMD-check/badge.svg)](https://github.com/yonicd/reactor/actions)
[![pkgdown](https://github.com/yonicd/reactor/workflows/pkgdown/badge.svg)](https://github.com/yonicd/reactor/actions)
[![Reactor](https://github.com/yonicd/reactor/workflows/Reactor/badge.svg)](https://github.com/yonicd/reactor/actions)
[![Covrpage Summary](https://img.shields.io/badge/covrpage-Last_Build_2020_12_21-brightgreen.svg)](https://tinyurl.com/yd2odf5g)
<!-- badges: end -->
When developing Shiny apps there is a lot of reactivity problems that can arise when one `reactive` or `observe` element triggers other elements. In some cases these can create cascading reactivity (the horror). The goal of `reactor` is to diagnose these reactivity problems and then plan unit tests to avert them during development to make development less painful.
## Installation
And the development version from [GitHub](https://github.com/) with:
``` r
# install.packages("remotes")
remotes::install_github("yonicd/reactor")
```
## Usage
Reactor is a pipeline driven api where the user does not need to learn RSelenium in order to be able to drive their applications
### Initializing Reactor
Start by creating a reactor class object
```{r}
library(reactor)
obj <- init_reactor()
obj
```
### Populating Specifications
You can see it is expecting to be populated by two objects
- __application__: Specifications for the background process that will host the application
- __driver__: Specifications for the webdriver that will interact with the application in the background process
Reactor comes with functions to help you create these specifications
- __application__:
- `set_runapp_args()` : Assumes that the application is located in a path on the machine and uses `shiny::runApp` as the function to launch the application
- `set_golem_args()`: Assumes that the application is a [golem](https://github.com/ThinkR-open/golem) package and uses the `golem` logic to launch the application.
- __driver__:
- `set_chrome_driver()`: Launches `RSelenium` with a chrome webdriver
- `set_firefox_driver()`: Launches `RSelenium` with a firefox (gecko) webdriver
```{r}
obj <- obj%>%
set_runapp_args(
appDir = system.file('examples/good_app.R',package = 'reactor')
)%>%
set_chrome_driver()
```
```{details, echo = FALSE,details.lang = 'yml',details.summary = 'reactor object'}
obj
```
If you want turn off headless mode you can update the object
```{r}
obj <- obj%>%
set_chrome_driver(
opts = chrome_options(headless = FALSE)
)
```
```{details, echo = FALSE, details.lang = 'yml',details.summary = 'reactor object'}
obj
```
### Starting Reactor
Once we have specifications in place we can start reactor using `start_reactor()`.
```{r,eval = FALSE}
obj%>%
start_reactor()
```
### Interacting with the application
Now that the app is running we can send to the webdriver to interact with the application
- `set_id_value()`:
- expects an input id and the new value
- returns back the reactor object
```{r,eval = FALSE}
obj%>%
set_id_value('n',500)
```
The user can use the following utility functions to interact and query with an application
Inject:
- Inputs
- `set_id_value()`: Sets a value for a shiny input object by id
- JavaScript
- `execute()`: Executes a JavaScript call
Query:
- Inputs
- `query_input_names()`: Returns names of the shiny input ids
- `query_input_id()`: Returns current values of a shiny input by id
- Outputs
- `query_output_names()`: Returns names of the shiny output ids
- `query_output_id()`: Returns current values of a shiny output by id
- JavaScript
- `query()`: Returns a value from JavaScript call
### Closing Reactor
To safely close reactor and all the child processes use `kill_app()`:
```{r,eval = FALSE}
obj%>%
kill_app()
```
### Pipeline Operations
Because each function is returning the reactor object it is simple to create reactor pipelines.
Reactor will wait for shiny to finish each action before proceeding to the next one.
```{r,eval = FALSE}
init_reactor()%>%
set_runapp_args(
appDir = system.file('examples/good_app.R',package = 'reactor')
)%>%
set_chrome_driver()%>%
start_reactor()%>%
set_id_value('n',500)%>%
set_id_value('n',300)%>%
kill_app()
```
### Testing Expectations
Finally reactor tests reactivity expectations in a `testthat` framework using the builtin `expect_reactivity()` function
```{r,eval = FALSE}
init_reactor()%>%
set_runapp_args(
appDir = system.file('examples/good_app.R',package = 'reactor')
)%>%
set_chrome_driver()%>%
start_reactor()%>%
set_id_value('n',500)%>%
expect_reactivity('hist',1)%>%
set_id_value('n',200)%>%
expect_reactivity('hist',2)%>%
kill_app()
```