diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..082b1943 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "makefile.configureOnOpen": false +} \ No newline at end of file diff --git a/inst/examples/restore-workspace/app.R b/inst/examples/restore-workspace/app.R index 66f19f51..ee30aa42 100644 --- a/inst/examples/restore-workspace/app.R +++ b/inst/examples/restore-workspace/app.R @@ -2,12 +2,14 @@ library(blockr) set_workspace( stack_1 = new_stack( + # Won't autoclick on submit block_11 = new_dataset_block("anscombe"), - block_12 = new_select_block(c("x1", "y1")) + block_12 = new_filter_block("x1", 10, ">") ), + # Submit autoclick stack_2 = new_stack( block_21 = new_dataset_block("anscombe"), - block_22 = new_select_block(c("x2", "y2")) + block_22 = new_filter_block("x1", 10, ">", submit = TRUE) ) ) diff --git a/tests/testthat/_snaps/block/block-app-001_.new.png b/tests/testthat/_snaps/block/block-app-001_.new.png index 81d792b4..cda1709a 100644 Binary files a/tests/testthat/_snaps/block/block-app-001_.new.png and b/tests/testthat/_snaps/block/block-app-001_.new.png differ diff --git a/tests/testthat/_snaps/block/block-app-003_.new.png b/tests/testthat/_snaps/block/block-app-003_.new.png index febafb5a..b4d056ed 100644 Binary files a/tests/testthat/_snaps/block/block-app-003_.new.png and b/tests/testthat/_snaps/block/block-app-003_.new.png differ diff --git a/tests/testthat/_snaps/block/block-app-004_.new.png b/tests/testthat/_snaps/block/block-app-004_.new.png index c05f8aff..7cf37837 100644 Binary files a/tests/testthat/_snaps/block/block-app-004_.new.png and b/tests/testthat/_snaps/block/block-app-004_.new.png differ diff --git a/tests/testthat/_snaps/block/block-autosubmit-app-001.json b/tests/testthat/_snaps/block/block-autosubmit-app-001.json new file mode 100644 index 00000000..0d06a854 --- /dev/null +++ b/tests/testthat/_snaps/block/block-autosubmit-app-001.json @@ -0,0 +1,181 @@ +{ + "input": { + "my_stack-block_2-submit": 0 + }, + "output": { + "my_stack-block_2-res": { + "x": { + "style": "bootstrap5", + "filter": "none", + "vertical": false, + "container": "\n \n \n
<\/th>\n x1<\/th>\n x2<\/th>\n x3<\/th>\n x4<\/th>\n y1<\/th>\n y2<\/th>\n y3<\/th>\n y4<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "options": { + "pageLength": 5, + "processing": false, + "columnDefs": [ + { + "className": "dt-right", + "targets": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "orderable": false, + "targets": 0 + }, + { + "name": " ", + "targets": 0 + }, + { + "name": "x1", + "targets": 1 + }, + { + "name": "x2", + "targets": 2 + }, + { + "name": "x3", + "targets": 3 + }, + { + "name": "x4", + "targets": 4 + }, + { + "name": "y1", + "targets": 5 + }, + { + "name": "y2", + "targets": 6 + }, + { + "name": "y3", + "targets": 7 + }, + { + "name": "y4", + "targets": 8 + } + ], + "order": [ + + ], + "autoWidth": false, + "orderClasses": false, + "lengthMenu": [ + 5, + 10, + 25, + 50, + 100 + ], + "ajax": { + "type": "POST", + "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = true;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" + }, + "serverSide": true + }, + "selection": { + "mode": "none", + "selected": null, + "target": "row", + "selectable": null + } + }, + "evals": [ + "options.ajax.data" + ], + "jsHooks": [ + + ], + "deps": [ + { + "name": "jquery", + "version": "3.6.0", + "src": { + "href": "jquery-3.6.0" + }, + "meta": null, + "script": "jquery-3.6.0.min.js", + "stylesheet": null, + "head": null, + "attachment": null, + "all_files": true + }, + { + "name": "dt-core-bootstrap5", + "version": "1.13.6", + "src": { + "href": "dt-core-bootstrap5-1.13.6" + }, + "meta": null, + "script": [ + "js/jquery.dataTables.min.js", + "js/dataTables.bootstrap5.min.js" + ], + "stylesheet": "css/dataTables.bootstrap5.min.css", + "head": null, + "attachment": null, + "package": null, + "all_files": false + }, + { + "name": "bootstrap", + "version": "5.3.1", + "src": { + "href": "bootstrap-5.3.1" + }, + "meta": { + "viewport": "width=device-width, initial-scale=1, shrink-to-fit=no" + }, + "script": "bootstrap.bundle.min.js", + "stylesheet": "bootstrap.min.css", + "head": null, + "attachment": null, + "package": null, + "all_files": true + }, + { + "name": "bs3compat", + "version": "0.8.0", + "src": { + "href": "bs3compat-0.8.0" + }, + "meta": null, + "script": [ + "transition.js", + "tabs.js", + "bs3compat.js" + ], + "stylesheet": null, + "head": null, + "attachment": null, + "all_files": true + }, + { + "name": "crosstalk", + "version": "1.2.1", + "src": { + "href": "crosstalk-1.2.1" + }, + "meta": null, + "script": "js/crosstalk.min.js", + "stylesheet": "css/crosstalk.min.css", + "head": null, + "attachment": null, + "all_files": true + } + ] + } + } +} diff --git a/tests/testthat/_snaps/block/block-submit-app-001.json b/tests/testthat/_snaps/block/block-submit-app-001.json new file mode 100644 index 00000000..2f7a4dfa --- /dev/null +++ b/tests/testthat/_snaps/block/block-submit-app-001.json @@ -0,0 +1,12 @@ +{ + "input": { + "my_stack-block_2-submit": 0 + }, + "output": { + "my_stack-block_2-res": [ + "", + "NULL", + "c(\"shiny.silent.error\", \"validation\")" + ] + } +} diff --git a/tests/testthat/_snaps/block/block-submit-app-002.json b/tests/testthat/_snaps/block/block-submit-app-002.json new file mode 100644 index 00000000..dcb7948a --- /dev/null +++ b/tests/testthat/_snaps/block/block-submit-app-002.json @@ -0,0 +1,181 @@ +{ + "input": { + "my_stack-block_2-submit": 1 + }, + "output": { + "my_stack-block_2-res": { + "x": { + "style": "bootstrap5", + "filter": "none", + "vertical": false, + "container": "\n \n \n
<\/th>\n x1<\/th>\n x2<\/th>\n x3<\/th>\n x4<\/th>\n y1<\/th>\n y2<\/th>\n y3<\/th>\n y4<\/th>\n <\/tr>\n <\/thead>\n<\/table>", + "options": { + "pageLength": 5, + "processing": false, + "columnDefs": [ + { + "className": "dt-right", + "targets": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ] + }, + { + "orderable": false, + "targets": 0 + }, + { + "name": " ", + "targets": 0 + }, + { + "name": "x1", + "targets": 1 + }, + { + "name": "x2", + "targets": 2 + }, + { + "name": "x3", + "targets": 3 + }, + { + "name": "x4", + "targets": 4 + }, + { + "name": "y1", + "targets": 5 + }, + { + "name": "y2", + "targets": 6 + }, + { + "name": "y3", + "targets": 7 + }, + { + "name": "y4", + "targets": 8 + } + ], + "order": [ + + ], + "autoWidth": false, + "orderClasses": false, + "lengthMenu": [ + 5, + 10, + 25, + 50, + 100 + ], + "ajax": { + "type": "POST", + "data": "function(d) {\nd.search.caseInsensitive = true;\nd.search.smart = true;\nd.escape = true;\nvar encodeAmp = function(x) { x.value = x.value.replace(/&/g, \"%26\"); }\nencodeAmp(d.search);\n$.each(d.columns, function(i, v) {encodeAmp(v.search);});\n}" + }, + "serverSide": true + }, + "selection": { + "mode": "none", + "selected": null, + "target": "row", + "selectable": null + } + }, + "evals": [ + "options.ajax.data" + ], + "jsHooks": [ + + ], + "deps": [ + { + "name": "jquery", + "version": "3.6.0", + "src": { + "href": "jquery-3.6.0" + }, + "meta": null, + "script": "jquery-3.6.0.min.js", + "stylesheet": null, + "head": null, + "attachment": null, + "all_files": true + }, + { + "name": "dt-core-bootstrap5", + "version": "1.13.6", + "src": { + "href": "dt-core-bootstrap5-1.13.6" + }, + "meta": null, + "script": [ + "js/jquery.dataTables.min.js", + "js/dataTables.bootstrap5.min.js" + ], + "stylesheet": "css/dataTables.bootstrap5.min.css", + "head": null, + "attachment": null, + "package": null, + "all_files": false + }, + { + "name": "bootstrap", + "version": "5.3.1", + "src": { + "href": "bootstrap-5.3.1" + }, + "meta": { + "viewport": "width=device-width, initial-scale=1, shrink-to-fit=no" + }, + "script": "bootstrap.bundle.min.js", + "stylesheet": "bootstrap.min.css", + "head": null, + "attachment": null, + "package": null, + "all_files": true + }, + { + "name": "bs3compat", + "version": "0.8.0", + "src": { + "href": "bs3compat-0.8.0" + }, + "meta": null, + "script": [ + "transition.js", + "tabs.js", + "bs3compat.js" + ], + "stylesheet": null, + "head": null, + "attachment": null, + "all_files": true + }, + { + "name": "crosstalk", + "version": "1.2.1", + "src": { + "href": "crosstalk-1.2.1" + }, + "meta": null, + "script": "js/crosstalk.min.js", + "stylesheet": "css/crosstalk.min.css", + "head": null, + "attachment": null, + "all_files": true + } + ] + } + } +} diff --git a/tests/testthat/_snaps/workspace/restore-workspace-app-001_.new.png b/tests/testthat/_snaps/workspace/restore-workspace-app-001_.new.png index d35bf4b7..ccb4007e 100644 Binary files a/tests/testthat/_snaps/workspace/restore-workspace-app-001_.new.png and b/tests/testthat/_snaps/workspace/restore-workspace-app-001_.new.png differ diff --git a/tests/testthat/test-block.R b/tests/testthat/test-block.R index 1ad9ffa0..d7a6e482 100644 --- a/tests/testthat/test-block.R +++ b/tests/testthat/test-block.R @@ -1,5 +1,4 @@ test_that("data blocks", { - dat1 <- datasets::iris blk1 <- new_dataset_block() @@ -38,7 +37,6 @@ test_that("data blocks", { }) test_that("filter blocks", { - data <- datasets::iris blk1 <- new_filter_block() @@ -65,7 +63,6 @@ test_that("filter blocks", { }) test_that("select blocks", { - data <- datasets::iris blk1 <- new_select_block() @@ -92,7 +89,6 @@ test_that("select blocks", { }) test_that("arrange blocks", { - data <- datasets::iris blk1 <- new_arrange_block() @@ -117,7 +113,6 @@ test_that("arrange blocks", { }) test_that("group_by blocks", { - data <- datasets::iris blk1 <- new_group_by_block() @@ -142,7 +137,6 @@ test_that("group_by blocks", { }) test_that("join blocks", { - datx <- dplyr::band_members daty <- dplyr::band_instruments @@ -170,7 +164,6 @@ test_that("join blocks", { }) test_that("head blocks", { - data <- datasets::iris blk1 <- new_head_block() @@ -197,7 +190,6 @@ test_that("head blocks", { }) test_that("summarize block", { - data <- datasets::iris blk1 <- new_summarize_block() @@ -225,7 +217,6 @@ test_that("summarize block", { test_that("upload block", { - blk1 <- new_upload_block() expect_s3_class(blk1, "data_block") @@ -252,7 +243,6 @@ test_that("upload block", { }) test_that("filesbrowser block", { - blk1 <- new_filesbrowser_block() expect_s3_class(blk1, "data_block") @@ -279,7 +269,6 @@ test_that("filesbrowser block", { }) test_that("csv parser block", { - data <- datasets::iris path <- withr::local_tempfile() @@ -298,7 +287,6 @@ test_that("csv parser block", { }) test_that("json parser block", { - data <- datasets::iris path <- withr::local_tempfile() @@ -317,7 +305,6 @@ test_that("json parser block", { }) test_that("rds parser block", { - data <- datasets::iris path <- withr::local_tempfile() @@ -336,7 +323,6 @@ test_that("rds parser block", { }) test_that("xpt parser block", { - data <- datasets::iris colnames(data) <- gsub("\\.", "_", colnames(data)) @@ -366,7 +352,6 @@ test_that("block title", { }) test_that("blocks can be constructed with default args", { - for (block in available_blocks()) { expect_s3_class(do.call(block, list()), "block") } @@ -391,13 +376,14 @@ test_that("submit works", { }) test_that("blocks can be updated", { - block_test_server <- function(id, x, dat = NULL, ...) { if (is.null(dat)) { generate_server(x = x, id = id, ...) } else { - generate_server(x = x, in_dat = shiny::reactive(dat), id = id, - is_prev_valid = shiny::reactive(TRUE), ...) + generate_server( + x = x, in_dat = shiny::reactive(dat), id = id, + is_prev_valid = shiny::reactive(TRUE), ... + ) } } @@ -588,3 +574,71 @@ test_that("block demo works", { output = blocks_outputs ) }) + +test_that("submit e2e", { + skip_on_cran() + skip_on_covr() + + stack <- new_stack( + block_1 = new_dataset_block("anscombe"), + block_2 = new_filter_block(columns = "x1", values = 10, filter_fun = ">") + ) + + blocks_app <- serve_stack(stack) + + app <- AppDriver$new( + blocks_app, + name = "block-submit-app" + ) + + app$click(selector = ".stack-edit-toggle") + + app$expect_values( + # Button should be 0 + input = "my_stack-block_2-submit", + # res should not be computed + output = "my_stack-block_2-res", + screenshot_args = FALSE + ) + + # Submit + app$click(selector = "#my_stack-block_2-submit") + + app$expect_values( + # Button should be 1 + input = "my_stack-block_2-submit", + # res should be computed + output = "my_stack-block_2-res", + screenshot_args = FALSE + ) + + # Submit is disabled if block is invalid + app$set_inputs("my_stack-block_2-filter_func" = "") + submit_btn <- app$get_html(selector = "#my_stack-block_2-submit") + expect_true(grepl("disabled", submit_btn)) + + app$stop() + + # Autoclick on submit + stack <- new_stack( + block_1 = new_dataset_block("anscombe"), + block_2 = new_filter_block(columns = "x1", values = 10, filter_fun = ">", submit = TRUE) + ) + + blocks_app <- serve_stack(stack) + + app <- AppDriver$new( + blocks_app, + name = "block-autosubmit-app" + ) + + app$click(selector = ".stack-edit-toggle") + + app$expect_values( + # Button should be 1 + input = "my_stack-block_2-submit", + # res should be computed + output = "my_stack-block_2-res", + screenshot_args = FALSE + ) +})