Nothing
library(shinytest2)
# Use edition 2 api of testthat
# Only using it locally here due to shinytest2 having issues with e3
local_edition(2)
# Init code to be able to call "checkForChange()"
setup_wait_for_change <- function(app) {
# Start counting changes to MainContent
app$run_js("
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || obj.nodeType !== 1 ) return;
if( MutationObserver ){
// define a new observer
var mutationObserver = new MutationObserver(callback)
// have the observer observe foo for changes in children
mutationObserver.observe( obj, { childList:true, subtree:true })
return mutationObserver
}
// browser support fallback
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false)
obj.addEventListener('DOMNodeRemoved', callback, false)
}
}
})();
window.numberOfChanges = 0;
observeDOM(document.getElementById('MainAction'), function () {
console.log('Change detected');
window.numberOfChanges++;
})
window.checkForChange = function (minNumberOfChanges = 1) {
if (window.numberOfChanges >= minNumberOfChanges) {
if (window.numberOfChanges > minNumberOfChanges) {
console.warn('Note: Higher Number of Changes than expected', window.numberOfChanges);
}
window.numberOfChanges = 0;
return true;
} else {
return false;
}
}
")
}
debug_test_case <- TRUE
debug_note <- function(...) {
if (debug_test_case) {
paste(
...,
sep = "\n"
) |>
cat()
}
}
is_ci <- !is.na(as.logical(Sys.getenv("CI"))) && !as.logical(Sys.getenv("CI"))
test_that("E2E: test case Koch", {
skip_on_ci()
skip_on_cran()
response_dir <- withr::local_tempdir()
app_settings <- create_app_settings(
require_respondent_id = TRUE,
save_to_file = TRUE,
response_output_dir = response_dir
)
app <- AppDriver$new(
app_dir = app(
questionnaire = questionnaire_demo(
show_feedback_page = FALSE
),
app_settings = app_settings
),
name = "test_1_koch",
height = 741,
width = 1139
)
wait_time <- 1
# Go to example URL
app$run_js("window.location.href = '/?respondent_id=test123&tense=present&extra_instructions=on&study_id=Test'")
Sys.sleep(wait_time)
setup_wait_for_change(app)
# Navigate beyond welcome page
debug_note("Welcome")
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()")
# Answer the freetext question
debug_note("Freetext (1)")
app$run_js("document.querySelector('input').value = 'Techniker/in - Informations- und Kommunikationselektronik'")
app$run_js("
var element = document.querySelector('input');
if ('createEvent' in document) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
} else {
element.fireEvent('onchange');
}
")
Sys.sleep(0.5)
app$click(selector = "#nextButton")
app$wait_for_js("document.querySelector('table')?.childNodes.length === 5")
app$run_js("window.numberOfChanges = 0;") # reset counter
# Select a suggestion
debug_note("Select Suggestion (1)")
app$click(selector = "#question1 > div > div:nth-child(5) > label > input[type=radio]")
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()")
# Follow up question
debug_note("Follow-Up (1)")
app$click(selector = "div.radio:nth-child(1) > label:nth-child(1)")
app$click(selector = "#nextButton")
app$wait_for_js("document.querySelector('table')?.childNodes.length === 5")
app$run_js("window.numberOfChanges = 0;") # reset counter
# Go back
# Back to follow-up
debug_note("Back - 1")
app$click(selector = "#previousButton")
app$wait_for_js("checkForChange()")
# Back to suggestion selection
debug_note("Back - 2")
app$click(selector = "#previousButton")
app$wait_for_js("document.querySelector('table')?.childNodes.length === 5")
app$run_js("window.numberOfChanges = 0;") # reset counter
# Back to free-text entry
debug_note("Back - 3")
app$click(selector = "#previousButton")
app$wait_for_js("checkForChange()")
# Answer the freetext question
debug_note("Freetext (2)")
app$run_js("document.querySelector('input').value = 'Koch'")
app$run_js("
var element = document.querySelector('input');
if ('createEvent' in document) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
} else {
element.fireEvent('onchange');
}
")
Sys.sleep(0.5)
app$click(selector = "#nextButton")
app$wait_for_js("document.querySelector('table')?.childNodes.length === 5")
app$run_js("window.numberOfChanges = 0;") # reset counter
# Check suggestions
app$expect_text("body")
# Select a suggestion
debug_note("Select Suggestion (2)")
app$click(selector = "#question1 > div > div:nth-child(1) > label > input[type=radio]")
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()")
# Follow up question
debug_note("Follow-Up (2)")
app$click(selector = "div.radio:nth-child(1) > label:nth-child(1)")
app$click(selector = "#nextButton")
app$wait_for_js("document.querySelector('table')?.childNodes.length === 5")
app$run_js("window.numberOfChanges = 0;") # reset counter
# Check final output
if (!detect_kldb_unavailable()) {
app$expect_text("body")
}
# To Output Shiny Logs in the end
# print(app$get_logs())
overview_data <- get_responses(app_settings = app_settings)
testthat::expect_equal(
overview_data,
data.table::data.table(
session_id = overview_data$session_id,
url_search = "?respondent_id=test123&tense=present&extra_instructions=on&study_id=Test",
isco_08 = "9411",
kldb_10 = "63312",
respondent_id = "test123",
P_welcome_Q_NA_R_id = "",
P_welcome_Q_NA_R_text = "",
P_freetext_1_Q_default_R_id = "",
P_freetext_1_Q_default_R_text = "Koch",
P_freetext_1_Q_no_answer_R_id = "no_answer_unchecked",
P_freetext_1_Q_no_answer_R_text = "",
P_select_suggestion_Q_default_R_id = "9079",
P_select_suggestion_Q_default_R_text = "Zubereitung von Speisen in Restaurants, Hotels und sonstigen gastronomischen Einrichtungen",
P_followup_1_Q_default_R_id = "1",
P_followup_1_Q_default_R_text = "nur einfache Speisen zum Sofortverkauf in Fast-Food-Restaurants"
)
)
})
test_that("Followup questions are correctly skipped: ESE test case Textiltechniker)", {
skip_on_ci()
skip_on_cran()
app <- AppDriver$new(
app_dir = app(
app_settings = create_app_settings(
# Don't write data from test to disk
save_to_file = FALSE
),
questionnaire = questionnaire_interviewer_administered(
show_feedback_page = FALSE
)
),
name = "test_2_textiltechniker",
height = 741,
width = 1139
) |>
expect_warning("saving to files has been disabled")
wait_time <- 1
# To Debug in Chrome
# app$view()
setup_wait_for_change(app)
# Answer the freetext question
app$run_js("document.querySelector('input').value = 'Textiltechniker'")
app$run_js("
var element = document.querySelector('input');
if ('createEvent' in document) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
} else {
element.fireEvent('onchange');
}
")
Sys.sleep(0.5)
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()") # Waiting for two changes here due to renderTable
app$run_js("document.querySelector('input').value = 'Arbeit mit Textilien'")
app$run_js("
var element = document.querySelector('input');
if ('createEvent' in document) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
element.dispatchEvent(evt);
} else {
element.fireEvent('onchange');
}
")
Sys.sleep(0.5)
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()") # Waiting for two changes here due to renderTable
# Check suggestions
app$expect_text("body")
# Select a suggestion
app$click(selector = "#question1 > div > div:nth-child(1) > label > input[type=radio]")
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()")
# Follow up question
app$click(selector = "div.radio:nth-child(1) > label:nth-child(1)")
app$click(selector = "#nextButton")
app$wait_for_js("checkForChange()") # Waiting for two changes here due to renderTable
# Check final output
app$expect_text("body")
# To Output Shiny Logs in the end
# print(app$get_logs())
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.