def test_dash_app(): 'Test the import and formation of the dash app orm wrappers' from django_plotly_dash.models import StatelessApp stateless_a = StatelessApp(app_name="Some name") assert stateless_a assert stateless_a.app_name assert str(stateless_a) == stateless_a.app_name
def test_dash_stateful_app_client_contract(client): 'Test the state management of a DashApp as well as the contract between the client and the Dash app' from django_plotly_dash.models import StatelessApp # create a DjangoDash, StatelessApp and DashApp ddash = DjangoDash(name="DDash") fill_in_test_app(ddash, write=False) stateless_a = StatelessApp(app_name="DDash") stateless_a.save() stateful_a = DashApp(stateless_app=stateless_a, instance_name="Some name", slug="my-app", save_on_change=True) stateful_a.save() # check app can be found back assert "DDash" in get_local_stateless_list() assert get_local_stateless_by_name("DDash") == ddash assert find_stateless_by_name("DDash") == ddash # check the current_state is empty assert stateful_a.current_state() == {} # set the initial expected state expected_state = { 'inp1': { 'n_clicks': 0, 'n_clicks_timestamp': 1611733453854 }, 'inp2': { 'n_clicks': 5, 'n_clicks_timestamp': 1611733454354 }, 'out1-0': { 'n_clicks': 1, 'n_clicks_timestamp': 1611733453954 }, 'out1-1': { 'n_clicks': 2, 'n_clicks_timestamp': 1611733454054 }, 'out1-2': { 'n_clicks': 3, 'n_clicks_timestamp': 1611733454154 }, 'out1-3': { 'n_clicks': 4, 'n_clicks_timestamp': 1611733454254 }, 'out2-0': { 'n_clicks': 6, 'n_clicks_timestamp': 1611733454454 }, 'out3': { 'n_clicks': 10, 'n_clicks_timestamp': 1611733454854 }, 'out4': { 'n_clicks': 14, 'n_clicks_timestamp': 1611733455254 }, 'out5': { 'n_clicks': 18, 'n_clicks_timestamp': 1611733455654 }, '{"_id":"inp-0","_type":"btn3"}': { 'n_clicks': 7, 'n_clicks_timestamp': 1611733454554 }, '{"_id":"inp-0","_type":"btn4"}': { 'n_clicks': 11, 'n_clicks_timestamp': 1611733454954 }, '{"_id":"inp-0","_type":"btn5"}': { 'n_clicks': 15, 'n_clicks_timestamp': 1611733455354 }, '{"_id":"inp-1","_type":"btn3"}': { 'n_clicks': 8, 'n_clicks_timestamp': 1611733454654 }, '{"_id":"inp-1","_type":"btn4"}': { 'n_clicks': 12, 'n_clicks_timestamp': 1611733455054 }, '{"_id":"inp-1","_type":"btn5"}': { 'n_clicks': 16, 'n_clicks_timestamp': 1611733455454 }, '{"_id":"inp-2","_type":"btn3"}': { 'n_clicks': 9, 'n_clicks_timestamp': 1611733454754 }, '{"_id":"inp-2","_type":"btn4"}': { 'n_clicks': 13, 'n_clicks_timestamp': 1611733455154 }, '{"_id":"inp-2","_type":"btn5"}': { 'n_clicks': 17, 'n_clicks_timestamp': 1611733455554 } } ########## test state management of the app and conversion of components ids # search for state values in dash layout stateful_a.populate_values() assert stateful_a.current_state() == expected_state assert stateful_a.have_current_state_entry("inp1", "n_clicks") assert stateful_a.have_current_state_entry( { "_type": "btn3", "_id": "inp-0" }, "n_clicks_timestamp") assert stateful_a.have_current_state_entry( '{"_id":"inp-0","_type":"btn3"}', "n_clicks_timestamp") assert not stateful_a.have_current_state_entry("checklist", "other-prop") # update a non existent state => no effect on current_state stateful_a.update_current_state("foo", "value", "random") assert stateful_a.current_state() == expected_state # update an existent state => update current_state stateful_a.update_current_state('{"_id":"inp-2","_type":"btn5"}', "n_clicks", 100) expected_state['{"_id":"inp-2","_type":"btn5"}'] = { 'n_clicks': 100, 'n_clicks_timestamp': 1611733455554 } assert stateful_a.current_state() == expected_state assert DashApp.objects.get(instance_name="Some name").current_state() == {} stateful_a.handle_current_state() assert DashApp.objects.get( instance_name="Some name").current_state() == expected_state # check initial layout serve has the correct values injected dash_instance = stateful_a.as_dash_instance() resp = dash_instance.serve_layout() # initialise layout with app state layout, mimetype = dash_instance.augment_initial_layout(resp, {}) assert '"n_clicks": 100' in layout # initialise layout with initial arguments layout, mimetype = dash_instance.augment_initial_layout( resp, {'{"_id":"inp-2","_type":"btn5"}': { "n_clicks": 200 }}) assert '"n_clicks": 100' not in layout assert '"n_clicks": 200' in layout ########### test contract between client and app by replaying interactions recorded in tests_dash_contract.json # get update component route url = reverse('the_django_plotly_dash:update-component', kwargs={'ident': 'my-app'}) # for all interactions in the tests_dash_contract.json for scenario in json.load(dash_contract_data.open("r")): body = scenario["body"] response = client.post(url, json.dumps(body), content_type="application/json") assert response.status_code == 200 response = json.loads(response.content) # compare first item in response with first result result = scenario["result"] if isinstance(result, list): result = result[0] content = response["response"].popitem()[1].popitem()[1] assert content == result # handle state stateful_a.handle_current_state() # check final state has been changed accordingly final_state = { 'inp1': { 'n_clicks': 1, 'n_clicks_timestamp': 1611736145932 }, 'inp2': { 'n_clicks': 6, 'n_clicks_timestamp': 1611736146875 }, 'out1-0': { 'n_clicks': 1, 'n_clicks_timestamp': 1611733453954 }, 'out1-1': { 'n_clicks': 2, 'n_clicks_timestamp': 1611733454054 }, 'out1-2': { 'n_clicks': 3, 'n_clicks_timestamp': 1611733454154 }, 'out1-3': { 'n_clicks': 4, 'n_clicks_timestamp': 1611733454254 }, 'out2-0': { 'n_clicks': 6, 'n_clicks_timestamp': 1611733454454 }, 'out3': { 'n_clicks': 10, 'n_clicks_timestamp': 1611733454854 }, 'out4': { 'n_clicks': 14, 'n_clicks_timestamp': 1611733455254 }, 'out5': { 'n_clicks': 18, 'n_clicks_timestamp': 1611733455654 }, '{"_id":"inp-0","_type":"btn3"}': { 'n_clicks': 8, 'n_clicks_timestamp': 1611736147644 }, '{"_id":"inp-0","_type":"btn4"}': { 'n_clicks': 12, 'n_clicks_timestamp': 1611733454954 }, '{"_id":"inp-0","_type":"btn5"}': { 'n_clicks': 16, 'n_clicks_timestamp': 1611733455354 }, '{"_id":"inp-1","_type":"btn3"}': { 'n_clicks': 9, 'n_clicks_timestamp': 1611736148172 }, '{"_id":"inp-1","_type":"btn4"}': { 'n_clicks': 13, 'n_clicks_timestamp': 1611733455054 }, '{"_id":"inp-1","_type":"btn5"}': { 'n_clicks': 18, 'n_clicks_timestamp': 1611733455454 }, '{"_id":"inp-2","_type":"btn3"}': { 'n_clicks': 10, 'n_clicks_timestamp': 1611736149140 }, '{"_id":"inp-2","_type":"btn4"}': { 'n_clicks': 13, 'n_clicks_timestamp': 1611733455154 }, '{"_id":"inp-2","_type":"btn5"}': { 'n_clicks': 19, 'n_clicks_timestamp': 1611733455554 } } assert DashApp.objects.get( instance_name="Some name").current_state() == final_state