def test_include_flags_in_snippets(webapp, webdriver): """Test including flags in snippets.""" # initialize webapp.control_tests.set_data_dir("{REAL}") init_webapp(webapp, webdriver) # prepare the scenario set_player(1, "german") select_tab("ob1") sortable = find_child("#ob_setups-sortable_1") add_simple_note(sortable, "OB setup note", None) # enable "show flags in snippets" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='include-flags-in-snippets']") assert not elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "include-flags-in-snippets", True) # make sure that it took effect ob_setup_snippet_btn = find_child("li img.snippet", sortable) ob_setup_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=True) # make sure it also affects vehicle/ordnance snippets ob_vehicles_snippet_btn = find_child( "button.generate[data-id='ob_vehicles_1']") ob_vehicles_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=True) ob_ordnance_snippet_btn = find_child( "button.generate[data-id='ob_ordnance_1']") ob_ordnance_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=True) # disable "show flags in snippets" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='include-flags-in-snippets']") assert elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "include-flags-in-snippets", False) # make sure that it took effect ob_setup_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=False) # make sure it also affects vehicle/ordnance snippets ob_vehicles_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=False) ob_ordnance_snippet_btn.click() wait_for_clipboard(2, "/flags/german", contains=False)
def _enable_vo_no_notes_as_images(enable): """Enable/disable vehicle/ordnance notes as images.""" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='vo-notes-as-images']") if (elem.is_selected() and not enable) or (not elem.is_selected() and enable): elem.click() click_dialog_button("OK") else: click_dialog_button("Cancel")
def test_multiple_images(webapp, webdriver): """Test handling of VASL counters that have multiple images.""" # initialize webapp.control_tests \ .set_data_dir( "{REAL}" ) \ .set_vasl_version( "random", None ) init_webapp(webapp, webdriver, scenario_persistence=1) # load the test scenario load_scenario({ "PLAYER_1": "british", "OB_VEHICLES_1": [{ "name": "2pdr Portee" }], }) # configure the user settings set_user_settings({ "scenario-images-source": SCENARIO_IMAGES_SOURCE_INTERNET, "include-vasl-images-in-snippets": True, }) # generate a snippet for the vehicle (using the default image) select_tab("ob1") btn = find_child("button[data-id='ob_vehicles_1']") btn.click() wait_for_clipboard( 2, re.compile( r'<img src="https://raw.githubusercontent.com/.+/br/vehicles/portee.gif"' )) # select the second image for the vehicle sortable = find_child("#ob_vehicles-sortable_1") elems = find_children("li", sortable) assert len(elems) == 1 ActionChains(webdriver).double_click(elems[0]).perform() btn = wait_for_elem(2, "#edit-vo input.select-vo-image") btn.click() images = find_children(".ui-dialog.select-vo-image .vo-images img") assert len(images) == 2 images[1].click() click_dialog_button("OK") # generate a snippet for the vehicle (using the new image) btn = find_child("button[data-id='ob_vehicles_1']") btn.click() wait_for_clipboard( 2, re.compile( r'<img src="https://raw.githubusercontent.com/.+/br/vehicles/portee0.gif"' ))
def test_vo_notes_as_images(webapp, webdriver): """Test showing vehicle/ordnance notes as HTML/images.""" # initialize webapp.control_tests.set_vo_notes_dir("{TEST}") init_webapp(webapp, webdriver, scenario_persistence=1) # load the test vehicle load_scenario({ "PLAYER_1": "greek", "OB_VEHICLES_1": [{ "name": "HTML note" }], }) select_tab("ob1") def check_snippet(expected): """Generate and check the vehicle note snippet.""" sortable = find_child("#ob_vehicles-sortable_1") elems = find_children("li", sortable) assert len(elems) == 1 btn = find_child("img.snippet", elems[0]) btn.click() contains = True if isinstance(expected, str) else None wait_for_clipboard(2, expected, contains=contains) # generate the vehicle snippet (should get the raw HTML) check_snippet("This is an HTML vehicle note (202).") # enable "show vehicle/ordnance notes as images" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='vo-notes-as-images']") assert not elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "vo-notes-as-images", True) # generate the vehicle snippet (should get a link to return an image) check_snippet(re.compile(r"http://.+?:\d+/vehicles/greek/note/202")) # disable "show vehicle/ordnance notes as images" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='vo-notes-as-images']") assert elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "vo-notes-as-images", False) # generate the vehicle snippet (should get the raw HTML) check_snippet("This is an HTML vehicle note (202).")
def do_test(tab_id, param): """Test checking for a dirty scenario.""" # change the specified field check_is_dirty(False) select_tab(tab_id) state = change_field(param) check_is_dirty(True) # make sure we get asked to confirm a "new scenario" operation select_menu_option("new_scenario") wait_for(2, lambda: find_child("#ask") is not None) elem = find_child("#ask") assert "This scenario has been changed" in elem.text # cancel the confirmation request, make sure the change we made is still there click_dialog_button("Cancel") select_tab(tab_id) check_field(param, state) check_is_dirty(True) # revert the change revert_field(param, state) check_is_dirty(False) # we should now be able to reset the scenario without a confirmation _ = set_stored_msg_marker("_last-info_") select_menu_option("new_scenario") wait_for( 2, lambda: get_stored_msg("_last-info_") == "The scenario was reset.") # change the field again select_tab(tab_id) state = change_field(param) check_is_dirty(True) # make sure we get asked to confirm a "load scenario" operation select_menu_option("load_scenario") wait_for(2, lambda: find_child("#ask") is not None) elem = find_child("#ask") assert "This scenario has been changed" in elem.text # cancel the confirmation request, make sure the change we made is still there click_dialog_button("Cancel") select_tab(tab_id) check_field(param, state) check_is_dirty(True) # revert the change revert_field(param, state) check_is_dirty(False)
def test_hide_unavailable_ma_notes(webapp, webdriver): """Test showing/hiding unavailable multi-applicable notes.""" # initialize webapp.control_tests.set_vo_notes_dir("{TEST}") init_webapp(webapp, webdriver, scenario_persistence=1) # load the test vehicle load_scenario({ "PLAYER_1": "german", "OB_VEHICLES_1": [{ "name": "missing multi-applicable note" }] }) select_tab("ob1") def test_ma_notes(ma_note_q_present): #pylint: disable=missing-docstring expected = [("A", 'German Multi-Applicable Vehicle Note "A".')] if ma_note_q_present: expected.append(("Q", "Unavailable.")) btn = find_child("button[data-id='ob_vehicles_ma_notes_1']") btn.click() wait_for_clipboard(2, expected, transform=extract_ma_notes) # generate the multi-applicable notes test_ma_notes(True) # enable "hide unavailable multi-applicable notes" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='hide-unavailable-ma-notes']") assert not elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "hide-unavailable-ma-notes", True) # generate the multi-applicable notes test_ma_notes(False) # disable "hide unavailable multi-applicable notes" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='hide-unavailable-ma-notes']") assert elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "hide-unavailable-ma-notes", False) # generate the multi-applicable notes test_ma_notes(True)
def set_user_settings(opts): """Configure the user settings.""" select_menu_option("user_settings") for key, val in opts.items(): if isinstance(val, bool): elem = find_child( ".ui-dialog.user-settings input[name='{}']".format(key)) if (val and not elem.is_selected()) or (not val and elem.is_selected()): elem.click() elif isinstance(val, int): elem = find_child( ".ui-dialog.user-settings select[name='{}']".format(key)) select_droplist_val(Select(elem), val) else: assert False click_dialog_button("OK")
def add_vo( webdriver, vo_type, player_no, name ): #pylint: disable=unused-argument """Add a vehicle/ordnance.""" # add the vehicle/ordnance select_tab( "ob{}".format( player_no ) ) elem = find_child( "#ob_{}-add_{}".format( vo_type, player_no ) ) elem.click() # FUDGE! Locating the vehicle/ordnance by name and selecting it is finicky, I suspect # because select2 is sensitive about where the mouse is, and we sometimes end up # selecting the wrong item :-/ Selecting by name won't work if there are multiple items # that start with the same thing, but that shouldn't be a problem. dlg = find_child( "#select-vo" ) elem = find_child( "input", dlg ) elem.send_keys( name ) entries = find_children( ".select2-results li", dlg ) assert len(entries) == 1 click_dialog_button( "OK" )
def test_include_vasl_images_in_snippets(webapp, webdriver): """Test including VASL counter images in snippets.""" # initialize webapp.control_tests.set_data_dir("{REAL}") init_webapp(webapp, webdriver) set_user_settings( {"scenario-images-source": SCENARIO_IMAGES_SOURCE_THIS_PROGRAM}) # add a vehicle set_player(1, "german") add_vo(webdriver, "vehicles", 1, "PzKpfw IB") # enable "show VASL images in snippets" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='include-vasl-images-in-snippets']" ) assert not elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "include-vasl-images-in-snippets", True) # make sure that it took effect snippet_btn = find_child("button[data-id='ob_vehicles_1']") snippet_btn.click() wait_for_clipboard(2, "/counter/2524/front", contains=True) # disable "show VASL images in snippets" select_menu_option("user_settings") elem = find_child( ".ui-dialog.user-settings input[name='include-vasl-images-in-snippets']" ) assert elem.is_selected() elem.click() click_dialog_button("OK") _check_cookies(webdriver, "include-vasl-images-in-snippets", False) # make sure that it took effect snippet_btn.click() wait_for_clipboard(2, "/counter/2524/front", contains=False)
def do_test( vo_type, vo_name ): #pylint: disable=missing-docstring # start to add a vehicle/ordnance add_btn = find_child( "#ob_" + vo_type + "-add_1" ) add_btn.click() assert vo_name in get_available_vo_entries() # add the vehicle/ordnance elem = find_child( ".ui-dialog .select2-search__field" ) elem.send_keys( vo_name ) elem.send_keys( Keys.RETURN ) # make sure it was added to the player's OB sortable = find_child( "#ob_" + vo_type + "-sortable_1" ) assert get_sortable_vo_names( sortable ) == [ vo_name ] # add the vehicle/ordnance, dismiss the warning add_btn.click() elem = find_child( ".ui-dialog .select2-search__field" ) elem.send_keys( vo_name ) elem.send_keys( Keys.RETURN ) elem = find_child( "#ask" ) assert "already in the OB" in elem.text click_dialog_button( "Cancel", find_child(".ui-dialog.ask") ) click_dialog_button( "Cancel" ) # make sure the player's OB is unchanged assert get_sortable_vo_names( sortable ) == [ vo_name ] # add the vehicle/ordnance, accept the warning add_btn.click() elem = find_child( ".ui-dialog .select2-search__field" ) elem.send_keys( vo_name ) elem.send_keys( Keys.RETURN ) elem = find_child( "#ask" ) assert "already in the OB" in elem.text click_dialog_button( "OK", find_child(".ui-dialog.ask") ) # make sure the vehicle/ordnance was added to the player's OB assert get_sortable_vo_names( sortable ) == [ vo_name, vo_name ]
def test_elite( webapp, webdriver ): #pylint: disable=too-many-statements """Test elite vehicles/ordnance.""" # initialize webapp.control_tests.set_data_dir( "{REAL}" ) init_webapp( webapp, webdriver, scenario_persistence=1 ) def get_sortable_elem(): """Find the sortable element for the test vehicle.""" sortable = find_child( "#ob_vehicles-sortable_1" ) elems = find_children( "li", sortable ) assert len(elems) == 1 return elems[0] def check_elite( expected, custom ): """Check the elite status of the vehicle in the main UI.""" vo_name = find_child( ".vo-name", get_sortable_elem() ).text caps = [ c.text for c in find_children(".vo-capability",get_sortable_elem()) ] if expected: assert vo_name.endswith( "\u24ba" ) expected = [ "H9", "s10", "sD7", "CS 5" ] if custom: expected.append( "HE11" ) assert caps == expected else: assert "\u24ba" not in vo_name expected = [ "H8", "s9", "sD7", "CS 5" ] if custom: expected.append( "HE10" ) assert caps == expected def check_elite2( expected, custom ): """Check the elite status of the vehicle in the edit dialog.""" vo_name = find_child( "#edit-vo .header .vo-name" ).text caps = [ c.get_attribute("value") for c in find_children("#vo_capabilities-sortable input[type='text']") ] if expected: assert vo_name.endswith( "\u24ba" ) expected = [ "H9", "s10", "sD7", "CS 5" ] if custom: expected.append( "HE11" ) assert caps == expected else: assert "\u24ba" not in vo_name expected = [ "H8", "s9", "sD7", "CS 5" ] if custom: expected.append( "HE10" ) assert caps == expected # load the scenario scenario_data = { "PLAYER_1": "german", "OB_VEHICLES_1": [ { "name": "PSW 233" } ], # H8 s9 sD7 CS 5 } load_scenario( scenario_data ) select_tab( "ob1" ) # check that the vehicle was loaded non-elite check_elite( False, False ) # add a custom capability ActionChains( webdriver ).double_click( get_sortable_elem() ).perform() elem = find_child( "#vo_capabilities-add" ) elem.click() elems = find_children( "#vo_capabilities-sortable input[type='text']" ) assert len(elems) == 5 elems[4].send_keys( "HE10" ) click_dialog_button( "OK" ) # make the vehicle elite ActionChains( webdriver ).double_click( get_sortable_elem() ).perform() check_elite2( False, True ) elem = find_child( "#edit-vo .capabilities .elite" ) elem.click() check_elite2( True, True ) click_dialog_button( "OK" ) check_elite( True, True ) # save the scenario, then reload it saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert saved_scenario["OB_VEHICLES_1"][0]["elite"] assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == \ [ "H9", "s10", "sD7", "CS 5", "HE11" ] select_menu_option( "new_scenario" ) load_scenario( saved_scenario ) select_tab( "ob1" ) check_elite( True, True ) # make the vehicle non-elite ActionChains( webdriver ).double_click( get_sortable_elem() ).perform() check_elite2( True, True ) elem = find_child( "#edit-vo .capabilities .elite" ) elem.click() check_elite2( False, True ) click_dialog_button( "OK" ) check_elite( False, True ) # save the scenario saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert "elite" not in saved_scenario["OB_VEHICLES_1"][0] assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == \ [ "H8", "s9", "sD7", "CS 5", "HE10" ] # make the vehicle elite, remove the custom capability ActionChains( webdriver ).double_click( get_sortable_elem() ).perform() check_elite2( False, True ) elem = find_child( "#edit-vo .capabilities .elite" ) elem.click() check_elite2( True, True ) elems = find_children( "#vo_capabilities-sortable li" ) webdriver.execute_script( "arguments[0].scrollIntoView(true);", elems[4] ) ActionChains( webdriver ).key_down( Keys.CONTROL ).click( elems[4] ).perform() ActionChains( webdriver ).key_up( Keys.CONTROL ).perform() click_dialog_button( "OK" ) check_elite( True, False ) # save the scenario, then reload it saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert saved_scenario["OB_VEHICLES_1"][0]["elite"] assert saved_scenario["OB_VEHICLES_1"][0]["custom_capabilities"] == [ "H9", "s10", "sD7", "CS 5" ] select_menu_option( "new_scenario" ) load_scenario( saved_scenario ) select_tab( "ob1" ) check_elite( True, False ) # make the vehicle non-elite ActionChains( webdriver ).double_click( get_sortable_elem() ).perform() check_elite2( True, False ) elem = find_child( "#edit-vo .capabilities .elite" ) elem.click() check_elite2( False, False ) click_dialog_button( "OK" ) check_elite( False, False ) # save the scenario saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert "elite" not in saved_scenario["OB_VEHICLES_1"][0] assert "custom_capabilities" not in saved_scenario["OB_VEHICLES_1"][0]
def test_capability_updates_in_ui( webapp, webdriver ): """Check that capabilities are updated in the UI correctly.""" # initialize webapp.control_tests.set_data_dir( "{REAL}" ) init_webapp( webapp, webdriver, scenario_persistence=1 ) # load the scenario scenario_data = { "PLAYER_1": "german", "OB_VEHICLES_1": [ { "name": "PzKpfw 38(t)A" } ], # A4[1]/5[2] ; sD6 ; CS 4 "OB_ORDNANCE_1": [ { "name": "3.7cm PaK 35/36" } ], # NT ; A4[1]/5[2]/4[3]/3[4] ; H6[9]† "PLAYER_2": "russian", "OB_VEHICLES_2": [ { "name": "Churchill III(b)" } ], # D6[J4]/7[5]† ; HE7[F3]/8[4+]† ; sD6[4+] ; sM8† ; CS 7 "OB_ORDNANCE_2": [ { "name": "45mm PTP obr. 32" } ], # NT ; A4[2]/5[3]/6[4]/7[5] } scenario_data["OB_VEHICLES_1"].append( { "name": "PzJg I" } ) # A5[1]/6[2]/5[3]; HE7 ; CS 3 load_scenario( scenario_data ) sortables = [ find_child( "#ob_vehicles-sortable_1" ), find_child( "#ob_ordnance-sortable_1" ), find_child( "#ob_vehicles-sortable_2" ), find_child( "#ob_ordnance-sortable_2" ), ] def check_capabilities( scenario_date, expected ): """Get the vehicle/ordnance capabilities from the UI.""" # set the scenario date set_scenario_date( scenario_date ) # check the vehicle/ordnance capabilities results = [] for sortable in sortables: results.append( [] ) vo_entries = find_children( "li", sortable ) for vo_entry in vo_entries: capabilities = find_children( "span.vo-capability", vo_entry ) results[-1].append( [ c.get_attribute("innerHTML") for c in capabilities ] ) for row in expected: for i,entries in enumerate(row): row[i] = [ e for e in entries if e not in _IGNORE_CAPABILITIES ] assert results == expected # no scenario date => we should be showing the raw capabilities check_capabilities( None, [ [ [ "A4<sup>1</sup>5<sup>2</sup>", "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3" ] ], [ [ "NT", "A4<sup>1</sup>5<sup>2</sup>4<sup>3</sup>3<sup>4</sup>", "H6[9]\u2020" ] ], [ [ "D6<sup>J4</sup>7<sup>5</sup>†", "HE7<sup>F3</sup>8<sup>4+</sup>\u2020", "sD6<sup>4+</sup>", "sM8\u2020", "CS 7" ] ], #pylint: disable=line-too-long [ [ "NT", "A4<sup>2</sup>5<sup>3</sup>6<sup>4</sup>7<sup>5</sup>" ] ] ] ) # edit the PzJg I's capabilities (nb: this locks them in, and they should not change # regardless of what the scenario date is set to) select_tab( "ob1" ) vehicles_sortable = find_child( "#ob_vehicles-sortable_1" ) elems = find_children( "li", vehicles_sortable ) assert len(elems) == 2 ActionChains( webdriver ).double_click( elems[1] ).perform() elem = find_child( "#vo_capabilities-add" ) elem.click() elems = find_children( "#vo_capabilities-sortable input[type='text']" ) assert len(elems) == 4 elems[3].send_keys( "foo!" ) click_dialog_button( "OK" ) # change the scenario date, check the capabilities select_tab( "scenario" ) check_capabilities( "01/01/1940", [ [ [ "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "H6[9]\u2020" ] ], [ [ "sM8\u2020", "CS 7" ] ], [ [ "NT" ] ] ] ) check_capabilities( "01/01/1941", [ [ [ "A4", "sD6", "CS 4" ] , [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "A4", "H6[9]\u2020" ] ], [ [ "sM8\u2020", "CS 7" ] ], [ [ "NT" ] ] ] ) check_capabilities( "01/01/1942", [ [ [ "A5", "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "A5", "H6[9]\u2020" ] ], [ [ "sM8\u2020", "CS 7" ] ], [ [ "NT", "A4" ] ] ] ) check_capabilities( "01/01/1943", [ [ [ "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "A4", "H6[9]\u2020" ] ], [ [ "sM8\u2020", "CS 7" ] ], [ [ "NT", "A5" ] ] ] ) check_capabilities( "01/01/1944", [ [ [ "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "A3", "H6[9]\u2020" ] ], [ [ "HE8\u2020", "sD6", "sM8\u2020", "CS 7" ] ], [ [ "NT", "A6" ] ] ] ) check_capabilities( "01/01/1945", [ [ [ "sD6", "CS 4" ], [ "A5<sup>1</sup>6<sup>2</sup>5<sup>3</sup>", "HE7", "CS 3", "foo!" ] ], [ [ "NT", "H6[9]\u2020" ] ], [ [ "D7\u2020", "HE8\u2020", "sD6", "sM8\u2020", "CS 7" ] ], [ [ "NT", "A7" ] ] ] )
def test_custom_comments( webapp, webdriver ): #pylint: disable=too-many-statements """Test custom comments.""" # NOTE: Vehicle/ordnance comments are not capabilities, but they are managed in the same place # and the code is virtually identical, so it makes sense to put the test code here. # initialize init_webapp( webapp, webdriver, scenario_persistence=1 ) # add a vehicle add_vo( webdriver, "vehicles", 1, "a commented german vehicle" ) snippet_btn = find_child( "button[data-id='ob_vehicles_1']" ) def extract_comments( clipboard ): """Extract the comments.""" mo = re.search( r"^- comments: (.*)$", clipboard, re.MULTILINE ) return mo.group(1) if mo else "" def check_snippet( expected ): """Check the vehicle's snippet.""" snippet_btn.click() wait_for_clipboard( 2, expected, transform=extract_comments ) def check_comments_in_dialog( expected ): """Check the vehicle's comments.""" elems = find_children( "#vo_comments-sortable li" ) elems2 = [ find_child("input[type='text']",c) for c in elems ] assert [ e.get_attribute("value") for e in elems2 ] == expected return elems # check the vehicle's snippet check_snippet( '"a comment" "another comment"' ) # edit the vehicle's comments vehicles_sortable = find_child( "#ob_vehicles-sortable_1" ) elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains( webdriver ).double_click( elems[0] ).perform() elems = check_comments_in_dialog( [ "a comment", "another comment" ] ) # edit one of the comments elem = find_child( "input[type='text']", elems[0] ) elem.clear() elem.send_keys( "a comment (modified)" ) # delete a comment ActionChains( webdriver ).key_down( Keys.CONTROL ).click( elems[1] ).perform() ActionChains( webdriver ).key_up( Keys.CONTROL ).perform() # add a new comment elem = find_child( "#vo_comments-add" ) elem.click() elems = find_children( "#vo_comments-sortable input[type='text']" ) assert len(elems) == 2 elems[1].send_keys( "a <i>new</i> comment" ) # save the changes and check the vehicle's snippet click_dialog_button( "OK" ) check_snippet( '"a comment (modified)" "a <i>new</i> comment"' ) # save the scenario saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert saved_scenario["OB_VEHICLES_1"][0]["custom_comments"] == [ "a comment (modified)", "a <i>new</i> comment" ] # reload the scenario, and check the vehicle's snippet select_menu_option( "new_scenario" ) load_scenario( saved_scenario ) select_tab( "ob1" ) check_snippet( '"a comment (modified)" "a <i>new</i> comment"' ) # make sure the comments are loaded correcly when editing the vehicle elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains( webdriver ).double_click( elems[0] ).perform() elems = check_comments_in_dialog( [ "a comment (modified)", "a <i>new</i> comment" ] ) # delete all comments for elem in elems: ActionChains( webdriver ).key_down( Keys.CONTROL ).click( elem ).perform() ActionChains( webdriver ).key_up( Keys.CONTROL ).perform() click_dialog_button( "OK" ) check_snippet( "" ) # save the scenario saved_scenario2 = save_scenario() assert len(saved_scenario2["OB_VEHICLES_1"]) == 1 assert saved_scenario2["OB_VEHICLES_1"][0]["custom_comments"] == [] # reload the scenario, and reset the vehicle's comments back to the default load_scenario( saved_scenario ) select_tab( "ob1" ) elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains( webdriver ).double_click( elems[0] ).perform() btn = find_child( "#vo_comments-reset" ) btn.click() click_dialog_button( "OK" ) check_snippet( '"a comment" "another comment"' ) # make sure the custom comments are no longer saved in the scenario saved_scenario2 = save_scenario() assert len(saved_scenario2["OB_VEHICLES_1"]) == 1 assert "custom_comments" not in saved_scenario2["OB_VEHICLES_1"][0] # reload the scenario, and manually set the vehicle's comments to be the same as the default load_scenario( saved_scenario ) select_tab( "ob1" ) elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains( webdriver ).double_click( elems[0] ).perform() elems = find_children( "#vo_comments-sortable input[type='text']" ) assert len(elems) == 2 elems[0].clear() elems[0].send_keys( "a comment" ) elems[1].clear() elems[1].send_keys( "another comment" ) click_dialog_button( "OK" ) # make sure the custom comments are no longer saved in the scenario saved_scenario = save_scenario() assert len(saved_scenario["OB_VEHICLES_1"]) == 1 assert "custom_comments" not in saved_scenario["OB_VEHICLES_1"][0]
def snippet_images_thread(webapp_url): """Test generating snippet images.""" with WebDriver() as webdriver: # initialize webdriver = webdriver.driver init_webapp(webdriver, webapp_url, ["snippet_image_persistence", "scenario_persistence"]) # load a scenario (so that we get some sortable's) scenario_data = { "SCENARIO_NOTES": [{ "caption": "Scenario note #1" }], "OB_SETUPS_1": [{ "caption": "OB setup note #1" }], "OB_NOTES_1": [{ "caption": "OB note #1" }], "OB_SETUPS_2": [{ "caption": "OB setup note #2" }], "OB_NOTES_2": [{ "caption": "OB note #2" }], } load_scenario(scenario_data, webdriver) # locate all the "generate snippet" buttons snippet_btns = find_snippet_buttons(webdriver) tab_ids = list(snippet_btns.keys()) while not shutdown_event.is_set(): try: # clear the return buffer ret_buffer = find_child("#_snippet-image-persistence_", webdriver) assert ret_buffer.tag_name == "textarea" webdriver.execute_script("arguments[0].value = arguments[1]", ret_buffer, "") # generate a snippet tab_id = random.choice(tab_ids) btn = random.choice(snippet_btns[tab_id]) log("Getting snippet image: {}", btn.get_attribute("data-id")) select_tab(tab_id, webdriver) start_time = time.time() ActionChains( webdriver ) \ .key_down( Keys.SHIFT ) \ .click( btn ) \ .key_up( Keys.SHIFT ) \ .perform() # wait for the snippet image to be generated wait_for(10 * thread_count, lambda: ret_buffer.get_attribute("value")) _, img_data = ret_buffer.get_attribute("value").split("|", 1) elapsed_time = time.time() - start_time # update the stats with stats_lock: stats["snippet image"][0] += 1 stats["snippet image"][1] += elapsed_time # FUDGE! Generating the snippet image for a sortable entry is sometimes interpreted as # a request to edit the entry (Selenium problem?) - we dismiss the dialog here and continue. dlg = find_child(".ui-dialog", webdriver) if dlg and dlg.is_displayed(): click_dialog_button("Cancel", webdriver) except (ConnectionRefusedError, ConnectionResetError, http.client.RemoteDisconnected): if shutdown_event.is_set(): break raise # check the generated snippet img_data = base64.b64decode(img_data) log("Received snippet image: #bytes={}", len(img_data)) assert img_data[:6] == b"\x89PNG\r\n"
def _click_import_button(dlg): """Click the "import scenario" button, and confirm the action (if necessary).""" find_child("button.import", dlg).click() if find_child("#ask").is_displayed(): click_dialog_button("OK")
def test_common_vo( webapp, webdriver ): #pylint: disable=too-many-locals """Test loading of common vehicles/ordnance and landing craft.""" # initialize webapp.control_tests.set_data_dir( "{REAL}" ) init_webapp( webapp, webdriver ) # initialize ALLIED_MINOR = [ "belgian", "danish", "dutch", "greek", "polish", "yugoslavian" ] AXIS_MINOR = [ "bulgarian", "croatian", "hungarian", "romanian", "slovakian" ] # get the common vehicles/ordnance def get_common_vo( fname ): """Get the vehicle/ordnance information from the specified file.""" fname = os.path.join( DATA_DIR, fname ) with open( fname, "r", encoding="utf-8" ) as fp: data = json.load( fp ) def get_gpid( val ): #pylint: disable=missing-docstring if isinstance( val, list ): val = val[0] assert isinstance(val,int) or val is None return val return [ ( vo["name"], get_gpid(vo["gpid"]) ) for vo in data ] common_vo = { "vehicles": { "allied": get_common_vo( "vehicles/allied-minor/common.json" ), "axis": get_common_vo( "vehicles/axis-minor/common.json" ), }, "ordnance": { "allied": get_common_vo( "ordnance/allied-minor/common.json" ), "axis": get_common_vo( "ordnance/axis-minor/common.json" ), }, } landing_craft = get_common_vo( "vehicles/landing-craft.json" ) tidy_vo_name_regex = re.compile( r" \([A-Za-z]+\)$" ) # nb: removes the trailing vehicle/ordnance type gpid_regex = re.compile( r"/counter/(\d+)/front" ) def get_vo_entry( elem ): """Get the vehicle/ordnance information from the Selenium element.""" vo_name = tidy_vo_name_regex.sub( "", elem.text ) image_url = find_child( "img", elem ).get_attribute( "src" ) mo = gpid_regex.search( image_url ) return ( vo_name, int(mo.group(1)) if mo else None ) def is_valid_vo_entry( vo_entry ): """Check if a V/O entry is valid.""" return isinstance( vo_entry, tuple ) and len(vo_entry) == 2 \ and isinstance( vo_entry[0], str ) \ and isinstance( vo_entry[1], (int,type(None)) ) def is_same_vo( lhs, rhs ): """Check if two V/O entries are the same.""" assert is_valid_vo_entry(lhs) and is_valid_vo_entry(rhs) return lhs == rhs def is_vo_entry_in_list( vo_entry, vo_entries ): """Check if a V/O entry appears in a list of V/O entries.""" assert is_valid_vo_entry( vo_entry ) return any( is_same_vo(vo_entry,e) for e in vo_entries ) # check the vehicles/ordnance for each nationality nationalities = get_nationalities( webapp ) for nat in nationalities: #pylint: disable=too-many-nested-blocks # select the next nationality set_player( 1, nat ) select_tab( "ob1" ) for vo_type in ("vehicles","ordnance"): # check if the nationality has any vehicles/ordnance elem = find_child( "#ob_{}-add_1".format( vo_type ) ) if nat in ["thai","indonesian","anzac","burmese","filipino"]: # nb: these are in the BFP extension assert not elem.is_enabled() continue if nat == "kfw-cpva" and vo_type == "vehicles": assert not elem.is_enabled() continue elem.click() # get the vehicles/ordnance vo_entries = find_children( "#select-vo .select2-results li" ) vo_entries = [ get_vo_entry(e) for e in vo_entries ] click_dialog_button( "Cancel" ) # check that the common vehicles/ordnance are present/absent if nat in ALLIED_MINOR: assert all( is_vo_entry_in_list( vo_entry, vo_entries ) for vo_entry in common_vo[vo_type]["allied"] ) elif nat in AXIS_MINOR: assert all( is_vo_entry_in_list( vo_entry, vo_entries ) for vo_entry in common_vo[vo_type]["axis"] ) else: assert all( not is_vo_entry_in_list( vo_entry, vo_entries ) for vo_entry in common_vo[vo_type]["allied"] ) assert all( not is_vo_entry_in_list( vo_entry, vo_entries ) for vo_entry in common_vo[vo_type]["axis"] ) # check that the landing craft are present/absent if vo_type == "vehicles": if nat in ("british","american"): for vo_entry in landing_craft: if vo_entry[0] in ("Daihatsu","Shohatsu"): assert not is_vo_entry_in_list( vo_entry, vo_entries ) else: assert is_vo_entry_in_list( vo_entry, vo_entries ) elif nat == "japanese": for vo_entry in landing_craft: if vo_entry[0] in ("Daihatsu","Shohatsu"): assert is_vo_entry_in_list( vo_entry, vo_entries ) else: assert not is_vo_entry_in_list( vo_entry, vo_entries ) else: assert all( not is_vo_entry_in_list( vo_entry, vo_entries ) for vo_entry in landing_craft )
def test_change_vo_image( webapp, webdriver ): """Test changing a V/O image.""" # initialize webapp.control_tests \ .set_data_dir( "{REAL}" ) \ .set_vasl_version( "random", None ) init_webapp( webapp, webdriver, scenario_persistence=1 ) # add an ISU-152 set_player( 2, "russian" ) add_vo( webdriver, "vehicles", 2, "ISU-152" ) # save the scenario saved_scenario = save_scenario() assert saved_scenario["OB_VEHICLES_2"] == [ { "id": "ru/v:049", "name": "ISU-152", "seq_id": 1 } ] # change the vehicle's image vehicles_sortable = find_child( "#ob_vehicles-sortable_2" ) elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains(webdriver).double_click( elems[0] ).perform() img = find_child( "#edit-vo img.vasl-image" ) assert img.get_attribute( "src" ).endswith( "/counter/657/front" ) btn = find_child( "#edit-vo input.select-vo-image" ) btn.click() images = find_children( ".ui-dialog.select-vo-image .vo-images img" ) assert len(images) == 2 images[1].click() assert img.get_attribute( "src" ).endswith( "/counter/659/front/0" ) click_dialog_button( "OK" ) elems = find_children( "img.vasl-image", vehicles_sortable ) assert len(elems) == 1 assert elems[0].get_attribute( "src" ).endswith( "/counter/659/front/0" ) # save the scenario saved_scenario = save_scenario() assert saved_scenario["OB_VEHICLES_2"] == [ { "id": "ru/v:049", "image_id": "659/0", "name": "ISU-152", "seq_id": 1 } ] # reload the scenario, and check the vehicle's image select_menu_option( "new_scenario" ) load_scenario( saved_scenario ) select_tab( "ob2" ) elems = find_children( "img.vasl-image", vehicles_sortable ) assert len(elems) == 1 assert elems[0].get_attribute( "src" ).endswith( "/counter/659/front/0" ) # change the vehicle's image back to the default elems = find_children( "li", vehicles_sortable ) assert len(elems) == 1 ActionChains(webdriver).double_click( elems[0] ).perform() img = find_child( "#edit-vo img.vasl-image" ) assert img.get_attribute( "src" ).endswith( "/counter/659/front/0" ) btn = find_child( "#edit-vo input.select-vo-image" ) btn.click() images = find_children( ".ui-dialog.select-vo-image .vo-images img" ) assert len(images) == 2 images[0].click() assert img.get_attribute( "src" ).endswith( "/counter/657/front/0" ) click_dialog_button( "OK" ) elems = find_children( "img.vasl-image", vehicles_sortable ) assert len(elems) == 1 assert elems[0].get_attribute( "src" ).endswith( "/counter/657/front/0" ) # save the scenario saved_scenario = save_scenario() assert saved_scenario["OB_VEHICLES_2"] == [ { "id": "ru/v:049", "image_id": "657/0", "name": "ISU-152", "seq_id": 1 } ]
def test_player_change( webapp, webdriver ): """Test changing players.""" # initialize init_webapp( webapp, webdriver ) select_tab( "scenario" ) ob_tabs = { 1: find_child( "#tabs .ui-tabs-nav a[href='#tabs-ob1']" ), 2: find_child( "#tabs .ui-tabs-nav a[href='#tabs-ob2']" ) } # make sure that the UI was updated correctly for the initial players for player_no in [1,2]: player_nat = get_player_nat( player_no ) expected = "{} OB".format( get_nationality_display_name( player_nat ) ) assert ob_tabs[ player_no ].text.strip() == expected # check that we can change the player nationalities without being asked to confirm # nb: the frontend ignores the vehicle/ordnance snippet widths when deciding if to ask for confirmation VO_WIDTHS = { "ob1": { "OB_VEHICLES_WIDTH_1": 123 }, "ob2": { "OB_ORDNANCE_WIDTH_2": 456 }, } load_scenario_params( VO_WIDTHS ) set_player( 1, "russian" ) assert ob_tabs[1].text.strip() == "{} OB".format( get_nationality_display_name("russian") ) set_player( 2, "german" ) assert ob_tabs[2].text.strip() == "{} OB".format( get_nationality_display_name("german") ) # load the OB tabs SCENARIO_PARAMS = { "ob1": { "OB_SETUPS_1": [ { "caption": "an ob setup", "width": "" } ], }, "ob2": { "OB_VEHICLES_2": [ "a german vehicle" ], }, } load_scenario_params( SCENARIO_PARAMS ) def get_sortable_counts( player_no ): """Get the contents of the player's OB tab.""" sortables = [ find_child( "#{}-sortable_{}".format( key, player_no ) ) for key in ["ob_setups","ob_notes","ob_vehicles","ob_ordnance"] ] return [ get_sortable_entry_count(s) for s in sortables ] for player_no in [1,2]: # try to change the player's nationality set_player( player_no, "finnish" ) wait_for( 2, lambda: find_child("#ask") ) # cancel the confirmation request and make sure nothing changed click_dialog_button( "Cancel" ) nat_id = "russian" if player_no == 1 else "german" assert ob_tabs[player_no].text.strip() == "{} OB".format( get_nationality_display_name(nat_id) ) assert get_sortable_counts( player_no ) == \ [1,0,0,0] if player_no == 1 else [0,0,1,0] # try to change the player's nationality set_player( player_no, "finnish" ) wait_for( 2, lambda: find_child("#ask") ) # confirm the request and make sure the OB tab was cleared click_dialog_button( "OK" ) assert ob_tabs[player_no].text.strip() == "{} OB".format( get_nationality_display_name("finnish") ) assert get_sortable_counts( player_no ) == [0,0,0,0]
def test_date_format(webapp, webdriver): """Test changing the date format.""" # initialize init_webapp(webapp, webdriver, template_pack_persistence=1, scenario_persistence=1) # customize the SCENARIO template upload_template_pack_file( "scenario.j2", "{{SCENARIO_YEAR}}-{{SCENARIO_MONTH}}-{{SCENARIO_DAY_OF_MONTH}}", False) scenario_date = find_child("input[name='SCENARIO_DATE']") snippet_btn = find_child("button.generate[data-id='scenario']") def set_scenario_date(date_string): """Set the scenario date.""" scenario_date.clear() scenario_date.send_keys(date_string) scenario_date.send_keys(Keys.TAB) assert scenario_date.get_attribute("value") == date_string def check_scenario_date(expected): """Check the scenario date is being interpreted correctly.""" assert isinstance(expected, tuple) and len(expected) == 3 assert 1 <= expected[0] <= 31 and 1 <= expected[ 1] <= 12 and 1940 <= expected[2] <= 1945 # check the snippet snippet_btn.click() wait_for_clipboard( 2, "{}-{}-{}".format(expected[2], expected[0], expected[1])) # check the save file (should always be ISO-8601 format) saved_scenario = save_scenario() assert saved_scenario["SCENARIO_DATE"] == "{:04}-{:02}-{:02}".format( expected[2], expected[0], expected[1]) # check the default format (MM/DD/YYYY) set_scenario_date("01/02/1940") check_scenario_date((1, 2, 1940)) saved_scenario = save_scenario() # change the date format to YYYY-MM-DD select_menu_option("user_settings") date_format_sel = Select( find_child(".ui-dialog.user-settings select[name='date-format']")) select_droplist_val(date_format_sel, "yy-mm-dd") click_dialog_button("OK") _check_cookies(webdriver, "date-format", "yy-mm-dd") # make sure that it took effect assert scenario_date.get_attribute("value") == "1940-01-02" check_scenario_date((1, 2, 1940)) # clear the scenario date, set the date format to DD-MM-YYY set_scenario_date("") select_menu_option("user_settings") select_droplist_val(date_format_sel, "dd/mm/yy") click_dialog_button("OK") _check_cookies(webdriver, "date-format", "dd/mm/yy") # set the scenario date set_scenario_date( "03/04/1945") # nb: this will be interpreted as DD/MM/YYYY check_scenario_date((4, 3, 1945)) # load the scenario we saved before and check the date load_scenario(saved_scenario) check_scenario_date((1, 2, 1940)) assert scenario_date.get_attribute("value") == "02/01/1940"