-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into testing-download
- Loading branch information
Showing
3 changed files
with
382 additions
and
310 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
{ | ||
"chapter1": { | ||
"toc": ["props", "children", 0], | ||
"body": ["props", "children", 1], | ||
"chapter1-header": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
0 | ||
], | ||
"chapter1-controls": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
1 | ||
], | ||
"chapter1-label": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
2 | ||
], | ||
"chapter1-graph": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
3 | ||
] | ||
}, | ||
"chapter2": { | ||
"toc": ["props", "children", 0], | ||
"body": ["props", "children", 1], | ||
"chapter2-header": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
0 | ||
], | ||
"chapter2-controls": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
1 | ||
], | ||
"chapter2-label": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
2 | ||
], | ||
"chapter2-graph": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
3 | ||
] | ||
}, | ||
"chapter3": { | ||
"toc": ["props", "children", 0], | ||
"body": ["props", "children", 1], | ||
"chapter3-header": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
0, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
0 | ||
], | ||
"chapter3-label": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
0, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
1 | ||
], | ||
"chapter3-graph": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
0, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
2 | ||
], | ||
"chapter3-controls": [ | ||
"props", | ||
"children", | ||
1, | ||
"props", | ||
"children", | ||
0, | ||
"props", | ||
"children", | ||
"props", | ||
"children", | ||
3 | ||
] | ||
} | ||
} |
236 changes: 236 additions & 0 deletions
236
tests/integration/callbacks/test_layout_paths_with_callbacks.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
import os | ||
import json | ||
from multiprocessing import Value | ||
import dash_core_components as dcc | ||
import dash_html_components as html | ||
from dash import Dash | ||
from dash.dependencies import Input, Output | ||
import dash.testing.wait as wait | ||
|
||
|
||
def test_cblp001_radio_buttons_callbacks_generating_children(dash_duo): | ||
TIMEOUT = 2 | ||
with open( | ||
os.path.join(os.path.dirname(__file__), "state_path.json") | ||
) as fp: | ||
EXPECTED_PATHS = json.load(fp) | ||
|
||
app = Dash(__name__) | ||
app.layout = html.Div( | ||
[ | ||
dcc.RadioItems( | ||
options=[ | ||
{"label": "Chapter 1", "value": "chapter1"}, | ||
{"label": "Chapter 2", "value": "chapter2"}, | ||
{"label": "Chapter 3", "value": "chapter3"}, | ||
{"label": "Chapter 4", "value": "chapter4"}, | ||
{"label": "Chapter 5", "value": "chapter5"}, | ||
], | ||
value="chapter1", | ||
id="toc", | ||
), | ||
html.Div(id="body"), | ||
] | ||
) | ||
for script in dcc._js_dist: | ||
app.scripts.append_script(script) | ||
|
||
chapters = { | ||
"chapter1": html.Div( | ||
[ | ||
html.H1("Chapter 1", id="chapter1-header"), | ||
dcc.Dropdown( | ||
options=[ | ||
{"label": i, "value": i} for i in ["NYC", "MTL", "SF"] | ||
], | ||
value="NYC", | ||
id="chapter1-controls", | ||
), | ||
html.Label(id="chapter1-label"), | ||
dcc.Graph(id="chapter1-graph"), | ||
] | ||
), | ||
# Chapter 2 has the some of the same components in the same order | ||
# as Chapter 1. This means that they won't get remounted | ||
# unless they set their own keys are differently. | ||
# Switching back and forth between 1 and 2 implicitly | ||
# tests how components update when they aren't remounted. | ||
"chapter2": html.Div( | ||
[ | ||
html.H1("Chapter 2", id="chapter2-header"), | ||
dcc.RadioItems( | ||
options=[ | ||
{"label": i, "value": i} for i in ["USA", "Canada"] | ||
], | ||
value="USA", | ||
id="chapter2-controls", | ||
), | ||
html.Label(id="chapter2-label"), | ||
dcc.Graph(id="chapter2-graph"), | ||
] | ||
), | ||
# Chapter 3 has a different layout and so the components | ||
# should get rewritten | ||
"chapter3": [ | ||
html.Div( | ||
html.Div( | ||
[ | ||
html.H3("Chapter 3", id="chapter3-header"), | ||
html.Label(id="chapter3-label"), | ||
dcc.Graph(id="chapter3-graph"), | ||
dcc.RadioItems( | ||
options=[ | ||
{"label": i, "value": i} | ||
for i in ["Summer", "Winter"] | ||
], | ||
value="Winter", | ||
id="chapter3-controls", | ||
), | ||
] | ||
) | ||
) | ||
], | ||
# Chapter 4 doesn't have an object to recursively traverse | ||
"chapter4": "Just a string", | ||
} | ||
|
||
call_counts = { | ||
"body": Value("i", 0), | ||
"chapter1-graph": Value("i", 0), | ||
"chapter1-label": Value("i", 0), | ||
"chapter2-graph": Value("i", 0), | ||
"chapter2-label": Value("i", 0), | ||
"chapter3-graph": Value("i", 0), | ||
"chapter3-label": Value("i", 0), | ||
} | ||
|
||
@app.callback(Output("body", "children"), [Input("toc", "value")]) | ||
def display_chapter(toc_value): | ||
call_counts["body"].value += 1 | ||
return chapters[toc_value] | ||
|
||
app.config.suppress_callback_exceptions = True | ||
|
||
def generate_graph_callback(counterId): | ||
def callback(value): | ||
call_counts[counterId].value += 1 | ||
return { | ||
"data": [ | ||
{ | ||
"x": ["Call Counter"], | ||
"y": [call_counts[counterId].value], | ||
"type": "bar", | ||
} | ||
], | ||
"layout": {"title": value}, | ||
} | ||
|
||
return callback | ||
|
||
def generate_label_callback(id_): | ||
def update_label(value): | ||
call_counts[id_].value += 1 | ||
return value | ||
|
||
return update_label | ||
|
||
for chapter in ["chapter1", "chapter2", "chapter3"]: | ||
app.callback( | ||
Output("{}-graph".format(chapter), "figure"), | ||
[Input("{}-controls".format(chapter), "value")], | ||
)(generate_graph_callback("{}-graph".format(chapter))) | ||
|
||
app.callback( | ||
Output("{}-label".format(chapter), "children"), | ||
[Input("{}-controls".format(chapter), "value")], | ||
)(generate_label_callback("{}-label".format(chapter))) | ||
|
||
dash_duo.start_server(app) | ||
|
||
def check_chapter(chapter): | ||
for key in dash_duo.redux_state_paths: | ||
assert dash_duo.find_elements( | ||
"#{}".format(key) | ||
), "each element should exist in the dom" | ||
|
||
value = ( | ||
chapters[chapter][0]["{}-controls".format(chapter)].value | ||
if chapter == "chapter3" | ||
else chapters[chapter]["{}-controls".format(chapter)].value | ||
) | ||
# check the actual values | ||
dash_duo.wait_for_text_to_equal("#{}-label".format(chapter), value) | ||
wait.until( | ||
lambda: ( | ||
dash_duo.driver.execute_script( | ||
"return document." | ||
'getElementById("{}-graph").'.format(chapter) | ||
+ "layout.title.text" | ||
) | ||
== value | ||
), | ||
TIMEOUT, | ||
) | ||
|
||
rqs = dash_duo.redux_state_rqs | ||
assert rqs, "request queue is not empty" | ||
assert all((rq["status"] == 200 and not rq["rejected"] for rq in rqs)) | ||
|
||
def check_call_counts(chapters, count): | ||
for chapter in chapters: | ||
assert call_counts[chapter + "-graph"].value == count | ||
assert call_counts[chapter + "-label"].value == count | ||
|
||
wait.until(lambda: call_counts["body"].value == 1, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter1-graph"].value == 1, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter1-label"].value == 1, TIMEOUT) | ||
check_call_counts(("chapter2", "chapter3"), 0) | ||
|
||
assert dash_duo.redux_state_paths == EXPECTED_PATHS["chapter1"] | ||
check_chapter("chapter1") | ||
dash_duo.percy_snapshot(name="chapter-1") | ||
|
||
dash_duo.find_elements('input[type="radio"]')[1].click() # switch chapters | ||
|
||
wait.until(lambda: call_counts["body"].value == 2, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter2-graph"].value == 1, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter2-label"].value == 1, TIMEOUT) | ||
check_call_counts(("chapter1",), 1) | ||
|
||
assert dash_duo.redux_state_paths == EXPECTED_PATHS["chapter2"] | ||
check_chapter("chapter2") | ||
dash_duo.percy_snapshot(name="chapter-2") | ||
|
||
# switch to 3 | ||
dash_duo.find_elements('input[type="radio"]')[2].click() | ||
|
||
wait.until(lambda: call_counts["body"].value == 3, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter3-graph"].value == 1, TIMEOUT) | ||
wait.until(lambda: call_counts["chapter3-label"].value == 1, TIMEOUT) | ||
check_call_counts(("chapter2", "chapter1"), 1) | ||
|
||
assert dash_duo.redux_state_paths == EXPECTED_PATHS["chapter3"] | ||
check_chapter("chapter3") | ||
dash_duo.percy_snapshot(name="chapter-3") | ||
|
||
dash_duo.find_elements('input[type="radio"]')[3].click() # switch to 4 | ||
dash_duo.wait_for_text_to_equal("#body", "Just a string") | ||
dash_duo.percy_snapshot(name="chapter-4") | ||
for key in dash_duo.redux_state_paths: | ||
assert dash_duo.find_elements( | ||
"#{}".format(key) | ||
), "each element should exist in the dom" | ||
|
||
assert dash_duo.redux_state_paths == { | ||
"toc": ["props", "children", 0], | ||
"body": ["props", "children", 1], | ||
} | ||
|
||
dash_duo.find_elements('input[type="radio"]')[0].click() | ||
|
||
wait.until( | ||
lambda: dash_duo.redux_state_paths == EXPECTED_PATHS["chapter1"], | ||
TIMEOUT, | ||
) | ||
check_chapter("chapter1") | ||
dash_duo.percy_snapshot(name="chapter-1-again") |
Oops, something went wrong.