diff --git a/conftest.py b/conftest.py index 53d55d7..a75404e 100644 --- a/conftest.py +++ b/conftest.py @@ -58,9 +58,15 @@ def webapp(): def make_webapp_url( endpoint, **kwargs ): """Generate a webapp URL.""" with app.test_request_context(): + # NOTE: When we perform actions at high speed, the notification balloons can build up + # very quickly, causing problems by obscuring other elements and making them non-clickable :-/ + # We used to explicitly dismiss them, but it's simpler to just always disable them. + kwargs["store_msgs"] = 1 + # check if the tests are being run headless if pytest.config.option.headless: #pylint: disable=no-member - # headless browsers have no clipboard support :-/ + # yup - there is no clipboard support :-/ pytest.config.option.no_clipboard = True #pylint: disable=no-member + # check if we should disable using the clipboard for snippets if pytest.config.option.no_clipboard: #pylint: disable=no-member # NOTE: It's not a bad idea to bypass the clipboard, even when running in a browser, # to avoid problems if something else uses the clipboard while the tests are running. diff --git a/vasl_templates/webapp/static/snippets.js b/vasl_templates/webapp/static/snippets.js index fcc7e7c..b1aae29 100644 --- a/vasl_templates/webapp/static/snippets.js +++ b/vasl_templates/webapp/static/snippets.js @@ -20,11 +20,6 @@ var gDefaultScenario = null ; function generate_snippet( $btn, extra_params ) { - // initialize - storeMsgForTestSuite( "_last-info_", "" ) ; - storeMsgForTestSuite( "_last-warning_", "" ) ; - storeMsgForTestSuite( "_last-error_", "" ) ; - // extract the scenario date components var params = {} ; var scenario_date = $("input[name='SCENARIO_DATE']").datepicker( "getDate" ) ; diff --git a/vasl_templates/webapp/static/utils.js b/vasl_templates/webapp/static/utils.js index 0f2e7de..e3df78e 100644 --- a/vasl_templates/webapp/static/utils.js +++ b/vasl_templates/webapp/static/utils.js @@ -146,62 +146,26 @@ function ask( title, msg, args ) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -function showInfoMsg( msg ) -{ - // show the informational message - $.growl( { - style: "notice", - title: null, - message: msg, - location: "br", - } ) ; - storeMsgForTestSuite( "_last-info_", msg ) ; -} +function showInfoMsg( msg ) { doShowNotificationMsg( "info", msg ) ; } +function showWarningMsg( msg ) { doShowNotificationMsg( "warning", msg ) ; } +function showErrorMsg( msg ) { doShowNotificationMsg( "error", msg ) ; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -function showWarningMsg( msg ) +function doShowNotificationMsg( msg_type, msg ) { - // show the warning message - $.growl( { - style: "warning", - title: null, - message: msg, - location: "br", - } ) ; - storeMsgForTestSuite( "_last-warning_", msg ) ; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if ( getUrlParam( "store_msgs" ) ) { + // store the message for the test suite + $( "#_last-" + msg_type + "_" ).val( msg ) ; + return ; + } -function showErrorMsg( msg ) -{ - // show the error message + // show the notification message $.growl( { - style: "error", + style: (msg_type === "info") ? "notice" : msg_type, title: null, message: msg, location: "br", - fixed: true, + fixed: (msg_type == "error"), } ) ; - storeMsgForTestSuite( "_last-error_", msg ) ; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -function storeMsgForTestSuite( id, msg ) -{ - // store a message for the test suite - if ( ! getUrlParam( "store_msgs" ) ) - return ; - var $elem = $( "#"+id ) ; - if ( $elem.length === 0 ) { - // NOTE: The
we store the message in must be visible, otherwise - // Selenium doesn't return any text for it :-/ - $elem = $( "
" ) ; - $("body").append( $elem ) ; - } - $elem.html( msg ) ; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vasl_templates/webapp/templates/index.html b/vasl_templates/webapp/templates/index.html index 444c68a..c04424e 100644 --- a/vasl_templates/webapp/templates/index.html +++ b/vasl_templates/webapp/templates/index.html @@ -24,6 +24,10 @@
+ + + + diff --git a/vasl_templates/webapp/tests/test_ob.py b/vasl_templates/webapp/tests/test_ob.py index 6771697..d25f7a1 100644 --- a/vasl_templates/webapp/tests/test_ob.py +++ b/vasl_templates/webapp/tests/test_ob.py @@ -6,7 +6,7 @@ import types from selenium.webdriver.support.ui import Select from vasl_templates.webapp.tests.utils import \ - get_nationalities, get_clipboard, get_stored_msg, select_tab, find_child, find_children, \ + get_nationalities, get_clipboard, get_stored_msg, set_stored_msg_marker, select_tab, find_child, find_children, \ add_simple_note, edit_simple_note, get_sortable_entry_count, drag_sortable_entry_to_trash, \ select_droplist_val @@ -92,7 +92,7 @@ def test_nationality_specific( webapp, webdriver ): #pylint: disable=too-many-lo """Check that nationality-specific buttons are shown/hidden correctly.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main" ) ) nationalities = get_nationalities( webapp ) # initialize @@ -108,16 +108,17 @@ def test_nationality_specific( webapp, webdriver ): #pylint: disable=too-many-lo # test snippet generation set_scenario_date( date ) select_tab( "ob1" ) + marker = set_stored_msg_marker( "_last-warning_" ) btn.click() assert get_clipboard() == expected # check if a warning was issued - last_warning = get_stored_msg( "_last-warning_" ) or "" + last_warning = get_stored_msg( "_last-warning_" ) image_url = find_child( "img", btn ).get_attribute( "src" ) if warning: assert "are only available" in last_warning assert "snippet-disabled.png" in image_url else: - assert last_warning == "" + assert last_warning == marker assert "snippet.png" in image_url # initialize diff --git a/vasl_templates/webapp/tests/test_scenario_persistence.py b/vasl_templates/webapp/tests/test_scenario_persistence.py index c9145d7..225c592 100644 --- a/vasl_templates/webapp/tests/test_scenario_persistence.py +++ b/vasl_templates/webapp/tests/test_scenario_persistence.py @@ -6,7 +6,7 @@ from selenium.webdriver.support.ui import Select from vasl_templates.webapp.tests.utils import \ get_nationalities, set_template_params, select_tab, select_menu_option, get_sortable_entry_text, \ - get_stored_msg, set_stored_msg, find_child, find_children + get_stored_msg, set_stored_msg, set_stored_msg_marker, find_child, find_children # --------------------------------------------------------------------- @@ -158,7 +158,7 @@ def test_unknown_vo( webapp, webdriver ): """Test detection of unknown vehicles/ordnance.""" # initialize - webdriver.get( webapp.url_for( "main", scenario_persistence=1, store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main", scenario_persistence=1 ) ) _ = _save_scenario() # nb: force the "scenario-persistence" element to be created # load a scenario that has unknown vehicles/ordnance @@ -170,6 +170,7 @@ def test_unknown_vo( webapp, webdriver ): "VEHICLES_2": [ "unknown vehicle 2" ], "ORDNANCE_2": [ "unknown ordnance 2" ], } + _ = set_stored_msg_marker( "_last-warning_" ) _load_scenario( scenario_params ) last_warning = get_stored_msg( "_last-warning_" ) assert last_warning.startswith( "Unknown vehicles/ordnance:" ) diff --git a/vasl_templates/webapp/tests/test_snippets.py b/vasl_templates/webapp/tests/test_snippets.py index 28da9fb..8c3b2d3 100644 --- a/vasl_templates/webapp/tests/test_snippets.py +++ b/vasl_templates/webapp/tests/test_snippets.py @@ -2,9 +2,9 @@ from selenium.webdriver.common.keys import Keys -from vasl_templates.webapp.tests.utils import select_tab, set_template_params, get_clipboard from vasl_templates.webapp.tests.utils import \ - wait_for_page_ready, get_stored_msg, dismiss_notifications, find_child, \ + select_tab, set_template_params, get_clipboard, \ + wait_for_page_ready, get_stored_msg, set_stored_msg_marker, find_child, \ for_each_template, add_simple_note, edit_simple_note, \ get_sortable_entry_count, generate_sortable_entry_snippet, drag_sortable_entry_to_trash @@ -14,7 +14,7 @@ def test_scenario_snippets( webapp, webdriver ): """Test HTML snippet generation.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main" ) ) select_tab( "scenario" ) btn = find_child( "button.generate[data-id='scenario']" ) @@ -65,7 +65,7 @@ def test_vc_snippets( webapp, webdriver ): """Test HTML snippet generation.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main" ) ) select_tab( "scenario" ) btn = find_child( "button.generate[data-id='victory_conditions']" ) @@ -100,7 +100,7 @@ def test_scenario_notes_snippets( webapp, webdriver ): """Test HTML snippet generation.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main" ) ) select_tab( "scenario" ) # add some scenario notes and check their snippets @@ -125,7 +125,7 @@ def test_players_snippets( webapp, webdriver ): """Test HTML snippet generation.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1 ) ) + webdriver.get( webapp.url_for( "main" ) ) select_tab( "scenario" ) btn = find_child( "button.generate[data-id='players']" ) @@ -183,7 +183,6 @@ def test_edit_templates( webapp, webdriver ): webdriver.execute_script( "$(arguments[0]).click();", elem ) edit_template( orig_template_id ) # check that the new template is being used - dismiss_notifications() elem = find_child( "button.generate[data-id='{}']".format( orig_template_id ) ) elem.click() assert get_clipboard() == "EDITED TEMPLATE: {}".format( orig_template_id ) @@ -239,6 +238,7 @@ def _test_snippet( btn, params, expected, expected2 ): # set the template parameters and generate the snippet set_template_params( params ) + marker = set_stored_msg_marker( "_last-warning_" ) btn.click() snippet = get_clipboard() lines = [ l.strip() for l in snippet.split("\n") ] @@ -246,7 +246,7 @@ def _test_snippet( btn, params, expected, expected2 ): assert snippet == expected # check warnings for mandatory parameters - last_warning = get_stored_msg( "_last-warning_" ) or "" + last_warning = get_stored_msg( "_last-warning_" ) if isinstance( expected2, list): # check for mandatory parameters param_names = [ "scenario name", "scenario location", "scenario date" ] @@ -261,4 +261,4 @@ def _test_snippet( btn, params, expected, expected2 ): else: # make sure there was no warning message assert expected2 is None - assert not last_warning + assert last_warning == marker diff --git a/vasl_templates/webapp/tests/test_ssr.py b/vasl_templates/webapp/tests/test_ssr.py index c18fd56..97e4806 100644 --- a/vasl_templates/webapp/tests/test_ssr.py +++ b/vasl_templates/webapp/tests/test_ssr.py @@ -3,7 +3,7 @@ import html from vasl_templates.webapp.tests.utils import \ - select_tab, find_child, get_clipboard, dismiss_notifications, \ + select_tab, find_child, get_clipboard, \ add_simple_note, edit_simple_note, drag_sortable_entry_to_trash, get_sortable_entry_count # --------------------------------------------------------------------- @@ -36,7 +36,6 @@ def test_ssr( webapp, webdriver ): if width: val += "\nwidth = [{}]".format( width ) assert html.unescape( get_clipboard() ) == val - dismiss_notifications() # add an SSR and generate the SSR snippet add_ssr( "This is my first SSR." ) diff --git a/vasl_templates/webapp/tests/test_template_packs.py b/vasl_templates/webapp/tests/test_template_packs.py index 8b65631..6508eb7 100644 --- a/vasl_templates/webapp/tests/test_template_packs.py +++ b/vasl_templates/webapp/tests/test_template_packs.py @@ -9,9 +9,8 @@ from selenium.webdriver.support.ui import Select from vasl_templates.webapp import snippets from vasl_templates.webapp.tests.utils import \ - select_tab, select_menu_option, dismiss_notifications, get_clipboard, \ - get_stored_msg, set_stored_msg, add_simple_note, for_each_template, find_child, find_children, \ - select_droplist_val, get_droplist_vals + select_tab, select_menu_option, get_clipboard, get_stored_msg, set_stored_msg, set_stored_msg_marker,\ + add_simple_note, for_each_template, find_child, find_children, select_droplist_val, get_droplist_vals # --------------------------------------------------------------------- @@ -19,13 +18,12 @@ def test_individual_files( webapp, webdriver ): """Test loading individual template files.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1, template_pack_persistence=1 ) ) + webdriver.get( webapp.url_for( "main", template_pack_persistence=1 ) ) # try uploading a customized version of each template def test_template( template_id, orig_template_id ): """Test uploading a customized version of the template.""" # make sure generating a snippet returns something - dismiss_notifications() elem, clipboard = _generate_snippet( template_id, orig_template_id ) assert clipboard != "" # upload a new template @@ -35,7 +33,6 @@ def test_individual_files( webapp, webdriver ): ) select_menu_option( "template_pack" ) # make sure generating a snippet returns the new version - dismiss_notifications() elem.click() assert get_clipboard() == "UPLOADED TEMPLATE" for_each_template( test_template ) @@ -44,16 +41,18 @@ def test_individual_files( webapp, webdriver ): set_stored_msg( "_template_pack_persistence_", "filename.xyz | UPLOADED TEMPLATE" ) + _ = set_stored_msg_marker( "_last-error_" ) select_menu_option( "template_pack" ) - last_error_msg = get_stored_msg("_last-error_" ) + last_error_msg = get_stored_msg( "_last-error_" ) assert "Invalid template extension" in last_error_msg # try uploading a template with an unknown filename set_stored_msg( "_template_pack_persistence_", "unknown.j2 | UPLOADED TEMPLATE" ) + _ = set_stored_msg_marker( "_last-error_" ) select_menu_option( "template_pack" ) - last_error_msg = get_stored_msg("_last-error_" ) + last_error_msg = get_stored_msg( "_last-error_" ) assert "Invalid template filename" in last_error_msg # --------------------------------------------------------------------- @@ -62,23 +61,26 @@ def test_zip_files( webapp, webdriver ): """Test loading ZIP'ed template packs.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1, template_pack_persistence=1 ) ) + webdriver.get( webapp.url_for( "main", template_pack_persistence=1 ) ) # upload a template pack that contains a full set of templates zip_data = _make_zip_from_files( "full" ) + marker = set_stored_msg_marker( "_last-error_" ) _upload_template_pack( zip_data ) - assert get_stored_msg("_last-error_") is None + assert get_stored_msg( "_last-error_" ) == marker # check that the uploaded templates are being used _check_snippets( lambda tid: "Customized {}.".format( tid.upper() ) ) # upload only part of template pack + _ = set_stored_msg_marker( "_last-error_" ) _upload_template_pack( zip_data[ : int(len(zip_data)/2) ] ) - assert get_stored_msg("_last-error_").startswith( "Can't unpack the ZIP:" ) + assert get_stored_msg( "_last-error_" ).startswith( "Can't unpack the ZIP:" ) # try uploading an empty template pack + _ = set_stored_msg_marker( "_last-error_" ) _upload_template_pack( b"" ) - assert get_stored_msg("_last-error_").startswith( "Can't unpack the ZIP:" ) + assert get_stored_msg( "_last-error_" ).startswith( "Can't unpack the ZIP:" ) # NOTE: We can't test the limit on template pack size, since it happens after the browser's # "open file" dialog has finished, but before we read the file data (i.e. we don't execute @@ -105,7 +107,7 @@ def test_nationality_data( webapp, webdriver ): """Test a template pack with nationality data.""" # initialize - webdriver.get( webapp.url_for( "main", store_msgs=1, template_pack_persistence=1 ) ) + webdriver.get( webapp.url_for( "main", template_pack_persistence=1 ) ) select_tab( "scenario" ) # select the British as player 1 @@ -122,8 +124,9 @@ def test_nationality_data( webapp, webdriver ): # upload a template pack that contains nationality data zip_data = _make_zip_from_files( "with-nationality-data" ) + marker = set_stored_msg_marker( "_last-error_" ) _upload_template_pack( zip_data ) - assert get_stored_msg("_last-error_") is None + assert get_stored_msg( "_last-error_" ) == marker # check that the UI was updated correctly assert tab_ob1.text.strip() == "Poms! OB" @@ -170,7 +173,6 @@ def _check_snippets( expected ): def test_template( template_id, orig_template_id ): """Test each template.""" - dismiss_notifications() _, clipboard = _generate_snippet( template_id, orig_template_id ) assert clipboard == expected( template_id ) for_each_template( test_template ) diff --git a/vasl_templates/webapp/tests/test_vehicles_ordnance.py b/vasl_templates/webapp/tests/test_vehicles_ordnance.py index 3d5a6ee..5a08742 100644 --- a/vasl_templates/webapp/tests/test_vehicles_ordnance.py +++ b/vasl_templates/webapp/tests/test_vehicles_ordnance.py @@ -7,7 +7,7 @@ from selenium.webdriver.common.action_chains import ActionChains from vasl_templates.webapp.tests.utils import \ wait_for_page_ready, select_tab, set_template_params, find_child, find_children, \ - get_clipboard, click_dialog_button, dismiss_notifications + get_clipboard, click_dialog_button # --------------------------------------------------------------------- @@ -64,7 +64,6 @@ def test_crud( webapp, webdriver ): """Check the generated vehicle/ordnance snippet.""" # check the snippet select_tab( "ob{}".format( player_no ) ) - dismiss_notifications() btn = find_child( "button[data-id='{}_{}']".format( vo_type, player_no ) ) btn.click() buf = get_clipboard() @@ -135,7 +134,6 @@ def test_snippets( webapp, webdriver ): vo_type0 = vo_type[:-1] if vo_type.endswith("s") else vo_type # test a full example add_vo( vo_type, 1, "a german {}".format(vo_type) ) - dismiss_notifications() btn = find_child( "button[data-id='{}_1']".format( vo_type ) ) btn.click() expected = [ @@ -152,7 +150,6 @@ def test_snippets( webapp, webdriver ): # test a partial example add_vo( vo_type, 1, "another german {}".format(vo_type) ) - dismiss_notifications() btn = find_child( "button[data-id='{}_1']".format( vo_type ) ) btn.click() expected = [ @@ -168,7 +165,6 @@ def test_snippets( webapp, webdriver ): # test a minimal example add_vo( vo_type, 1, "name only" ) - dismiss_notifications() btn = find_child( "button[data-id='{}_1']".format( vo_type ) ) btn.click() assert get_clipboard() == \ @@ -194,7 +190,6 @@ def test_variable_capabilities( webapp, webdriver ): vehicles2 = find_child( "button.generate[data-id='vehicles_2']" ) def do_test( month, year, expected ): """Set the date and check the vehicle snippet.""" - dismiss_notifications() select_tab( "scenario" ) set_template_params( { "SCENARIO_DATE": "{:02d}/01/{}".format(month,year) } ) select_tab( "ob2" ) diff --git a/vasl_templates/webapp/tests/utils.py b/vasl_templates/webapp/tests/utils.py index 2827129..c6cfab0 100644 --- a/vasl_templates/webapp/tests/utils.py +++ b/vasl_templates/webapp/tests/utils.py @@ -5,6 +5,7 @@ import urllib.request import json import time import re +import uuid import pytest from PyQt5.QtWidgets import QApplication @@ -233,22 +234,24 @@ def find_sortable_helper( sortable, tag ): # --------------------------------------------------------------------- -def get_stored_msg( msg_id ): +def get_stored_msg( msg_type ): """Get a message stored for us by the front-end.""" - elem = find_child( "#"+msg_id ) - if not elem: - return None - if elem.tag_name == "div": - return elem.text + elem = find_child( "#" + msg_type ) assert elem.tag_name == "textarea" return elem.get_attribute( "value" ) -def set_stored_msg( msg_id, val ): +def set_stored_msg( msg_type, val ): """Set a message for the front-end.""" - elem = find_child( "#"+msg_id ) + elem = find_child( "#" + msg_type ) assert elem.tag_name == "textarea" _webdriver.execute_script( "arguments[0].value = arguments[1]", elem, val ) +def set_stored_msg_marker( msg_type ): + """Store marker text in the message buffer (so we can tell if the front-end changes it).""" + marker = "marker:{}:{}".format( msg_type, uuid.uuid4() ) + set_stored_msg( msg_type, marker ) + return marker + # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def find_child( sel, parent=None ): @@ -295,6 +298,7 @@ def get_droplist_vals( sel ): def dismiss_notifications(): """Dismiss all notifications.""" + assert False, "Shouldn't need to call this function." # nb: notifications have been disabled during tests while True: elem = find_child( ".growl-close" ) if not elem: