Skip to content

Commit

Permalink
Add unit tests (#3)
Browse files Browse the repository at this point in the history
* Add unit tests

* Fix description length exceeding 100 characters for binary documentation

* Fix example
  • Loading branch information
coatless authored Jan 3, 2025
1 parent cbdf131 commit b4ee7b7
Show file tree
Hide file tree
Showing 12 changed files with 807 additions and 11 deletions.
5 changes: 4 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ RoxygenNote: 7.3.2
Suggests:
knitr,
rmarkdown,
quarto
quarto,
withr,
testthat (>= 3.0.0)
VignetteBuilder: quarto
Config/testthat/edition: 3
10 changes: 5 additions & 5 deletions R/writers.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@
#' type = "text"
#' )
#'
#' # Writing a binary file (base64-encoded content)
#' write_file_content(
#' content = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
#' file_path = "app/www/image.png",
#' type = "binary"
#' # Write base64 encoded image
#' b64img <- paste0(
#' "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAA",
#' "DUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=="
#' )
#' write_file_content(b64img, "test.png", type = "binary")
#' }
#'
#' @keywords internal
Expand Down
10 changes: 5 additions & 5 deletions man/write_file_content.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions tests/testthat.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# This file is part of the standard setup for testthat.
# It is recommended that you do not modify it.
#
# Where should you do additional test configuration?
# Learn more about the roles of various files in:
# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
# * https://testthat.r-lib.org/articles/special-files.html

library(testthat)
library(peeky)

test_check("peeky")
1 change: 1 addition & 0 deletions tests/testthat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
converted_shiny_app
104 changes: 104 additions & 0 deletions tests/testthat/test-find.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Test find_shinylive_app_json() ----

test_that("find_shinylive_app_json(): validates JSON structure correctly", {
# Create a valid app.json structure with required fields
valid_json <- list(
list(
name = "app.R",
content = "library(shiny)\n...",
type = "text"
)
)

# Create a mock HTTP response with valid JSON content
valid_resp <- base::structure(
list(
headers = list("content-type" = "application/json"),
content = base::charToRaw(jsonlite::toJSON(valid_json))
),
class = "response"
)

# Mock httr functions to simulate successful API response
testthat::local_mocked_bindings(
GET = function(...) valid_resp,
content = function(...) jsonlite::toJSON(valid_json),
.package = "httr"
)

# Test with valid JSON
result <- find_shinylive_app_json("http://example.com/app.json")

# Verify successful validation
testthat::expect_true(result$valid)
testthat::expect_equal(result$url, "http://example.com/app.json")
testthat::expect_equal(result$data, valid_json)

# Create a mock response with invalid JSON (empty object)
invalid_resp <- base::structure(
list(
headers = list("content-type" = "application/json"),
content = base::charToRaw("{}")
),
class = "response"
)

# Mock httr functions to simulate invalid JSON response
testthat::local_mocked_bindings(
GET = function(...) invalid_resp,
content = function(...) "{}",
.package = "httr"
)

# Test with invalid JSON
result <- find_shinylive_app_json("http://example.com/app.json")

# Verify failed validation
testthat::expect_false(result$valid)
testthat::expect_null(result$url)
testthat::expect_null(result$data)
})

# Test find_shinylive_code() ----

test_that("find_shinylive_code(): extracts code blocks correctly", {
# Create HTML content containing both R and Python Shinylive code blocks
# Note the different structures and options in each block
html_content <- '
<pre class="shinylive-r" data-engine="r">
#| viewerHeight: 500
#| standalone: true
## file: app.R
library(shiny)
ui <- fluidPage()
server <- function(input, output) {}
shinyApp(ui, server)
</pre>
<pre class="shinylive-python" data-engine="python">
#| standalone: true
## file: app.py
from shiny import App, ui
app = App(app_ui)
</pre>
'

# Parse the HTML content to find code blocks
result <- find_shinylive_code(html_content)

# Verify number of code blocks found
testthat::expect_equal(base::length(result), 2)

# Verify correct engine identification for each block
testthat::expect_equal(result[[1]]$engine, "r")
testthat::expect_equal(result[[2]]$engine, "python")

# Verify R code block structure and options
testthat::expect_true("viewerHeight" %in% base::names(result[[1]]$options))
testthat::expect_equal(result[[1]]$options$viewerHeight, 500)
testthat::expect_true("app.R" %in% base::names(result[[1]]$files))

# Verify Python code block structure and options
testthat::expect_true("standalone" %in% base::names(result[[2]]$options))
testthat::expect_true(result[[2]]$options$standalone)
testthat::expect_true("app.py" %in% base::names(result[[2]]$files))
})
160 changes: 160 additions & 0 deletions tests/testthat/test-peek.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Test peek_shinylive_app() ----

test_that("peek_shinylive_app(): handles HTML content correctly", {
# Create sample HTML content with an embedded R Shiny application
# The content simulates a Quarto document structure with a shinylive-r code block
html_content <- '<!DOCTYPE html><html><body><main class="content" id="quarto-document-content">
<pre class="shinylive-r" data-engine="r">
#| viewerHeight: 500
## file: app.R
library(shiny)
ui <- fluidPage()
server <- function(input, output) {}
shinyApp(ui, server)
</pre>
</main></body></html>'

# Mock HTTP-related functions to simulate web requests
testthat::local_mocked_bindings(
# Mock GET to return HTML content with appropriate headers
GET = function(...) base::structure(
list(
headers = list("content-type" = "text/html"),
content = base::charToRaw(html_content)
),
class = "response"
),
# Mock http_error to always return FALSE (success)
http_error = function(...) FALSE,
# Mock content function to return the HTML content
content = function(...) html_content,
.package = "httr"
)

# Test the function with a sample URL
result <- peek_shinylive_app("http://example.com")

# Verify the result is a quarto_shinylive_apps object
testthat::expect_s3_class(result, "quarto_shinylive_apps")
})

test_that("peek_shinylive_app(): handles app.json content correctly", {
# Create sample JSON content representing a standalone Shiny application
json_content <- jsonlite::toJSON(list(
list(
name = "app.R",
content = "library(shiny)\n...",
type = "text"
)
))

# Mock HTTP-related functions for JSON response
testthat::local_mocked_bindings(
# Mock GET to return JSON content with appropriate headers
GET = function(...) base::structure(
list(
headers = list("content-type" = "application/json"),
content = base::charToRaw(json_content)
),
class = "response"
),
http_error = function(...) FALSE,
content = function(...) json_content,
.package = "httr"
)

# Test the function with a URL pointing to app.json
result <- peek_shinylive_app("http://example.com/app.json")

# Verify the result is a standalone_shinylive_app object
testthat::expect_s3_class(result, "standalone_shinylive_app")
})

test_that("peek_quarto_shinylive_app(): handles app-dir format correctly", {
# Create sample HTML content with a Shiny application
html_content <- '
<pre class="shinylive-r" data-engine="r">
#| viewerHeight: 500
## file: app.R
library(shiny)
ui <- fluidPage()
server <- function(input, output) {}
shinyApp(ui, server)
</pre>
'

# Mock HTTP-related functions
testthat::local_mocked_bindings(
GET = function(...) base::structure(
list(
headers = list("content-type" = "text/html"),
content = base::charToRaw(html_content)
),
class = "response"
),
http_error = function(...) FALSE,
content = function(...) html_content,
.package = "httr"
)

# Create temporary directory for output
temp_dir <- base::tempfile()

# Test the function with app-dir output format
result <- peek_quarto_shinylive_app(
"http://example.com",
output_format = "app-dir",
output_path = temp_dir
)

# Verify result type and format
testthat::expect_s3_class(result, "quarto_shinylive_apps")
testthat::expect_equal(result$output_format, "app-dir")

# Clean up temporary directory
base::unlink(temp_dir, recursive = TRUE)
})

# Test peek_standalone_shinylive_app() ----

test_that("peek_standalone_shinylive_app(): processes standalone app correctly", {
# Create sample app.json content
app_json <- list(
list(
name = "app.R",
content = "library(shiny)\n...",
type = "text"
)
)

# Mock HTTP-related functions
testthat::local_mocked_bindings(
# Mock GET to return JSON content with appropriate headers
GET = function(...) base::structure(
list(
headers = list("content-type" = "application/json"),
content = base::charToRaw(jsonlite::toJSON(app_json))
),
class = "response"
),
http_error = function(...) FALSE,
content = function(...) jsonlite::toJSON(app_json),
.package = "httr"
)

# Create temporary directory for output
temp_dir <- base::tempfile()

# Test standalone app processing
result <- peek_standalone_shinylive_app(
"http://example.com/app.json",
output_dir = temp_dir
)

# Verify result type and file creation
testthat::expect_s3_class(result, "standalone_shinylive_app")
testthat::expect_true(base::file.exists(base::file.path(temp_dir, "app.R")))

# Clean up temporary directory
base::unlink(temp_dir, recursive = TRUE)
})
Loading

0 comments on commit b4ee7b7

Please sign in to comment.