Skip to content

Commit b4ee7b7

Browse files
authored
Add unit tests (#3)
* Add unit tests * Fix description length exceeding 100 characters for binary documentation * Fix example
1 parent cbdf131 commit b4ee7b7

12 files changed

+807
-11
lines changed

DESCRIPTION

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,8 @@ RoxygenNote: 7.3.2
2121
Suggests:
2222
knitr,
2323
rmarkdown,
24-
quarto
24+
quarto,
25+
withr,
26+
testthat (>= 3.0.0)
2527
VignetteBuilder: quarto
28+
Config/testthat/edition: 3

R/writers.R

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@
3939
#' type = "text"
4040
#' )
4141
#'
42-
#' # Writing a binary file (base64-encoded content)
43-
#' write_file_content(
44-
#' content = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
45-
#' file_path = "app/www/image.png",
46-
#' type = "binary"
42+
#' # Write base64 encoded image
43+
#' b64img <- paste0(
44+
#' "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAA",
45+
#' "DUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
4746
#' )
47+
#' write_file_content(b64img, "test.png", type = "binary")
4848
#' }
4949
#'
5050
#' @keywords internal

man/write_file_content.Rd

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat.R

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This file is part of the standard setup for testthat.
2+
# It is recommended that you do not modify it.
3+
#
4+
# Where should you do additional test configuration?
5+
# Learn more about the roles of various files in:
6+
# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
7+
# * https://testthat.r-lib.org/articles/special-files.html
8+
9+
library(testthat)
10+
library(peeky)
11+
12+
test_check("peeky")

tests/testthat/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
converted_shiny_app

tests/testthat/test-find.R

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Test find_shinylive_app_json() ----
2+
3+
test_that("find_shinylive_app_json(): validates JSON structure correctly", {
4+
# Create a valid app.json structure with required fields
5+
valid_json <- list(
6+
list(
7+
name = "app.R",
8+
content = "library(shiny)\n...",
9+
type = "text"
10+
)
11+
)
12+
13+
# Create a mock HTTP response with valid JSON content
14+
valid_resp <- base::structure(
15+
list(
16+
headers = list("content-type" = "application/json"),
17+
content = base::charToRaw(jsonlite::toJSON(valid_json))
18+
),
19+
class = "response"
20+
)
21+
22+
# Mock httr functions to simulate successful API response
23+
testthat::local_mocked_bindings(
24+
GET = function(...) valid_resp,
25+
content = function(...) jsonlite::toJSON(valid_json),
26+
.package = "httr"
27+
)
28+
29+
# Test with valid JSON
30+
result <- find_shinylive_app_json("http://example.com/app.json")
31+
32+
# Verify successful validation
33+
testthat::expect_true(result$valid)
34+
testthat::expect_equal(result$url, "http://example.com/app.json")
35+
testthat::expect_equal(result$data, valid_json)
36+
37+
# Create a mock response with invalid JSON (empty object)
38+
invalid_resp <- base::structure(
39+
list(
40+
headers = list("content-type" = "application/json"),
41+
content = base::charToRaw("{}")
42+
),
43+
class = "response"
44+
)
45+
46+
# Mock httr functions to simulate invalid JSON response
47+
testthat::local_mocked_bindings(
48+
GET = function(...) invalid_resp,
49+
content = function(...) "{}",
50+
.package = "httr"
51+
)
52+
53+
# Test with invalid JSON
54+
result <- find_shinylive_app_json("http://example.com/app.json")
55+
56+
# Verify failed validation
57+
testthat::expect_false(result$valid)
58+
testthat::expect_null(result$url)
59+
testthat::expect_null(result$data)
60+
})
61+
62+
# Test find_shinylive_code() ----
63+
64+
test_that("find_shinylive_code(): extracts code blocks correctly", {
65+
# Create HTML content containing both R and Python Shinylive code blocks
66+
# Note the different structures and options in each block
67+
html_content <- '
68+
<pre class="shinylive-r" data-engine="r">
69+
#| viewerHeight: 500
70+
#| standalone: true
71+
## file: app.R
72+
library(shiny)
73+
ui <- fluidPage()
74+
server <- function(input, output) {}
75+
shinyApp(ui, server)
76+
</pre>
77+
<pre class="shinylive-python" data-engine="python">
78+
#| standalone: true
79+
## file: app.py
80+
from shiny import App, ui
81+
app = App(app_ui)
82+
</pre>
83+
'
84+
85+
# Parse the HTML content to find code blocks
86+
result <- find_shinylive_code(html_content)
87+
88+
# Verify number of code blocks found
89+
testthat::expect_equal(base::length(result), 2)
90+
91+
# Verify correct engine identification for each block
92+
testthat::expect_equal(result[[1]]$engine, "r")
93+
testthat::expect_equal(result[[2]]$engine, "python")
94+
95+
# Verify R code block structure and options
96+
testthat::expect_true("viewerHeight" %in% base::names(result[[1]]$options))
97+
testthat::expect_equal(result[[1]]$options$viewerHeight, 500)
98+
testthat::expect_true("app.R" %in% base::names(result[[1]]$files))
99+
100+
# Verify Python code block structure and options
101+
testthat::expect_true("standalone" %in% base::names(result[[2]]$options))
102+
testthat::expect_true(result[[2]]$options$standalone)
103+
testthat::expect_true("app.py" %in% base::names(result[[2]]$files))
104+
})

tests/testthat/test-peek.R

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Test peek_shinylive_app() ----
2+
3+
test_that("peek_shinylive_app(): handles HTML content correctly", {
4+
# Create sample HTML content with an embedded R Shiny application
5+
# The content simulates a Quarto document structure with a shinylive-r code block
6+
html_content <- '<!DOCTYPE html><html><body><main class="content" id="quarto-document-content">
7+
<pre class="shinylive-r" data-engine="r">
8+
#| viewerHeight: 500
9+
## file: app.R
10+
library(shiny)
11+
ui <- fluidPage()
12+
server <- function(input, output) {}
13+
shinyApp(ui, server)
14+
</pre>
15+
</main></body></html>'
16+
17+
# Mock HTTP-related functions to simulate web requests
18+
testthat::local_mocked_bindings(
19+
# Mock GET to return HTML content with appropriate headers
20+
GET = function(...) base::structure(
21+
list(
22+
headers = list("content-type" = "text/html"),
23+
content = base::charToRaw(html_content)
24+
),
25+
class = "response"
26+
),
27+
# Mock http_error to always return FALSE (success)
28+
http_error = function(...) FALSE,
29+
# Mock content function to return the HTML content
30+
content = function(...) html_content,
31+
.package = "httr"
32+
)
33+
34+
# Test the function with a sample URL
35+
result <- peek_shinylive_app("http://example.com")
36+
37+
# Verify the result is a quarto_shinylive_apps object
38+
testthat::expect_s3_class(result, "quarto_shinylive_apps")
39+
})
40+
41+
test_that("peek_shinylive_app(): handles app.json content correctly", {
42+
# Create sample JSON content representing a standalone Shiny application
43+
json_content <- jsonlite::toJSON(list(
44+
list(
45+
name = "app.R",
46+
content = "library(shiny)\n...",
47+
type = "text"
48+
)
49+
))
50+
51+
# Mock HTTP-related functions for JSON response
52+
testthat::local_mocked_bindings(
53+
# Mock GET to return JSON content with appropriate headers
54+
GET = function(...) base::structure(
55+
list(
56+
headers = list("content-type" = "application/json"),
57+
content = base::charToRaw(json_content)
58+
),
59+
class = "response"
60+
),
61+
http_error = function(...) FALSE,
62+
content = function(...) json_content,
63+
.package = "httr"
64+
)
65+
66+
# Test the function with a URL pointing to app.json
67+
result <- peek_shinylive_app("http://example.com/app.json")
68+
69+
# Verify the result is a standalone_shinylive_app object
70+
testthat::expect_s3_class(result, "standalone_shinylive_app")
71+
})
72+
73+
test_that("peek_quarto_shinylive_app(): handles app-dir format correctly", {
74+
# Create sample HTML content with a Shiny application
75+
html_content <- '
76+
<pre class="shinylive-r" data-engine="r">
77+
#| viewerHeight: 500
78+
## file: app.R
79+
library(shiny)
80+
ui <- fluidPage()
81+
server <- function(input, output) {}
82+
shinyApp(ui, server)
83+
</pre>
84+
'
85+
86+
# Mock HTTP-related functions
87+
testthat::local_mocked_bindings(
88+
GET = function(...) base::structure(
89+
list(
90+
headers = list("content-type" = "text/html"),
91+
content = base::charToRaw(html_content)
92+
),
93+
class = "response"
94+
),
95+
http_error = function(...) FALSE,
96+
content = function(...) html_content,
97+
.package = "httr"
98+
)
99+
100+
# Create temporary directory for output
101+
temp_dir <- base::tempfile()
102+
103+
# Test the function with app-dir output format
104+
result <- peek_quarto_shinylive_app(
105+
"http://example.com",
106+
output_format = "app-dir",
107+
output_path = temp_dir
108+
)
109+
110+
# Verify result type and format
111+
testthat::expect_s3_class(result, "quarto_shinylive_apps")
112+
testthat::expect_equal(result$output_format, "app-dir")
113+
114+
# Clean up temporary directory
115+
base::unlink(temp_dir, recursive = TRUE)
116+
})
117+
118+
# Test peek_standalone_shinylive_app() ----
119+
120+
test_that("peek_standalone_shinylive_app(): processes standalone app correctly", {
121+
# Create sample app.json content
122+
app_json <- list(
123+
list(
124+
name = "app.R",
125+
content = "library(shiny)\n...",
126+
type = "text"
127+
)
128+
)
129+
130+
# Mock HTTP-related functions
131+
testthat::local_mocked_bindings(
132+
# Mock GET to return JSON content with appropriate headers
133+
GET = function(...) base::structure(
134+
list(
135+
headers = list("content-type" = "application/json"),
136+
content = base::charToRaw(jsonlite::toJSON(app_json))
137+
),
138+
class = "response"
139+
),
140+
http_error = function(...) FALSE,
141+
content = function(...) jsonlite::toJSON(app_json),
142+
.package = "httr"
143+
)
144+
145+
# Create temporary directory for output
146+
temp_dir <- base::tempfile()
147+
148+
# Test standalone app processing
149+
result <- peek_standalone_shinylive_app(
150+
"http://example.com/app.json",
151+
output_dir = temp_dir
152+
)
153+
154+
# Verify result type and file creation
155+
testthat::expect_s3_class(result, "standalone_shinylive_app")
156+
testthat::expect_true(base::file.exists(base::file.path(temp_dir, "app.R")))
157+
158+
# Clean up temporary directory
159+
base::unlink(temp_dir, recursive = TRUE)
160+
})

0 commit comments

Comments
 (0)