Allow multiple OB setup's

master
Pacman Ghost 6 years ago
parent f7dda94b90
commit 13ae3074cc
  1. 24
      vasl_templates/webapp/static/css/main.css
  2. 34
      vasl_templates/webapp/static/css/tabs-ob.css
  3. 27
      vasl_templates/webapp/static/main.js
  4. 87
      vasl_templates/webapp/static/ob_setup.js
  5. 48
      vasl_templates/webapp/static/snippets.js
  6. 110
      vasl_templates/webapp/static/sortable.js
  7. 17
      vasl_templates/webapp/static/utils.js
  8. 49
      vasl_templates/webapp/templates/index.html
  9. 113
      vasl_templates/webapp/tests/test_ob_setup.py
  10. 3
      vasl_templates/webapp/tests/test_players.py
  11. 16
      vasl_templates/webapp/tests/test_scenario_persistence.py
  12. 32
      vasl_templates/webapp/tests/test_snippets.py
  13. 3
      vasl_templates/webapp/tests/test_ssr.py
  14. 31
      vasl_templates/webapp/tests/test_template_packs.py
  15. 11
      vasl_templates/webapp/tests/utils.py

@ -43,21 +43,25 @@ body { height: 100% ; }
#tabs-ob1, #tabs-ob2 {
display: grid ; display: -ms-grid ;
grid-template-rows: 10em 1fr ; -ms-grid-rows: 10em 1fr ;
grid-template-rows: 1fr 1fr ; -ms-grid-rows: 1fr 1fr ;
grid-template-columns: 1fr 1fr ; -ms-grid-columns: 1fr 1fr ;
}
#tabs-ob1 fieldset.tl, #tab-ob2 fieldset.tl {
#tabs-ob1 fieldset.tl, #tabs-ob2 fieldset.tl {
grid-row-start: 1 ; -ms-grid-row: 1 ;
grid-column-start: 1 ; -ms-grid-row: 1 ;
grid-column-start: 1 ; -ms-grid-column: 1 ;
}
#tabs-ob1 fieldset.r, #tabs-ob2 fieldset.r {
#tabs-ob1 fieldset.bl, #tabs-ob2 fieldset.bl {
grid-row-start: 2 ; -ms-grid-row: 2 ;
grid-column-start: 1 ; -ms-grid-column: 1 ;
}
#tabs-ob1 fieldset.tr, #tabs-ob2 fieldset.tr {
grid-row-start: 1 ; -ms-grid-row: 1 ;
grid-row-end: 3 ; -ms-grid-row-span: 2 ;
grid-column-start: 2 ; -ms-grid-column: 2 ;
}
#tabs-ob1 fieldset.bl, #tabs-ob2 fieldset.bl {
-ms-grid-row: 2 ; -ms-grid-column: 1 ;
#tabs-ob1 fieldset.br, #tabs-ob2 fieldset.br {
grid-row-start: 2 ; -ms-grid-row: 2 ;
grid-column-start: 2 ; -ms-grid-column: 2 ;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
@ -107,6 +111,12 @@ input[type="text"] { margin-bottom: 0.25em ; }
.ui-dialog.edit-ssr textarea { resize: none ; width: calc(100% - 4px) ; height: calc(100% - 1.25em) ; }
.ui-dialog.edit-ssr button { margin: 0 0 0 5px ; padding: 0.1em 0.2em ; }
.ui-dialog.edit-ob_setup .ui-dialog-titlebar { display: none ; }
.ui-dialog.edit-ob_setup .ui-dialog-buttonpane { border: none ; padding: 0 ; font-size: 75% ; }
#edit-ob_setup { padding: 2px ; }
.ui-dialog.edit-ob_setup textarea { resize: none ; width: calc(100% - 4px) ; height: calc(100% - 3em) ; }
.ui-dialog.edit-ob_setup button { margin: 0 0 0 5px ; padding: 0.1em 0.2em ; }
#select-vo { overflow: hidden ; }
#select-vo .header { height: 2em ; }
#select-vo select { width: 100% ; top: 2em ; height: calc(100% - 2em) ; }

@ -1,19 +1,37 @@
/* -------------------------------------------------------------------- */
.panel-obsetup {
.panel-ob_setup {
height: 100% ;
display: grid ; display: -ms-grid ;
grid-template-rows: 1fr 2.5em ; -ms-grid-rows: 1fr 2.5em ;
grid-template-rows: 1fr 2em ; -ms-grid-rows: 1fr 2em ;
grid-template-columns: 1fr ; -ms-grid-columns: 1fr ;
}
/* FUDGE! IE hackamathon follows... */
.panel-ob_setup .content { -ms-grid-row: 1 ; -ms-grid-column: 1 ; }
.panel-ob_setup .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-ob_setup ul.sortable li input[type="button"] { float: right ; }
.panel-ob_setup .footer { text-align: right ; font-size: 75% ; }
.panel-ob_setup .footer .l { float: left ; }
.ob_setup-trash { margin-left: 5px ; height: 2em ; }
.ob_setup-hint { width:100% ; height: calc(100% - 1.5em) ; font-size: 80% ; font-style: italic ; }
.ob_setup-hint p { margin-bottom: 1em ; }
/* -------------------------------------------------------------------- */
.panel-ob_notes {
height: 100% ;
display: grid ; display: -ms-grid ;
grid-template-rows: 1fr 2em ; -ms-grid-rows: 1fr 2em ;
grid-template-columns: 1fr ; -ms-grid-columns: 1fr ;
}
/* FUDGE! IE hackamathon follows... */
.panel-obsetup .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-ob_notes .content { -ms-grid-row: 1 ; -ms-grid-column: 1 ; }
.panel-ob_notes .footer { -ms-grid-row: 2 ; -ms-grid-column: 1 ; }
.panel-obsetup textarea { width: 100% ; height: 100% ; resize: none ; }
.panel-obsetup .footer { font-size: 75% ; }
.panel-obsetup div.snippet-control { float: left ; margin: 0.25em 0.25em 0 0 ; }
.panel-obsetup .footer .r { display: block-inline ; float: right ; }
.panel-obsetup .footer .r div.snippet-control { float: none ; margin-right: 0 ; }
.panel-ob_notes .footer { font-size: 75% ; }
.panel-ob_notes div.snippet-control { float: left ; margin: 0.25em 0.25em 0 0 ; }
/* -------------------------------------------------------------------- */

@ -86,12 +86,24 @@ $(document).ready( function () {
$("#ssr-trash").sortable( {
receive: function( evt, ui ) { ui.item.remove() ; update_ssr_hint() ; }
} ) ;
$("#edit-ssr textarea").keydown( function(evt) {
if ( evt.keyCode == 13 && evt.ctrlKey ) {
$(".ui-dialog.edit-ssr button:contains('OK')").click() ;
evt.preventDefault() ;
}
enable_ctrl_enter( $("#edit-ssr"), "OK" ) ;
// initialize OB setup controls
init_sortable( $("#ob_setup-sortable_1"),
function() { add_ob_setup(1) ; },
edit_ob_setup
) ;
$("#panel-ob_setup1 input[type='button'][data-id='ob_setup']").click( function() {
edit_template( "ob_setup" ) ;
} ) ;
init_sortable( $("#ob_setup-sortable_2"),
function() { add_ob_setup(2) ; },
edit_ob_setup
) ;
$("#panel-ob_setup2 input[type='button'][data-id='ob_setup']").click( function() {
edit_template( "ob_setup" ) ;
} ) ;
enable_ctrl_enter( $("#edit-ob_setup"), "OK" ) ;
// initialize vehicle controls (1)
$("#vehicle-sortable_1").sortable( { connectWith: "#vehicle-trash_1", cursor: "move" } ) ;
@ -241,11 +253,12 @@ $(document).ready( function () {
// handle requests to generate/edit HTML snippets
$("input[type='button'].generate").click( function() {
generate_snippet( $(this) ) ;
generate_snippet( $(this), null ) ;
} ) ;
$("div.snippet-control select").on( "selectmenuselect", function() {
edit_template( $(this).attr("data-id") ) ;
} ) ;
enable_ctrl_enter( $("#edit-template"), "Close" ) ;
// initialize hotkeys
init_hotkeys() ;
@ -347,7 +360,7 @@ function on_player_change( $select )
for ( var nat in _NATIONALITY_SPECIFIC_BUTTONS ) {
for ( var i=0 ; i < _NATIONALITY_SPECIFIC_BUTTONS[nat].length ; ++i ) {
var button_id = _NATIONALITY_SPECIFIC_BUTTONS[nat][i] ;
$elem = $( "#panel-obsetup" + player_id + " div.snippet-control[data-id='" + button_id + "']" ) ;
$elem = $( "#panel-ob_notes" + player_id + " div.snippet-control[data-id='" + button_id + "']" ) ;
$elem.css( "display", nat == player_nat ? "block" : "none" ) ;
}
}

@ -0,0 +1,87 @@
// --------------------------------------------------------------------
function add_ob_setup( player_id )
{
// add a new OB setup
edit_ob_setup( $("#ob_setup-sortable_"+player_id), null ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function edit_ob_setup( $sortable, $entry )
{
var $caption, $width ;
// let the user edit the OB setup
$("#edit-ob_setup").dialog( {
dialogClass: "edit-ob_setup",
modal: true,
minWidth: 400,
minHeight: 150,
open: function() {
$caption = $(this).children( "textarea" ) ;
$width = $(this).children( "input[type='text']" ) ;
if ( $entry ) {
var data = $entry.data( "sortable-data" ) ;
$caption.val( data.caption ) ;
$width.val( data.width ) ;
}
else {
$caption.val( "" ) ;
$width.val( "" ) ;
}
$(this).height( $(this).height() ) ; // fudge: force the textarea to resize
},
buttons: {
OK: function() {
var caption = $caption.val().trim() ;
var width = $width.val().trim() ;
if ( $entry ) {
// update the existing OB setup
if ( caption === "" )
delete_sortable_entry( $entry ) ;
else {
$entry.data("sortable-data").caption = caption ;
$entry.data("sortable-data").width = width ;
$entry.empty().append( _make_sortable_entry( caption ) ) ;
}
}
else {
// create a new OB setup
if ( caption !== "" ) {
data = { caption: caption, width: width } ;
do_add_ob_setup( $sortable, data ) ;
}
}
$(this).dialog( "close" ) ;
},
Cancel: function() { $(this).dialog( "close" ) ; },
},
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function do_add_ob_setup( $sortable, data )
{
// add a new sortable entry
add_sortable( $sortable, _make_sortable_entry(data.caption), data ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function _make_sortable_entry( caption )
{
// generate the sortable entry
var $content = $( "<div><input type='button' data-id='ob_setup' value='Snippet'>" + caption + "</div>" ) ;
// add a handler for the snippet button
$content.children("input[type='button']").click( function() {
var data = $(this).parent().parent().data( "sortable-data" ) ;
var extra_params = { OB_SETUP: data.caption, OB_SETUP_WIDTH: data.width } ;
generate_snippet( $(this), extra_params ) ;
} ) ;
return $content ;
}

@ -16,7 +16,7 @@ var _DAY_OF_MONTH_POSTFIXES = { // nb: we assume English :-/
// --------------------------------------------------------------------
function generate_snippet( $btn )
function generate_snippet( $btn, extra_params )
{
// initialize
storeMsgForTestSuite( "_last-info_", "" ) ;
@ -44,18 +44,6 @@ function generate_snippet( $btn )
unload_params( params, true ) ;
// set player-specific parameters
// NOTE: We used to delete the player-specific parameters (e.g. OB_SETUP_1/2)
// and just return a generic player-independent one (e.g. OB_SETUP), but now,
// we just leave them in place, in case a user-defined template wants them both.
if ( template_id === "ob_setup_1" ) {
template_id = "ob_setup" ;
params.OB_SETUP = params.OB_SETUP_1 ;
params.OB_SETUP_WIDTH = params.OB_SETUP_WIDTH_1 ;
} else if ( template_id === "ob_setup_2" ) {
template_id = "ob_setup" ;
params.OB_SETUP = params.OB_SETUP_2 ;
params.OB_SETUP_WIDTH = params.OB_SETUP_WIDTH_2 ;
}
var nationalities = gTemplatePack.nationalities ;
var curr_tab = $("#tabs .ui-tabs-active a").attr( "href" ) ;
if ( curr_tab === "#tabs-ob1" ) {
@ -154,6 +142,10 @@ function generate_snippet( $btn )
showWarningMsg( "ATMM are only available from 1944." ) ;
}
// add in any extra parameters
if ( extra_params )
$.extend( true, params, extra_params ) ;
// check that the players have different nationalities
if ( params.PLAYER_1 === params.PLAYER_2 )
showWarningMsg( "Both players have the same nationality!" ) ;
@ -511,8 +503,16 @@ function do_load_scenario( params )
params_loaded[key] = true ;
continue ;
}
var player_id ;
if ( key === "OB_SETUP_1" || key === "OB_SETUP_2" ) {
player_id = key.substring( key.length-1 ) ;
var $sortable = $( "#ob_setup-sortable_" + player_id ) ;
for ( i=0 ; i < params[key].length ; ++i )
do_add_ob_setup( $sortable, params[key][i] ) ;
params_loaded[key] = true ;
}
if ( key === "VEHICLES_1" || key === "ORDNANCE_1" || key === "VEHICLES_2" || key === "ORDNANCE_2" ) {
var player_id = key.substring( key.length-1 ) ;
player_id = key.substring( key.length-1 ) ;
var nat = params[ "PLAYER_" + player_id ] ;
var vo_type = key.substring(0,9) === "VEHICLES_" ? "vehicle" : "ordnance" ;
for ( i=0 ; i < params[key].length ; ++i ) {
@ -562,6 +562,13 @@ function do_load_scenario( params )
function on_save_scenario()
{
// unload the template parameters
function unload_ob_setups( $sortable ) {
var entries = [] ;
$sortable.children("li").each( function() {
entries.push( $(this).data( "sortable-data" ) ) ;
} ) ;
return entries ;
}
function extract_vo_names( key ) { // nb: we only need to save the vehicle/ordnance name
if ( !(key in params) )
return ;
@ -570,8 +577,10 @@ function on_save_scenario()
names.push( params[key][i].name ) ;
params[key] = names ;
}
var params = {};
var params = {} ;
unload_params( params, false ) ;
params.OB_SETUP_1 = unload_ob_setups( $("#ob_setup-sortable_1") ) ;
params.OB_SETUP_2 = unload_ob_setups( $("#ob_setup-sortable_2") ) ;
extract_vo_names( "VEHICLES_1" ) ;
extract_vo_names( "ORDNANCE_1" ) ;
extract_vo_names( "VEHICLES_2" ) ;
@ -619,10 +628,11 @@ function on_new_scenario( verbose )
update_ssr_hint() ;
// reset all the template parameters
delete_all_vo( "vehicle", 1 ) ;
delete_all_vo( "ordnance", 1 ) ;
delete_all_vo( "vehicle", 2 ) ;
delete_all_vo( "ordnance", 2 ) ;
for ( var i=1 ; i <= 2 ; ++i ) {
delete_all_sortable_entries( $("#ob_setup-sortable_"+i) ) ;
delete_all_vo( "vehicle", i ) ;
delete_all_vo( "ordnance", i ) ;
}
// provide some feedback to the user
if ( verbose )

@ -0,0 +1,110 @@
// --------------------------------------------------------------------
function init_sortable( $sortable, on_add, on_edit )
{
// initialize the support elements
var $add = _find_sortable_helper( $sortable, "add" ) ;
$add.click( on_add ) ;
$sortable.data( "on_edit", on_edit ) ;
// handle dragging entries to the trash
var $trash = _find_sortable_helper( $sortable, "trash" ) ;
$sortable.sortable( { connectWith: $trash, cursor: "move" } ) ;
$trash.sortable( {
receive: function( evt, ui ) {
ui.item.remove() ;
update_sortable_hint($sortable) ;
}
} ) ;
}
// --------------------------------------------------------------------
function add_sortable( $sortable, $content, sortable_data )
{
// add a new entry to the sortable
var $entry = $( "<li></li>" ) ;
$entry.append( $content ) ;
$entry.data( "sortable-data", sortable_data ) ;
$sortable.append( $entry ) ;
init_sortable_entry( $entry ) ;
// update the hint
update_sortable_hint( $sortable ) ;
return $entry ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function init_sortable_entry( $entry )
{
// initialize the sortable entry
var $sortable = $entry.parent() ;
$entry.dblclick( function() {
$sortable.data("on_edit")( $sortable, $entry ) ;
} ) ;
$entry.click( function( evt ) {
if ( evt.ctrlKey )
delete_sortable_entry( $(this) ) ;
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function update_sortable_hint( $sortable )
{
// show/hide the hint
var $hint = _find_sortable_helper( $sortable, "hint" ) ;
if ( $sortable.children("li").length === 0 ) {
$sortable.hide() ;
$hint.show() ;
} else {
$sortable.show() ;
$hint.hide() ;
}
}
// --------------------------------------------------------------------
function delete_sortable_entry( $entry )
{
// initialize
var $sortable = $entry.parent() ;
// ask if it's OK to delete the entry
$entry.addClass( "highlighted" ) ;
var caption = $entry.data("sortable-data").caption ;
if ( ! caption )
caption = $entry.html() ;
ask( "OK to delete?", escapeHTML(caption), {
"ok": function() {
// yup - make it so
$entry.remove() ;
update_sortable_hint( $sortable ) ;
},
"close": function() { $entry.removeClass("highlighted") ; },
} ) ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function delete_all_sortable_entries( $sortable )
{
// delete all entries from the sortable
$sortable.children("li").each( function() {
$(this).remove() ;
} ) ;
update_sortable_hint( $sortable ) ;
}
// --------------------------------------------------------------------
function _find_sortable_helper( $sortable, type )
{
// find a support element for the specified sortable
var id = $sortable.prop( "id" ) ;
var pos = id.indexOf( "sortable" ) ;
return $( "#" + id.substring(0,pos) + type+ id.substring(pos+8) ) ;
}

@ -77,6 +77,23 @@ jQuery.fn.filterByText = function( $textbox ) {
// --------------------------------------------------------------------
function enable_ctrl_enter( $dlg, btn_text )
{
// allow Ctrl-Enter to dismiss a dialog
var dismiss_dialog = function( evt ) {
if ( evt.keyCode == 13 && evt.ctrlKey ) {
// locate the OK button (nb: we assume the dialog was created with a class the same as its ID)
var id = $(this).parent().prop( "id" ) ;
$( ".ui-dialog" + "."+id + " button:contains('"+btn_text+"')" ).click() ;
evt.preventDefault() ;
}
} ;
$dlg.find("input[type='text']").keydown( dismiss_dialog ) ;
$dlg.find("textarea").keydown( dismiss_dialog ) ;
}
// --------------------------------------------------------------------
function ask( title, msg, args )
{
// ask a question

@ -88,25 +88,36 @@
<div id="tabs-ob1">
<fieldset class="tl"> <legend>OB setup</legend>
<div id="panel-obsetup1" class="panel-obsetup">
<textarea name="OB_SETUP_1" type="text" class="param"></textarea>
<div id="panel-ob_setup1" class="panel-ob_setup">
<div class="content">
<div id="ob_setup-hint_1" class="ob_setup-hint"> <p>Click on the "+" below to add a new setup note. <p>To re-order the setup notes, use the mouse to drag them around. <p>Ctrl-click on a setup note to delete it, or drag it into the trashcan below. </div>
<ul id="ob_setup-sortable_1" class="sortable" style="display:none;"></ul>
</div>
<div class="footer">
<input type="button" class="generate" data-id="mol" value="MOL">
<input type="button" class="generate" data-id="mol-p" value="MOL-P">
<input type="button" class="generate" data-id="pf" value="PF">
<input type="button" class="generate" data-id="psk" value="PSK">
<input type="button" class="generate" data-id="atmm" value="ATMM">
<input type="button" class="generate" data-id="baz" value="BAZ">
<input type="button" class="generate" data-id="piat" value="PIAT">
<div class="r">
<label for="OB_SETUP_WIDTH_1">Width:</label>
<input type="text" class="param" name="OB_SETUP_WIDTH_1" size="5">
<input type="button" class="generate" data-id="ob_setup_1" value="Snippet">
<div class="l">
<input type="button" id="ob_setup-add_1" value="+">
<img id="ob_setup-trash_1" class="ob_setup-trash" src="{{url_for('static',filename='images/trash.png')}}">
</div>
<input type="button" data-id="ob_setup" value="EDIT TEMPLATE">
</div>
</div>
</fieldset>
<fieldset class="r"> <legend>Vehicles</legend>
<fieldset class="bl"> <legend>Notes</legend>
<div id="panel-ob_notes1" class="panel-ob_notes">
<div class="content">
</div>
<div class="footer">
<input type="button" class="generate" data-id="mol" value="MOL">
<input type="button" class="generate" data-id="mol-p" value="MOL-P">
<input type="button" class="generate" data-id="pf" value="PF">
<input type="button" class="generate" data-id="psk" value="PSK">
<input type="button" class="generate" data-id="atmm" value="ATMM">
<input type="button" class="generate" data-id="baz" value="BAZ">
<input type="button" class="generate" data-id="piat" value="PIAT">
</div>
</div>
</fieldset>
<fieldset class="tr"> <legend>Vehicles</legend>
<div id="panel-vehicles_1" class="panel-vehicles">
<div class="content">
<div id="vehicle-hint_1" class="vehicle-hint"> <p>Click on the "+" below to add a new Vehicle. <p>To re-order the Vehicles, use the mouse to drag them around. <p>Ctrl-click on an Vehicle to delete it, or drag it into the trashcan below. </div>
@ -123,7 +134,7 @@
</div>
</div>
</fieldset>
<fieldset class="bl"> <legend>Ordnance</legend>
<fieldset class="br"> <legend>Ordnance</legend>
<div id="panel-ordnance_1" class="panel-ordnance">
<div class="content">
<div id="ordnance-hint_1" class="ordnance-hint"> <p>Click on the "+" below to add a new Gun. <p>To re-order the Gun's, use the mouse to drag them around. <p>Ctrl-click on an Gun to delete it, or drag it into the trashcan below. </div>
@ -154,8 +165,12 @@
<div id="edit-template" style="display:none;"> <textarea></textarea> </div>
<div id="edit-ssr" style="display:none;"> <b>Enter the SSR content:</b> <textarea></textarea> </div>
<div id="edit-ob_setup" style="display:none;">
<textarea></textarea>
<label>Width:</label> <input type="text" size="5">
</div>
<div id="select-vo" style="display:none;">
<div class="header"> <b>Filter by:</b> <input type="text" size=10> </div>
<div class="header"> <b>Filter by:</b> <input type="text" size="10"> </div>
<select size=2></select> </div>
</div>
<div id="ask" style="display:none;"></div>
@ -180,7 +195,9 @@ gOrdnanceListingsUrl = "{{url_for('get_ordnance_listings')}}" ;
<script src="{{url_for('static',filename='main.js')}}"></script>
<script src="{{url_for('static',filename='snippets.js')}}"></script>
<script src="{{url_for('static',filename='ssr.js')}}"></script>
<script src="{{url_for('static',filename='ob_setup.js')}}"></script>
<script src="{{url_for('static',filename='vehicles_ordnance.js')}}"></script>
<script src="{{url_for('static',filename='sortable.js')}}"></script>
<script src="{{url_for('static',filename='utils.js')}}"></script>
</html>

@ -3,8 +3,10 @@
import types
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.action_chains import ActionChains
from vasl_templates.webapp.tests.utils import select_tab, get_nationalities, get_clipboard, get_stored_msg, find_child
from vasl_templates.webapp.tests.utils import get_nationalities, get_clipboard, get_stored_msg
from vasl_templates.webapp.tests.utils import select_tab, find_child, find_children, click_dialog_button
# ---------------------------------------------------------------------
@ -15,50 +17,43 @@ def test_ob_setup( webapp, webdriver ):
webdriver.get( webapp.url_for( "main" ) )
# generate OB SETUP snippets for both players
def check_snippet( player_id, entry_no, expected ):
"""Generate the snippet for an OB setup."""
select_tab( "ob{}".format( player_id ) )
elems = find_children( "#ob_setup-sortable_{} li input[type='button']".format( player_id ) )
elems[entry_no].click()
assert get_clipboard() == expected
add_ob_setup( webdriver, 1, "ob setup #1" )
add_ob_setup( webdriver, 1, "ob setup #2", "2px" )
add_ob_setup( webdriver, 2, "ob <i>setup</i> #3", "3px" )
check_snippet( 1, 0, "[German] [ob setup #1] (col=[OBCOL:german/OBCOL2:german])" )
check_snippet( 1, 1, "[German] [ob setup #2] (col=[OBCOL:german/OBCOL2:german]) (width=[2px])" )
check_snippet( 2, 0, "[Russian] [ob <i>setup</i> #3] (col=[OBCOL:russian/OBCOL2:russian]) (width=[3px])" )
# make some changes and check the snippets again
edit_ob_setup( webdriver, 2, 0, "updated ob setup #3", "" )
edit_ob_setup( webdriver, 1, 1, "<i>updated ob setup #2</i>", "200px" )
edit_ob_setup( webdriver, 1, 0, None, "100px" )
check_snippet( 2, 0, "[Russian] [updated ob setup #3] (col=[OBCOL:russian/OBCOL2:russian])" )
check_snippet( 1, 1, "[German] [<i>updated ob setup #2</i>] (col=[OBCOL:german/OBCOL2:german]) (width=[200px])" )
check_snippet( 1, 0, "[German] [ob setup #1] (col=[OBCOL:german/OBCOL2:german]) (width=[100px])" )
# delete an OB setup by dragging it into the trash
def count_entries( player_id ):
"""Count the number of OB setup's."""
elems = find_children( "#ob_setup-sortable_{} li".format( player_id ) )
return len(elems)
select_tab( "ob1" )
textarea1 = find_child( "textarea[name='OB_SETUP_1']" )
textarea1.clear()
textarea1.send_keys( "setup <i>here</i>." )
btn1 = find_child( "input[type='button'][data-id='ob_setup_1']" )
select_tab( "ob2" )
textarea2 = find_child( "textarea[name='OB_SETUP_2']" )
textarea2.clear()
textarea2.send_keys( "setup <b>there</b>." )
btn2 = find_child( "input[type='button'][data-id='ob_setup_2']" )
btn2.click()
assert get_clipboard() == "[Russian] [setup <b>there</b>.] (col=[OBCOL:russian/OBCOL2:russian])"
select_tab( "ob1" )
btn1.click()
assert get_clipboard() == "[German] [setup <i>here</i>.] (col=[OBCOL:german/OBCOL2:german])"
# change the player nationalities and generate the OB SETUP snippets again
select_tab( "scenario" )
sel = Select(
find_child( "select[name='PLAYER_1']" )
)
sel.select_by_value( "british" )
sel = Select(
find_child( "select[name='PLAYER_2']" )
)
sel.select_by_value( "french" )
select_tab( "ob1" )
btn1.click()
assert get_clipboard() == "[British] [] (col=[OBCOL:british/OBCOL2:british])"
select_tab( "ob2" )
btn2.click()
assert get_clipboard() == "[French] [] (col=[OBCOL:french/OBCOL2:french])"
assert count_entries(1) == 2
elem = find_child( "#ob_setup-sortable_1 li[2]" )
trash = find_child( "#ob_setup-trash_1" )
ActionChains(webdriver).drag_and_drop( elem, trash ).perform()
assert count_entries(1) == 1
# set the snippet widths and generate the snippets again
select_tab( "ob1" )
elem = find_child( "input[name='OB_SETUP_WIDTH_1']" )
elem.send_keys( "100px" )
btn1.click()
assert get_clipboard() == "[British] [] (col=[OBCOL:british/OBCOL2:british]) (width=[100px])"
select_tab( "ob2" )
elem = find_child( "input[name='OB_SETUP_WIDTH_2']" )
elem.send_keys( "200px" )
btn2.click()
assert get_clipboard() == "[French] [] (col=[OBCOL:french/OBCOL2:french]) (width=[200px])"
# delete an OB setup by emptying its caption
edit_ob_setup( webdriver, 1, 0, "", None )
click_dialog_button( "OK" ) # nb: confirm the deletion
assert count_entries(1) == 0
# ---------------------------------------------------------------------
@ -169,3 +164,35 @@ def test_nationality_specific( webapp, webdriver ):
else:
# it should be hidden for all other nationalities
assert not elem.is_displayed()
# ---------------------------------------------------------------------
def add_ob_setup( webdriver, player_id, caption, width=None ):
"""Add a new OB setup."""
select_tab( "ob{}".format( player_id ) )
elem = find_child( "#ob_setup-add_{}".format( player_id ) )
elem.click()
edit_ob_setup( webdriver, player_id, None, caption, width )
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def edit_ob_setup( webdriver, player_id, entry_no, caption, width ):
"""Edit an OB setup."""
# locate the requested entry and start editing it
if entry_no is not None:
select_tab( "ob{}".format( player_id ) )
elems = find_children( "#ob_setup-sortable_{} li".format( player_id ) )
elem = elems[ entry_no ]
ActionChains(webdriver).double_click( elem ).perform()
# edit the OB setup
if caption is not None:
elem = find_child( "#edit-ob_setup textarea" )
elem.clear()
elem.send_keys( caption )
if width is not None:
elem = find_child( "#edit-ob_setup input[type='text']" )
elem.clear()
elem.send_keys( width )
click_dialog_button( "OK" )

@ -2,7 +2,7 @@
from selenium.webdriver.support.ui import Select
from vasl_templates.webapp.tests.utils import get_nationalities, find_child
from vasl_templates.webapp.tests.utils import get_nationalities, select_tab, find_child
# ---------------------------------------------------------------------
@ -20,6 +20,7 @@ def test_player_change( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main" ) )
select_tab( "scenario" )
nationalities = get_nationalities( webapp )
# make sure that the UI was updated correctly for the initial players

@ -34,14 +34,14 @@ def test_scenario_persistence( webapp, webdriver ):
"SSR_WIDTH": "103",
},
"ob1": {
"OB_SETUP_1": "Player 1's OB", "OB_SETUP_WIDTH_1": "201",
"OB_SETUP_1": [ { "caption": "ob setup 1a", "width": "" }, { "caption": "ob setup 1b", "width": "200px" } ],
"VEHICLES_1": [ "a russian vehicle", "another russian vehicle" ],
"VEHICLES_WIDTH_1": "202",
"ORDNANCE_1": [ "a russian ordnance", "another russian ordnance" ],
"ORDNANCE_WIDTH_1": "203",
},
"ob2": {
"OB_SETUP_2": "Player 2's OB", "OB_SETUP_WIDTH_2": "301",
"OB_SETUP_2": [ { "caption": "ob setup 2", "width": "" } ],
"VEHICLES_2": [ "a german vehicle" ],
"VEHICLES_WIDTH_2": "302",
"ORDNANCE_2": [ "a german ordnance" ],
@ -77,6 +77,8 @@ def test_scenario_persistence( webapp, webdriver ):
for field,val in scenario_params[tab_id].items():
if field == "SSR":
continue # nb: this requires special handling, we do it below
if field in ("OB_SETUP_1","OB_SETUP_2"):
continue # nb: this requires special handling, we do it below
if field in ("VEHICLES_1","ORDNANCE_1","VEHICLES_2","ORDNANCE_2"):
continue # nb: this requires special handling, we do it below
elem = next( c for c in ( \
@ -89,6 +91,8 @@ def test_scenario_persistence( webapp, webdriver ):
assert elem.get_attribute("value") == val
ssrs = _get_ssrs()
assert ssrs == scenario_params["scenario"]["SSR"]
assert _get_ob_setups(1) == [ obs["caption"] for obs in scenario_params["ob1"]["OB_SETUP_1"] ]
assert _get_ob_setups(2) == [ obs["caption"] for obs in scenario_params["ob2"]["OB_SETUP_2"] ]
assert _get_vo("vehicle",1) == scenario_params["ob1"]["VEHICLES_1"]
assert _get_vo("ordnance",1) == scenario_params["ob1"]["ORDNANCE_1"]
assert _get_vo("vehicle",2) == scenario_params["ob2"]["VEHICLES_2"]
@ -160,6 +164,14 @@ def _get_ssrs():
select_tab( "scenario" )
return [ c.text for c in find_children("#ssr-sortable li") ]
def _get_ob_setups( player_id ):
"""Get the OB setup's from the UI."""
select_tab( "ob{}".format( player_id ) )
return [
c.text
for c in find_children( "#ob_setup-sortable_{} li".format( player_id ) )
]
def _get_vo( vo_type, player_id ):
"""Get the vehicles/ordnance from the UI."""
select_tab( "ob{}".format( player_id ) )

@ -2,7 +2,7 @@
from selenium.webdriver.common.keys import Keys
from vasl_templates.webapp.tests.utils import set_template_params, get_clipboard
from vasl_templates.webapp.tests.utils import select_tab, set_template_params, get_clipboard
from vasl_templates.webapp.tests.utils import get_stored_msg, dismiss_notifications, find_child
from vasl_templates.webapp.tests.utils import for_each_template, wait_for
@ -13,6 +13,7 @@ def test_scenario_snippets( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main", store_msgs=1 ) )
select_tab( "scenario" )
# generate a SCENARIO snippet
_test_snippet( webdriver, "scenario", {
@ -62,6 +63,7 @@ def test_vc_snippets( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main", store_msgs=1 ) )
select_tab( "scenario" )
# generate a VC snippet
_test_snippet( webdriver, "victory_conditions", {
@ -95,6 +97,7 @@ def test_players_snippets( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main", store_msgs=1 ) )
select_tab( "scenario" )
# generate a PLAYERS snippet
_test_snippet( webdriver, "players", {
@ -160,15 +163,20 @@ def test_edit_templates( webapp, webdriver ):
webdriver.get( webapp.url_for( "main", edit_template_links=1 ) )
# try uploading a customized version of each template
def edit_template( template_id ):
"""Edit a template."""
elem = find_child( "#edit-template textarea" )
elem.clear()
elem.send_keys( "EDITED TEMPLATE: {}".format( template_id ) )
elem.send_keys( Keys.ESCAPE )
def test_template( template_id, orig_template_id ):
"""Test editing a template."""
if template_id == "ob_setup":
return # nb: this requires special handling (done below)
# edit the template
elem = find_child( "a.edit-template-link[data-id='{}']".format( template_id ) )
webdriver.execute_script( "$(arguments[0]).click();", elem )
elem = find_child( "#edit-template textarea" )
elem.clear()
elem.send_keys( "EDITED TEMPLATE: {}".format( orig_template_id ) )
elem.send_keys( Keys.ESCAPE )
edit_template( orig_template_id )
# check that the new template is being used
dismiss_notifications()
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
@ -177,3 +185,17 @@ def test_edit_templates( webapp, webdriver ):
lambda: get_clipboard() == "EDITED TEMPLATE: {}".format( orig_template_id )
)
for_each_template( test_template )
# customize the OB SETUP template
select_tab( "ob2" )
elem = find_child( "#tabs-ob2 input[type='button'][data-id='ob_setup']" )
elem.click()
edit_template( "ob_setup" )
# check that the new template is being used
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup
for player_id in range(1,2+1):
add_ob_setup( webdriver, player_id, "ob setup (ignored)" )
elem = find_child( "#ob_setup-sortable_{} li input[type='button']".format( player_id ) )
elem.click()
assert get_clipboard() == "EDITED TEMPLATE: ob_setup"

@ -4,7 +4,7 @@ import html
from selenium.webdriver.common.action_chains import ActionChains
from vasl_templates.webapp.tests.utils import find_child, find_children
from vasl_templates.webapp.tests.utils import select_tab, find_child, find_children
from vasl_templates.webapp.tests.utils import get_clipboard, dismiss_notifications, click_dialog_button
# ---------------------------------------------------------------------
@ -14,6 +14,7 @@ def test_ssr( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main" ) )
select_tab( "scenario" )
# initialize
expected = []

@ -8,9 +8,10 @@ import base64
from selenium.webdriver.support.ui import Select
from vasl_templates.webapp import snippets
from vasl_templates.webapp.tests.utils import select_menu_option, get_clipboard
from vasl_templates.webapp.tests.utils import get_stored_msg, set_stored_msg, dismiss_notifications, find_child
from vasl_templates.webapp.tests.utils import for_each_template
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup
from vasl_templates.webapp.tests.utils import select_tab, select_menu_option, dismiss_notifications
from vasl_templates.webapp.tests.utils import get_clipboard, get_stored_msg, set_stored_msg
from vasl_templates.webapp.tests.utils import for_each_template, find_child, find_children
# ---------------------------------------------------------------------
@ -25,7 +26,13 @@ def test_individual_files( webapp, webdriver ):
"""Test uploading a customized version of the template."""
# make sure generating a snippet returns something
dismiss_notifications()
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
if template_id == "ob_setup":
select_tab( "ob1" )
add_ob_setup( webdriver, 1, "test ob setup" )
elems = find_children( "#ob_setup-sortable_1 li input[type='button']" )
elem = elems[0]
else:
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
elem.click()
assert get_clipboard() != ""
# upload a new template
@ -36,7 +43,6 @@ def test_individual_files( webapp, webdriver ):
select_menu_option( "template_pack" )
# make sure generating a snippet returns the new version
dismiss_notifications()
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
elem.click()
assert get_clipboard() == "UPLOADED TEMPLATE"
for_each_template( test_template )
@ -71,7 +77,7 @@ def test_zip_files( webapp, webdriver ):
assert get_stored_msg("_last-error_") is None
# check that the uploaded templates are being used
_check_snippets(
_check_snippets( webdriver,
lambda tid: "Customized {}.".format( tid.upper() )
)
@ -100,7 +106,7 @@ def test_new_default_template_pack( webapp, webdriver, monkeypatch ):
webdriver.get( webapp.url_for( "main" ) )
# check that the new templates are being used
_check_snippets(
_check_snippets( webdriver,
lambda tid: "New default {}.".format( tid.upper() )
)
@ -111,6 +117,7 @@ def test_nationality_data( webapp, webdriver ):
# initialize
webdriver.get( webapp.url_for( "main", store_msgs=1, template_pack_persistence=1 ) )
select_tab( "scenario" )
# select the British as player 1
sel = Select(
@ -142,13 +149,19 @@ def test_nationality_data( webapp, webdriver ):
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def _check_snippets( func ):
def _check_snippets( webdriver, func ):
"""Check that snippets are being generated as expected."""
def test_template( template_id, orig_template_id ):
"""Test each template."""
dismiss_notifications()
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
if template_id == "ob_setup":
select_tab( "ob1" )
add_ob_setup( webdriver, 1, "test ob setup" )
elems = find_children( "#ob_setup-sortable_1 li input[type='button']" )
elem = elems[0]
else:
elem = find_child( "input.generate[data-id='{}']".format( orig_template_id ) )
elem.click()
assert get_clipboard() == func( template_id )
for_each_template( test_template )

@ -43,8 +43,8 @@ def for_each_template( func ):
# test the standard templates
for tab_id,template_ids in _STD_TEMPLATES.items():
select_tab( tab_id )
for template_id in template_ids:
select_tab( tab_id )
if template_id.startswith( "ob_setup_" ):
template_id2 = "ob_setup"
elif template_id.startswith( "vehicles_" ):
@ -101,6 +101,15 @@ def set_template_params( params ):
add_ssr( _webdriver, ssr )
continue
# check for OB set up (these require special handling)
if key in ("OB_SETUP_1","OB_SETUP_2"):
# add them in (nb: we don't consider any existing OB setup's)
from vasl_templates.webapp.tests.test_ob_setup import add_ob_setup #pylint: disable=cyclic-import
player_id = int( key[-1] )
for entry in val:
add_ob_setup( _webdriver, player_id, entry.get("caption",""), entry.get("width","") )
continue
# check for vehicles/ordnance (these require special handling)
if key in ("VEHICLES_1","ORDNANCE_1","VEHICLES_2","ORDNANCE_2"):
# add them in (nb: we don't consider any existing vehicles/ordnance)

Loading…
Cancel
Save