-
Notifications
You must be signed in to change notification settings - Fork 145
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Action loop and callback mapping tests (#93)
- Loading branch information
Showing
9 changed files
with
552 additions
and
8 deletions.
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
...gelog.d/20231004_152109_petar_pejovic_action_loop_and_callback_mapping_tests.md
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,41 @@ | ||
<!-- | ||
A new scriv changelog fragment. | ||
Uncomment the section that is right (remove the HTML comment wrapper). | ||
--> | ||
|
||
<!-- | ||
### Removed | ||
- A bullet item for the Removed category. | ||
--> | ||
<!-- | ||
### Added | ||
- A bullet item for the Added category. | ||
--> | ||
<!-- | ||
### Changed | ||
- A bullet item for the Changed category. | ||
--> | ||
<!-- | ||
### Deprecated | ||
- A bullet item for the Deprecated category. | ||
--> | ||
|
||
### Fixed | ||
|
||
- If the `targets` argument in the `export_data` action function is specified as `"falsy"` value (`None`, `[]`), triggering the action will result in the same outcome as if the argument were not set, exporting data from all charts on the current page. ([#93](https://github.com/mckinsey/vizro/pull/93)) | ||
|
||
<!-- | ||
### Security | ||
- A bullet item for the Security category. | ||
--> |
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
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
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
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
168 changes: 168 additions & 0 deletions
168
vizro-core/tests/unit/vizro/actions/_action_loop/test_get_action_loop_components.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,168 @@ | ||
"""Unit tests for vizro.actions._action_loop._get_action_loop_components file.""" | ||
|
||
import json | ||
|
||
import dash | ||
import plotly | ||
import pytest | ||
from dash import dcc, html | ||
|
||
import vizro.models as vm | ||
import vizro.plotly.express as px | ||
from vizro import Vizro | ||
from vizro.actions import export_data | ||
from vizro.actions._action_loop._get_action_loop_components import _get_action_loop_components | ||
from vizro.managers import model_manager | ||
|
||
|
||
@pytest.fixture | ||
def fundamental_components(): | ||
return [ | ||
dcc.Store(id="action_finished"), | ||
dcc.Store(id="remaining_actions", data=[]), | ||
html.Div(id="cycle_breaker_div", style={"display": "hidden"}), | ||
dcc.Store(id="cycle_breaker_empty_output_store"), | ||
] | ||
|
||
|
||
@pytest.fixture | ||
def gateway_components(request): | ||
components = request.param | ||
actions_chain_ids = [model_manager[component].actions[0].id for component in components] | ||
return [ | ||
dcc.Store( | ||
id={"type": "gateway_input", "trigger_id": actions_chain_id}, | ||
data=f"{actions_chain_id}", | ||
) | ||
for actions_chain_id in actions_chain_ids | ||
] | ||
|
||
|
||
@pytest.fixture | ||
def action_trigger_components(request): | ||
components = request.param | ||
actions_ids = [model_manager[component].actions[0].actions[0].id for component in components] | ||
return [dcc.Store(id={"type": "action_trigger", "action_name": action_id}) for action_id in actions_ids] | ||
|
||
|
||
@pytest.fixture | ||
def action_trigger_actions_id_component(request): | ||
components = request.param | ||
actions_ids = [model_manager[component].actions[0].actions[0].id for component in components] | ||
return dcc.Store( | ||
id="action_trigger_actions_id", | ||
data=actions_ids, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def trigger_to_actions_chain_mapper_component(request): | ||
components = request.param | ||
actions_chain_ids = [model_manager[component].actions[0].id for component in components] | ||
return dcc.Store( | ||
id="trigger_to_actions_chain_mapper", | ||
data={ | ||
actions_chain_id: [action.id for action in model_manager[actions_chain_id].actions] | ||
for actions_chain_id in actions_chain_ids | ||
}, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def managers_one_page_two_components_two_controls(): | ||
"""Instantiates managers with one page that contains two controls and two components.""" | ||
page = vm.Page( | ||
id="test_page", | ||
title="First page", | ||
components=[ | ||
vm.Graph( | ||
id="scatter_chart", | ||
figure=px.scatter(px.data.gapminder(), x="lifeExp", y="gdpPercap"), | ||
), | ||
vm.Button( | ||
id="export_data_button", | ||
actions=[vm.Action(id="export_data_action", function=export_data())], | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(id="filter_continent", column="continent", selector=vm.Dropdown(id="filter_continent_selector")), | ||
vm.Parameter( | ||
id="parameter_x", | ||
targets=["scatter_chart.x"], | ||
selector=vm.Dropdown( | ||
id="parameter_x_selector", | ||
options=["lifeExp", "gdpPercap", "pop"], | ||
), | ||
), | ||
], | ||
) | ||
# TODO: Call the Dashboard._pre_build() method once the pages registration is moved into this method. | ||
yield Vizro().build(vm.Dashboard(pages=[page])) | ||
del dash.page_registry["test_page"] | ||
|
||
|
||
@pytest.fixture | ||
def managers_one_page_no_actions(): | ||
"""Instantiates managers with one "empty" page.""" | ||
page = vm.Page( | ||
id="test_page_no_actions", | ||
title="Second page", | ||
components=[vm.Card(text="")], | ||
) | ||
# TODO: Call the Dashboard._pre_build() method once the pages registration is moved into this method. | ||
yield Vizro().build(vm.Dashboard(pages=[page])) | ||
del dash.page_registry["test_page_no_actions"] | ||
|
||
|
||
class TestGetActionLoopComponents: | ||
"""Tests getting required components for the action loop.""" | ||
|
||
@pytest.mark.usefixtures("managers_one_page_no_actions") | ||
def test_no_components(self): | ||
result = _get_action_loop_components() | ||
result = json.loads(json.dumps(result, cls=plotly.utils.PlotlyJSONEncoder)) | ||
|
||
expected = html.Div(id="action_loop_components_div") | ||
expected = json.loads(json.dumps(expected, cls=plotly.utils.PlotlyJSONEncoder)) | ||
|
||
assert result == expected | ||
|
||
@pytest.mark.usefixtures("managers_one_page_two_components_two_controls") | ||
@pytest.mark.parametrize( | ||
"gateway_components, " | ||
"action_trigger_components, " | ||
"action_trigger_actions_id_component, " | ||
"trigger_to_actions_chain_mapper_component", | ||
[ | ||
( | ||
["test_page", "export_data_button", "filter_continent_selector", "parameter_x_selector"], | ||
["test_page", "export_data_button", "filter_continent_selector", "parameter_x_selector"], | ||
["test_page", "export_data_button", "filter_continent_selector", "parameter_x_selector"], | ||
["test_page", "export_data_button", "filter_continent_selector", "parameter_x_selector"], | ||
) | ||
], | ||
indirect=True, | ||
) | ||
def test_all_action_loop_components( # noqa: PLR0913 # pylint: disable=too-many-arguments | ||
self, | ||
fundamental_components, | ||
gateway_components, | ||
action_trigger_components, | ||
action_trigger_actions_id_component, | ||
trigger_to_actions_chain_mapper_component, | ||
): | ||
result = _get_action_loop_components() | ||
result = json.loads(json.dumps(result, cls=plotly.utils.PlotlyJSONEncoder)) | ||
|
||
all_action_loop_components_expected = ( | ||
fundamental_components | ||
+ gateway_components | ||
+ action_trigger_components | ||
+ [action_trigger_actions_id_component] | ||
+ [trigger_to_actions_chain_mapper_component] | ||
) | ||
|
||
expected = html.Div(children=all_action_loop_components_expected, id="action_loop_components_div") | ||
expected = json.loads(json.dumps(expected, cls=plotly.utils.PlotlyJSONEncoder)) | ||
|
||
assert result == expected |
Oops, something went wrong.