There seems to be some kind of problem with detecting custom shiny inputs with shinytest.
Using recordApp App is working correctly, all values are recorded and all inputs are reactive correctly. It contains some custom made shinyInputs likertRadioButtons.
Unfortunately, after saving the recording of the test and initial testApp running I get error stating that the input isn't found (id for the first likertRadioButtons object triggered during test:
Running mytest.R Error in session_makeRequest(self, private, endpoint, data, params, headers) :
Unable to find input binding for element with id second_link-from_gsheet-test8
Input UI is correctly rendered (checked in app$getAllValues()$output).
It isn't correctly detected as input (not available in `app$getAllValues()$input')
likertRadioButtons rendered in App, during html inspection have correct css classes (mainly shiny-bound-input, which isn't added during R function UI rendering, so I guess it is appended automatically by Shiny JS during ShinyApp initialization.
I guess I created all necessary bindings for the custom input:
// create a binding object
var likertRadioButtonsBinding = new Shiny.InputBinding();
// add methods to it using jQuery's extend method
$.extend(likertRadioButtonsBinding, {
find: function(scope) {
// find all instances of class
return $(scope).find(".shiny-input-likert-radiobuttons");
},
initialize: function(el) {
// bind function onchange to update indicator
var indicators = document.getElementById(Shiny.$escape(el.id)).
getElementsByClassName('likert-input-radio indicator-updater')
// only if the indicator is there!
if (indicators.length != 0) {
$(indicators).change(function(){
var text=$(this).attr('choice-name');
var id=$(this).attr('name');
document.getElementById(id).getElementsByClassName('likert-input-radio-indicator')[0].textContent=text;
});
};
},
getValue(el) {
// Select the radio objects that have name equal to the grouping div's id
const checkedItems = $(
'input:radio[name="' + Shiny.$escape(el.id) + '"]:checked'
);
if (checkedItems.length === 0) {
return null;
}
return Number(checkedItems.val());
},
setValue(el, value) {
if ($.isArray(value) && value.length === 0) {
// Removing all checked item if the sent data is empty
$('input:radio[name="' + Shiny.$escape(el.id) + '"]').prop("checked", false);
} else {
$(
'input:radio[name="' +
Shiny.$escape(el.id) +
'"][value="' +
value +
'"]'
).prop("checked", true);
}
$(el).trigger("change");
},
subscribe(el, callback) {
$(el).on("change.likertRadioButtonsBinding", function () {
callback(false);
});
},
unsubscribe(el) {
$(el).off(".likertRadioButtonsBinding");
}
});
Shiny.inputBindings.register(likertRadioButtonsBinding);
Should any other actions be done when testing app with custom inputs (like declaring new input bindings directly)? Or maybe the receiveMessage method is crucial for shinytest to work correctly (I haven't created updateLikertRadioButtons and this method in JS yet, as I am not quite good at JS ATM)
Update: creating small mockup shinyApp with two likertRadioButtons input and using browser() I can see that the inputs are declared there. shinytest don't detect them though. How does it detect the inputs? Going through source files it seemed like it takes them directly from input element, but it seems like that isn't complete story.
> runApp('test/likertInputTests')
Listening on http://127.0.0.1:6591
Called from: server(...)
Browse[1]> input
<ReactiveValues>
Values: first, second
Readonly: TRUE
Update 2: For more in-depth checks, you can install shiny.quetzio and call shiny.quetzio:::testthat_likert_app() for exemplary app with inputs not visible to shinytest during testApp runs.
There seems to be some kind of problem with detecting custom shiny inputs with shinytest.
recordApp
App is working correctly, all values are recorded and all inputs are reactive correctly. It contains some custom made shinyInputslikertRadioButtons
.testApp
running I get error stating that the input isn't found (id for the firstlikertRadioButtons
object triggered during test:app$getAllValues()$output
).likertRadioButtons
rendered in App, during html inspection have correct css classes (mainlyshiny-bound-input
, which isn't added during R function UI rendering, so I guess it is appended automatically byShiny
JS during ShinyApp initialization.I guess I created all necessary bindings for the custom input:
Should any other actions be done when testing app with custom inputs (like declaring new input bindings directly)? Or maybe the
receiveMessage
method is crucial forshinytest
to work correctly (I haven't createdupdateLikertRadioButtons
and this method in JS yet, as I am not quite good at JS ATM)Update: creating small mockup shinyApp with two
likertRadioButtons
input and usingbrowser()
I can see that the inputs are declared there.shinytest
don't detect them though. How does it detect the inputs? Going through source files it seemed like it takes them directly frominput
element, but it seems like that isn't complete story.Update 2: For more in-depth checks, you can install
shiny.quetzio
and callshiny.quetzio:::testthat_likert_app()
for exemplary app with inputs not visible toshinytest
duringtestApp
runs.