Skip to content

Commit

Permalink
Better race-time handline (#72)
Browse files Browse the repository at this point in the history
* In-progress tweaks.

I made these changes months ago and never finished. I'm walking away but committing in case I come back to it.

* Better race-time handling.
  • Loading branch information
jonthegeek committed Oct 2, 2023
1 parent ece313e commit d0f38ae
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 13 deletions.
5 changes: 4 additions & 1 deletion R/server.R
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ get_cookie <- function(cookie_name,
# When the app first loads, you might get a weird race condition where the
# input isn't populated yet, so you need to use the request object even for
# normal cookies.
if (.is_http_only(cookie_name, session)) {
if (
.is_http_only(cookie_name, session) ||
!(isTRUE(session$input$cookies_ready))
) {
return(extract_cookie(session$request, cookie_name, missing))
} else {
# Once the cookies are initialized, use the input value (even if there isn't
Expand Down
4 changes: 4 additions & 0 deletions inst/js/cookie_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

function getCookies(){
var res = Cookies.get();
/*res.map(function(cookie) {
}); */
Shiny.setInputValue('cookies', res);
}

Expand Down Expand Up @@ -45,6 +48,7 @@ $(document).on('shiny:connected', function(ev){
let jsCookiesStart = Cookies.get();
Shiny.setInputValue('cookies_start', jsCookiesStart);
getCookies();
Shiny.setInputValue('cookies_ready', true);
});

window.addEventListener('focus', function() {
Expand Down
86 changes: 74 additions & 12 deletions tests/testthat/test-server.R
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
test_that("set_cookie works.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}
return(
jsonlite::toJSON(message)
)
}

test_that("set_cookie works.", {
expect_snapshot(
set_cookie(
cookie_name = "testname",
Expand Down Expand Up @@ -69,12 +69,36 @@ test_that("set_cookie works.", {
})

test_that("remove_cookie works.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}

expect_snapshot(
remove_cookie("testname", session = session)
)
})

test_that("get_cookie works.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}

session$input <- list(cookies_start = list(key = "value"))
session$request <- list(HTTP_COOKIE = "key=value")
expect_identical(
Expand All @@ -85,13 +109,26 @@ test_that("get_cookie works.", {
cookies = list(key = "value2"),
cookies_start = list(key = "value2")
)
session$input$cookies_ready <- TRUE
expect_identical(
get_cookie("key", session = session),
"value2"
)
})

test_that("get_cookie works inside modules.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}

# When you're in a module, the session is a special session_proxy that has its
# parent inside of it. Make sure we can still get cookies.
root_session <- structure(
Expand All @@ -102,7 +139,8 @@ test_that("get_cookie works inside modules.", {
key = "value",
key2 = "value2"
),
cookies_start = list(key = "value")
cookies_start = list(key = "value"),
cookies_ready = TRUE
)
),
class = "ShinySession"
Expand All @@ -123,6 +161,18 @@ test_that("get_cookie works inside modules.", {
})

test_that("set_cookie errors appropriately.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}

session$input <- list(
cookies_start = list(normal_cookie = 2)
)
Expand All @@ -146,6 +196,18 @@ test_that("set_cookie errors appropriately.", {
})

test_that("remove_cookie errors appropriately.", {
# Stub a session so we can test these outside of shiny.
session <- structure(list(), class = "ShinySession")
session$sendCustomMessage <- function(type, message) {
my_types <- c("cookie-set", "cookie-remove")
if (!(type %in% my_types)) {
stop("Bad type.")
}
return(
jsonlite::toJSON(message)
)
}

session$input <- list(
cookies_start = list(normal_cookie = 2)
)
Expand Down

0 comments on commit d0f38ae

Please sign in to comment.