def test_parameter_dist(dash_threaded): app = dash.Dash(__name__) app.css.config.serve_locally = True app.scripts.config.serve_locally = True app.config.suppress_callback_exceptions = True cache.init_app(app.server) driver = dash_threaded.driver container_settings = {'scratch_ensembles': {'iter-0': ''}} ensemble = 'iter-0' with mock.patch(get_parameters) as mock_parameters: mock_parameters.return_value = pd.read_csv('tests/data/parameters.csv') p = _parameter_distribution.\ ParameterDistribution(app, container_settings, ensemble) app.layout = p.layout dash_threaded(app) my_component = wait_for_element_by_css_selector( driver, f'#{p.dropdown_vector_id}') if 'REAL' != my_component.text: raise AssertionError()
def test_showlegend(dash_threaded): """Test the legend display.""" def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: if PROP_TYPES['bool'](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, oncoprint_props_callback, 'showlegend', 'False', prop_type='bool', component_base=COMPONENT_REACT_BASE, data=TEST_DATA ) driver = dash_threaded.driver # assert there is a legend (bar) legend = wait_for_elements_by_css_selector(driver, 'g.traces') assert len(legend) != 0 # trigger change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert there is no more legend (bar) legend = driver.find_elements_by_class_name('legendbar') assert len(legend) == 0
def template_test_python_component_prop(dash_threaded, app_name, assert_callback, update_component_callback, prop_name, prop_value, prop_type=None, component_base=COMPONENT_PYTHON_BASE, **kwargs): template_test_component(dash_threaded, app_name, assert_callback, update_component_callback, prop_name, prop_value, prop_type=prop_type, component_base=component_base, **kwargs) driver = dash_threaded.driver btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(app_name)) btn.click() wait_for_text_to_equal(driver, '#test-{}-assert-value-div'.format(app_name), 'PASSED')
def test_dash_threaded(dash_threaded): app = dash.Dash(__name__) app.layout = html.Div([ html.Button('click me', id='clicker'), html.Div(id='output') ]) call_count = Queue() @app.callback(Output('output', 'children'), [Input('clicker', 'n_clicks')]) def on_click(n_clicks): call_count.put(1) if n_clicks is None: raise PreventUpdate return n_clicks dash_threaded(app, port=8090) assert 'http://localhost:8090' in dash_threaded.driver.current_url clicker = wait_for_element_by_css_selector( dash_threaded.driver, '#clicker' ) for i in range(6): clicker.click() wait_for_text_to_equal(dash_threaded.driver, '#output', str(i + 1)) assert call_count.qsize() == 7
def test_table_of_contents(dash_threaded): from test_apps.table_of_contents import app selenium = dash_threaded.driver dash_threaded(app) toc_elem = wait_for_element_by_css_selector(selenium, '#toc') elements = toc_elem.find_elements_by_xpath('//a[contains(@href, "toc")]') assert 9 == len(elements), 'Nine toc elements were not created'
def test_resolution(dash_threaded): """Test setting the resolution.""" prop_type = 'int' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'resolution', '10', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS ) driver = dash_threaded.driver # handle of the dcc.Input to change the prop value prop_value_input = wait_for_element_by_css_selector( driver, '#test-{}-prop-value-input'.format(APP_NAME) ) # loop through allowed values for resolution for res in ['450', '550', '850']: clear_field(prop_value_input) prop_value_input.send_keys(res) # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the presence of an ideogram component wait_for_element_by_id(driver, '_ideogram')
def test_homology(dash_threaded): """Test the display of a basic homology""" prop_type = 'dict' prop_val = { "chrOne": { "organism": "9606", "start": [10001, 105101383], "stop": [27814790, 156030895], }, "chrTwo": { "organism": "9606", "start": [3000000, 125101383], "stop": [9000000, 196130895], }, } def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'homology', json.dumps(prop_val), prop_type=prop_type, component_base=COMPONENT_REACT_BASE, perspective="comparative", chromosomes=["1", "2"], **BASIC_PROPS ) driver = dash_threaded.driver # assert the absence of homology region regions = driver.find_elements_by_class_name('syntenicRegion') assert len(regions) == 0 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the presence of homology region regions = wait_for_elements_by_css_selector(driver, '.syntenicRegion', timeout=20) assert len(regions) > 0
def element_selector(self, selector): """ Find an element by selector when found in the tree. :Example: ``{#radio-items > label:nth-child(9) > input[type="radio"]}`` :kind: value :param selector: Text contained between `{` & `}` """ return wait_for_element_by_css_selector( self.driver, selector.lstrip('{').rstrip('}'))
def test_sex(dash_threaded): """Test the hiding of chromosome Y if sex is set to female.""" prop_type = 'str' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component(dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'sex', 'female', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS) driver = dash_threaded.driver # assert the presence of the chromosome Y chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome') num_chromosoms = len(chromosomes) assert num_chromosoms == 24 has_chr_y = False for chromosome in chromosomes: if 'chrY' in chromosome.get_attribute('id'): has_chr_y = True assert has_chr_y is True # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the absence of the chromosome Y chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome', timeout=20) num_chromosoms = len(chromosomes) assert num_chromosoms == 23 has_chr_y = False for chromosome in chromosomes: if 'chrY' in chromosome.get_attribute('id'): has_chr_y = True assert has_chr_y is False
def test_PROPNAME_1(dash_threaded): """Test that some prop updates correctly when changed, for a React component.""" def assert_callback(nclicks, component_PROPNAME, input_PROPNAME): """Determine the pass/fail status of this test. :param nclicks (int): The n_clicks value of the button in the simple test app (not used here). :param component_PROPNAME (string): The value of PROPNAME for the component after it is set. :param input_PROPNAME (string): The value of PROPNAME that is sent to the component. :return (string): 'PASSED' for a test that passed, or 'FAILED' for a test that failed """ # avoid triggering this callback when the button is first created if nclicks is not None: # check for the pass/fail condition here; this is a # shallow comparison, so write your own if necessary if component_PROPNAME == input_PROPNAME: return PASS return FAIL # replace "None" with a string that defines the type of the prop # (e.g., 'int', 'float', 'list') prop_type = None template_test_component( dash_threaded, APP_NAME, assert_callback, COMPONENTNAME_test_props_callback, PROPNAME, input_PROPNAME, prop_type=prop_type, component_base=COMPONENT_REACT_BASE # add any arguments you want to send to your component, # e.g., # sequence='GATTACA', # showLineNumbers=False ) driver = dash_threaded.driver # driver.find_elements_by_class_name('...') # assert something about this element (before changing it) # trigger change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click()
def test_application(dash_threaded): driver = dash_threaded.driver app = import_app('webApp') counts = {'clicks': 0} dash_threaded(app) btn = wait_for.wait_for_element_by_css_selector(driver, '#date-picker') btn.click() wait_for.wait_for_text_to_equal(driver, '#out', '')
def test_annotations_path(dash_threaded): """Test the loading of annotations form a provided URL.""" prop_type = 'str' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'annotationsPath', 'https://eweitz.github.io/ideogram/data/annotations/all_human_genes.json', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS) driver = dash_threaded.driver # assert the absence of annotations annots = driver.find_elements_by_class_name('annot') assert len(annots) == 0 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # raise an error if no element with 'annot' class is found wait_for_element_by_css_selector(driver, '.annot')
def test_subprocess(dash_subprocess): dash_subprocess('test_apps.simple_app', port=8080) driver = dash_subprocess.driver assert 'http://localhost:8080' in driver.current_url value_input = driver.find_element_by_id('value') value_input.clear() value_input.send_keys('Hello dash subprocess') wait_for_property_to_equal( driver, '#value', 'value', 'Hello dash subprocess' ) btn = wait_for_element_by_css_selector(driver, '#style-btn') btn.click() wait_for_style_to_equal(driver, '#style-output', 'padding', '10px')
def test_brush(dash_threaded): """Test enabling the brush prop.""" prop_type = 'str' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'brush', 'chr3:3500000-40000000', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, chromosomes=['3'], orientation="horizontal", brush="chr3:200000-2000000", **BASIC_PROPS ) driver = dash_threaded.driver # verify the existence of the brush brush = driver.find_elements_by_class_name('brush') assert len(brush) == 1 # selection = driver.find_elements_by_class_name('selection')[0] # selection_width_before = selection.get_attribute('width') # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() brush = driver.find_elements_by_class_name('brush') assert len(brush) == 1
def test_orientation(dash_threaded): """Test orientation prop.""" prop_type = 'str' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component(dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'orientation', 'horizontal', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS) driver = dash_threaded.driver # assert presence of chromosomes' rotation chromosoms = wait_for_elements_by_css_selector( driver, '.chromosome-set-container') for chromosom in chromosoms: assert 'rotate(90)' in str(chromosom.get_attribute('transform')) # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert absence of chromosomes' rotation chromosoms = wait_for_elements_by_css_selector( driver, '.chromosome-set-container') for chromosom in chromosoms: assert 'rotate(90)' not in str(chromosom.get_attribute('transform'))
def test_full_chromosome_labels(dash_threaded): """Test the full chromosome label display/hiding""" prop_type = 'bool' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'fullChromosomeLabels', 'True', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, chromosomes=['1'], fullChromosomeLabels=False, **BASIC_PROPS ) driver = dash_threaded.driver # assert the absence of a full label regions = wait_for_elements_by_css_selector(driver, 'tspan') assert len(regions) == 1 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the presence of a full label regions = wait_for_elements_by_css_selector(driver, 'tspan', timeout=20) assert len(regions) == 2
def test_chromosomes_wrong_input(dash_threaded): """Test input of a wrong chromosome name.""" prop_type = 'list' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component(dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'chromosomes', '1,D,3', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS) driver = dash_threaded.driver # assert 22 chromosomes + X and Y chromosomes chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome') assert len(chromosomes) == 24 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the set of chromosomes contains 2 chromosomes chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome', timeout=20) assert len(chromosomes) == 2
def test_ploidy(dash_threaded): """Test duplication of each chromosome.""" prop_type = 'int' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component(dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'ploidy', '2', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS) driver = dash_threaded.driver # assert 22 chromosomes + X and Y chromosomes chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome') assert len(chromosomes) == 24 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert doubling of the 22 chromosomes + X and Y chromosomes chromosomes = wait_for_elements_by_css_selector(driver, '.chromosome', timeout=20) assert len(chromosomes) == 46
def test_suggestions_input(dash_threaded): from test_apps.suggestions_input import app selenium = dash_threaded.driver dash_threaded(app) suggestion_input = wait_for_element_by_css_selector( selenium, '#suggestions') # Tests all suggestion types. suggestion_input.send_keys('$Term\t') wait_for_text_to_equal(selenium, '#suggestions-output', 'Terminator') # Backend/Callback powered suggestions # need a small delay for the suggestions to appear # without losing the focus on the component for the modal to stay up. # test might be flaky... clear_input(suggestion_input) time.sleep(1) suggestion_input.send_keys('@call') time.sleep(1) suggestion_input.send_keys('\t') wait_for_text_to_equal(selenium, '#suggestions-output', 'callback')
def test_show_chromosome_labels(dash_threaded): """Test the display/hiding of chromosomes labels.""" prop_type = 'bool' def assert_callback(prop_value, nclicks, input_value): answer = '' if nclicks is not None: answer = FAIL if PROP_TYPES[prop_type](input_value) == prop_value: answer = PASS return answer template_test_component( dash_threaded, APP_NAME, assert_callback, ideogram_test_props_callback, 'showChromosomeLabels', 'True', prop_type=prop_type, component_base=COMPONENT_REACT_BASE, **BASIC_PROPS ) driver = dash_threaded.driver # assert the absence of chromosomes' labels labels = driver.find_elements_by_class_name('chrLabel') assert len(labels) == 0 # trigger a change of the component prop btn = wait_for_element_by_css_selector(driver, '#test-{}-btn'.format(APP_NAME)) btn.click() # assert the presence of chromosomes' labels labels = wait_for_elements_by_css_selector(driver, '.chrLabel', timeout=20) assert len(labels) > 0
def test_render_component(dash_threaded): # Start a dash app contained in `usage.py` # dash_threaded is a fixture by pytest-dash # It will load a py file containing a Dash instance named `app` # and start it in a thread. driver = dash_threaded.driver app = import_app('usage') dash_threaded(app) # Get the generated component input with selenium # The html input will be a children of the #input dash component my_component = wait_for_element_by_css_selector(driver, '#input > input') assert 'my-value' == my_component.get_attribute('value') # Clear the input my_component.clear() # Send keys to the custom input. my_component.send_keys('Hello dash') # Wait for the text to equal, if after the timeout (default 10 seconds) # the text is not equal it will fail the test. wait_for_text_to_equal(driver, '#output', 'You have entered Hello dash')
def test_install(cookies, dash_threaded): results = cookies.bake(extra_context={ 'project_name': 'Test Component', 'author_name': 'test', 'author_email': 'test', }) # Add the generated project to the path so it can be loaded from usage.py # It lies somewhere in a temp directory created by pytest-cookies sys.path.insert(0, str(results.project)) selenium = dash_threaded.driver # Test that `usage.py` works after building the default component. dash_threaded(import_app('usage')) input_component = wait_for_element_by_css_selector( selenium, '#input > input' ) input_component.clear() input_component.send_keys('Hello dash component') wait_for_text_to_equal( selenium, '#output', 'You have entered Hello dash component' ) node_modules = str(results.project.join('node_modules')) if sys.platform == 'win32': # Fix delete long names on windows. # pytest-cookies have trouble deleting some file generated by webpack. node_modules = '\\\\?\\' + node_modules shutil.rmtree(node_modules)
def template_test_component(dash_threaded, app_name, assert_callback, update_component_callback, prop_name, prop_value, prop_type=None, component_base=COMPONENT_PYTHON_BASE, **kwargs): """Share reusable test code for testing single props assignation to a component. :param dash_threaded: from pytest_dash :param app_name: (string) name of the app :param assert_callback: (func) this function is where the test should be explicitly defined, this 'assert_callback' function should typically be defined within a test function which calls 'template_test_python_component_prop'. :param update_component_callback: (func) this function will be assigned as a callback which output is the component prop and which is triggered programmatically by a click on a button which is inside the simple_app created to test the component :param prop_name: (string) name of the component prop to test :param prop_value: (string) value to pass to the component prop :param prop_type: (string) specify what type is the component prop is, see PROP_TYPES default: None :param component_base: (string) specify whether the component is based on react or python default: COMPONENT_PYTHON_BASE :return: """ driver = dash_threaded.driver simple_app = dash.Dash(__name__) # generate a simple app to test the component's prop simple_app.layout = create_test_layout(app_name, component_base, **kwargs) # the following callbacks depends whether the component is python or react based if component_base == COMPONENT_REACT_BASE: component_prop = prop_name else: component_prop = 'figure' @simple_app.callback( Output('test-{}-component'.format(app_name), component_prop), [Input('test-{}-btn'.format(app_name), 'n_clicks')], [ State('test-{}-prop-name-input'.format(app_name), 'value'), State('test-{}-prop-value-input'.format(app_name), 'value') ]) def update_component(nclicks, p_name, p_value): """Update the prop of the component when the button is clicked.""" return update_component_callback(nclicks, p_name, p_value, prop_type) @simple_app.callback( Output('test-{}-assert-value-div'.format(app_name), 'children'), [Input('test-{}-component'.format(app_name), component_prop)], [ State('test-{}-btn'.format(app_name), 'n_clicks'), State('test-{}-prop-value-input'.format(app_name), 'value') ]) def assert_value(p_value, nclicks, input_value): """Callback provided by the test user is called here. This callback should return the string 'PASSED' if the test defined in it is successful. """ return assert_callback(p_value, nclicks, input_value) dash_threaded(simple_app) prop_name_input = wait_for_element_by_css_selector( driver, '#test-{}-prop-name-input'.format(app_name)) prop_value_input = wait_for_element_by_css_selector( driver, '#test-{}-prop-value-input'.format(app_name)) prop_name_input.send_keys(prop_name) prop_value_input.send_keys(prop_value)