From 040c41d8b3f80c8056d56911830e4cfe758cda9b Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Tue, 21 Oct 2025 17:55:54 -0400 Subject: [PATCH 01/67] update existing tests to pass --- features/ignite_only.feature | 2 +- features/surface_and_crown.feature | 2 +- features/surface_only.feature | 743 ++++++++++++++--------------- projects/behave_cms/deps.edn | 8 +- steps/Given.clj | 39 +- 5 files changed, 407 insertions(+), 387 deletions(-) diff --git a/features/ignite_only.feature b/features/ignite_only.feature index ed28b160e..e00fee261 100644 --- a/features/ignite_only.feature +++ b/features/ignite_only.feature @@ -1,7 +1,7 @@ Feature: Ignite Only Worksheets Scenario: Fire Behavior Output Selected - Given I have started a Surface Worksheet + Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - Fire Behavior > Ignition > Probability of Ignition diff --git a/features/surface_and_crown.feature b/features/surface_and_crown.feature index b25260393..1afb0045d 100644 --- a/features/surface_and_crown.feature +++ b/features/surface_and_crown.feature @@ -1,7 +1,7 @@ Feature: Surface and Crown Worksheets Scenario: Probability of Ignition Output Selected - Given I have started a Surface & Crown Worksheet + Given I have started a new Surface & Crown Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - Fire Behavior > Ignition > Probability of Ignition diff --git a/features/surface_only.feature b/features/surface_only.feature index f26594df2..d5a12bfa6 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -1,389 +1,386 @@ Feature: Surface Only Worksheets + +As a user when I create a new worksheet and have Selected Surface Only in the Module Selection Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available to me in the inputs page. Scenario: Fire Behavior Output Selected - Given I have started a Surface Worksheet + Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: - """ - - Fire Behavior > Direction Mode > Heading - - Fire Behavior > Surface Fire > Rate of Spread - """ + """ + - Fire Behavior > Direction Mode > Heading + - Fire Behavior > Surface Fire > Rate of Spread + """ Then the following input Submodule > Groups are displayed: """ - Fuel Model > Standard > Fuel Model - Fuel Moisture > Moisture Input Mode - - Wind and Slope > Wind Speed - Wind and Slope > Wind and slope are - Wind and Slope > Slope """ # - Wind and Slope > Wind measured at: @kenny this fails because Wind measured at: has a # - trailing space in the dom and (extract-submodule-groups) trims this. + + Scenario: Size Submodule Outputs Selected + Given I have started a new Surface Worksheet in Guided Mode + When I select these outputs Submodule > Group > Output: + """ + - Size > Surface - Fire Size > Fire Area + """ + Then the following input Submodule > Groups are displayed: + """ + - Size > Elapsed Time + """ + + # Scenario: Length-to-Width Output Selected + # Given I have started a Surface & Mortality Worksheet in Guided Mode + # When I select the output "Length-to-Width Ratio" in the "Size" submodule + # Then the following input Submodule > Groups are displayed: + # """ + # - Fuel Model + # - Fuel Moisture > Moisture Input Mode + # - Wind and Slope > Wind Speed + # - Wind and Slope > Wind and Slope are: + # - Wind and Slope > Slope + # """ + + # Scenario: Size Outputs Selected + # Given I have started a Surface Worksheet in Guided Mode + # When The size outputs below are selected: + # - Size > Fire Area + # - Size > Fire Perimeter + # - Size > Spread Distance + # Then the following input Submodule > Groups are displayed: + # """ + # - Fuel Model + # - Fuel Moisture > Moisture Input Mode + # - Wind and Slope > Wind Speed + # - Wind and Slope > Wind and Slope are: + # - Wind and Slope > Slope + # - Size > Elapsed Time + # """ -# Feature: Mortality Only -# Scenario: Mortality Only Test -# Given I have started a Mortality Worksheet -# When I select the output "Rate of Spread" in the "Fire Behavior" submodule -# Then the following input Submodule > Groups are displayed: -# """ -# - Fuel Model -# - Fuel Moisture > Moisture Input Mode -# - Wind and Slope > Wind Measured at: -# - Wind and Slope > Wind Speed -# - Wind and Slope > Wind and Slope are: -# - Wind and Slope > Slope + # Scenario: Size Outputs Selected + # Given I have started a Surface Worksheet in Guided Mode + # Then the following outputs are displayed: + # """ + # - Spot -> Burning Pile + # - Spot -> Wind-Driven Surface Fire # """ -# Scenario: Length-to-Width Output Selected -# Given I have started a Surface Worksheet -# When I select the output "Length-to-Width Ratio" in the "Size" submodule -# Then the following input Submodule > Groups are displayed: -# """ -# - Fuel Model -# - Fuel Moisture > Moisture Input Mode -# - Wind and Slope > Wind Measured at: -# - Wind and Slope > Wind Speed -# - Wind and Slope > Wind and Slope are: -# - Wind and Slope > Slope -# """ - -# Scenario: Size Outputs Selected -# Given I have started a Surface Worksheet -# When The size outputs below are selected: -# - Size > Fire Area -# - Size > Fire Perimeter -# - Size > Spread Distance -# Then the following input Submodule > Groups are displayed: -# """ -# - Fuel Model -# - Fuel Moisture > Moisture Input Mode -# - Wind and Slope > Wind Measured at: -# - Wind and Slope > Wind Speed -# - Wind and Slope > Wind and Slope are: -# - Wind and Slope > Slope -# - Size > Elapsed Time -# """ -# -# Scenario: Size Outputs Selected -# Given I have started a Surface Worksheet -# Then the following outputs are displayed: -# """ -# - Spot -> Burning Pile -# - Spot -> Wind-Driven Surface Fire -# """ -# Then and should be the only two options under Maximum Spotting Distance -# -# Given I have started a Surface Worksheet -# When Any outputs are selected, other than Burning Pile -# Then Maximum Spotting Distance: Burning Pile should be deactivated -# -# Given I have started a Surface Worksheet -# When Burning Pile is selected from Maximum Spotting Distance -# Then All other outputs should be deactivated and the ONLY inputs should -# be: -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot autoselected -# - Wind Speed -# - *No WAF* -# - *No Wind and Slope are* -# - *No Slope* -# - Spot -# - Downwind Canopy Cover -# - Downwind Canopy Height -# - Flame Height (from a Burning Bile) -# - Topography -# - Ridge-to-Valley Elevation Difference -# - Ridge-to-Valley Horizontal Distance (Dependent on Elevation -# Difference) -# - Spotting Source Location (Dependent on Elevation Difference) -# -# Given I have started a Surface Worksheet -# When Fire Behavior or Size is selected with Wind-Driven Surface Fire -# from Spot -# Then Fuel Model should be replaced with Wind Driven Fuel Models which -# only contain grass fuel models -# -# Given I have started a Surface Worksheet -# When Fire Behavior or Size is selected with Wind-Driven Surface Fire -# from Spot -# Then Surface Fire Flame Length should come from Surface and should not -# be an input -# -# Given I have started a Surface Worksheet -# When When Wind-Drive Surface fire is not run with Fire Behavior -# Then Only the inputs below are required -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot auto-selected -# - Wind Speed -# - *No WAF* -# - *No Wind and Slope are* -# - *No Slope* -# - Spot -# - Downwind Canopy Cover -# - Downwind Canopy Height -# - Topography -# - Ridge-to-Valley Elevation Difference -# - Ridge-to-Valley Horizontal Distance (Dependent on Elevation -# Difference) -# - Spotting Source Location (Dependent on Elevation Difference) -# - *Surface Fire Flame Length* -# -# Given I have started a Surface Worksheet -# When 0 is entered into Ridge-to-Valley Elevation Difference -# Then Ridge-to-Valley Horizontal Distance and Spotting Source Location -# should not be available inputs -# -# Given I have started a Surface Worksheet -# When A value greater than 0 is entered into Ridge-to-Valley Elevation -# Difference -# Then Ridge-to-Valley Horizontal Distance and Spotting Source Location -# should be required inputs -# -# Given I have started a Surface Worksheet -# When Direction of Interest is selected from Direction Mode -# Then The Wind/Slope/Spread Diagram should be automatically output on -# the Run Results -# -# Given I have started a Surface Worksheet -# When Direction of Interest is selected from Direction Mode -# Then The Direction of Spread should be automatically output on the Run -# Results. The Direction of Spread should be consisted with the Direction -# Mode selected (Heading or Heading Flanking Backing) -# -# Given I have started a Surface Worksheet -# When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not -# aligned -# Then The Wind/Slope/Spread Diagram should be automatically output on -# the Run Results -# -# Given I have started a Surface Worksheet -# When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not -# aligned -# Then The Direction of Spread should be automatically ouput on the Run -# Results. The Direction of Spread should be consisted with the Direction -# Mode selected (Heading or Heading Flanking Backing) -# -# Given I have started a Surface Worksheet -# When Maximum Spotting DIstance from a Burning Pile is run -# Then Firebrand Height from a Burning Pile should be automatically -# output -# * Surface and Crown -# -# Given I have started a Surface and Crown Worksheet -# When Surface and Crown are run together -# Then Heading should be automatically run for Direction Mode. *It should not be automatically selected because the user may not run Fire Behavior.* -# -# Given I have started a Surface and Crown Worksheet -# When Any output is selected, other than a Spot model -# Then Fire Type should be automatically selected as an output but it -# should not shown on the worksheet -# -# Given I have started a Surface and Crown Worksheet -# When Fire behavior has a selected output (RoS, FL, or FI) -# Then The following Submodules w/inputs are the ONLY required inputs -# - Fuel Model -# - Fuel Moisture -# - Moisture Input Mode -# - Appropriate Moisture Inputs -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot autoselected -# - Wind Speed -# - WAF -# - Wind and Slope are: -# - Slope -# - Calculations Options -# - Fuel Moisture -# - Foliar Moisture -# - Canopy Fuel -# - Canopy Base Height -# - Canopy Bulk Density -# - Canopy Height -# -# Given I have started a Surface and Crown Worksheet -# When Length-to-Width Ratio output in the Size submodule is selected -# Then The following Submodules w/inputs are the ONLY required inputs -# - Fuel Model -# - Fuel Moisture -# - Moisture Input Mode -# - Appropriate Moisture Inputs -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot autoselected -# - Wind Speed -# - WAF -# - WAF(if applicable) -# - Wind and Slope are: -# - Slope -# - Fuel Moisture -# - Foliar Moisture -# - Calculations Options -# - Canopy Fuel -# - Canopy Base Height -# - Canopy Bulk Density -# - Canopy Height -# -# Given I have started a Surface and Crown Worksheet -# When Any Fire Type output are selected -# Then The following Submodules w/inputs are the ONLY required inputs -# - Fuel Model -# - Fuel Moisture -# - Moisture Input Mode -# - Appropriate Moisture Inputs -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot autoselected -# - Wind Speed -# - WAF -# - WAF(if applicable) -# - Wind and Slope are: -# - Slope -# - Fuel Moisture -# - Foliar Moisture -# - Calculations Options -# - Canopy Fuel -# - Canopy Base Height -# - Canopy Bulk Density -# - Canopy Height -# -# Given I have started a Surface and Crown Worksheet -# When The size outputs below are selected: -# - Fire Area -# - Fire Perimeter -# - Spread Distance -# - (**Exclude Length-to-Width Ratio) -# Then The following Submodules w/inputs are the ONLY required inputs -# - Fuel Model -# - Fuel Moisture -# - Moisture Input Mode -# - Appropriate Moisture Inputs -# - Wind and Slope -# - Wind Measured at: -# - Wind Speed -# - WAF(if applicable) -# - Wind and Slope are: -# - Slope -# - Size -# - Elapsed Time -# -# Given I have started a Surface and Crown Worksheet -# When Surface and Crown are run together -# Then Only Torching Trees and Active Crown fire should be available options under Maximum Spotting Distance -# -# Given I have started a Surface and Crown Worksheet -# When Surface and Crown are run together -# Then Torching Tree and Active Crown fire should be able to both be run under Maximum Spotting Distance -# -# Given I have started a Surface and Crown Worksheet -# When Active Crown Fire is selected as an out, *WITHOUT Fire Behavior* -# Then The inputs below are required -# - Canopy Fuel -# - Canopy Height -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot auto-selected -# - Wind Speed -# - *No WAF* -# - *No Wind and Slope are* -# - *No Slope* -# - Spot -# - Topography -# - Ridge-to-Valley Elevation Difference -# - Ridge-to-Valley Horizontal Distance (Dependent on Elevation -# Difference) -# - Spotting Source Location (Dependent on Elevation Difference) -# - *Active Crown Fire Flame Length* -# -# Given I have started a Surface and Crown Worksheet -# When Active Crown Fire is selected as an output with Fire Behavior -# Then The inputs below are required -# - Canopy Fuel -# - Canopy Height -# - Wind and Slope -# - Wind Measured at: -# - Midflame should be deactivate and 20-Foot auto-selected -# - Wind Speed -# - *No WAF* -# - *No Wind and Slope are* -# - *No Slope* -# - Spot -# - Topography -# - Ridge-to-Valley Elevation Difference -# - Ridge-to-Valley Horizontal Distance (Dependent on Elevation -# Difference) -# - Spotting Source Location (Dependent on Elevation Difference) -# - *Active Crown Fire Flame Length* -# -# Given I have started a Surface and Crown Worksheet -# When Fire Behavior or Size is selected with Active Crown Fire from Spot -# Then Active Crown Fire Flame Length should come from Crown and should not be an input -# * Surface and Contain -# -# Given I have started a Surface and Contain Worksheet -# Then Spot should not be on worksheet -# -# Given I have started a Surface and Contain Worksheet -# Then Surface Fire Behavior and Size conditionals should be treated the same as Surface being run alone -# -# Given I have started a Surface and Contain Worksheet -# Then Heading in Fire Behavior's Direction Mode should be the only option available. Heading, Backing, and Flanking, and DIrection of Interest should be deactivated -# * Surface and Mortality -# -# Given I have started a Surface and Mortality Worksheet -# Then Heading and Heading Flanking, Backing in Fire Behavior's Direction Mode should be the only options available. -# And: Direction of Interest should be deactivated -# -# Given I have started a Surface and Mortality Worksheet -# Then There should be no Size output module -# And: There should be no Size input submodules -# -# Given I have started a Surface and Mortality Worksheet -# Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation -# -# Given I have started a Surface and Mortality Worksheet -# Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation -# -# Given I have started a Surface and Mortality Worksheet -# Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation -# -# Given I have started a Surface and Mortality Worksheet -# Then Flame Length is needed to calculate PoM so Surface Fire Behavior conditionals should be used to calculate Flame Length -# -# Given I have started a Surface and Mortality Worksheet -# Then PoM equation used should be based on the Mortality tree species used, see [[https://sig-gis.atlassian.net/browse/BHP1-839?atlOrigin=eyJpIjoiZTdjZDg4MDNhYTBlNDE2NDljZTRhZTEzNThlNDI5NzgiLCJwIjoiaiJ9][BHP1-839]] -# -# Given I have started a Surface and Mortality Worksheet -# Then DBH and Mortality Tree species are both required user inputs, regardless of PoM equation -# -# Given I have started a Surface and Mortality Worksheet -# Then Probability of Mortality is automatically calculated -# -# Given I have started a Surface and Mortality Worksheet -# Then Mortality Outputs should match the format in [[https://sig-gis.atlassian.net/browse/BHP1-926?atlOrigin=eyJpIjoiYTQwNWFjMmExZDE5NGNjYWI3NDYxNTNjY2MwMmIwMTAiLCJwIjoiaiJ9][ticket]] and [[https://usfs.box.com/s/u6uknqwzt751top5awzn0am4u4s8dkj3][table]] -# -# Given I have started a Surface and Crown Worksheet -# When The PoM equation used is Crown Scorch -# Then The user inputs below are required -# - Air Temp -# - MidFlame Windspeed or (20ft or 10m x WAF = Midflame Windspeed) -# - Canopy Height -# - Crown Ratio -# -# Given I have started a Surface and Crown Worksheet -# When The PoM equation used is Crown Scorch -# Then The calculated Flame Length needs to be used to calculate Scorch Height -# -# Given I have started a Surface and Crown Worksheet -# When The PoM equation used is Bark Char -# Then The calculated Flame Length is used to calculate Bark Char Height, Flame Length/1.8 -# -# Given I have started a Surface and Crown Worksheet -# When The PoM equation used is Crown Scorch -# Then Automated outputs that should be calculated including: -# - Crown Length Scorched -# - Crown Volume Scorched -# - Scorch Height -# -# Given I have started a Surface and Crown Worksheet -# When The PoM equation used is Bark Char -# Then Bark Char Height is an automated output that should be calculated include + # Then and should be the only two options under Maximum Spotting Distance + + # Given I have started a Surface Worksheet + # When Any outputs are selected, other than Burning Pile + # Then Maximum Spotting Distance: Burning Pile should be deactivated + + # Given I have started a Surface Worksheet + # When Burning Pile is selected from Maximum Spotting Distance + # Then All other outputs should be deactivated and the ONLY inputs should + # be: + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Downwind Canopy Cover + # - Downwind Canopy Height + # - Flame Height (from a Burning Bile) + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + + # Given I have started a Surface Worksheet + # When Fire Behavior or Size is selected with Wind-Driven Surface Fire + # from Spot + # Then Fuel Model should be replaced with Wind Driven Fuel Models which + # only contain grass fuel models + + # Given I have started a Surface Worksheet + # When Fire Behavior or Size is selected with Wind-Driven Surface Fire + # from Spot + # Then Surface Fire Flame Length should come from Surface and should not + # be an input + + # Given I have started a Surface Worksheet + # When When Wind-Drive Surface fire is not run with Fire Behavior + # Then Only the inputs below are required + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Downwind Canopy Cover + # - Downwind Canopy Height + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Surface Fire Flame Length* + + # Given I have started a Surface Worksheet + # When 0 is entered into Ridge-to-Valley Elevation Difference + # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location + # should not be available inputs + + # Given I have started a Surface Worksheet + # When A value greater than 0 is entered into Ridge-to-Valley Elevation + # Difference + # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location + # should be required inputs + + # Given I have started a Surface Worksheet + # When Direction of Interest is selected from Direction Mode + # Then The Wind/Slope/Spread Diagram should be automatically output on + # the Run Results + + # Given I have started a Surface Worksheet + # When Direction of Interest is selected from Direction Mode + # Then The Direction of Spread should be automatically output on the Run + # Results. The Direction of Spread should be consisted with the Direction + # Mode selected (Heading or Heading Flanking Backing) + + # Given I have started a Surface Worksheet + # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not + # aligned + # Then The Wind/Slope/Spread Diagram should be automatically output on + # the Run Results + + # Given I have started a Surface Worksheet + # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not + # aligned + # Then The Direction of Spread should be automatically ouput on the Run + # Results. The Direction of Spread should be consisted with the Direction + # Mode selected (Heading or Heading Flanking Backing) + + # Given I have started a Surface Worksheet + # When Maximum Spotting DIstance from a Burning Pile is run + # Then Firebrand Height from a Burning Pile should be automatically + # output + # * Surface and Crown + + # Given I have started a Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Heading should be automatically run for Direction Mode. *It should not be automatically selected because the user may not run Fire Behavior.* + + # Given I have started a Surface and Crown Worksheet + # When Any output is selected, other than a Spot model + # Then Fire Type should be automatically selected as an output but it + # should not shown on the worksheet + + # Given I have started a Surface and Crown Worksheet + # When Fire behavior has a selected output (RoS, FL, or FI) + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - Wind and Slope are: + # - Slope + # - Calculations Options + # - Fuel Moisture + # - Foliar Moisture + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a Surface and Crown Worksheet + # When Length-to-Width Ratio output in the Size submodule is selected + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Fuel Moisture + # - Foliar Moisture + # - Calculations Options + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a Surface and Crown Worksheet + # When Any Fire Type output are selected + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Fuel Moisture + # - Foliar Moisture + # - Calculations Options + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a Surface and Crown Worksheet + # When The size outputs below are selected: + # - Fire Area + # - Fire Perimeter + # - Spread Distance + # - (**Exclude Length-to-Width Ratio) + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Wind Speed + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Size + # - Elapsed Time + + # Given I have started a Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Only Torching Trees and Active Crown fire should be available options under Maximum Spotting Distance + + # Given I have started a Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Torching Tree and Active Crown fire should be able to both be run under Maximum Spotting Distance + + # Given I have started a Surface and Crown Worksheet + # When Active Crown Fire is selected as an out, *WITHOUT Fire Behavior* + # Then The inputs below are required + # - Canopy Fuel + # - Canopy Height + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Active Crown Fire Flame Length* + + # Given I have started a Surface and Crown Worksheet + # When Active Crown Fire is selected as an output with Fire Behavior + # Then The inputs below are required + # - Canopy Fuel + # - Canopy Height + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Active Crown Fire Flame Length* + + # Given I have started a Surface and Crown Worksheet + # When Fire Behavior or Size is selected with Active Crown Fire from Spot + # Then Active Crown Fire Flame Length should come from Crown and should not be an input + # * Surface and Contain + + # Given I have started a Surface and Contain Worksheet + # Then Spot should not be on worksheet + + # Given I have started a Surface and Contain Worksheet + # Then Surface Fire Behavior and Size conditionals should be treated the same as Surface being run alone + + # Given I have started a Surface and Contain Worksheet + # Then Heading in Fire Behavior's Direction Mode should be the only option available. Heading, Backing, and Flanking, and DIrection of Interest should be deactivated + # * Surface and Mortality + + # Given I have started a Surface and Mortality Worksheet + # Then Heading and Heading Flanking, Backing in Fire Behavior's Direction Mode should be the only options available. + # And: Direction of Interest should be deactivated + + # Given I have started a Surface and Mortality Worksheet + # Then There should be no Size output module + # And: There should be no Size input submodules + + # Given I have started a Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a Surface and Mortality Worksheet + # Then Flame Length is needed to calculate PoM so Surface Fire Behavior conditionals should be used to calculate Flame Length + + # Given I have started a Surface and Mortality Worksheet + # Then PoM equation used should be based on the Mortality tree species used, see [[https://sig-gis.atlassian.net/browse/BHP1-839?atlOrigin=eyJpIjoiZTdjZDg4MDNhYTBlNDE2NDljZTRhZTEzNThlNDI5NzgiLCJwIjoiaiJ9][BHP1-839]] + + # Given I have started a Surface and Mortality Worksheet + # Then DBH and Mortality Tree species are both required user inputs, regardless of PoM equation + + # Given I have started a Surface and Mortality Worksheet + # Then Probability of Mortality is automatically calculated + + # Given I have started a Surface and Mortality Worksheet + # Then Mortality Outputs should match the format in [[https://sig-gis.atlassian.net/browse/BHP1-926?atlOrigin=eyJpIjoiYTQwNWFjMmExZDE5NGNjYWI3NDYxNTNjY2MwMmIwMTAiLCJwIjoiaiJ9][ticket]] and [[https://usfs.box.com/s/u6uknqwzt751top5awzn0am4u4s8dkj3][table]] + + # Given I have started a Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then The user inputs below are required + # - Air Temp + # - MidFlame Windspeed or (20ft or 10m x WAF = Midflame Windspeed) + # - Canopy Height + # - Crown Ratio + + # Given I have started a Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then The calculated Flame Length needs to be used to calculate Scorch Height + + # Given I have started a Surface and Crown Worksheet + # When The PoM equation used is Bark Char + # Then The calculated Flame Length is used to calculate Bark Char Height, Flame Length/1.8 + + # Given I have started a Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then Automated outputs that should be calculated including: + # - Crown Length Scorched + # - Crown Volume Scorched + # - Scorch Height + + # Given I have started a Surface and Crown Worksheet + # When The PoM equation used is Bark Char + # Then Bark Char Height is an automated output that should be calculated include diff --git a/projects/behave_cms/deps.edn b/projects/behave_cms/deps.edn index 56eb949d0..2fc76426a 100644 --- a/projects/behave_cms/deps.edn +++ b/projects/behave_cms/deps.edn @@ -74,7 +74,13 @@ sig/behave-schema {:local/root "../../bases/behave_schema"} sig/datomic-store {:local/root "../../bases/datomic_store" :exclusions [io.replikativ/datahike]}} - :aliases {:server {:main-opts ["-m" "behave-cms.server"]} + :aliases {:nrepl {:extra-paths ["test"] + :extra-deps {nrepl/nrepl {:mvn/version "1.3.1"}} + ;; this allows nrepl to interrupt runaway repl evals + :jvm-opts ["-Djdk.attach.allowAttachSelf"] + :main-opts ["-m" "nrepl.cmdline" "--port" "7888"]} + + :server {:main-opts ["-m" "behave-cms.server"]} :figwheel-lib {:extra-deps {com.bhauman/figwheel-main {:mvn/version "0.2.13"}}} :figwheel {:extra-paths ["test/cljs"] :extra-deps {com.bhauman/figwheel-main {:mvn/version "0.2.13"} diff --git a/steps/Given.clj b/steps/Given.clj index bc7345e0e..22da5d3f9 100644 --- a/steps/Given.clj +++ b/steps/Given.clj @@ -12,7 +12,7 @@ [:surface :mortality] "Surface and Mortality" [:mortality] "Mortality Only"}) -(defn- select-independent-worksheet +(defn- select-new-worksheet-in-guided [modules {:keys [driver url]}] (w/maximize driver) @@ -20,17 +20,33 @@ (w/execute-script! driver "window.location.href = window.location.href") (w/goto driver url)) + ;; Wait for Working Area component to load (let [wait (w/wait driver 5000)] - (.until wait (w/presence-of (by/css ".card__header")))) + (.until wait (w/presence-of (by/css ".working-area")))) - ;; Select Standard Workflow - (-> (e/find-el driver (by/attr= :text "Standard Workflow")) + ;; Click New Run button + (-> (e/find-el driver (by/attr= :text "New Run")) (e/click!)) + (Thread/sleep 500) + + ;; Click Next button (-> (e/find-el driver (by/css ".button--highlight")) (e/click!)) - (Thread/sleep 1000) + (Thread/sleep 500) + + ;; Click "Open using Guided workflow" button + (-> (e/find-el driver (by/attr= :text "Open using Guided Workflow")) + (e/click!)) + + (Thread/sleep 500) + + ;; Click Next button + (-> (e/find-el driver (by/css ".button--highlight")) + (e/click!)) + + (Thread/sleep 500) ;; Select Surface Only worksheet (-> (e/find-el driver (by/attr= :text (get worksheet-modules (or modules [:surface])))) (e/click!)) @@ -38,18 +54,19 @@ (let [el (e/find-el driver (by/css ".button--highlight"))] (w/execute-script! driver "arguments[0].scrollIntoView(true)" el)) + ;; Click Next button (-> (e/find-el driver (by/css ".button--highlight")) (e/click!)) (w/execute-script! driver "window.scrollTo(0,0)") {:driver driver}) -(Given "I have started a Surface Worksheet" (partial select-independent-worksheet [:surface])) - -(Given "I have started a Surface & Crown Worksheet" (partial select-independent-worksheet [:surface :crown])) +(Given "I have started a new Surface Worksheet in Guided Mode" + (partial select-new-worksheet-in-guided [:surface])) -(Given "I have started a Surface and Contain Worksheet" (partial select-independent-worksheet [:surface :contain])) +(Given "I have started a new Surface & Mortality Worksheet in Guided Mode" + (partial select-new-worksheet-in-guided [:surface :mortality])) -(Given "I have started a Surface and Mortality Worksheet" (partial select-independent-worksheet [:surface :mortality])) +;; (Given "I have started a new Surface & Crown Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :crown])) +;; (Given "I have started a new Surface & Contain Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :contain])) -(Given "I have started a Mortality Worksheet" (partial select-independent-worksheet [:mortality])) From ef866c45edfaa73df4daa1e7dff6c3f64d4af5bb Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Wed, 22 Oct 2025 13:56:15 -0400 Subject: [PATCH 02/67] update for headless mode --- components/cucumber/src/cucumber/runner.clj | 2 +- .../cucumber/src/cucumber/webdriver.clj | 28 ++++--- development/user.clj | 74 ++++++++++++------- features/ignite_only.feature | 8 +- features/surface_and_crown.feature | 8 +- features/surface_only.feature | 16 ++-- steps/Given.clj | 16 ++-- steps/Then.clj | 2 +- steps/When.clj | 2 +- 9 files changed, 93 insertions(+), 63 deletions(-) diff --git a/components/cucumber/src/cucumber/runner.clj b/components/cucumber/src/cucumber/runner.clj index 45dfe7f84..ae4e42ea1 100644 --- a/components/cucumber/src/cucumber/runner.clj +++ b/components/cucumber/src/cucumber/runner.clj @@ -50,7 +50,7 @@ ;; Quit Driver (when-not debug? (w/quit driver)) - results))) + (:tegere.runner/outcome-summary-report results)))) (comment diff --git a/components/cucumber/src/cucumber/webdriver.clj b/components/cucumber/src/cucumber/webdriver.clj index 474d46b94..4fdc712f3 100644 --- a/components/cucumber/src/cucumber/webdriver.clj +++ b/components/cucumber/src/cucumber/webdriver.clj @@ -68,17 +68,25 @@ (defn chrome-driver "Instatiate a Chrome WebDriver." - [{:keys [browser-path]}] - (let [options (ChromeOptions.)] + [{:keys [browser-path headless]}] + (let [options (ChromeOptions.) + args (if headless + ["--headless=new" + "--window-size=1920,1080" + "disable-infobars" + "--disable-extensions" + "--disable-gpu" + "--disable-dev-shm-usage" + "--no-sandbox"] + ["start-maximized" + "disable-infobars" + "--disable-extensions" + "--disable-gpu" + "--disable-dev-shm-usage" + "--no-sandbox" + "--remote-debugging-port=9222"])] (when browser-path (.setBinary options browser-path)) - (.addArguments options (into-array - ["start-maximized" ; // open Browser in maximized mode - "disable-infobars" ; // disabling infobars - "--disable-extensions" ; // disabling extensions - "--disable-gpu" ; // applicable to windows os only - "--disable-dev-shm-usage" ; // overcome limited resource problems - "--no-sandbox" ; // Bypass OS security model - "--remote-debugging-port=9222"])) + (.addArguments options (into-array args)) (System/setProperty "webdriver.chrome.driver" "/usr/local/bin/chromedriver") (ChromeDriver. options))) diff --git a/development/user.clj b/development/user.clj index 83ad96dce..7ac9c166f 100644 --- a/development/user.clj +++ b/development/user.clj @@ -1,4 +1,33 @@ -(ns user) +(ns user + (:require [cucumber.runner :refer [run-cucumber-tests]])) + +(comment + ;; Headless mode (no visible browser) + (run-cucumber-tests + {:headless true + :browser :chrome + :features "features" + :steps "steps" + :url "http://localhost:8081/worksheets"}) + + ;; Normal mode (visible browser) + (run-cucumber-tests + {:debug? true + :features "features" + :steps "steps" + :browser :chrome + :url "http://localhost:8081/worksheets"}) + + + + ) + +#_(run-cucumber-tests {:debug? true + :features "./../../features" + :steps "./../../steps" + :browser :chrome + :browser-path "/usr/bin/google-chrome" + :url "http://localhost:8081/worksheets"}) (comment (require '[behave.server :as server] @@ -93,7 +122,7 @@ (defn generate-snippet [title help-key body-as-hiccup] (let [body (if (empty? body-as-hiccup) nil body-as-hiccup)] - (insert-topic-doctype + (insert-topic-doctype (xml/indent-str (xml/sexp-as-element [:topic {:id title} @@ -133,14 +162,13 @@ [:map (map gen-topic-ref dita-topics)])))) - (gen-ditamap [{:href "Content/Modules/Modules.dita" - :title "Modules" - :topics [{:href "Content/Modules/Surface.dita" - :title "Surface"}]}]) - + (gen-ditamap [{:href "Content/Modules/Modules.dita" + :title "Modules" + :topics [{:href "Content/Modules/Surface.dita" + :title "Surface"}]}]) ;; Markdown to Hiccup - + db ;; Generate DITA Project Layout @@ -163,8 +191,6 @@ ;; - Mortality ;; - Outputs ;; - Inputs - - module-help-pages (map #(let [submodule %] @@ -206,19 +232,15 @@ [snippet-name help-key]))] (spit submodule-topic-file - (generate-topic - (str/replace submodule #" " "_") - submodule - (->snake submodule) - - (concat - '([:h1 submodule]) - (map #(let [[snippet-name help-key] % - ref (str "../../../../Resources/Snippets/Variables/" snippet-name ".dita#" )] - [:p {:conref %}]))) - [] - [:h1 "Hello World"]) - - - ))))))) - ) + (generate-topic + (str/replace submodule #" " "_") + submodule + (->snake submodule) + + (concat + '([:h1 submodule]) + (map #(let [[snippet-name help-key] % + ref (str "../../../../Resources/Snippets/Variables/" snippet-name ".dita#")] + [:p {:conref %}]))) + [] + [:h1 "Hello World"]))))))))) diff --git a/features/ignite_only.feature b/features/ignite_only.feature index e00fee261..5ed394ab7 100644 --- a/features/ignite_only.feature +++ b/features/ignite_only.feature @@ -4,11 +4,11 @@ Feature: Ignite Only Worksheets Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - - Fire Behavior > Ignition > Probability of Ignition + -- Fire Behavior > Ignition > Probability of Ignition """ Then the following input Submodule > Groups are displayed: """ - - Fuel Moisture > Moisture Input Mode - - Weather > Air Temperature - - Weather > Fuel Shading From the Sun + -- Fuel Moisture > Moisture Input Mode + -- Weather > Air Temperature + -- Weather > Fuel Shading From the Sun """ diff --git a/features/surface_and_crown.feature b/features/surface_and_crown.feature index 1afb0045d..91c3adaec 100644 --- a/features/surface_and_crown.feature +++ b/features/surface_and_crown.feature @@ -4,12 +4,12 @@ Feature: Surface and Crown Worksheets Given I have started a new Surface & Crown Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - - Fire Behavior > Ignition > Probability of Ignition + -- Fire Behavior > Ignition > Probability of Ignition """ Then the following input Submodule > Groups are displayed: """ - - Fuel Moisture > Moisture Input Mode - - Weather > Air Temperature - - Weather > Fuel Shading From the Sun + -- Fuel Moisture > Moisture Input Mode + -- Weather > Air Temperature + -- Weather > Fuel Shading From the Sun """ diff --git a/features/surface_only.feature b/features/surface_only.feature index d5a12bfa6..9c34e31d7 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -6,15 +6,15 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - - Fire Behavior > Direction Mode > Heading - - Fire Behavior > Surface Fire > Rate of Spread + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Surface Fire > Rate of Spread """ Then the following input Submodule > Groups are displayed: """ - - Fuel Model > Standard > Fuel Model - - Fuel Moisture > Moisture Input Mode - - Wind and Slope > Wind and slope are - - Wind and Slope > Slope + -- Fuel Model > Standard > Fuel Model + -- Fuel Moisture > Moisture Input Mode + -- Wind and Slope > Wind and slope are + -- Wind and Slope > Slope """ # - Wind and Slope > Wind measured at: @kenny this fails because Wind measured at: has a @@ -24,11 +24,11 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ - - Size > Surface - Fire Size > Fire Area + -- Size > Surface - Fire Size > Fire Area """ Then the following input Submodule > Groups are displayed: """ - - Size > Elapsed Time + -- Size > Elapsed Time """ # Scenario: Length-to-Width Output Selected diff --git a/steps/Given.clj b/steps/Given.clj index 22da5d3f9..188dfe9c9 100644 --- a/steps/Given.clj +++ b/steps/Given.clj @@ -6,11 +6,11 @@ [cucumber.webdriver :as w])) (def ^:private worksheet-modules - {[:surface] "Surface Only" - [:surface :contain] "Surface and Contain" - [:surface :crown] "Surface & Crown" + {[:surface] "Surface Only" + [:surface :contain] "Surface and Contain" + [:surface :crown] "Surface & Crown" [:surface :mortality] "Surface and Mortality" - [:mortality] "Mortality Only"}) + [:mortality] "Mortality Only"}) (defn- select-new-worksheet-in-guided [modules {:keys [driver url]}] @@ -62,11 +62,11 @@ {:driver driver}) (Given "I have started a new Surface Worksheet in Guided Mode" - (partial select-new-worksheet-in-guided [:surface])) + (partial select-new-worksheet-in-guided [:surface])) (Given "I have started a new Surface & Mortality Worksheet in Guided Mode" - (partial select-new-worksheet-in-guided [:surface :mortality])) + (partial select-new-worksheet-in-guided [:surface :mortality])) -;; (Given "I have started a new Surface & Crown Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :crown])) -;; (Given "I have started a new Surface & Contain Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :contain])) +(Given "I have started a new Surface & Crown Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :crown])) +(Given "I have started a new Surface & Contain Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :contain])) diff --git a/steps/Then.clj b/steps/Then.clj index 26d9fb515..b3fea72f3 100644 --- a/steps/Then.clj +++ b/steps/Then.clj @@ -10,7 +10,7 @@ [submodule-groups] (-> submodule-groups (str/replace "\"\"\"" "") - (str/split #"- ") + (str/split #"-- ") (->> (map str/trim) (remove empty?) (map #(str/split % #" > "))))) diff --git a/steps/When.clj b/steps/When.clj index cec07fc12..76ab6e75c 100644 --- a/steps/When.clj +++ b/steps/When.clj @@ -11,7 +11,7 @@ [submodule-groups] (-> submodule-groups (str/replace "\"\"\"" "") - (str/split #"- ") + (str/split #"-- ") (->> (map str/trim) (remove empty?) (map #(str/split % #" > "))))) From e06b1e3fe14455209a0e9a5f2dee95854e9341b6 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Wed, 22 Oct 2025 16:14:15 -0400 Subject: [PATCH 03/67] optimize tests --- .../cucumber/src/cucumber/webdriver.clj | 28 +++++++------------ development/user.clj | 23 ++++++--------- steps/Given.clj | 16 ++++------- 3 files changed, 23 insertions(+), 44 deletions(-) diff --git a/components/cucumber/src/cucumber/webdriver.clj b/components/cucumber/src/cucumber/webdriver.clj index 4fdc712f3..97025ba0b 100644 --- a/components/cucumber/src/cucumber/webdriver.clj +++ b/components/cucumber/src/cucumber/webdriver.clj @@ -68,25 +68,17 @@ (defn chrome-driver "Instatiate a Chrome WebDriver." - [{:keys [browser-path headless]}] - (let [options (ChromeOptions.) - args (if headless - ["--headless=new" - "--window-size=1920,1080" - "disable-infobars" - "--disable-extensions" - "--disable-gpu" - "--disable-dev-shm-usage" - "--no-sandbox"] - ["start-maximized" - "disable-infobars" - "--disable-extensions" - "--disable-gpu" - "--disable-dev-shm-usage" - "--no-sandbox" - "--remote-debugging-port=9222"])] + [{:keys [browser-path]}] + (let [options (ChromeOptions.)] (when browser-path (.setBinary options browser-path)) - (.addArguments options (into-array args)) + (.addArguments options (into-array + ["start-maximized" + "disable-infobars" + "--disable-extensions" + "--disable-gpu" + "--disable-dev-shm-usage" + "--no-sandbox" + "--remote-debugging-port=9222"])) (System/setProperty "webdriver.chrome.driver" "/usr/local/bin/chromedriver") (ChromeDriver. options))) diff --git a/development/user.clj b/development/user.clj index 7ac9c166f..3cf5d7931 100644 --- a/development/user.clj +++ b/development/user.clj @@ -4,7 +4,8 @@ (comment ;; Headless mode (no visible browser) (run-cucumber-tests - {:headless true + {:debug? false + :headless true :browser :chrome :features "features" :steps "steps" @@ -18,24 +19,16 @@ :browser :chrome :url "http://localhost:8081/worksheets"}) - - ) -#_(run-cucumber-tests {:debug? true - :features "./../../features" - :steps "./../../steps" - :browser :chrome - :browser-path "/usr/bin/google-chrome" - :url "http://localhost:8081/worksheets"}) - (comment - (require '[behave.server :as server] - '[behave.handlers :refer [vms-sync!]] - '[config.interface :refer [get-config load-config]]) + (do + (require '[behave.server :as server] + '[behave.handlers :refer [vms-sync!]] + '[config.interface :refer [get-config load-config]]) - (server/init-config!) - (server/init-db! (get-config :database :config)) + (server/init-config!) + (server/init-db! (get-config :database :config))) (vms-sync!) diff --git a/steps/Given.clj b/steps/Given.clj index 188dfe9c9..759a7e15c 100644 --- a/steps/Given.clj +++ b/steps/Given.clj @@ -20,41 +20,35 @@ (w/execute-script! driver "window.location.href = window.location.href") (w/goto driver url)) - ;; Wait for Working Area component to load (let [wait (w/wait driver 5000)] (.until wait (w/presence-of (by/css ".working-area")))) - ;; Click New Run button (-> (e/find-el driver (by/attr= :text "New Run")) (e/click!)) - (Thread/sleep 500) + (Thread/sleep 100) - ;; Click Next button (-> (e/find-el driver (by/css ".button--highlight")) (e/click!)) - (Thread/sleep 500) + (Thread/sleep 100) - ;; Click "Open using Guided workflow" button (-> (e/find-el driver (by/attr= :text "Open using Guided Workflow")) (e/click!)) - (Thread/sleep 500) + (Thread/sleep 100) - ;; Click Next button (-> (e/find-el driver (by/css ".button--highlight")) (e/click!)) - (Thread/sleep 500) - ;; Select Surface Only worksheet + (Thread/sleep 100) + (-> (e/find-el driver (by/attr= :text (get worksheet-modules (or modules [:surface])))) (e/click!)) (let [el (e/find-el driver (by/css ".button--highlight"))] (w/execute-script! driver "arguments[0].scrollIntoView(true)" el)) - ;; Click Next button (-> (e/find-el driver (by/css ".button--highlight")) (e/click!)) From a37d97323cd5dcd71667132997e1ffb65ec84239 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Wed, 22 Oct 2025 16:35:55 -0400 Subject: [PATCH 04/67] update feature name --- development/user.clj | 12 +----------- features/surface_only.feature | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/development/user.clj b/development/user.clj index 3cf5d7931..50110b052 100644 --- a/development/user.clj +++ b/development/user.clj @@ -2,18 +2,8 @@ (:require [cucumber.runner :refer [run-cucumber-tests]])) (comment - ;; Headless mode (no visible browser) (run-cucumber-tests - {:debug? false - :headless true - :browser :chrome - :features "features" - :steps "steps" - :url "http://localhost:8081/worksheets"}) - - ;; Normal mode (visible browser) - (run-cucumber-tests - {:debug? true + {:debug? false :features "features" :steps "steps" :browser :chrome diff --git a/features/surface_only.feature b/features/surface_only.feature index 9c34e31d7..8516bf997 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -1,4 +1,4 @@ -Feature: Surface Only Worksheets +Feature: Surface Only Output Selection Conditionals As a user when I create a new worksheet and have Selected Surface Only in the Module Selection Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available to me in the inputs page. From afa0b6df0fbc384a27678b1a0423c78f5226a048 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Wed, 22 Oct 2025 16:41:01 -0400 Subject: [PATCH 05/67] add comments back in --- components/cucumber/src/cucumber/webdriver.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/cucumber/src/cucumber/webdriver.clj b/components/cucumber/src/cucumber/webdriver.clj index 97025ba0b..474d46b94 100644 --- a/components/cucumber/src/cucumber/webdriver.clj +++ b/components/cucumber/src/cucumber/webdriver.clj @@ -72,12 +72,12 @@ (let [options (ChromeOptions.)] (when browser-path (.setBinary options browser-path)) (.addArguments options (into-array - ["start-maximized" - "disable-infobars" - "--disable-extensions" - "--disable-gpu" - "--disable-dev-shm-usage" - "--no-sandbox" + ["start-maximized" ; // open Browser in maximized mode + "disable-infobars" ; // disabling infobars + "--disable-extensions" ; // disabling extensions + "--disable-gpu" ; // applicable to windows os only + "--disable-dev-shm-usage" ; // overcome limited resource problems + "--no-sandbox" ; // Bypass OS security model "--remote-debugging-port=9222"])) (System/setProperty "webdriver.chrome.driver" "/usr/local/bin/chromedriver") (ChromeDriver. options))) From df56d3726f55096438264ecf4abed544e158dcf2 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Thu, 23 Oct 2025 12:07:00 -0400 Subject: [PATCH 06/67] rename scenarios --- features/surface_only.feature | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/features/surface_only.feature b/features/surface_only.feature index 8516bf997..ac3da96e2 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -2,7 +2,7 @@ Feature: Surface Only Output Selection Conditionals As a user when I create a new worksheet and have Selected Surface Only in the Module Selection Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available to me in the inputs page. - Scenario: Fire Behavior Output Selected + Scenario: Heading Rate of Spread is Selected Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ @@ -20,7 +20,7 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo # - Wind and Slope > Wind measured at: @kenny this fails because Wind measured at: has a # - trailing space in the dom and (extract-submodule-groups) trims this. - Scenario: Size Submodule Outputs Selected + Scenario: Fire Area is Selected Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: """ @@ -30,6 +30,28 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo """ -- Size > Elapsed Time """ + + Scenario: Fire Perimeter is Selected + Given I have started a new Surface Worksheet in Guided Mode + When I select these outputs Submodule > Group > Output: + """ + -- Size > Surface - Fire Size > Fire Perimeter + """ + Then the following input Submodule > Groups are displayed: + """ + -- Size > Elapsed Time + """ + + Scenario: Spread Distance is Selected + Given I have started a new Surface Worksheet in Guided Mode + When I select these outputs Submodule > Group > Output: + """ + -- Size > Surface - Fire Size > Spread Distance + """ + Then the following input Submodule > Groups are displayed: + """ + -- Size > Elapsed Time + """ # Scenario: Length-to-Width Output Selected # Given I have started a Surface & Mortality Worksheet in Guided Mode From c4e8aa068d368368df28c6df6248991c980cf818 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Thu, 23 Oct 2025 12:10:20 -0400 Subject: [PATCH 07/67] fix format --- features/surface_only.feature | 686 ++++++++++++++++------------------ 1 file changed, 330 insertions(+), 356 deletions(-) diff --git a/features/surface_only.feature b/features/surface_only.feature index ac3da96e2..8e1734f63 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -1,6 +1,8 @@ Feature: Surface Only Output Selection Conditionals - -As a user when I create a new worksheet and have Selected Surface Only in the Module Selection Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available to me in the inputs page. + + As a user when I create a new worksheet and have Selected Surface Only in the Module Selection + Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available + to me in the inputs page. Scenario: Heading Rate of Spread is Selected Given I have started a new Surface Worksheet in Guided Mode @@ -19,7 +21,7 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo # - Wind and Slope > Wind measured at: @kenny this fails because Wind measured at: has a # - trailing space in the dom and (extract-submodule-groups) trims this. - + Scenario: Fire Area is Selected Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: @@ -30,7 +32,7 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo """ -- Size > Elapsed Time """ - + Scenario: Fire Perimeter is Selected Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: @@ -53,356 +55,328 @@ As a user when I create a new worksheet and have Selected Surface Only in the Mo -- Size > Elapsed Time """ - # Scenario: Length-to-Width Output Selected - # Given I have started a Surface & Mortality Worksheet in Guided Mode - # When I select the output "Length-to-Width Ratio" in the "Size" submodule - # Then the following input Submodule > Groups are displayed: - # """ - # - Fuel Model - # - Fuel Moisture > Moisture Input Mode - # - Wind and Slope > Wind Speed - # - Wind and Slope > Wind and Slope are: - # - Wind and Slope > Slope - # """ - - # Scenario: Size Outputs Selected - # Given I have started a Surface Worksheet in Guided Mode - # When The size outputs below are selected: - # - Size > Fire Area - # - Size > Fire Perimeter - # - Size > Spread Distance - # Then the following input Submodule > Groups are displayed: - # """ - # - Fuel Model - # - Fuel Moisture > Moisture Input Mode - # - Wind and Slope > Wind Speed - # - Wind and Slope > Wind and Slope are: - # - Wind and Slope > Slope - # - Size > Elapsed Time - # """ - - # Scenario: Size Outputs Selected - # Given I have started a Surface Worksheet in Guided Mode - # Then the following outputs are displayed: - # """ - # - Spot -> Burning Pile - # - Spot -> Wind-Driven Surface Fire + # Scenario: Burning Pile is Selected + # Given I have started a new Surface Worksheet in Guided Mode + # Then the following outputs are displayed: + # """ + # - Spot -> Burning Pile + # - Spot -> Wind-Driven Surface Fire # """ - # Then and should be the only two options under Maximum Spotting Distance - - # Given I have started a Surface Worksheet - # When Any outputs are selected, other than Burning Pile - # Then Maximum Spotting Distance: Burning Pile should be deactivated - - # Given I have started a Surface Worksheet - # When Burning Pile is selected from Maximum Spotting Distance - # Then All other outputs should be deactivated and the ONLY inputs should - # be: - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Downwind Canopy Cover - # - Downwind Canopy Height - # - Flame Height (from a Burning Bile) - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - - # Given I have started a Surface Worksheet - # When Fire Behavior or Size is selected with Wind-Driven Surface Fire - # from Spot - # Then Fuel Model should be replaced with Wind Driven Fuel Models which - # only contain grass fuel models - - # Given I have started a Surface Worksheet - # When Fire Behavior or Size is selected with Wind-Driven Surface Fire - # from Spot - # Then Surface Fire Flame Length should come from Surface and should not - # be an input - - # Given I have started a Surface Worksheet - # When When Wind-Drive Surface fire is not run with Fire Behavior - # Then Only the inputs below are required - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Downwind Canopy Cover - # - Downwind Canopy Height - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Surface Fire Flame Length* - - # Given I have started a Surface Worksheet - # When 0 is entered into Ridge-to-Valley Elevation Difference - # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location - # should not be available inputs - - # Given I have started a Surface Worksheet - # When A value greater than 0 is entered into Ridge-to-Valley Elevation - # Difference - # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location - # should be required inputs - - # Given I have started a Surface Worksheet - # When Direction of Interest is selected from Direction Mode - # Then The Wind/Slope/Spread Diagram should be automatically output on - # the Run Results - - # Given I have started a Surface Worksheet - # When Direction of Interest is selected from Direction Mode - # Then The Direction of Spread should be automatically output on the Run - # Results. The Direction of Spread should be consisted with the Direction - # Mode selected (Heading or Heading Flanking Backing) - - # Given I have started a Surface Worksheet - # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not - # aligned - # Then The Wind/Slope/Spread Diagram should be automatically output on - # the Run Results - - # Given I have started a Surface Worksheet - # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not - # aligned - # Then The Direction of Spread should be automatically ouput on the Run - # Results. The Direction of Spread should be consisted with the Direction - # Mode selected (Heading or Heading Flanking Backing) - - # Given I have started a Surface Worksheet - # When Maximum Spotting DIstance from a Burning Pile is run - # Then Firebrand Height from a Burning Pile should be automatically - # output - # * Surface and Crown - - # Given I have started a Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Heading should be automatically run for Direction Mode. *It should not be automatically selected because the user may not run Fire Behavior.* - - # Given I have started a Surface and Crown Worksheet - # When Any output is selected, other than a Spot model - # Then Fire Type should be automatically selected as an output but it - # should not shown on the worksheet - - # Given I have started a Surface and Crown Worksheet - # When Fire behavior has a selected output (RoS, FL, or FI) - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - Wind and Slope are: - # - Slope - # - Calculations Options - # - Fuel Moisture - # - Foliar Moisture - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a Surface and Crown Worksheet - # When Length-to-Width Ratio output in the Size submodule is selected - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Fuel Moisture - # - Foliar Moisture - # - Calculations Options - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a Surface and Crown Worksheet - # When Any Fire Type output are selected - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Fuel Moisture - # - Foliar Moisture - # - Calculations Options - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a Surface and Crown Worksheet - # When The size outputs below are selected: - # - Fire Area - # - Fire Perimeter - # - Spread Distance - # - (**Exclude Length-to-Width Ratio) - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Wind Speed - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Size - # - Elapsed Time - - # Given I have started a Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Only Torching Trees and Active Crown fire should be available options under Maximum Spotting Distance - - # Given I have started a Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Torching Tree and Active Crown fire should be able to both be run under Maximum Spotting Distance - - # Given I have started a Surface and Crown Worksheet - # When Active Crown Fire is selected as an out, *WITHOUT Fire Behavior* - # Then The inputs below are required - # - Canopy Fuel - # - Canopy Height - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Active Crown Fire Flame Length* - - # Given I have started a Surface and Crown Worksheet - # When Active Crown Fire is selected as an output with Fire Behavior - # Then The inputs below are required - # - Canopy Fuel - # - Canopy Height - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Active Crown Fire Flame Length* - - # Given I have started a Surface and Crown Worksheet - # When Fire Behavior or Size is selected with Active Crown Fire from Spot - # Then Active Crown Fire Flame Length should come from Crown and should not be an input - # * Surface and Contain - - # Given I have started a Surface and Contain Worksheet - # Then Spot should not be on worksheet - - # Given I have started a Surface and Contain Worksheet - # Then Surface Fire Behavior and Size conditionals should be treated the same as Surface being run alone - - # Given I have started a Surface and Contain Worksheet - # Then Heading in Fire Behavior's Direction Mode should be the only option available. Heading, Backing, and Flanking, and DIrection of Interest should be deactivated - # * Surface and Mortality - - # Given I have started a Surface and Mortality Worksheet - # Then Heading and Heading Flanking, Backing in Fire Behavior's Direction Mode should be the only options available. - # And: Direction of Interest should be deactivated - - # Given I have started a Surface and Mortality Worksheet - # Then There should be no Size output module - # And: There should be no Size input submodules - - # Given I have started a Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a Surface and Mortality Worksheet - # Then Flame Length is needed to calculate PoM so Surface Fire Behavior conditionals should be used to calculate Flame Length - - # Given I have started a Surface and Mortality Worksheet - # Then PoM equation used should be based on the Mortality tree species used, see [[https://sig-gis.atlassian.net/browse/BHP1-839?atlOrigin=eyJpIjoiZTdjZDg4MDNhYTBlNDE2NDljZTRhZTEzNThlNDI5NzgiLCJwIjoiaiJ9][BHP1-839]] - - # Given I have started a Surface and Mortality Worksheet - # Then DBH and Mortality Tree species are both required user inputs, regardless of PoM equation - - # Given I have started a Surface and Mortality Worksheet - # Then Probability of Mortality is automatically calculated - - # Given I have started a Surface and Mortality Worksheet - # Then Mortality Outputs should match the format in [[https://sig-gis.atlassian.net/browse/BHP1-926?atlOrigin=eyJpIjoiYTQwNWFjMmExZDE5NGNjYWI3NDYxNTNjY2MwMmIwMTAiLCJwIjoiaiJ9][ticket]] and [[https://usfs.box.com/s/u6uknqwzt751top5awzn0am4u4s8dkj3][table]] - - # Given I have started a Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then The user inputs below are required - # - Air Temp - # - MidFlame Windspeed or (20ft or 10m x WAF = Midflame Windspeed) - # - Canopy Height - # - Crown Ratio - - # Given I have started a Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then The calculated Flame Length needs to be used to calculate Scorch Height - - # Given I have started a Surface and Crown Worksheet - # When The PoM equation used is Bark Char - # Then The calculated Flame Length is used to calculate Bark Char Height, Flame Length/1.8 - - # Given I have started a Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then Automated outputs that should be calculated including: - # - Crown Length Scorched - # - Crown Volume Scorched - # - Scorch Height - - # Given I have started a Surface and Crown Worksheet - # When The PoM equation used is Bark Char - # Then Bark Char Height is an automated output that should be calculated include + # Then and should be the only two options under Maximum Spotting Distance + + # Given I have started a new Surface Worksheet + # When Any outputs are selected, other than Burning Pile + # Then Maximum Spotting Distance: Burning Pile should be deactivated + + # Given I have started a new Surface Worksheet + # When Burning Pile is selected from Maximum Spotting Distance + # Then All other outputs should be deactivated and the ONLY inputs should + # be: + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Downwind Canopy Cover + # - Downwind Canopy Height + # - Flame Height (from a Burning Bile) + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + + # Given I have started a new Surface Worksheet + # When Fire Behavior or Size is selected with Wind-Driven Surface Fire + # from Spot + # Then Fuel Model should be replaced with Wind Driven Fuel Models which + # only contain grass fuel models + + # Given I have started a new Surface Worksheet + # When Fire Behavior or Size is selected with Wind-Driven Surface Fire + # from Spot + # Then Surface Fire Flame Length should come from Surface and should not + # be an input + + # Given I have started a new Surface Worksheet + # When When Wind-Drive Surface fire is not run with Fire Behavior + # Then Only the inputs below are required + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Downwind Canopy Cover + # - Downwind Canopy Height + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Surface Fire Flame Length* + + # Given I have started a new Surface Worksheet + # When 0 is entered into Ridge-to-Valley Elevation Difference + # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location + # should not be available inputs + + # Given I have started a new Surface Worksheet + # When A value greater than 0 is entered into Ridge-to-Valley Elevation + # Difference + # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location + # should be required inputs + + # Given I have started a new Surface Worksheet + # When Direction of Interest is selected from Direction Mode + # Then The Wind/Slope/Spread Diagram should be automatically output on + # the Run Results + + # Given I have started a new Surface Worksheet + # When Direction of Interest is selected from Direction Mode + # Then The Direction of Spread should be automatically output on the Run + # Results. The Direction of Spread should be consisted with the Direction + # Mode selected (Heading or Heading Flanking Backing) + + # Given I have started a new Surface Worksheet + # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not + # aligned + # Then The Wind/Slope/Spread Diagram should be automatically output on + # the Run Results + + # Given I have started a new Surface Worksheet + # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not + # aligned + # Then The Direction of Spread should be automatically ouput on the Run + # Results. The Direction of Spread should be consisted with the Direction + # Mode selected (Heading or Heading Flanking Backing) + + # Given I have started a new Surface Worksheet + # When Maximum Spotting DIstance from a Burning Pile is run + # Then Firebrand Height from a Burning Pile should be automatically + # output + # * Surface and Crown + + # Given I have started a new Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Heading should be automatically run for Direction Mode. *It should not be automatically selected because the user may not run Fire Behavior.* + + # Given I have started a new Surface and Crown Worksheet + # When Any output is selected, other than a Spot model + # Then Fire Type should be automatically selected as an output but it + # should not shown on the worksheet + + # Given I have started a new Surface and Crown Worksheet + # When Fire behavior has a selected output (RoS, FL, or FI) + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - Wind and Slope are: + # - Slope + # - Calculations Options + # - Fuel Moisture + # - Foliar Moisture + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a new Surface and Crown Worksheet + # When Length-to-Width Ratio output in the Size submodule is selected + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Fuel Moisture + # - Foliar Moisture + # - Calculations Options + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a new Surface and Crown Worksheet + # When Any Fire Type output are selected + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot autoselected + # - Wind Speed + # - WAF + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Fuel Moisture + # - Foliar Moisture + # - Calculations Options + # - Canopy Fuel + # - Canopy Base Height + # - Canopy Bulk Density + # - Canopy Height + + # Given I have started a new Surface and Crown Worksheet + # When The size outputs below are selected: + # - Fire Area + # - Fire Perimeter + # - Spread Distance + # - (**Exclude Length-to-Width Ratio) + # Then The following Submodules w/inputs are the ONLY required inputs + # - Fuel Model + # - Fuel Moisture + # - Moisture Input Mode + # - Appropriate Moisture Inputs + # - Wind and Slope + # - Wind Measured at: + # - Wind Speed + # - WAF(if applicable) + # - Wind and Slope are: + # - Slope + # - Size + # - Elapsed Time + + # Given I have started a new Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Only Torching Trees and Active Crown fire should be available options under Maximum Spotting Distance + + # Given I have started a new Surface and Crown Worksheet + # When Surface and Crown are run together + # Then Torching Tree and Active Crown fire should be able to both be run under Maximum Spotting Distance + + # Given I have started a new Surface and Crown Worksheet + # When Active Crown Fire is selected as an out, *WITHOUT Fire Behavior* + # Then The inputs below are required + # - Canopy Fuel + # - Canopy Height + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Active Crown Fire Flame Length* + + # Given I have started a new Surface and Crown Worksheet + # When Active Crown Fire is selected as an output with Fire Behavior + # Then The inputs below are required + # - Canopy Fuel + # - Canopy Height + # - Wind and Slope + # - Wind Measured at: + # - Midflame should be deactivate and 20-Foot auto-selected + # - Wind Speed + # - *No WAF* + # - *No Wind and Slope are* + # - *No Slope* + # - Spot + # - Topography + # - Ridge-to-Valley Elevation Difference + # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation + # Difference) + # - Spotting Source Location (Dependent on Elevation Difference) + # - *Active Crown Fire Flame Length* + + # Given I have started a new Surface and Crown Worksheet + # When Fire Behavior or Size is selected with Active Crown Fire from Spot + # Then Active Crown Fire Flame Length should come from Crown and should not be an input + # * Surface and Contain + + # Given I have started a new Surface and Contain Worksheet + # Then Spot should not be on worksheet + + # Given I have started a new Surface and Contain Worksheet + # Then Surface Fire Behavior and Size conditionals should be treated the same as Surface being run alone + + # Given I have started a new Surface and Contain Worksheet + # Then Heading in Fire Behavior's Direction Mode should be the only option available. Heading, Backing, and Flanking, and DIrection of Interest should be deactivated + # * Surface and Mortality + + # Given I have started a new Surface and Mortality Worksheet + # Then Heading and Heading Flanking, Backing in Fire Behavior's Direction Mode should be the only options available. + # And: Direction of Interest should be deactivated + + # Given I have started a new Surface and Mortality Worksheet + # Then There should be no Size output module + # And: There should be no Size input submodules + + # Given I have started a new Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a new Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a new Surface and Mortality Worksheet + # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation + + # Given I have started a new Surface and Mortality Worksheet + # Then Flame Length is needed to calculate PoM so Surface Fire Behavior conditionals should be used to calculate Flame Length + + # Given I have started a new Surface and Mortality Worksheet + # Then PoM equation used should be based on the Mortality tree species used, see [[https://sig-gis.atlassian.net/browse/BHP1-839?atlOrigin=eyJpIjoiZTdjZDg4MDNhYTBlNDE2NDljZTRhZTEzNThlNDI5NzgiLCJwIjoiaiJ9][BHP1-839]] + + # Given I have started a new Surface and Mortality Worksheet + # Then DBH and Mortality Tree species are both required user inputs, regardless of PoM equation + + # Given I have started a new Surface and Mortality Worksheet + # Then Probability of Mortality is automatically calculated + + # Given I have started a new Surface and Mortality Worksheet + # Then Mortality Outputs should match the format in [[https://sig-gis.atlassian.net/browse/BHP1-926?atlOrigin=eyJpIjoiYTQwNWFjMmExZDE5NGNjYWI3NDYxNTNjY2MwMmIwMTAiLCJwIjoiaiJ9][ticket]] and [[https://usfs.box.com/s/u6uknqwzt751top5awzn0am4u4s8dkj3][table]] + + # Given I have started a new Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then The user inputs below are required + # - Air Temp + # - MidFlame Windspeed or (20ft or 10m x WAF = Midflame Windspeed) + # - Canopy Height + # - Crown Ratio + + # Given I have started a new Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then The calculated Flame Length needs to be used to calculate Scorch Height + + # Given I have started a new Surface and Crown Worksheet + # When The PoM equation used is Bark Char + # Then The calculated Flame Length is used to calculate Bark Char Height, Flame Length/1.8 + + # Given I have started a new Surface and Crown Worksheet + # When The PoM equation used is Crown Scorch + # Then Automated outputs that should be calculated including: + # - Crown Length Scorched + # - Crown Volume Scorched + # - Scorch Height + + # Given I have started a new Surface and Crown Worksheet + # When The PoM equation used is Bark Char + # Then Bark Char Height is an automated output that should be calculated include From 4c0c0aab8294b653981cfc74aaeba71516880388 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Thu, 23 Oct 2025 15:47:28 -0400 Subject: [PATCH 08/67] refactor --- deps.edn | 50 +++--- features/surface_only.feature | 4 - steps/Given.clj | 70 ++------ steps/Then.clj | 65 ++------ steps/When.clj | 78 ++------- steps/helpers.clj | 289 ++++++++++++++++++++++++++++++++++ steps/inputs.clj | 72 +++++++++ steps/outputs.clj | 66 ++++++++ steps/worksheet.clj | 89 +++++++++++ 9 files changed, 581 insertions(+), 202 deletions(-) create mode 100644 steps/helpers.clj create mode 100644 steps/inputs.clj create mode 100644 steps/outputs.clj create mode 100644 steps/worksheet.clj diff --git a/deps.edn b/deps.edn index 31d284008..291430949 100644 --- a/deps.edn +++ b/deps.edn @@ -37,7 +37,6 @@ "bases/datomic_store/src" "bases/datom_store/src"] - :extra-deps {;; Clojure Deps bk/ring-gzip {:mvn/version "0.3.0"} clj-http/clj-http {:mvn/version "3.10.1"} @@ -76,31 +75,34 @@ org.clojure/data.csv {:mvn/version "1.0.0"} ;; Clojure/Script Deps - com.bhauman/figwheel-main {:mvn/version "0.2.18"} - org.clojure/clojurescript {:mvn/version "1.11.54"} - org.clojure/core.async {:mvn/version "1.2.603"} - binaryage/devtools {:mvn/version "1.0.5"} - re-frisk/re-frisk {:mvn/version "1.6.0"} - com.cognitect/transit-cljs {:mvn/version "0.8.264"} - re-frame/re-frame {:mvn/version "1.3.0-rc3"} - day8.re-frame/http-fx {:mvn/version "0.2.4"} - re-posh/re-posh {:mvn/version "0.3.3"} - reagent/reagent {:mvn/version "0.10.0"} - re-frame-utils/re-frame-utils {:mvn/version "0.1.0"} - cljsjs/vega {:mvn/version "5.25.0-0"} - cljsjs/vega-embed {:mvn/version "6.22.2-0"} - cljsjs/vega-lite {:mvn/version "5.14.1-0"} - day8.re-frame/test {:mvn/version "0.1.5"} - austinbirch/reactive-entity {:mvn/version "0.2.0"} + com.bhauman/figwheel-main {:mvn/version "0.2.18"} + org.clojure/clojurescript {:mvn/version "1.11.54"} + org.clojure/core.async {:mvn/version "1.2.603"} + binaryage/devtools {:mvn/version "1.0.5"} + re-frisk/re-frisk {:mvn/version "1.6.0"} + com.cognitect/transit-cljs {:mvn/version "0.8.264"} + re-frame/re-frame {:mvn/version "1.3.0-rc3"} + day8.re-frame/http-fx {:mvn/version "0.2.4"} + re-posh/re-posh {:mvn/version "0.3.3"} + reagent/reagent {:mvn/version "0.10.0"} + re-frame-utils/re-frame-utils {:mvn/version "0.1.0"} + cljsjs/vega {:mvn/version "5.25.0-0"} + cljsjs/vega-embed {:mvn/version "6.22.2-0"} + cljsjs/vega-lite {:mvn/version "5.14.1-0"} + day8.re-frame/test {:mvn/version "0.1.5"} + austinbirch/reactive-entity {:mvn/version "0.2.0"} ;; Behave CMS - applied-science/js-interop {:mvn/version "0.3.3"} - com.draines/postal {:mvn/version "2.0.3"} - garden/garden {:mvn/version "1.3.10"} - herb/herb {:mvn/version "0.10.0"} - hickory/hickory {:mvn/version "0.7.1"} - markdown-clj/markdown-clj {:mvn/version "1.11.1"} - org.clojure/tools.cli {:mvn/version "1.0.194"}} + applied-science/js-interop {:mvn/version "0.3.3"} + com.draines/postal {:mvn/version "2.0.3"} + garden/garden {:mvn/version "1.3.10"} + herb/herb {:mvn/version "0.10.0"} + hickory/hickory {:mvn/version "0.7.1"} + markdown-clj/markdown-clj {:mvn/version "1.11.1"} + org.clojure/tools.cli {:mvn/version "1.0.194"} + + ;; Testing + org.seleniumhq.selenium/selenium-java {:mvn/version "4.23.0"}} :jvm-opts ["--add-exports=java.base/java.lang=ALL-UNNAMED" "--add-exports=java.desktop/sun.awt=ALL-UNNAMED" diff --git a/features/surface_only.feature b/features/surface_only.feature index 8e1734f63..f5fa4a77b 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -1,9 +1,5 @@ Feature: Surface Only Output Selection Conditionals - As a user when I create a new worksheet and have Selected Surface Only in the Module Selection - Page and I've chosen certain outputs in the outputs page I expect certain inputs to be available - to me in the inputs page. - Scenario: Heading Rate of Spread is Selected Given I have started a new Surface Worksheet in Guided Mode When I select these outputs Submodule > Group > Output: diff --git a/steps/Given.clj b/steps/Given.clj index 759a7e15c..53b1df4ae 100644 --- a/steps/Given.clj +++ b/steps/Given.clj @@ -1,66 +1,18 @@ (ns Given - (:require - [cucumber.by :as by] - [cucumber.element :as e] - [cucumber.steps :refer [Given]] - [cucumber.webdriver :as w])) - -(def ^:private worksheet-modules - {[:surface] "Surface Only" - [:surface :contain] "Surface and Contain" - [:surface :crown] "Surface & Crown" - [:surface :mortality] "Surface and Mortality" - [:mortality] "Mortality Only"}) - -(defn- select-new-worksheet-in-guided - [modules {:keys [driver url]}] - (w/maximize driver) - - (if (= "https://behave-dev.sig-gis.com" (w/execute-script! driver "window.location.href")) - (w/execute-script! driver "window.location.href = window.location.href") - (w/goto driver url)) - - (let [wait (w/wait driver 5000)] - (.until wait (w/presence-of (by/css ".working-area")))) - - (-> (e/find-el driver (by/attr= :text "New Run")) - (e/click!)) - - (Thread/sleep 100) - - (-> (e/find-el driver (by/css ".button--highlight")) - (e/click!)) - - (Thread/sleep 100) - - (-> (e/find-el driver (by/attr= :text "Open using Guided Workflow")) - (e/click!)) - - (Thread/sleep 100) - - (-> (e/find-el driver (by/css ".button--highlight")) - (e/click!)) - - (Thread/sleep 100) - - (-> (e/find-el driver (by/attr= :text (get worksheet-modules (or modules [:surface])))) - (e/click!)) - - (let [el (e/find-el driver (by/css ".button--highlight"))] - (w/execute-script! driver "arguments[0].scrollIntoView(true)" el)) - - (-> (e/find-el driver (by/css ".button--highlight")) - (e/click!)) - - (w/execute-script! driver "window.scrollTo(0,0)") - {:driver driver}) + (:require [cucumber.steps :refer [Given]] + [steps.worksheet :as ws])) (Given "I have started a new Surface Worksheet in Guided Mode" - (partial select-new-worksheet-in-guided [:surface])) + (partial ws/start-worksheet [:surface])) (Given "I have started a new Surface & Mortality Worksheet in Guided Mode" - (partial select-new-worksheet-in-guided [:surface :mortality])) + (partial ws/start-worksheet [:surface :mortality])) + +(Given "I have started a new Surface & Crown Worksheet in Guided Mode" + (partial ws/start-worksheet [:surface :crown])) -(Given "I have started a new Surface & Crown Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :crown])) -(Given "I have started a new Surface & Contain Worksheet in Guided Mode" (partial select-new-worksheet-in-guided [:surface :contain])) +(Given "I have started a new Surface & Contain Worksheet in Guided Mode" + (partial ws/start-worksheet [:surface :contain])) +(Given "I have started a new Mortality Only Worksheet in Guided Mode" + (partial ws/start-worksheet [:mortality])) diff --git a/steps/Then.clj b/steps/Then.clj index b3fea72f3..615871fa1 100644 --- a/steps/Then.clj +++ b/steps/Then.clj @@ -1,58 +1,17 @@ (ns Then - (:require - [clojure.string :as str] - [cucumber.element :as e] - [cucumber.by :as by] - [cucumber.webdriver :as w] - [cucumber.steps :refer [Then]])) - -(defn- extract-submodule-groups - [submodule-groups] - (-> submodule-groups - (str/replace "\"\"\"" "") - (str/split #"-- ") - (->> (map str/trim) - (remove empty?) - (map #(str/split % #" > "))))) - -(defn- select-submodule [driver submodule] - (-> (e/find-el driver (by/css ".wizard")) - (e/find-el (by/attr= :text submodule)) - (e/click!))) - -(defn- navigate-to-inputs [driver] - (-> (e/find-el driver (by/css ".wizard-header__io-tabs")) - (e/find-el (by/attr= :text "Inputs")) - (e/click!))) - -(defn- group-exits? [driver [submodule & groups]] - (select-submodule driver submodule) - (doall - (map #(let [wait (w/wait driver 300)] - (.until wait (w/presence-of-nested-elements - (by/css ".wizard-page__body") - (by/attr= :text %)))) - groups))) + (:require [cucumber.steps :refer [Then]] + [cucumber.by :as by] + [steps.helpers :as h] + [steps.inputs :as inputs])) (Then "(?m)the following input Submodule > Groups are displayed: {submodule-groups}" - (fn [{:keys [driver]} submodule-groups] - (navigate-to-inputs driver) - (let [wait (w/wait driver 5000)] - (.until wait (w/presence-of (by/css ".wizard-page__body")))) - (let [submodule-groups (extract-submodule-groups submodule-groups)] - ;; incorrect-groups (filter (fn [[_submodule group]] (= "Slope" group)) submodule-groups)] - (doall (map (partial group-exits? driver) submodule-groups)) - (assert (pos? (count submodule-groups)))))) - -(comment - (count incorrect-groups) - (pr-str (map pr-str incorrect-groups))) - + inputs/verify-input-groups) -(comment - (do - (require '[cucumber.runner :as r] - '[cucumber.webdriver :as w]) +(Then "the element with text {string} should be visible" + (fn [{:keys [driver]} text] + (h/wait-for-nested-element driver (by/css "body") text 5000) + {:driver driver})) - (let [d r/driver-atom] - (e/find-el @d (by/attr= :text "Wind measured at: "))))) +(Then "the {string} tab should be active" + (fn [{:keys [driver]} tab-name] + {:driver driver})) diff --git a/steps/When.clj b/steps/When.clj index 76ab6e75c..3ebcd9a12 100644 --- a/steps/When.clj +++ b/steps/When.clj @@ -1,63 +1,17 @@ (ns When - (:require - [cucumber.by :as by] - [cucumber.element :as e] - [cucumber.steps :refer [When]] - [clojure.string :as str] - [cucumber.runner :as r] - [cucumber.webdriver :as w])) - -(defn- extract-submodule-groups - [submodule-groups] - (-> submodule-groups - (str/replace "\"\"\"" "") - (str/split #"-- ") - (->> (map str/trim) - (remove empty?) - (map #(str/split % #" > "))))) - -(defn- select-submodule [driver submodule] - (-> (e/find-el driver (by/css ".wizard-header__submodules")) - (e/find-el (by/attr= :text submodule)) - (e/click!))) - -(defn- find-groups [driver groups] - (doseq [group groups] - (let [wait (w/wait driver 300)] - (.until wait (w/presence-of-nested-elements - (by/css ".wizard-group__header") - (by/attr= :text group)))))) - -(defn- select-output [driver output] - (-> (e/find-el driver (by/css ".wizard-group__outputs")) - (e/find-el (by/attr= :text output)) - (e/click!))) - -(defn- select-submodule-and-output [driver [submodule & groups]] - (select-submodule driver submodule) - (find-groups driver (butlast groups)) - (select-output driver (last groups))) - -(defn- select-submodule-and-outputs - [{:keys [driver]} submodule-groups] - (let [wait (w/wait driver 5000)] - (.until wait (w/presence-of (by/css ".wizard")))) - (let [submodule-groups (extract-submodule-groups submodule-groups)] - (doseq [output submodule-groups] - (select-submodule-and-output driver output)) - {:driver driver})) - -(When "I select these outputs Submodule > Group > Output: {outputs}" select-submodule-and-outputs) - -(comment - (do - (require '[cucumber.runner :as r] - '[cucumber.webdriver :as w]) - - (let [d r/driver-atom] - (select-submodule @d "Fire Behavior")) - - (let [d r/driver-atom] - (select-submodule-and-output - @d - ["Fire Behavior" "Direction Mode" "Heading"])))) + (:require [cucumber.steps :refer [When]] + [steps.helpers :as h] + [steps.outputs :as outputs])) + +(When "I select these outputs Submodule > Group > Output: {outputs}" + outputs/select-outputs) + +(When "I navigate to the {string} tab" + (fn [{:keys [driver]} tab-name] + (h/navigate-to-tab driver tab-name) + {:driver driver})) + +(When "I click {string}" + (fn [{:keys [driver]} button-text] + (h/click-button-with-text driver button-text) + {:driver driver})) diff --git a/steps/helpers.clj b/steps/helpers.clj new file mode 100644 index 000000000..9ecc45cbc --- /dev/null +++ b/steps/helpers.clj @@ -0,0 +1,289 @@ +(ns steps.helpers + "Shared utility functions for Cucumber step definitions. + + This namespace provides reusable helper functions for common operations + in BDD tests including navigation, element selection, waiting, and parsing." + (:require [cucumber.by :as by] + [cucumber.element :as e] + [cucumber.webdriver :as w] + [clojure.string :as str])) + +;;; ============================================================================= +;;; Parsing Utilities +;;; ============================================================================= + +(defn parse-multiline-list + "Parse triple-quoted multiline list into vector of vectors. + + Converts Gherkin multiline strings into structured data for processing. + + Example: + Input: \"\"\" + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Surface Fire > Rate of Spread + \"\"\" + Output: [[\"Fire Behavior\" \"Direction Mode\" \"Heading\"] + [\"Fire Behavior\" \"Surface Fire\" \"Rate of Spread\"]]" + [text] + (-> text + (str/replace "\"\"\"" "") + (str/split #"-- ") + (->> (map str/trim) + (remove empty?) + (map #(str/split % #" > "))))) + +;;; ============================================================================= +;;; Element Finding +;;; ============================================================================= + +(defn selector->by + "Convert a selector map to a Selenium By object. + + This function provides the bridge between our map-based selector API + and Selenium's By objects for use in WebDriverWait conditions. + + Selector Types: + - :id - Find by element ID + - :css - Find by CSS selector + - :xpath - Find by XPath expression + - :tag - Find by tag name + - :class - Find by class name + - :text - Find by exact text content + - :name - Find by name attribute + + Args: + selector - Map with a single selector key/value pair + + Returns: + Selenium By object + + Throws: + ExceptionInfo if selector type is unknown + + Examples: + (selector->by {:id \"submit-button\"}) ; => By.id(\"submit-button\") + (selector->by {:css \".wizard-header\"}) ; => By.cssSelector(\".wizard-header\") + (selector->by {:text \"New Run\"}) ; => By with xpath for text + (selector->by {:tag :div}) ; => By.tagName(\"div\")" + [selector] + (cond + (:id selector) (by/id (:id selector)) + (:css selector) (by/css (:css selector)) + (:xpath selector) (by/xpath (:xpath selector)) + (:tag selector) (by/tag-name (name (:tag selector))) + (:class selector) (by/class-name (:class selector)) + (:text selector) (by/attr= :text (:text selector)) + (:name selector) (by/input-name (:name selector)) + :else (throw (ex-info "Unknown selector type" {:selector selector})))) + +(defn find-element + "Find an element using various selector strategies. + + This function provides a unified interface for finding elements using + different selector types. It delegates to selector->by for converting + the selector map to a Selenium By object. + + Selector Types: + - :id - Find by element ID + - :css - Find by CSS selector + - :xpath - Find by XPath expression + - :tag - Find by tag name + - :class - Find by class name + - :text - Find by exact text content + - :name - Find by name attribute + + Args: + driver - WebDriver instance + selector - Map with a single selector key/value pair + + Returns: + WebElement if found + + Throws: + NoSuchElementException if element not found + ExceptionInfo if selector type is unknown + + Examples: + (find-element driver {:id \"submit-button\"}) + (find-element driver {:css \".wizard-header\"}) + (find-element driver {:xpath \"//button[text()='Next']\"}) + (find-element driver {:tag :div}) + (find-element driver {:class \"button--highlight\"}) + (find-element driver {:text \"New Run\"}) + (find-element driver {:name \"username\"}) + + See also: + selector->by - For converting selectors to Selenium By objects" + [driver selector] + (e/find-el driver (selector->by selector))) + +;;; ============================================================================= +;;; Navigation +;;; ============================================================================= + +(defn navigate-to-tab + "Navigate to a specific tab in the wizard interface. + + Args: + driver - WebDriver instance + tab-name - Name of the tab (e.g., \"Inputs\", \"Outputs\")" + [driver tab-name] + (-> (find-element driver {:css ".wizard-header__io-tabs"}) + (e/find-el (by/attr= :text tab-name)) + (e/click!))) + +(defn navigate-to-inputs + "Navigate to the Inputs tab in the wizard." + [driver] + (navigate-to-tab driver "Inputs")) + +(defn navigate-to-outputs + "Navigate to the Outputs tab in the wizard." + [driver] + (navigate-to-tab driver "Outputs")) + +;;; ============================================================================= +;;; Submodule Selection +;;; ============================================================================= + +(defn select-submodule + "Select a submodule within a given container. + + Args: + driver - WebDriver instance + submodule - Name of the submodule to select + selector - Selector map (e.g., {:css \".wizard\"})" + [driver submodule selector] + (-> (find-element driver selector) + (e/find-el (by/attr= :text submodule)) + (e/click!))) + +(defn select-submodule-in-wizard + "Select a submodule in the wizard header. + + Used primarily in the Outputs tab for selecting submodules." + [driver submodule] + (select-submodule driver submodule {:css ".wizard-header__submodules"})) + +(defn select-submodule-in-page + "Select a submodule in the wizard page body. + + Used primarily in the Inputs tab for selecting submodules." + [driver submodule] + (select-submodule driver submodule {:css ".wizard"})) + +;;; ============================================================================= +;;; Waiting Utilities +;;; ============================================================================= + +(defn wait-for-wizard + "Wait for the wizard interface to be present (up to 5 seconds)." + [driver] + (let [wait (w/wait driver 5000)] + (.until wait (w/presence-of (selector->by {:css ".wizard"}))))) + +(defn wait-for-working-area + "Wait for the working area to be present (up to 5 seconds)." + [driver] + (let [wait (w/wait driver 5000)] + (.until wait (w/presence-of (selector->by {:css ".working-area"}))))) + +(defn wait-for-nested-element + "Wait for a nested element to appear within a parent element. + + Args: + driver - WebDriver instance + parent-selector - Selector map for parent element (e.g., {:css \".wizard\"}) + text - Text content to search for in child element + timeout-ms - Maximum wait time in milliseconds + + Examples: + (wait-for-nested-element driver {:css \".wizard-group__header\"} \"Fire Behavior\" 300)" + [driver parent-selector text timeout-ms] + (let [wait (w/wait driver timeout-ms)] + (.until wait (w/presence-of-nested-elements + (selector->by parent-selector) + (selector->by {:text text}))))) + +(defn wait-for-groups + "Wait for groups to appear as properly nested elements in hierarchical order. + + This function verifies that groups form a parent-child chain in the DOM. + For example, if groups = [\"Fire Behavior\" \"Direction Mode\" \"Heading\"], + it ensures: + 1. \"Fire Behavior\" exists under .wizard-page__body + 2. \"Direction Mode\" is nested within \"Fire Behavior\" + 3. \"Heading\" is nested within \"Direction Mode\" + + Args: + driver - WebDriver instance + groups - Collection of group names in hierarchical order (parent to child) + + Example: + (wait-for-groups driver [\"parent-a\" \"parent-b\" \"parent-c\" \"last-child\"])" + [driver groups] + (when (seq groups) + (wait-for-nested-element driver + {:css ".wizard-page__body"} + (first groups) + 300) + (doseq [[parent child] (partition 2 1 groups)] + (let [wait (w/wait driver 300)] + (.until wait (w/presence-of-nested-elements + (selector->by {:text parent}) + (selector->by {:text child}))))))) + +;;; ============================================================================= +;;; Output Selection +;;; ============================================================================= + +(defn select-output + "Select an output in the wizard outputs section. + + Args: + driver - WebDriver instance + output - Name of the output to select" + [driver output] + (-> (find-element driver {:css ".wizard-group__outputs"}) + (find-element {:text output}) + (e/click!))) + +;;; ============================================================================= +;;; Button Operations +;;; ============================================================================= + +(defn click-highlighted-button + "Click the highlighted button in the current view. + + This is typically the primary action button (e.g., Next, Finish)." + [driver] + (-> (find-element driver {:css ".button--highlight"}) + (e/click!))) + +(defn click-button-with-text + "Click a button with specific text content. + + Args: + driver - WebDriver instance + text - Text content of the button to click" + [driver text] + (-> (find-element driver {:text text}) + (e/click!))) + +;;; ============================================================================= +;;; Scrolling +;;; ============================================================================= + +(defn scroll-to-element + "Scroll the page so that the given element is visible. + + Args: + driver - WebDriver instance + element - WebElement to scroll to" + [driver element] + (w/execute-script! driver "arguments[0].scrollIntoView(true)" element)) + +(defn scroll-to-top + "Scroll the page to the top." + [driver] + (w/execute-script! driver "window.scrollTo(0,0)")) diff --git a/steps/inputs.clj b/steps/inputs.clj new file mode 100644 index 000000000..fe8395a33 --- /dev/null +++ b/steps/inputs.clj @@ -0,0 +1,72 @@ +(ns steps.inputs + "Input verification logic for BehavePlus Cucumber tests. + + This namespace handles verifying that expected input groups are displayed + in the Inputs tab of the worksheet wizard." + (:require [cucumber.by :as by] + [steps.helpers :as h])) + +;;; ============================================================================= +;;; Private Helper Functions +;;; ============================================================================= + +(defn- verify-groups-exist + "Verify that all groups exist under a given submodule in the Inputs tab. + + This function: + 1. Selects the submodule in the wizard page + 2. Waits for each group to appear (300ms timeout per group) + 3. Throws an exception if any group is not found + + Args: + driver - WebDriver instance + submodule+groups - Vector where: + - First element is the submodule name + - Remaining elements are group names to verify + + Example: + (verify-groups-exist driver [\"Wind and Slope\" \"Wind measured at\" \"Wind Speed\"])" + [driver [submodule & groups]] + (h/select-submodule-in-page driver submodule) + (h/wait-for-groups driver groups)) + +;;; ============================================================================= +;;; Public API +;;; ============================================================================= + +(defn verify-input-groups + "Verify that expected input groups are displayed in the Inputs tab. + + This is the main entry point for the Then step that verifies inputs. + It navigates to the Inputs tab, parses the expected groups, and verifies + each one is present in the UI. + + Args: + context - Map containing :driver key with WebDriver instance + submodule-groups-text - Multiline string in format: + \"\"\" + -- Submodule > Group1 > Group2 + -- Submodule > Group3 + \"\"\" + + Returns: + Map with :driver key for passing to next step + + Throws: + AssertionError if no groups are specified or any group is not found + + Example: + (verify-input-groups {:driver driver} + \"\"\" + -- Fuel Model > Standard > Fuel Model + -- Fuel Moisture > Moisture Input Mode + \"\"\")" + [{:keys [driver]} submodule-groups-text] + (h/navigate-to-inputs driver) + (h/wait-for-wizard driver) + + (let [submodule-groups (h/parse-multiline-list submodule-groups-text)] + (doseq [sg submodule-groups] + (verify-groups-exist driver sg)) + (assert (pos? (count submodule-groups))) + {:driver driver})) diff --git a/steps/outputs.clj b/steps/outputs.clj new file mode 100644 index 000000000..0a076e32e --- /dev/null +++ b/steps/outputs.clj @@ -0,0 +1,66 @@ +(ns steps.outputs + "Output selection logic for BehavePlus Cucumber tests. + + This namespace handles selecting outputs in the worksheet wizard, + including navigating submodules, waiting for groups, and clicking outputs." + (:require [steps.helpers :as h])) + +;;; ============================================================================= +;;; Private Helper Functions +;;; ============================================================================= + +(defn- select-single-output + "Select a single output by navigating through submodule hierarchy. + + This function handles the three-level hierarchy: + 1. Selects the submodule (e.g., 'Fire Behavior') + 2. Waits for intermediate groups (e.g., 'Direction Mode') + 3. Clicks the final output (e.g., 'Heading') + + Args: + driver - WebDriver instance + submodule+groups - Vector where: + - First element is the submodule name + - Middle elements are group names + - Last element is the output name + + Example: + (select-single-output driver [\"Fire Behavior\" \"Direction Mode\" \"Heading\"])" + [driver [submodule & groups]] + (h/select-submodule-in-wizard driver submodule) + (h/wait-for-groups driver (butlast groups)) + (h/select-output driver (last groups))) + +;;; ============================================================================= +;;; Public API +;;; ============================================================================= + +(defn select-outputs + "Select multiple outputs from a multiline Gherkin string. + + This is the main entry point for the When step that selects outputs. + It parses the multiline text and selects each output in sequence. + + Args: + context - Map containing :driver key with WebDriver instance + outputs-text - Multiline string in format: + \"\"\" + -- Submodule > Group > Output + -- Submodule > Group > Output + \"\"\" + + Returns: + Map with :driver key for passing to next step + + Example: + (select-outputs {:driver driver} + \"\"\" + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Surface Fire > Rate of Spread + \"\"\")" + [{:keys [driver]} outputs-text] + (h/wait-for-wizard driver) + (let [outputs (h/parse-multiline-list outputs-text)] + (doseq [output outputs] + (select-single-output driver output)) + {:driver driver})) diff --git a/steps/worksheet.clj b/steps/worksheet.clj new file mode 100644 index 000000000..2c035100d --- /dev/null +++ b/steps/worksheet.clj @@ -0,0 +1,89 @@ +(ns steps.worksheet + "Worksheet creation logic for BehavePlus Cucumber tests. + + This namespace handles the creation of new worksheets in guided mode, + including navigating through the workflow wizard and selecting module types." + (:require [cucumber.by :as by] + [cucumber.element :as e] + [cucumber.webdriver :as w] + [steps.helpers :as h])) + +;;; ============================================================================= +;;; Worksheet Module Mappings +;;; ============================================================================= + +(def ^:private worksheet-modules + "Maps module keyword vectors to their display names in the UI. + + Available worksheet types: + - [:surface] - Surface fire modeling only + - [:surface :contain] - Surface fire with containment + - [:surface :crown] - Surface and crown fire modeling + - [:surface :mortality] - Surface fire with tree mortality + - [:mortality] - Tree mortality only" + {[:surface] "Surface Only" + [:surface :contain] "Surface and Contain" + [:surface :crown] "Surface & Crown" + [:surface :mortality] "Surface and Mortality" + [:mortality] "Mortality Only"}) + +;;; ============================================================================= +;;; Worksheet Creation +;;; ============================================================================= + +(defn start-worksheet + "Create a new worksheet in guided mode. + + This function automates the entire worksheet creation workflow: + 1. Maximizes the browser window + 2. Navigates to the application URL + 3. Waits for the working area to load + 4. Clicks through the 'New Run' wizard + 5. Selects 'Guided Workflow' mode + 6. Selects the specified module type(s) + 7. Completes the wizard + + Args: + modules - Vector of module keywords (e.g., [:surface :crown]) + context - Map containing: + :driver - WebDriver instance + :url - Application URL + + Returns: + Map with :driver key containing the WebDriver instance + + Example: + (start-worksheet [:surface :crown] {:driver driver :url \"http://localhost:8081/worksheets\"})" + [modules {:keys [driver url]}] + (w/maximize driver) + (w/goto driver url) + + (h/wait-for-working-area driver) + + ;; Click "New Run" button + (h/click-button-with-text driver "New Run") + (Thread/sleep 100) + + ;; Proceed through initial dialog + (h/click-highlighted-button driver) + (Thread/sleep 100) + + ;; Select "Guided Workflow" + (h/click-button-with-text driver "Open using Guided Workflow") + (Thread/sleep 100) + + ;; Proceed to module selection + (h/click-highlighted-button driver) + (Thread/sleep 100) + + ;; Select the desired module type + (h/click-button-with-text driver (get worksheet-modules modules)) + + ;; Scroll to the next button and click it + (let [el (h/find-element driver {:css ".button--highlight"})] + (h/scroll-to-element driver el)) + + (h/click-highlighted-button driver) + (h/scroll-to-top driver) + + {:driver driver}) From d22673811613f092dade9ff9cbbaf2b104c6da64 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Thu, 23 Oct 2025 15:48:20 -0400 Subject: [PATCH 09/67] fix format --- deps.edn | 64 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/deps.edn b/deps.edn index 291430949..881c0d053 100644 --- a/deps.edn +++ b/deps.edn @@ -65,44 +65,44 @@ tegere/tegere {:mvn/version "0.1.5"} ;; Clojure Common - bidi/bidi {:mvn/version "2.1.6"} - datascript/datascript {:mvn/version "1.5.3"} - cljs-ajax/cljs-ajax {:mvn/version "0.8.4"} - nano-id/nano-id {:mvn/version "1.1.0"} - com.github.rosejn/msgpack-cljc {:mvn/version "2.0.359"} - sig-gis/triangulum {:git/url "https://github.com/sig-gis/triangulum" - :sha "3d41dab63e1bc8ebe046f64db44ae3df986f5bdf"} - org.clojure/data.csv {:mvn/version "1.0.0"} + bidi/bidi {:mvn/version "2.1.6"} + datascript/datascript {:mvn/version "1.5.3"} + cljs-ajax/cljs-ajax {:mvn/version "0.8.4"} + nano-id/nano-id {:mvn/version "1.1.0"} + com.github.rosejn/msgpack-cljc {:mvn/version "2.0.359"} + sig-gis/triangulum {:git/url "https://github.com/sig-gis/triangulum" + :sha "3d41dab63e1bc8ebe046f64db44ae3df986f5bdf"} + org.clojure/data.csv {:mvn/version "1.0.0"} ;; Clojure/Script Deps - com.bhauman/figwheel-main {:mvn/version "0.2.18"} - org.clojure/clojurescript {:mvn/version "1.11.54"} - org.clojure/core.async {:mvn/version "1.2.603"} - binaryage/devtools {:mvn/version "1.0.5"} - re-frisk/re-frisk {:mvn/version "1.6.0"} - com.cognitect/transit-cljs {:mvn/version "0.8.264"} - re-frame/re-frame {:mvn/version "1.3.0-rc3"} - day8.re-frame/http-fx {:mvn/version "0.2.4"} - re-posh/re-posh {:mvn/version "0.3.3"} - reagent/reagent {:mvn/version "0.10.0"} - re-frame-utils/re-frame-utils {:mvn/version "0.1.0"} - cljsjs/vega {:mvn/version "5.25.0-0"} - cljsjs/vega-embed {:mvn/version "6.22.2-0"} - cljsjs/vega-lite {:mvn/version "5.14.1-0"} - day8.re-frame/test {:mvn/version "0.1.5"} - austinbirch/reactive-entity {:mvn/version "0.2.0"} + com.bhauman/figwheel-main {:mvn/version "0.2.18"} + org.clojure/clojurescript {:mvn/version "1.11.54"} + org.clojure/core.async {:mvn/version "1.2.603"} + binaryage/devtools {:mvn/version "1.0.5"} + re-frisk/re-frisk {:mvn/version "1.6.0"} + com.cognitect/transit-cljs {:mvn/version "0.8.264"} + re-frame/re-frame {:mvn/version "1.3.0-rc3"} + day8.re-frame/http-fx {:mvn/version "0.2.4"} + re-posh/re-posh {:mvn/version "0.3.3"} + reagent/reagent {:mvn/version "0.10.0"} + re-frame-utils/re-frame-utils {:mvn/version "0.1.0"} + cljsjs/vega {:mvn/version "5.25.0-0"} + cljsjs/vega-embed {:mvn/version "6.22.2-0"} + cljsjs/vega-lite {:mvn/version "5.14.1-0"} + day8.re-frame/test {:mvn/version "0.1.5"} + austinbirch/reactive-entity {:mvn/version "0.2.0"} ;; Behave CMS - applied-science/js-interop {:mvn/version "0.3.3"} - com.draines/postal {:mvn/version "2.0.3"} - garden/garden {:mvn/version "1.3.10"} - herb/herb {:mvn/version "0.10.0"} - hickory/hickory {:mvn/version "0.7.1"} - markdown-clj/markdown-clj {:mvn/version "1.11.1"} - org.clojure/tools.cli {:mvn/version "1.0.194"} + applied-science/js-interop {:mvn/version "0.3.3"} + com.draines/postal {:mvn/version "2.0.3"} + garden/garden {:mvn/version "1.3.10"} + herb/herb {:mvn/version "0.10.0"} + hickory/hickory {:mvn/version "0.7.1"} + markdown-clj/markdown-clj {:mvn/version "1.11.1"} + org.clojure/tools.cli {:mvn/version "1.0.194"} ;; Testing - org.seleniumhq.selenium/selenium-java {:mvn/version "4.23.0"}} + org.seleniumhq.selenium/selenium-java {:mvn/version "4.23.0"}} :jvm-opts ["--add-exports=java.base/java.lang=ALL-UNNAMED" "--add-exports=java.desktop/sun.awt=ALL-UNNAMED" From 0fd7265b48eed166a1d5c2f2269fcf9b79203645 Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Fri, 24 Oct 2025 16:59:01 -0400 Subject: [PATCH 10/67] add step functions for ensuring outputs are NOT selected and inputs are NOT displayed --- development/user.clj | 50 ++++++++--- features/ignite_only.feature | 2 +- features/surface_and_crown.feature | 2 +- features/surface_only.feature | 37 +++++++- steps/Then.clj | 14 +-- steps/When.clj | 14 +-- steps/helpers.clj | 134 +++++++++++++++++++++++------ steps/inputs.clj | 82 +++++++++++++++--- steps/outputs.clj | 50 ++++++++++- steps/worksheet.clj | 8 +- 10 files changed, 306 insertions(+), 87 deletions(-) diff --git a/development/user.clj b/development/user.clj index 50110b052..f24199e59 100644 --- a/development/user.clj +++ b/development/user.clj @@ -3,19 +3,17 @@ (comment (run-cucumber-tests - {:debug? false + {:debug? false :features "features" - :steps "steps" - :browser :chrome - :url "http://localhost:8081/worksheets"}) - - ) + :steps "steps" + :browser :chrome + :url "http://localhost:8081/worksheets"})) (comment (do (require '[behave.server :as server] - '[behave.handlers :refer [vms-sync!]] - '[config.interface :refer [get-config load-config]]) + '[behave.handlers :refer [vms-sync!]] + '[config.interface :refer [get-config load-config]]) (server/init-config!) (server/init-db! (get-config :database :config))) @@ -92,11 +90,11 @@ (def module-help-pages (map (partial get-module-help-pages db) modules)) - (def DOCTYPES {:map "" + (def DOCTYPES {:map "" :topic ""}) (defn insert-doctype [doctype xml] - (let [lines (str/split-lines xml) + (let [lines (str/split-lines xml) result (concat (take 1 lines) [(get DOCTYPES doctype)] (drop 1 lines))] (str/join "\n" result))) @@ -145,9 +143,9 @@ [:map (map gen-topic-ref dita-topics)])))) - (gen-ditamap [{:href "Content/Modules/Modules.dita" - :title "Modules" - :topics [{:href "Content/Modules/Surface.dita" + (gen-ditamap [{:href "Content/Modules/Modules.dita" + :title "Modules" + :topics [{:href "Content/Modules/Surface.dita" :title "Surface"}]}]) ;; Markdown to Hiccup @@ -223,7 +221,31 @@ (concat '([:h1 submodule]) (map #(let [[snippet-name help-key] % - ref (str "../../../../Resources/Snippets/Variables/" snippet-name ".dita#")] + ref (str "../../../../Resources/Snippets/Variables/" snippet-name ".dita#")] [:p {:conref %}]))) [] [:h1 "Hello World"]))))))))) + +;; =========================================================================================================== +;; Test Matrix Generator +;; =========================================================================================================== +;; Generate comprehensive test matrix report for all :group/conditionals in the schema +;; This helps identify which conditionals need Cucumber tests + +(comment + ;; Initialize CMS database first + (require '[behave-cms.server :as cms]) + (cms/init-db!) + + ;; Load test matrix generator + (require '[test-matrix-generator :as tmg] :reload) + + ;; Print quick summary + (tmg/print-summary) + + ;; Generate full test matrix report (Markdown + EDN) + ;; Creates: development/test_matrix_report.md and development/test_matrix_data.edn + (tmg/generate-test-matrix!) + + ;; Generate with custom paths + (tmg/generate-test-matrix! "custom-report.md" "custom-data.edn")) diff --git a/features/ignite_only.feature b/features/ignite_only.feature index 5ed394ab7..9cbdb5002 100644 --- a/features/ignite_only.feature +++ b/features/ignite_only.feature @@ -2,7 +2,7 @@ Feature: Ignite Only Worksheets Scenario: Fire Behavior Output Selected Given I have started a new Surface Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Fire Behavior > Ignition > Probability of Ignition """ diff --git a/features/surface_and_crown.feature b/features/surface_and_crown.feature index 91c3adaec..ea0bf2c23 100644 --- a/features/surface_and_crown.feature +++ b/features/surface_and_crown.feature @@ -2,7 +2,7 @@ Feature: Surface and Crown Worksheets Scenario: Probability of Ignition Output Selected Given I have started a new Surface & Crown Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Fire Behavior > Ignition > Probability of Ignition """ diff --git a/features/surface_only.feature b/features/surface_only.feature index f5fa4a77b..031b84983 100644 --- a/features/surface_only.feature +++ b/features/surface_only.feature @@ -2,7 +2,7 @@ Feature: Surface Only Output Selection Conditionals Scenario: Heading Rate of Spread is Selected Given I have started a new Surface Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Fire Behavior > Direction Mode > Heading -- Fire Behavior > Surface Fire > Rate of Spread @@ -20,7 +20,7 @@ Feature: Surface Only Output Selection Conditionals Scenario: Fire Area is Selected Given I have started a new Surface Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Size > Surface - Fire Size > Fire Area """ @@ -31,7 +31,7 @@ Feature: Surface Only Output Selection Conditionals Scenario: Fire Perimeter is Selected Given I have started a new Surface Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Size > Surface - Fire Size > Fire Perimeter """ @@ -42,7 +42,7 @@ Feature: Surface Only Output Selection Conditionals Scenario: Spread Distance is Selected Given I have started a new Surface Worksheet in Guided Mode - When I select these outputs Submodule > Group > Output: + When these outputs are selected Submodule > Group > Output: """ -- Size > Surface - Fire Size > Spread Distance """ @@ -51,6 +51,35 @@ Feature: Surface Only Output Selection Conditionals -- Size > Elapsed Time """ + Scenario: Spot Submodule Should Appear + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Spot > Maximum Spotting Distance > Wind-Driven Surface Fire + """ + And these outputs are NOT selected Submodule > Group > Output: + """ + -- Fire Behavior > Direction Mode > Direction of Interest + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Direction Mode > Heading, Flanking, Backing + """ + + Then the following input Submodule > Groups are displayed: + """ + -- Spot + """ + + Scenario: Spot Submodule Should Not Appear when Direction Mode Heading is Selected + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Fire Behavior > Direction Mode > Direction of Interest + """ + Then the following input Submodule > Groups are NOT displayed: + """ + -- Spot + """ + # Scenario: Burning Pile is Selected # Given I have started a new Surface Worksheet in Guided Mode # Then the following outputs are displayed: diff --git a/steps/Then.clj b/steps/Then.clj index 615871fa1..7e0da2210 100644 --- a/steps/Then.clj +++ b/steps/Then.clj @@ -1,17 +1,9 @@ (ns Then (:require [cucumber.steps :refer [Then]] - [cucumber.by :as by] - [steps.helpers :as h] [steps.inputs :as inputs])) (Then "(?m)the following input Submodule > Groups are displayed: {submodule-groups}" - inputs/verify-input-groups) + inputs/verify-input-groups-are-displayed) -(Then "the element with text {string} should be visible" - (fn [{:keys [driver]} text] - (h/wait-for-nested-element driver (by/css "body") text 5000) - {:driver driver})) - -(Then "the {string} tab should be active" - (fn [{:keys [driver]} tab-name] - {:driver driver})) +(Then "(?m)the following input Submodule > Groups are NOT displayed: {submodule-groups}" + inputs/verify-input-groups-not-displayed) diff --git a/steps/When.clj b/steps/When.clj index 3ebcd9a12..e5d44492a 100644 --- a/steps/When.clj +++ b/steps/When.clj @@ -1,17 +1,9 @@ (ns When (:require [cucumber.steps :refer [When]] - [steps.helpers :as h] [steps.outputs :as outputs])) -(When "I select these outputs Submodule > Group > Output: {outputs}" +(When "these outputs are selected Submodule > Group > Output: {outputs}" outputs/select-outputs) -(When "I navigate to the {string} tab" - (fn [{:keys [driver]} tab-name] - (h/navigate-to-tab driver tab-name) - {:driver driver})) - -(When "I click {string}" - (fn [{:keys [driver]} button-text] - (h/click-button-with-text driver button-text) - {:driver driver})) +(When "these outputs are NOT selected Submodule > Group > Output: {outputs}" + outputs/verify-outputs-not-selected) diff --git a/steps/helpers.clj b/steps/helpers.clj index 9ecc45cbc..7e4cdaacd 100644 --- a/steps/helpers.clj +++ b/steps/helpers.clj @@ -117,31 +117,6 @@ [driver selector] (e/find-el driver (selector->by selector))) -;;; ============================================================================= -;;; Navigation -;;; ============================================================================= - -(defn navigate-to-tab - "Navigate to a specific tab in the wizard interface. - - Args: - driver - WebDriver instance - tab-name - Name of the tab (e.g., \"Inputs\", \"Outputs\")" - [driver tab-name] - (-> (find-element driver {:css ".wizard-header__io-tabs"}) - (e/find-el (by/attr= :text tab-name)) - (e/click!))) - -(defn navigate-to-inputs - "Navigate to the Inputs tab in the wizard." - [driver] - (navigate-to-tab driver "Inputs")) - -(defn navigate-to-outputs - "Navigate to the Outputs tab in the wizard." - [driver] - (navigate-to-tab driver "Outputs")) - ;;; ============================================================================= ;;; Submodule Selection ;;; ============================================================================= @@ -270,6 +245,53 @@ (-> (find-element driver {:text text}) (e/click!))) +;;; ============================================================================= +;;; Checkbox Utilities +;;; ============================================================================= + +(defn output-checked? + "Check if an output checkbox is checked by looking for 'input-checkbox--checked' class on parent elements. + + This function takes an element and walks up the DOM tree checking parent divs + for the 'input-checkbox--checked' class. It stops when it finds the class, + reaches a .wizard-output parent, or runs out of parents. + + Args: + element - WebElement to start checking from + + Returns: + Boolean - true if checked (class found), false otherwise + + Example: + (let [output-elem (h/find-element driver {:text \"Rate of Spread\"})] + (h/output-checked? output-elem)) + ; => true if the Rate of Spread output is checked" + [element] + (try + (loop [current-element element + iterations 0] + (if (and current-element (< iterations 20)) ; Safety limit + (let [class-attr (.getAttribute current-element "class") + classes (when class-attr (str/split class-attr #"\s+"))] + (cond + ;; Found the checked class + (some #(= "input-checkbox--checked" %) classes) + true + + ;; Reached the wizard-output boundary + (some #(= "wizard-output" %) classes) + false + + ;; Keep walking up + :else + (let [parent (try + (e/find-el current-element (by/xpath "..")) + (catch Exception _ nil))] + (recur parent (inc iterations))))) + false)) + (catch Exception _ + false))) + ;;; ============================================================================= ;;; Scrolling ;;; ============================================================================= @@ -287,3 +309,65 @@ "Scroll the page to the top." [driver] (w/execute-script! driver "window.scrollTo(0,0)")) + +;;; ============================================================================= +;;; Navigation +;;; ============================================================================= + +(defn navigate-to-tab + "Navigate to a specific tab in the wizard interface. + + Args: + driver - WebDriver instance + tab-name - Name of the tab (e.g., \"Inputs\", \"Outputs\")" + [driver tab-name] + (-> (find-element driver {:css ".wizard-header__io-tabs"}) + (e/find-el (by/attr= :text tab-name)) + (e/click!))) + +(defn navigate-to-inputs + "Navigate to the Inputs tab in the wizard." + [driver] + (navigate-to-tab driver "Inputs")) + +(defn navigate-to-outputs + "Navigate to the Outputs tab in the wizard." + [driver] + (navigate-to-tab driver "Outputs")) + +(defn navigate-to-group + "Navigate through submodule and groups in Outputs wizard, returning driver and last group element. + + This helper navigates to a specific group by: + 1. Selecting the submodule in the wizard header + 2. Waiting for all groups in the hierarchy to appear + 3. Finding and returning the last group element + + Args: + driver - WebDriver instance + submodule+groups - Collection where: + - First element is the submodule name + - Remaining elements are group names in hierarchical order + Example: [\"Fire Behavior\" \"Direction Mode\"] + + Returns: + Map with: + :driver - The WebDriver instance + :group-element - The DOM element of the last group + + Example: + (navigate-to-group driver [\"Fire Behavior\" \"Direction Mode\"]) + ; => {:driver driver, :group-element } + + ;; Use in a step definition: + (let [{:keys [driver group-element]} (navigate-to-group driver [\"Fire Behavior\" \"Direction Mode\"])] + (e/find-el group-element (by/css \".some-class\")))" + [driver submodule+groups] + (let [[submodule & groups] submodule+groups] + (select-submodule-in-wizard driver submodule) + (if (seq groups) + (do (wait-for-groups driver groups) + (let [last-group-name (last groups)] + (find-element driver {:text last-group-name}))) + (find-element driver {:text submodule})))) + diff --git a/steps/inputs.clj b/steps/inputs.clj index fe8395a33..1d4bf5b6b 100644 --- a/steps/inputs.clj +++ b/steps/inputs.clj @@ -3,8 +3,7 @@ This namespace handles verifying that expected input groups are displayed in the Inputs tab of the worksheet wizard." - (:require [cucumber.by :as by] - [steps.helpers :as h])) + (:require [steps.helpers :as h])) ;;; ============================================================================= ;;; Private Helper Functions @@ -26,15 +25,40 @@ Example: (verify-groups-exist driver [\"Wind and Slope\" \"Wind measured at\" \"Wind Speed\"])" - [driver [submodule & groups]] - (h/select-submodule-in-page driver submodule) - (h/wait-for-groups driver groups)) + [driver path] + (h/navigate-to-group driver path)) + +(defn- verify-groups-not-exist + "Verify that groups do NOT exist under a given submodule in the Inputs tab. + + This function: + 1. Selects the submodule in the wizard page + 2. Attempts to find each group element + 3. Throws an exception if any group IS found (because we expect it NOT to be there) + + Args: + driver - WebDriver instance + submodule+groups - Vector where: + - First element is the submodule name + - Remaining elements are group names that should NOT exist + + Example: + (verify-groups-not-exist driver [\"Wind and Slope\" \"Wind Speed\"])" + [driver path] + (try + (h/navigate-to-group driver path) + ;; If we found the element, that's an error - it should NOT exist + (throw (ex-info (str "Group should NOT be displayed but was found: " path) + {:path path})) + (catch org.openqa.selenium.NoSuchElementException _ + ;; This is good - the element doesn't exist as expected + nil))) ;;; ============================================================================= ;;; Public API ;;; ============================================================================= -(defn verify-input-groups +(defn verify-input-groups-are-displayed "Verify that expected input groups are displayed in the Inputs tab. This is the main entry point for the Then step that verifies inputs. @@ -56,11 +80,11 @@ AssertionError if no groups are specified or any group is not found Example: - (verify-input-groups {:driver driver} - \"\"\" - -- Fuel Model > Standard > Fuel Model - -- Fuel Moisture > Moisture Input Mode - \"\"\")" + (verify-input-groups-are-displayed {:driver driver} + \"\"\" + -- Fuel Model > Standard > Fuel Model + -- Fuel Moisture > Moisture Input Mode + \"\"\")" [{:keys [driver]} submodule-groups-text] (h/navigate-to-inputs driver) (h/wait-for-wizard driver) @@ -70,3 +94,39 @@ (verify-groups-exist driver sg)) (assert (pos? (count submodule-groups))) {:driver driver})) + +(defn verify-input-groups-not-displayed + "Verify that input groups are NOT displayed in the Inputs tab. + + This is the inverse of verify-input-groups. It navigates to the Inputs tab, + parses the expected-to-be-absent groups, and verifies each one is NOT + present in the UI. + + Args: + context - Map containing :driver key with WebDriver instance + submodule-groups-text - Multiline string in format: + \"\"\" + -- Submodule > Group1 > Group2 + -- Submodule > Group3 + \"\"\" + + Returns: + Map with :driver key for passing to next step + + Throws: + ExceptionInfo if any group IS found (when it should NOT be) + + Example: + (verify-input-groups-not-displayed {:driver driver} + \"\"\" + -- Wind and Slope > Wind Speed + \"\"\")" + [{:keys [driver]} submodule-groups-text] + (h/navigate-to-inputs driver) + (h/wait-for-wizard driver) + + (let [submodule-groups (h/parse-multiline-list submodule-groups-text)] + (doseq [sg submodule-groups] + (verify-groups-not-exist driver sg)) + (assert (pos? (count submodule-groups))) + {:driver driver})) diff --git a/steps/outputs.clj b/steps/outputs.clj index 0a076e32e..b3fc566b0 100644 --- a/steps/outputs.clj +++ b/steps/outputs.clj @@ -3,7 +3,8 @@ This namespace handles selecting outputs in the worksheet wizard, including navigating submodules, waiting for groups, and clicking outputs." - (:require [steps.helpers :as h])) + (:require [steps.helpers :as h] + [cucumber.element :as e])) ;;; ============================================================================= ;;; Private Helper Functions @@ -43,7 +44,7 @@ Args: context - Map containing :driver key with WebDriver instance - outputs-text - Multiline string in format: + paths-text - Multiline string in format: \"\"\" -- Submodule > Group > Output -- Submodule > Group > Output @@ -58,9 +59,50 @@ -- Fire Behavior > Direction Mode > Heading -- Fire Behavior > Surface Fire > Rate of Spread \"\"\")" - [{:keys [driver]} outputs-text] + [{:keys [driver]} paths-text] (h/wait-for-wizard driver) - (let [outputs (h/parse-multiline-list outputs-text)] + (let [outputs (h/parse-multiline-list paths-text)] (doseq [output outputs] (select-single-output driver output)) {:driver driver})) + +(defn verify-outputs-not-selected + "Verify that specified outputs are NOT currently selected. + + This function checks that each output in the list is not checked/selected. + If any output is found to be selected, it throws an assertion error. + + Args: + context - Map containing :driver key with WebDriver instance + paths-text - Multiline string in format: + \"\"\" + -- Submodule > Group > Output + -- Submodule > Group > Output + \"\"\" + + Returns: + Map with :driver key for passing to next step + + Throws: + ExceptionInfo if any output is found to be selected + + Example: + (verify-outputs-not-selected {:driver driver} + \"\"\" + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Surface Fire > Rate of Spread + \"\"\")" + [{:keys [driver]} paths-text] + (h/wait-for-wizard driver) + (let [parsed-paths (h/parse-multiline-list paths-text)] + (doseq [path parsed-paths] + (let [[submodule & groups] path + output-name (last path) + last-group (h/navigate-to-group driver path) + is-checked? (h/output-checked? last-group)] + (when is-checked? + (throw (ex-info (str "Output should NOT be selected but was: " output-name) + {:output output-name + :submodule submodule + :groups groups}))))) + {:driver driver})) diff --git a/steps/worksheet.clj b/steps/worksheet.clj index 2c035100d..7d1e20ef7 100644 --- a/steps/worksheet.clj +++ b/steps/worksheet.clj @@ -3,9 +3,7 @@ This namespace handles the creation of new worksheets in guided mode, including navigating through the workflow wizard and selecting module types." - (:require [cucumber.by :as by] - [cucumber.element :as e] - [cucumber.webdriver :as w] + (:require [cucumber.webdriver :as w] [steps.helpers :as h])) ;;; ============================================================================= @@ -80,10 +78,10 @@ (h/click-button-with-text driver (get worksheet-modules modules)) ;; Scroll to the next button and click it - (let [el (h/find-element driver {:css ".button--highlight"})] + (let [el (h/find-element driver {:text "Next"})] (h/scroll-to-element driver el)) - (h/click-highlighted-button driver) + (h/click-button-with-text driver "Next") (h/scroll-to-top driver) {:driver driver}) From ca32c2e89783ca0cdbdc1e5d2d37377a8e3df92e Mon Sep 17 00:00:00 2001 From: Kenneth Cheung Date: Tue, 28 Oct 2025 15:15:23 -0400 Subject: [PATCH 11/67] simplify tests to core set of scenarios for conditionals --- features/core_conditional_scenarios.feature | 95 +++++ features/surface_and_crown.feature | 9 +- features/surface_only.feature | 407 -------------------- steps/Then.clj | 4 +- steps/When.clj | 6 +- steps/helpers.clj | 174 ++++++++- steps/inputs.clj | 90 +++++ steps/worksheet.clj | 29 +- 8 files changed, 382 insertions(+), 432 deletions(-) create mode 100644 features/core_conditional_scenarios.feature delete mode 100644 features/surface_only.feature diff --git a/features/core_conditional_scenarios.feature b/features/core_conditional_scenarios.feature new file mode 100644 index 000000000..922715cc3 --- /dev/null +++ b/features/core_conditional_scenarios.feature @@ -0,0 +1,95 @@ +Feature: Core Conditional Scenarios + + # 1. Input Group should appear when output group is selected + Scenario: Heading Rate of Spread is Selected + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Surface Fire > Rate of Spread + """ + Then the following input Submodule > Groups are displayed: + """ + -- Fuel Model > Standard > Fuel Model + -- Fuel Moisture > Moisture Input Mode + -- Wind and Slope > Wind and slope are + -- Wind and Slope > Slope + """ + + # 5. Input Submodule should appear when Output Group is selected + Scenario: Elapsed Time should Appear in the Inputs when Fire Area Output is Selected + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Size > Surface - Fire Size > Fire Area + """ + Then the following input Submodule > Groups are displayed: + """ + -- Size > Elapsed Time + """ + + # 4. Input Group should appear when some Output Groups are selected and some Output Groups are NOT selected + Scenario: Spot Submodule Should Appear when + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Spot > Maximum Spotting Distance > Wind-Driven Surface Fire + """ + And these outputs are NOT selected Submodule > Group > Output: + """ + -- Fire Behavior > Direction Mode > Heading + -- Fire Behavior > Direction Mode > Heading, Flanking, Backing + -- Fire Behavior > Direction Mode > Direction of Interest + """ + + Then the following input Submodule > Groups are displayed: + """ + -- Spot + """ + + # 2. Input Submodule should NOT appear when output group is selected + Scenario: Spot Submodule Should Not Appear when Direction Mode: Heading is Selected + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Fire Behavior > Direction Mode > Heading + """ + Then the following input Submodule > Groups are NOT displayed: + """ + -- Spot + """ + + # 3. Input Group should appear when another Input Group has a value is selected + Scenario: By Size Class Appears when Moisture Input Mode is Individual Size Class + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Fire Behavior > Fire Behavior > Rate of Spread + """ + And these inputs are entered Submodule > Group > Input: + """ + --- Fuel Moisture > Moisture Input Mode > Individual Size Class + """ + Then the following input Submodule > Groups are displayed: + """ + -- Fuel Moisture > By Size Class + """ + + # - Input is displayed when Input is Selected + Scenario: 10-h, 100-h, and Live Herbaceous Fuel Moisture Inputs Appears when Fuel Model: FB1/2 is Selected + Given I have started a new Surface Worksheet in Guided Mode + When these outputs are selected Submodule > Group > Output: + """ + -- Fire Behavior > Fire Behavior > Rate of Spread + """ + And these inputs are entered Submodule > Group > Input: + """ + --- Fuel Model > Standard > Fuel Model > FB2/2 - Timber grass and understory (Static) + --- Fuel Moisture > Moisture Input Mode > Individual Size Class + """ + Then the following input Submodule > Groups are displayed: + """ + -- Fuel Moisture > By Size Class > 10-h Fuel Moisture + -- Fuel Moisture > By Size Class > 100-h Fuel Moisture + -- Fuel Moisture > By Size Class > Live Herbaceous Fuel Moisture + """ diff --git a/features/surface_and_crown.feature b/features/surface_and_crown.feature index ea0bf2c23..5fc401ea2 100644 --- a/features/surface_and_crown.feature +++ b/features/surface_and_crown.feature @@ -3,13 +3,12 @@ Feature: Surface and Crown Worksheets Scenario: Probability of Ignition Output Selected Given I have started a new Surface & Crown Worksheet in Guided Mode When these outputs are selected Submodule > Group > Output: - """ - -- Fire Behavior > Ignition > Probability of Ignition - """ + """ + -- Fire Behavior > Ignition > Probability of Ignition + """ Then the following input Submodule > Groups are displayed: """ -- Fuel Moisture > Moisture Input Mode -- Weather > Air Temperature - -- Weather > Fuel Shading From the Sun + -- Weather > Fuel Shading From the Sun """ - diff --git a/features/surface_only.feature b/features/surface_only.feature deleted file mode 100644 index 031b84983..000000000 --- a/features/surface_only.feature +++ /dev/null @@ -1,407 +0,0 @@ -Feature: Surface Only Output Selection Conditionals - - Scenario: Heading Rate of Spread is Selected - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Fire Behavior > Direction Mode > Heading - -- Fire Behavior > Surface Fire > Rate of Spread - """ - Then the following input Submodule > Groups are displayed: - """ - -- Fuel Model > Standard > Fuel Model - -- Fuel Moisture > Moisture Input Mode - -- Wind and Slope > Wind and slope are - -- Wind and Slope > Slope - """ - - # - Wind and Slope > Wind measured at: @kenny this fails because Wind measured at: has a - # - trailing space in the dom and (extract-submodule-groups) trims this. - - Scenario: Fire Area is Selected - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Size > Surface - Fire Size > Fire Area - """ - Then the following input Submodule > Groups are displayed: - """ - -- Size > Elapsed Time - """ - - Scenario: Fire Perimeter is Selected - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Size > Surface - Fire Size > Fire Perimeter - """ - Then the following input Submodule > Groups are displayed: - """ - -- Size > Elapsed Time - """ - - Scenario: Spread Distance is Selected - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Size > Surface - Fire Size > Spread Distance - """ - Then the following input Submodule > Groups are displayed: - """ - -- Size > Elapsed Time - """ - - Scenario: Spot Submodule Should Appear - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Spot > Maximum Spotting Distance > Wind-Driven Surface Fire - """ - And these outputs are NOT selected Submodule > Group > Output: - """ - -- Fire Behavior > Direction Mode > Direction of Interest - -- Fire Behavior > Direction Mode > Heading - -- Fire Behavior > Direction Mode > Heading, Flanking, Backing - """ - - Then the following input Submodule > Groups are displayed: - """ - -- Spot - """ - - Scenario: Spot Submodule Should Not Appear when Direction Mode Heading is Selected - Given I have started a new Surface Worksheet in Guided Mode - When these outputs are selected Submodule > Group > Output: - """ - -- Fire Behavior > Direction Mode > Direction of Interest - """ - Then the following input Submodule > Groups are NOT displayed: - """ - -- Spot - """ - - # Scenario: Burning Pile is Selected - # Given I have started a new Surface Worksheet in Guided Mode - # Then the following outputs are displayed: - # """ - # - Spot -> Burning Pile - # - Spot -> Wind-Driven Surface Fire - # """ - # Then and should be the only two options under Maximum Spotting Distance - - # Given I have started a new Surface Worksheet - # When Any outputs are selected, other than Burning Pile - # Then Maximum Spotting Distance: Burning Pile should be deactivated - - # Given I have started a new Surface Worksheet - # When Burning Pile is selected from Maximum Spotting Distance - # Then All other outputs should be deactivated and the ONLY inputs should - # be: - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Downwind Canopy Cover - # - Downwind Canopy Height - # - Flame Height (from a Burning Bile) - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - - # Given I have started a new Surface Worksheet - # When Fire Behavior or Size is selected with Wind-Driven Surface Fire - # from Spot - # Then Fuel Model should be replaced with Wind Driven Fuel Models which - # only contain grass fuel models - - # Given I have started a new Surface Worksheet - # When Fire Behavior or Size is selected with Wind-Driven Surface Fire - # from Spot - # Then Surface Fire Flame Length should come from Surface and should not - # be an input - - # Given I have started a new Surface Worksheet - # When When Wind-Drive Surface fire is not run with Fire Behavior - # Then Only the inputs below are required - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Downwind Canopy Cover - # - Downwind Canopy Height - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Surface Fire Flame Length* - - # Given I have started a new Surface Worksheet - # When 0 is entered into Ridge-to-Valley Elevation Difference - # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location - # should not be available inputs - - # Given I have started a new Surface Worksheet - # When A value greater than 0 is entered into Ridge-to-Valley Elevation - # Difference - # Then Ridge-to-Valley Horizontal Distance and Spotting Source Location - # should be required inputs - - # Given I have started a new Surface Worksheet - # When Direction of Interest is selected from Direction Mode - # Then The Wind/Slope/Spread Diagram should be automatically output on - # the Run Results - - # Given I have started a new Surface Worksheet - # When Direction of Interest is selected from Direction Mode - # Then The Direction of Spread should be automatically output on the Run - # Results. The Direction of Spread should be consisted with the Direction - # Mode selected (Heading or Heading Flanking Backing) - - # Given I have started a new Surface Worksheet - # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not - # aligned - # Then The Wind/Slope/Spread Diagram should be automatically output on - # the Run Results - - # Given I have started a new Surface Worksheet - # When Heading OR Heading, Backing, Flanking, AND Wind and Slope are not - # aligned - # Then The Direction of Spread should be automatically ouput on the Run - # Results. The Direction of Spread should be consisted with the Direction - # Mode selected (Heading or Heading Flanking Backing) - - # Given I have started a new Surface Worksheet - # When Maximum Spotting DIstance from a Burning Pile is run - # Then Firebrand Height from a Burning Pile should be automatically - # output - # * Surface and Crown - - # Given I have started a new Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Heading should be automatically run for Direction Mode. *It should not be automatically selected because the user may not run Fire Behavior.* - - # Given I have started a new Surface and Crown Worksheet - # When Any output is selected, other than a Spot model - # Then Fire Type should be automatically selected as an output but it - # should not shown on the worksheet - - # Given I have started a new Surface and Crown Worksheet - # When Fire behavior has a selected output (RoS, FL, or FI) - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - Wind and Slope are: - # - Slope - # - Calculations Options - # - Fuel Moisture - # - Foliar Moisture - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a new Surface and Crown Worksheet - # When Length-to-Width Ratio output in the Size submodule is selected - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Fuel Moisture - # - Foliar Moisture - # - Calculations Options - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a new Surface and Crown Worksheet - # When Any Fire Type output are selected - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot autoselected - # - Wind Speed - # - WAF - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Fuel Moisture - # - Foliar Moisture - # - Calculations Options - # - Canopy Fuel - # - Canopy Base Height - # - Canopy Bulk Density - # - Canopy Height - - # Given I have started a new Surface and Crown Worksheet - # When The size outputs below are selected: - # - Fire Area - # - Fire Perimeter - # - Spread Distance - # - (**Exclude Length-to-Width Ratio) - # Then The following Submodules w/inputs are the ONLY required inputs - # - Fuel Model - # - Fuel Moisture - # - Moisture Input Mode - # - Appropriate Moisture Inputs - # - Wind and Slope - # - Wind Measured at: - # - Wind Speed - # - WAF(if applicable) - # - Wind and Slope are: - # - Slope - # - Size - # - Elapsed Time - - # Given I have started a new Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Only Torching Trees and Active Crown fire should be available options under Maximum Spotting Distance - - # Given I have started a new Surface and Crown Worksheet - # When Surface and Crown are run together - # Then Torching Tree and Active Crown fire should be able to both be run under Maximum Spotting Distance - - # Given I have started a new Surface and Crown Worksheet - # When Active Crown Fire is selected as an out, *WITHOUT Fire Behavior* - # Then The inputs below are required - # - Canopy Fuel - # - Canopy Height - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Active Crown Fire Flame Length* - - # Given I have started a new Surface and Crown Worksheet - # When Active Crown Fire is selected as an output with Fire Behavior - # Then The inputs below are required - # - Canopy Fuel - # - Canopy Height - # - Wind and Slope - # - Wind Measured at: - # - Midflame should be deactivate and 20-Foot auto-selected - # - Wind Speed - # - *No WAF* - # - *No Wind and Slope are* - # - *No Slope* - # - Spot - # - Topography - # - Ridge-to-Valley Elevation Difference - # - Ridge-to-Valley Horizontal Distance (Dependent on Elevation - # Difference) - # - Spotting Source Location (Dependent on Elevation Difference) - # - *Active Crown Fire Flame Length* - - # Given I have started a new Surface and Crown Worksheet - # When Fire Behavior or Size is selected with Active Crown Fire from Spot - # Then Active Crown Fire Flame Length should come from Crown and should not be an input - # * Surface and Contain - - # Given I have started a new Surface and Contain Worksheet - # Then Spot should not be on worksheet - - # Given I have started a new Surface and Contain Worksheet - # Then Surface Fire Behavior and Size conditionals should be treated the same as Surface being run alone - - # Given I have started a new Surface and Contain Worksheet - # Then Heading in Fire Behavior's Direction Mode should be the only option available. Heading, Backing, and Flanking, and DIrection of Interest should be deactivated - # * Surface and Mortality - - # Given I have started a new Surface and Mortality Worksheet - # Then Heading and Heading Flanking, Backing in Fire Behavior's Direction Mode should be the only options available. - # And: Direction of Interest should be deactivated - - # Given I have started a new Surface and Mortality Worksheet - # Then There should be no Size output module - # And: There should be no Size input submodules - - # Given I have started a new Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a new Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a new Surface and Mortality Worksheet - # Then There should be no mortality output submodules because all outputs are automated based on species selected and their PoM equation - - # Given I have started a new Surface and Mortality Worksheet - # Then Flame Length is needed to calculate PoM so Surface Fire Behavior conditionals should be used to calculate Flame Length - - # Given I have started a new Surface and Mortality Worksheet - # Then PoM equation used should be based on the Mortality tree species used, see [[https://sig-gis.atlassian.net/browse/BHP1-839?atlOrigin=eyJpIjoiZTdjZDg4MDNhYTBlNDE2NDljZTRhZTEzNThlNDI5NzgiLCJwIjoiaiJ9][BHP1-839]] - - # Given I have started a new Surface and Mortality Worksheet - # Then DBH and Mortality Tree species are both required user inputs, regardless of PoM equation - - # Given I have started a new Surface and Mortality Worksheet - # Then Probability of Mortality is automatically calculated - - # Given I have started a new Surface and Mortality Worksheet - # Then Mortality Outputs should match the format in [[https://sig-gis.atlassian.net/browse/BHP1-926?atlOrigin=eyJpIjoiYTQwNWFjMmExZDE5NGNjYWI3NDYxNTNjY2MwMmIwMTAiLCJwIjoiaiJ9][ticket]] and [[https://usfs.box.com/s/u6uknqwzt751top5awzn0am4u4s8dkj3][table]] - - # Given I have started a new Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then The user inputs below are required - # - Air Temp - # - MidFlame Windspeed or (20ft or 10m x WAF = Midflame Windspeed) - # - Canopy Height - # - Crown Ratio - - # Given I have started a new Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then The calculated Flame Length needs to be used to calculate Scorch Height - - # Given I have started a new Surface and Crown Worksheet - # When The PoM equation used is Bark Char - # Then The calculated Flame Length is used to calculate Bark Char Height, Flame Length/1.8 - - # Given I have started a new Surface and Crown Worksheet - # When The PoM equation used is Crown Scorch - # Then Automated outputs that should be calculated including: - # - Crown Length Scorched - # - Crown Volume Scorched - # - Scorch Height - - # Given I have started a new Surface and Crown Worksheet - # When The PoM equation used is Bark Char - # Then Bark Char Height is an automated output that should be calculated include diff --git a/steps/Then.clj b/steps/Then.clj index 7e0da2210..8b86e1dc6 100644 --- a/steps/Then.clj +++ b/steps/Then.clj @@ -2,8 +2,8 @@ (:require [cucumber.steps :refer [Then]] [steps.inputs :as inputs])) -(Then "(?m)the following input Submodule > Groups are displayed: {submodule-groups}" +(Then "the following input Submodule > Groups are displayed: {submodule-groups}" inputs/verify-input-groups-are-displayed) -(Then "(?m)the following input Submodule > Groups are NOT displayed: {submodule-groups}" +(Then "the following input Submodule > Groups are NOT displayed: {submodule-groups}" inputs/verify-input-groups-not-displayed) diff --git a/steps/When.clj b/steps/When.clj index e5d44492a..22c0119cb 100644 --- a/steps/When.clj +++ b/steps/When.clj @@ -1,9 +1,13 @@ (ns When (:require [cucumber.steps :refer [When]] - [steps.outputs :as outputs])) + [steps.outputs :as outputs] + [steps.inputs :as inputs])) (When "these outputs are selected Submodule > Group > Output: {outputs}" outputs/select-outputs) (When "these outputs are NOT selected Submodule > Group > Output: {outputs}" outputs/verify-outputs-not-selected) + +(When "these inputs are entered Submodule > Group > Input: {inputs}" + inputs/enter-inputs) diff --git a/steps/helpers.clj b/steps/helpers.clj index 7e4cdaacd..07f29dc2d 100644 --- a/steps/helpers.clj +++ b/steps/helpers.clj @@ -32,6 +32,50 @@ (remove empty?) (map #(str/split % #" > "))))) +(defn parse-input-multiline-list + "Parse triple-quoted multiline list for inputs into vector of vectors. + + Similar to parse-multiline-list, but uses '---' (three dashes) as delimiter + instead of '--' (two dashes). This is specifically for input entry steps. + + Example: + Input: \"\"\" + --- Fuel Moisture > Moisture Input Mode > Individual Size Class + --- Fuel Moisture > By Size Class > 1-h Fuel Moisture > 1 + \"\"\" + Output: [[\"Fuel Moisture\" \"Moisture Input Mode\" \"Individual Size Class\"] + [\"Fuel Moisture\" \"By Size Class\" \"1-h Fuel Moisture\" \"1\"]]" + [text] + (-> text + (str/replace "\"\"\"" "") + (str/split #"--- ") + (->> (map str/trim) + (remove empty?) + (map #(str/split % #" > "))))) + +(defn numeric-or-multi-value? + "Check if a string looks like a numeric value or comma-separated values. + + Returns true if the string contains only digits, spaces, commas, decimal points, + and minus signs. This helps distinguish input values from field/option names. + + Args: + s - String to check + + Returns: + Boolean - true if it looks like a value to enter + + Examples: + (numeric-or-multi-value? \"1\") ; => true + (numeric-or-multi-value? \"3.14\") ; => true + (numeric-or-multi-value? \"1, 2, 3\") ; => true + (numeric-or-multi-value? \"10.5, 20\") ; => true + (numeric-or-multi-value? \"Individual Size Class\") ; => false" + [s] + (and (string? s) + (not (str/blank? s)) + (re-matches #"^[0-9.,\s-]+$" (str/trim s)))) + ;;; ============================================================================= ;;; Element Finding ;;; ============================================================================= @@ -67,14 +111,14 @@ (selector->by {:tag :div}) ; => By.tagName(\"div\")" [selector] (cond - (:id selector) (by/id (:id selector)) - (:css selector) (by/css (:css selector)) + (:id selector) (by/id (:id selector)) + (:css selector) (by/css (:css selector)) (:xpath selector) (by/xpath (:xpath selector)) - (:tag selector) (by/tag-name (name (:tag selector))) + (:tag selector) (by/tag-name (name (:tag selector))) (:class selector) (by/class-name (:class selector)) - (:text selector) (by/attr= :text (:text selector)) - (:name selector) (by/input-name (:name selector)) - :else (throw (ex-info "Unknown selector type" {:selector selector})))) + (:text selector) (by/attr= :text (:text selector)) + (:name selector) (by/input-name (:name selector)) + :else (throw (ex-info "Unknown selector type" {:selector selector})))) (defn find-element "Find an element using various selector strategies. @@ -117,6 +161,28 @@ [driver selector] (e/find-el driver (selector->by selector))) +(defn find-input-by-label + "Find an input element (text field, radio, or dropdown) by its label text. + + This function searches for a label with the given text and returns the + associated input element. Works with text inputs, radio buttons, and dropdowns. + + Args: + driver - WebDriver instance + label-text - The label text to search for + + Returns: + WebElement of the input field + + Throws: + NoSuchElementException if label or input not found + + Examples: + (find-input-by-label driver \"1-h Fuel Moisture\") + (find-input-by-label driver \"Air Temperature\")" + [driver label-text] + (find-element driver {:text label-text})) + ;;; ============================================================================= ;;; Submodule Selection ;;; ============================================================================= @@ -245,6 +311,97 @@ (-> (find-element driver {:text text}) (e/click!))) +;;; ============================================================================= +;;; Input Operations +;;; ============================================================================= + +(defn enter-text-value + "Enter a value into a text input field. + + This function finds the input field by searching for text content, + then finding the nearest input element. + + Args: + driver - WebDriver instance + label-text - The label text of the input field + value - The value to enter (string, can be comma-separated) + + Examples: + (enter-text-value driver \"1-h Fuel Moisture\" \"1\") + (enter-text-value driver \"Air Temperature\" \"77\") + (enter-text-value driver \"Wind Speed\" \"5, 10, 15\")" + [driver label-text value] + ;; Use XPath to find input that's near any element containing the label text + ;; This is more flexible than requiring a