From 749e2da02b02b84514881c081fe98ecd17d1ec89 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Fri, 21 Aug 2020 13:33:15 -0700 Subject: [PATCH 1/6] Allow leafletProxy arguments to contain JS() Fixes #420, #440 --- NEWS | 2 +- R/utils.R | 4 +++- inst/htmlwidgets/leaflet.js | 15 ++++++++++++++- javascript/src/index.js | 13 ++++++++++++- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index ee20f4319..bb32ca8e0 100644 --- a/NEWS +++ b/NEWS @@ -5,7 +5,7 @@ FEATURES * BUG FIXES and IMPROVEMENTS -* +* Enable JS function literals (wrapped in `htmlwidgets::JS()`) to be included in arguments to methods invoked on `leafletProxy` objects. (JS function literals could already be included with methods invoked on `leaflet` objects, so this change just brings `leafletProxy` to parity.) (#420) diff --git a/R/utils.R b/R/utils.R index 13a89f0d0..64aad6038 100644 --- a/R/utils.R +++ b/R/utils.R @@ -202,7 +202,9 @@ invokeRemote <- function(map, method, args = list()) { list( dependencies = lapply(deps, shiny::createWebDependency), method = method, - args = args + args = lapply(args, function(arg) { + list(arg = arg, evals = htmlwidgets:::JSEvals(arg)) + }) ) ) ) diff --git a/inst/htmlwidgets/leaflet.js b/inst/htmlwidgets/leaflet.js index c71927b02..88a0f6ac6 100644 --- a/inst/htmlwidgets/leaflet.js +++ b/inst/htmlwidgets/leaflet.js @@ -833,6 +833,18 @@ _htmlwidgets2["default"].widget({ } }); +function unpackArgs(arg) { + if (!arg.hasOwnProperty("arg") && !arg.hasOwnProperty("evals")) { + throw new Error("Malformed argument; .arg and .evals expected"); + } + + for (var i = 0; i < arg.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(arg.arg, arg.evals[i]); + } + + return arg.arg; +} + if (_htmlwidgets2["default"].shinyMode) { _shiny2["default"].addCustomMessageHandler("leaflet-calls", function (data) { var id = data.id; @@ -846,12 +858,13 @@ if (_htmlwidgets2["default"].shinyMode) { for (var i = 0; i < data.calls.length; i++) { var call = data.calls[i]; + var args = call.args.map(unpackArgs); if (call.dependencies) { _shiny2["default"].renderDependencies(call.dependencies); } - if (methods[call.method]) methods[call.method].apply(map, call.args);else (0, _util.log)("Unknown method " + call.method); + if (methods[call.method]) methods[call.method].apply(map, args);else (0, _util.log)("Unknown method " + call.method); } }); } diff --git a/javascript/src/index.js b/javascript/src/index.js index 3230ec298..5e842464d 100644 --- a/javascript/src/index.js +++ b/javascript/src/index.js @@ -280,6 +280,16 @@ HTMLWidgets.widget({ } }); +function unpackArgs(arg) { + if (!arg.hasOwnProperty("arg") && !arg.hasOwnProperty("evals")) { + throw new Error("Malformed argument; .arg and .evals expected"); + } + for (let i = 0; i < arg.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(arg.arg, arg.evals[i]); + } + return arg.arg; +} + if (HTMLWidgets.shinyMode) { Shiny.addCustomMessageHandler("leaflet-calls", function(data) { let id = data.id; @@ -292,11 +302,12 @@ if (HTMLWidgets.shinyMode) { for (let i = 0; i < data.calls.length; i++) { let call = data.calls[i]; + let args = call.args.map(unpackArgs); if (call.dependencies) { Shiny.renderDependencies(call.dependencies); } if (methods[call.method]) - methods[call.method].apply(map, call.args); + methods[call.method].apply(map, args); else log("Unknown method " + call.method); } From 6046fae795c13c3192a83f98e088de6f2fb4a53b Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Fri, 21 Aug 2020 15:01:53 -0700 Subject: [PATCH 2/6] Pass tests --- R/utils.R | 2 +- inst/htmlwidgets/leaflet.js | 4 ++-- javascript/src/index.js | 4 ++-- tests/testthat/test-remote.R | 11 ++++------- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/R/utils.R b/R/utils.R index 64aad6038..27a3a8193 100644 --- a/R/utils.R +++ b/R/utils.R @@ -203,7 +203,7 @@ invokeRemote <- function(map, method, args = list()) { dependencies = lapply(deps, shiny::createWebDependency), method = method, args = lapply(args, function(arg) { - list(arg = arg, evals = htmlwidgets:::JSEvals(arg)) + list(value = arg, evals = htmlwidgets:::JSEvals(arg)) }) ) ) diff --git a/inst/htmlwidgets/leaflet.js b/inst/htmlwidgets/leaflet.js index 88a0f6ac6..032ff46ad 100644 --- a/inst/htmlwidgets/leaflet.js +++ b/inst/htmlwidgets/leaflet.js @@ -839,10 +839,10 @@ function unpackArgs(arg) { } for (var i = 0; i < arg.evals.length; i++) { - window.HTMLWidgets.evaluateStringMember(arg.arg, arg.evals[i]); + window.HTMLWidgets.evaluateStringMember(arg.value, arg.evals[i]); } - return arg.arg; + return arg.value; } if (_htmlwidgets2["default"].shinyMode) { diff --git a/javascript/src/index.js b/javascript/src/index.js index 5e842464d..76bfe37ca 100644 --- a/javascript/src/index.js +++ b/javascript/src/index.js @@ -285,9 +285,9 @@ function unpackArgs(arg) { throw new Error("Malformed argument; .arg and .evals expected"); } for (let i = 0; i < arg.evals.length; i++) { - window.HTMLWidgets.evaluateStringMember(arg.arg, arg.evals[i]); + window.HTMLWidgets.evaluateStringMember(arg.value, arg.evals[i]); } - return arg.arg; + return arg.value; } if (HTMLWidgets.shinyMode) { diff --git a/tests/testthat/test-remote.R b/tests/testthat/test-remote.R index dee27413d..9e6ae0075 100644 --- a/tests/testthat/test-remote.R +++ b/tests/testthat/test-remote.R @@ -152,8 +152,7 @@ test_that("mockSession tests", { mockSession$.flush() # nolint start - expected <- list(structure(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addPolygons\",\"args\":[[[[{\"lng\":[1,2,3,4,5],\"lat\":[1,2,3,4,5]}]]],null,null,{\"interactive\":true,\"className\":\"\",\"stroke\":true,\"color\":\"#03F\",\"weight\":5,\"opacity\":0.5,\"fill\":true,\"fillColor\":\"#03F\",\"fillOpacity\":0.2,\"smoothFactor\":1,\"noClip\":false},null,null,null,{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},null]}]}", class = "json")), .Names = c("type", - "message"))) + expected <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addPolygons\",\"args\":[{\"value\":[[[{\"lng\":[1,2,3,4,5],\"lat\":[1,2,3,4,5]}]]],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"className\":\"\",\"stroke\":true,\"color\":\"#03F\",\"weight\":5,\"opacity\":0.5,\"fill\":true,\"fillColor\":\"#03F\",\"fillOpacity\":0.2,\"smoothFactor\":1,\"noClip\":false},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) # nolint end # dput(mockSession$.calls) @@ -170,8 +169,7 @@ test_that("mockSession tests", { ) # Check that addMarkers() takes effect immediately, no flush required remote2 %>% addMarkers() - expected2 <- list(structure(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[[10,9,8,7,6,5,4,3,2,1],[10,9,8,7,6,5,4,3,2,1],null,null,null,{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},null,null,null,null,null,{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},null]}]}", class = "json")), .Names = c("type", - "message"))) # nolint + expected2 <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) # nolint # cat(deparse(mockSession$.calls), "\n") expect_equal(mockSession$.calls, expected2) # Flushing should do nothing @@ -189,9 +187,8 @@ test_that("mockSession tests", { expect_equal(mockSession$.calls, list()) mockSession$.flush() # nolint start - expected3 <- list(structure(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"clearShapes\",\"args\":[]}]}", class = "json")), .Names = c("type", - "message")), structure(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[[10,9,8,7,6,5,4,3,2,1],[10,9,8,7,6,5,4,3,2,1],null,null,null,{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},null,null,null,null,null,{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},null]}]}", class = "json")), .Names = c("type", - "message"))) + expected3 <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"clearShapes\",\"args\":[]}]}", class = "json")), + list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) # nolint end # Check that multiple calls are invoked in order From aab8e78ef181f84ab868e6b1ae3160b0ff5923c7 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Tue, 25 Aug 2020 15:10:50 -0700 Subject: [PATCH 3/6] Use version of htmlwidgets that exports JSEvals --- DESCRIPTION | 4 +++- R/utils.R | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 998d10811..a1bea8472 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -37,7 +37,7 @@ Depends: R (>= 3.1.0) Imports: base64enc, crosstalk, - htmlwidgets, + htmlwidgets (>= 1.5.1.9002), htmltools, magrittr, markdown, @@ -61,6 +61,8 @@ Suggests: RJSONIO, purrr, testthat +Remotes: + ramnathv/htmlwidgets RoxygenNote: 7.1.1 Encoding: UTF-8 LazyData: true diff --git a/R/utils.R b/R/utils.R index 27a3a8193..eece5431b 100644 --- a/R/utils.R +++ b/R/utils.R @@ -203,7 +203,7 @@ invokeRemote <- function(map, method, args = list()) { dependencies = lapply(deps, shiny::createWebDependency), method = method, args = lapply(args, function(arg) { - list(value = arg, evals = htmlwidgets:::JSEvals(arg)) + list(value = arg, evals = htmlwidgets::JSEvals(arg)) }) ) ) From 6dabf5a34ac970d7df3d45ed461068bef6a676ee Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Wed, 22 Sep 2021 10:32:01 -0700 Subject: [PATCH 4/6] Fix incorrect arg/evals validation --- inst/htmlwidgets/leaflet.js | 4 ++-- javascript/src/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/inst/htmlwidgets/leaflet.js b/inst/htmlwidgets/leaflet.js index 032ff46ad..8c4d818e1 100644 --- a/inst/htmlwidgets/leaflet.js +++ b/inst/htmlwidgets/leaflet.js @@ -834,8 +834,8 @@ _htmlwidgets2["default"].widget({ }); function unpackArgs(arg) { - if (!arg.hasOwnProperty("arg") && !arg.hasOwnProperty("evals")) { - throw new Error("Malformed argument; .arg and .evals expected"); + if (!Object.prototype.hasOwnProperty.call(arg, "value") || !Object.prototype.hasOwnProperty.call(arg, "evals")) { + throw new Error("Malformed argument; .value and .evals expected"); } for (var i = 0; i < arg.evals.length; i++) { diff --git a/javascript/src/index.js b/javascript/src/index.js index 76bfe37ca..cc882484c 100644 --- a/javascript/src/index.js +++ b/javascript/src/index.js @@ -281,8 +281,8 @@ HTMLWidgets.widget({ }); function unpackArgs(arg) { - if (!arg.hasOwnProperty("arg") && !arg.hasOwnProperty("evals")) { - throw new Error("Malformed argument; .arg and .evals expected"); + if (!Object.prototype.hasOwnProperty.call(arg, "value") || !Object.prototype.hasOwnProperty.call(arg, "evals")) { + throw new Error("Malformed argument; .value and .evals expected"); } for (let i = 0; i < arg.evals.length; i++) { window.HTMLWidgets.evaluateStringMember(arg.value, arg.evals[i]); From 5035a286c8f16e2f3e4b85ec40b9eb3ce5756d67 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Wed, 22 Sep 2021 10:53:15 -0700 Subject: [PATCH 5/6] More efficient JS() serialization for leafletProxy Also, use snapshot testing for remote unit tests --- DESCRIPTION | 2 +- R/utils.R | 5 ++- inst/htmlwidgets/leaflet.js | 18 +++-------- javascript/src/index.js | 15 +++------ tests/testthat/_snaps/remote.md | 52 +++++++++++++++++++++++++++++++ tests/testthat/test-remote.R | 54 ++++++++++++++++++++++----------- 6 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 tests/testthat/_snaps/remote.md diff --git a/DESCRIPTION b/DESCRIPTION index a1bea8472..a91a11b36 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -60,7 +60,7 @@ Suggests: R6, RJSONIO, purrr, - testthat + testthat (>= 3.0.0) Remotes: ramnathv/htmlwidgets RoxygenNote: 7.1.1 diff --git a/R/utils.R b/R/utils.R index eece5431b..a7c775cbe 100644 --- a/R/utils.R +++ b/R/utils.R @@ -202,9 +202,8 @@ invokeRemote <- function(map, method, args = list()) { list( dependencies = lapply(deps, shiny::createWebDependency), method = method, - args = lapply(args, function(arg) { - list(value = arg, evals = htmlwidgets::JSEvals(arg)) - }) + args = args, + evals = htmlwidgets::JSEvals(args) ) ) ) diff --git a/inst/htmlwidgets/leaflet.js b/inst/htmlwidgets/leaflet.js index 8c4d818e1..40c6b65a6 100644 --- a/inst/htmlwidgets/leaflet.js +++ b/inst/htmlwidgets/leaflet.js @@ -833,18 +833,6 @@ _htmlwidgets2["default"].widget({ } }); -function unpackArgs(arg) { - if (!Object.prototype.hasOwnProperty.call(arg, "value") || !Object.prototype.hasOwnProperty.call(arg, "evals")) { - throw new Error("Malformed argument; .value and .evals expected"); - } - - for (var i = 0; i < arg.evals.length; i++) { - window.HTMLWidgets.evaluateStringMember(arg.value, arg.evals[i]); - } - - return arg.value; -} - if (_htmlwidgets2["default"].shinyMode) { _shiny2["default"].addCustomMessageHandler("leaflet-calls", function (data) { var id = data.id; @@ -858,7 +846,11 @@ if (_htmlwidgets2["default"].shinyMode) { for (var i = 0; i < data.calls.length; i++) { var call = data.calls[i]; - var args = call.args.map(unpackArgs); + var args = call.args; + + for (var _i = 0; _i < call.evals.length; _i++) { + window.HTMLWidgets.evaluateStringMember(args, call.evals[_i]); + } if (call.dependencies) { _shiny2["default"].renderDependencies(call.dependencies); diff --git a/javascript/src/index.js b/javascript/src/index.js index cc882484c..ca7048e66 100644 --- a/javascript/src/index.js +++ b/javascript/src/index.js @@ -280,16 +280,6 @@ HTMLWidgets.widget({ } }); -function unpackArgs(arg) { - if (!Object.prototype.hasOwnProperty.call(arg, "value") || !Object.prototype.hasOwnProperty.call(arg, "evals")) { - throw new Error("Malformed argument; .value and .evals expected"); - } - for (let i = 0; i < arg.evals.length; i++) { - window.HTMLWidgets.evaluateStringMember(arg.value, arg.evals[i]); - } - return arg.value; -} - if (HTMLWidgets.shinyMode) { Shiny.addCustomMessageHandler("leaflet-calls", function(data) { let id = data.id; @@ -302,7 +292,10 @@ if (HTMLWidgets.shinyMode) { for (let i = 0; i < data.calls.length; i++) { let call = data.calls[i]; - let args = call.args.map(unpackArgs); + let args = call.args; + for (let i = 0; i < call.evals.length; i++) { + window.HTMLWidgets.evaluateStringMember(args, call.evals[i]); + } if (call.dependencies) { Shiny.renderDependencies(call.dependencies); } diff --git a/tests/testthat/_snaps/remote.md b/tests/testthat/_snaps/remote.md new file mode 100644 index 000000000..627aefb18 --- /dev/null +++ b/tests/testthat/_snaps/remote.md @@ -0,0 +1,52 @@ +# mockSession tests + + [[1]] + [[1]]$type + [1] "leaflet-calls" + + [[1]]$message + {"id":"map","calls":[{"dependencies":[],"method":"addPolygons","args":[[[[{"lng":[1,2,3,4,5],"lat":[1,2,3,4,5]}]]],null,null,{"interactive":true,"className":"","stroke":true,"color":"#03F","weight":5,"opacity":0.5,"fill":true,"fillColor":"#03F","fillOpacity":0.2,"smoothFactor":1,"noClip":false},null,null,null,{"interactive":false,"permanent":false,"direction":"auto","opacity":1,"offset":[0,0],"textsize":"10px","textOnly":false,"className":"","sticky":true},null],"evals":[]}]} + + + +--- + + [[1]] + [[1]]$type + [1] "leaflet-calls" + + [[1]]$message + {"id":"map","calls":[{"dependencies":[],"method":"addMarkers","args":[[10,9,8,7,6,5,4,3,2,1],[10,9,8,7,6,5,4,3,2,1],null,null,null,{"interactive":true,"draggable":false,"keyboard":true,"title":"","alt":"","zIndexOffset":0,"opacity":1,"riseOnHover":false,"riseOffset":250},null,null,null,null,null,{"interactive":false,"permanent":false,"direction":"auto","opacity":1,"offset":[0,0],"textsize":"10px","textOnly":false,"className":"","sticky":true},null],"evals":[]}]} + + + +--- + + [[1]] + [[1]]$type + [1] "leaflet-calls" + + [[1]]$message + {"id":"map","calls":[{"dependencies":[],"method":"clearShapes","args":[],"evals":[]}]} + + + [[2]] + [[2]]$type + [1] "leaflet-calls" + + [[2]]$message + {"id":"map","calls":[{"dependencies":[],"method":"addMarkers","args":[[10,9,8,7,6,5,4,3,2,1],[10,9,8,7,6,5,4,3,2,1],null,null,null,{"interactive":true,"draggable":false,"keyboard":true,"title":"","alt":"","zIndexOffset":0,"opacity":1,"riseOnHover":false,"riseOffset":250},null,null,null,null,null,{"interactive":false,"permanent":false,"direction":"auto","opacity":1,"offset":[0,0],"textsize":"10px","textOnly":false,"className":"","sticky":true},null],"evals":[]}]} + + + +# leafletProxy with JS() + + [[1]] + [[1]]$type + [1] "leaflet-calls" + + [[1]]$message + {"id":"map","calls":[{"dependencies":[{"name":"leaflet-markercluster","version":"1.0.5","src":{"href":"leaflet-markercluster-1.0.5"},"meta":null,"script":["leaflet.markercluster.js","leaflet.markercluster.freezable.js","leaflet.markercluster.layersupport.js"],"stylesheet":["MarkerCluster.css","MarkerCluster.Default.css"],"head":null,"attachment":null,"package":null,"all_files":true}],"method":"addMarkers","args":[[52.37712,52.37783,52.37755],[4.905167,4.906357,4.905831],null,null,null,{"interactive":true,"draggable":false,"keyboard":true,"title":"","alt":"","zIndexOffset":0,"opacity":1,"riseOnHover":false,"riseOffset":250},null,null,{"showCoverageOnHover":true,"zoomToBoundsOnClick":true,"spiderfyOnMaxZoom":true,"removeOutsideVisibleBounds":true,"spiderLegPolylineOptions":{"weight":1.5,"color":"#222","opacity":0.5},"freezeAtZoom":false,"iconCreateFunction":"function(cluster) {console.log('Here comes cluster',cluster); return new L.DivIcon({html: '
' + cluster.getChildCount() + '<\/div>',className: 'marker-cluster'});}"},null,null,{"interactive":false,"permanent":false,"direction":"auto","opacity":1,"offset":[0,0],"textsize":"10px","textOnly":false,"className":"","sticky":true},null],"evals":["8.iconCreateFunction"]}]} + + + diff --git a/tests/testthat/test-remote.R b/tests/testthat/test-remote.R index 9e6ae0075..3cf817f6b 100644 --- a/tests/testthat/test-remote.R +++ b/tests/testthat/test-remote.R @@ -139,6 +139,8 @@ MockSession <- R6Class("MockSession", test_that("mockSession tests", { + testthat::local_edition(3) + local <- leaflet() mockSession <- MockSession$new() @@ -151,13 +153,8 @@ test_that("mockSession tests", { expect_equal(mockSession$.calls, list()) mockSession$.flush() - # nolint start - expected <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addPolygons\",\"args\":[{\"value\":[[[{\"lng\":[1,2,3,4,5],\"lat\":[1,2,3,4,5]}]]],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"className\":\"\",\"stroke\":true,\"color\":\"#03F\",\"weight\":5,\"opacity\":0.5,\"fill\":true,\"fillColor\":\"#03F\",\"fillOpacity\":0.2,\"smoothFactor\":1,\"noClip\":false},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) - # nolint end - - # dput(mockSession$.calls) - expect_equal(mockSession$.calls, expected) + expect_snapshot_output(mockSession$.calls) # Reset mock session mockSession$.calls <- list() @@ -169,13 +166,11 @@ test_that("mockSession tests", { ) # Check that addMarkers() takes effect immediately, no flush required remote2 %>% addMarkers() - expected2 <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) # nolint - # cat(deparse(mockSession$.calls), "\n") - expect_equal(mockSession$.calls, expected2) + expect_snapshot_output(mockSession$.calls) + beforeFlush <- mockSession$.calls # Flushing should do nothing mockSession$.flush() - # cat(deparse(mockSession$.calls), "\n") - expect_equal(mockSession$.calls, expected2) + expect_identical(mockSession$.calls, beforeFlush) # Reset mock session mockSession$.calls <- list() @@ -186,11 +181,36 @@ test_that("mockSession tests", { remote3 %>% clearShapes() %>% addMarkers() expect_equal(mockSession$.calls, list()) mockSession$.flush() - # nolint start - expected3 <- list(list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"clearShapes\",\"args\":[]}]}", class = "json")), - list(type = "leaflet-calls", message = structure("{\"id\":\"map\",\"calls\":[{\"dependencies\":[],\"method\":\"addMarkers\",\"args\":[{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":[10,9,8,7,6,5,4,3,2,1],\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":true,\"draggable\":false,\"keyboard\":true,\"title\":\"\",\"alt\":\"\",\"zIndexOffset\":0,\"opacity\":1,\"riseOnHover\":false,\"riseOffset\":250},\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":null,\"evals\":[]},{\"value\":{\"interactive\":false,\"permanent\":false,\"direction\":\"auto\",\"opacity\":1,\"offset\":[0,0],\"textsize\":\"10px\",\"textOnly\":false,\"className\":\"\",\"sticky\":true},\"evals\":[]},{\"value\":null,\"evals\":[]}]}]}", class = "json"))) - # nolint end + expect_snapshot_output(mockSession$.calls) +}) + +test_that("leafletProxy with JS()", { + testthat::local_edition(3) + + some_data <- data.frame( + "lon"=c(4.905167,4.906357,4.905831), + "lat"=c(52.37712,52.37783,52.37755), + "number_var"=c(5,9,7), + "name"=c("Jane","Harold","Mike"), + stringsAsFactors = F + ) + + mockSession <- MockSession$new() + remote <- leafletProxy("map", mockSession) + remote %>% addMarkers( + lng = some_data$lon, + lat = some_data$lat, + clusterOptions = markerClusterOptions( + iconCreateFunction = JS(paste0("function(cluster) {", + "console.log('Here comes cluster',cluster); ", + "return new L.DivIcon({", + "html: '
' + cluster.getChildCount() + '
',", + "className: 'marker-cluster'", + "});", + "}")) + ) + ) + mockSession$.flush() - # Check that multiple calls are invoked in order - expect_equal(mockSession$.calls, expected3) + expect_snapshot_output(mockSession$.calls) }) From 385895ab5a011efae00207d109fc8d999dc64f28 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Wed, 22 Sep 2021 11:03:57 -0700 Subject: [PATCH 6/6] Remove htmlwidgets from Remotes --- DESCRIPTION | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index a91a11b36..cafa6022b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -37,7 +37,7 @@ Depends: R (>= 3.1.0) Imports: base64enc, crosstalk, - htmlwidgets (>= 1.5.1.9002), + htmlwidgets (>= 1.5.4), htmltools, magrittr, markdown, @@ -61,8 +61,6 @@ Suggests: RJSONIO, purrr, testthat (>= 3.0.0) -Remotes: - ramnathv/htmlwidgets RoxygenNote: 7.1.1 Encoding: UTF-8 LazyData: true