Skip to content

Commit

Permalink
trap ID errors during callback dispatch
Browse files Browse the repository at this point in the history
so we can clear the pendingCallbacks queue and show errors in the devtools
  • Loading branch information
alexcjohnson committed Apr 7, 2020
1 parent 90eb451 commit 7c47b05
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 25 deletions.
49 changes: 28 additions & 21 deletions dash-renderer/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,24 +244,31 @@ async function fireReadyCallbacks(dispatch, getState, callbacks) {
const {output, inputs, state, clientside_function} = cb.callback;
const {requestId, resolvedId} = cb;
const {allOutputs, allPropIds} = outputStash[requestId];
const outputs = allOutputs.map((out, i) =>
unwrapIfNotMulti(
paths,
map(pick(['id', 'property']), out),
cb.callback.outputs[i],
cb.anyVals,
'Output'
)
);

const payload = {
output,
outputs: isMultiOutputProp(output) ? outputs : outputs[0],
inputs: fillVals(paths, layout, cb, inputs, 'Input'),
changedPropIds: keys(cb.changedPropIds),
};
if (cb.callback.state.length) {
payload.state = fillVals(paths, layout, cb, state, 'State');
let payload;
try {
const outputs = allOutputs.map((out, i) =>
unwrapIfNotMulti(
paths,
map(pick(['id', 'property']), out),
cb.callback.outputs[i],
cb.anyVals,
'Output'
)
);

payload = {
output,
outputs: isMultiOutputProp(output) ? outputs : outputs[0],
inputs: fillVals(paths, layout, cb, inputs, 'Input'),
changedPropIds: keys(cb.changedPropIds),
};
if (cb.callback.state.length) {
payload.state = fillVals(paths, layout, cb, state, 'State');
}
} catch (e) {
handleError(e);
return fireNext();
}

function updatePending(pendingCallbacks, skippedProps) {
Expand Down Expand Up @@ -361,10 +368,10 @@ async function fireReadyCallbacks(dispatch, getState, callbacks) {
// that have other changed inputs will still fire.
updatePending(pendingCallbacks, allPropIds);
}
let message = `Callback error updating ${map(
combineIdAndProp,
flatten([payload.outputs])
).join(', ')}`;
const outputs = payload
? map(combineIdAndProp, flatten([payload.outputs])).join(', ')
: output;
let message = `Callback error updating ${outputs}`;
if (clientside_function) {
const {namespace: ns, function_name: fn} = clientside_function;
message += ` via clientside function ${ns}.${fn}`;
Expand Down
28 changes: 24 additions & 4 deletions tests/integration/devtools/test_callback_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def check_errors(dash_duo, specs):
for i in range(cnt):
msg = dash_duo.find_elements(".dash-fe-error__title")[i].text
dash_duo.find_elements(".test-devtools-error-toggle")[i].click()
txt = dash_duo.wait_for_element(".dash-backend-error").text
txt = dash_duo.wait_for_element(".dash-backend-error,.dash-fe-error__info").text
dash_duo.find_elements(".test-devtools-error-toggle")[i].click()
dash_duo.wait_for_no_elements(".dash-backend-error")
found.append((msg, txt))
Expand Down Expand Up @@ -47,6 +47,9 @@ def check_errors(dash_duo, specs):
)
)

# ensure the errors didn't leave items in the pendingCallbacks queue
assert dash_duo.driver.execute_script('return document.title') == 'Dash'


def test_dvcv001_blank(dash_duo):
app = Dash(__name__)
Expand Down Expand Up @@ -412,6 +415,24 @@ def h(a):
return app


# These ones are raised by bad_id_app whether suppressing callback exceptions or not
dispatch_specs = [
[
"A nonexistent object was used in an `Input` of a Dash callback. "
"The id of this object is `yeah-no` and the property is `value`. "
"The string ids in the current layout are: "
"[main, outer-div, inner-div, inner-input, outer-input]", []
],
[
"A nonexistent object was used in an `Output` of a Dash callback. "
"The id of this object is `nope` and the property is `children`. "
"The string ids in the current layout are: "
"[main, outer-div, inner-div, inner-input, outer-input]", []
]
]



def test_dvcv008_wrong_callback_id(dash_duo):
dash_duo.start_server(bad_id_app(), **debugging)

Expand Down Expand Up @@ -461,14 +482,13 @@ def test_dvcv008_wrong_callback_id(dash_duo):
],
],
]
check_errors(dash_duo, specs)
check_errors(dash_duo, dispatch_specs + specs)


def test_dvcv009_suppress_callback_exceptions(dash_duo):
dash_duo.start_server(bad_id_app(suppress_callback_exceptions=True), **debugging)

dash_duo.find_element(".dash-debug-menu")
dash_duo.wait_for_no_elements(".test-devtools-error-count")
check_errors(dash_duo, dispatch_specs)


def test_dvcv010_bad_props(dash_duo):
Expand Down

0 comments on commit 7c47b05

Please sign in to comment.