From 2e24b2b710ef62d03141775a288f314ad4edcfca Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 15:13:50 -0800 Subject: [PATCH 01/22] feat: well inventory bulk upload csv --- features/backend/well-inventory-csv.feature | 169 ++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 features/backend/well-inventory-csv.feature diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature new file mode 100644 index 0000000..c8d39e0 --- /dev/null +++ b/features/backend/well-inventory-csv.feature @@ -0,0 +1,169 @@ +@backend @BDMS-?? @production +Feature: Upload a well inventory spreadsheet (CSV) + As a hydrogeologist or data specialist + I want to upload a CSV file containing well inventory data for multiple wells + So that many wells can be imported quickly and accurately into the system + + Background: + Given a functioning api + And my CSV file is encoded in UTF-8 and uses commas as separators + + @positive @happy_path + Scenario: Upload a well inventory CSV with all required and optional fields correctly filled out + # is provided means the field is required and must be filled out + # is included if available means the field is optional and may be filled out + + # Field Visit Event fields + And the field "project" is provided + And the field "well_name_point_id" is provided and unique per row + And the field "site_name" is provided + And the field "date_time" is provided as a valid timestamp in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00Z-08:00" + And the field "field_staff" is provided and contains the first and last name of the primary person who measured or logged the data + And the field "field_staff_2" is included if available + And the field "field_staff_3" is included if available + + # Well Contact (Owner) fields + And the field "contact_1_name" is provided + And the field "contact_1_organization" is included if available + And the field "contact_1_role" is provided and one of the contact_role lexicon values + And the field "contact_1_type" is provided and one of the contact_type lexicon values + + # Phone and Email fields are optional + And the field "contact_1_phone_1" is included if available + And the field "contact_1_phone__1_type" is included if contact_1_phone_1 is provided and is one of the phone_type lexicon values + And the field "contact_1_phone_2" is included if available + And the field "contact_1_phone_2_type" is included if contact_1_phone_2 is provided and is one of the phone_type lexicon values + And the field "contact_1_email_1" is included if available + And the field "contact_1_email_1_type" is included if contact_1_email_1 is provided and is one of the email_type lexicon values + And the field "contact_1_email_2" is included if available + And the field "contact_1_email_2_type" is included if contact_1_email_2 is provided and is one of the email_type lexicon values + + # Address fields are optional + And the field "contact_1_address_1_line_1" is provided + And the field "contact_1_address_1_line_2" is included if available + And the field "contact_1_address_1_type" is provided and one of the address_type lexicon values + And the field "contact_1_address_1_state" is provided + And the field "contact_1_address_1_city" is provided + And the field "contact_1_address_1_postal_code" is provided + And the field "contact_1_address_2_line_1" is included if available + And the field "contact_1_address_2_line_2" is included if available + And the field "contact_1_address_2_type" is included if contact_1_address_2_line_1 is provided and is one of the address_type lexicon values + And the field "contact_1_address_2_state" is included if contact_1_address_2_line_1 is provided + And the field "contact_1_address_2_city" is included if contact_1_address_2_line_1 is provided + And the field "contact_1_address_2_postal_code" is included if contact_1_address_2_line_1 is provided + + # Location notes + And the field "directions_to_site" is included if available + And the field "specific_location_of_well" is included if available + + # Permissions + And the field "repeat_measurement_permission" is included if available as true or false + And the field "sampling_permission" is included if available as true or false + And the field "datalogger_installation_permission" is included if available as true or false + And the field "public_availability_acknowledgement" is included if available as true or false + + # Special requests + And the field "special_requests" is included if available + + # Location fields + And the field "utm_easting" is provided as a numeric value in NAD83 UTM Zone 13 + And the field "utm_northing" is provided as a numeric value in NAD83 UTM Zone 13 + And the field "elevation_ft" is provided as a numeric value in NAVD88 + And the field "elevation_method" is provided and one of the elevation_method lexicon values + + # Well attributes + And the field "ose_well_record_id" is included if available + And the field "date_drilled" is included if available as a valid date in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00Z-08:00" + And the field "completion_source" is included if available + And the field "total_well_depth_ft" is included if available as a numeric value in feet + And the field "static_water_depth_ft" is included if available as a numeric value + And the field "depth_source" is included if available + And the field "well_pump_type" is included if available and one of the well_pump_type lexicon values + And the field "well_pump_depth_ft" is included if available as a numeric value in feet + And the field "is_open" is included if available as true or false + And the field "datalogger_possible" is included if available as true or false + And the field "casing_diameter_ft" is included if available as a numeric value in feet + And the field "measuring_point_height_ft" is provided as a numeric value in feet + And the field "measuring_point_description" is included if available + And the field "well_use_purpose" is included if available and one of the well_use_purpose lexicon values + And the field "well_hole_status" is included if available and one of the well_hole_status lexicon values + And the field "monitoring_frequency" is included if available and one of the monitoring_frequency lexicon values + + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 201 Created status code + And the system should return a response in JSON format + And null values in the response should be represented as JSON null (not placeholder strings) + + # Upload Summary + And the response should include a summary with total rows processed + And the response should include a summary with total rows successfully imported + And the response should include a summary with any validation errors or warnings + + # Created Well Objects + And the response should include an array of created water well objects + + @negative @validation + Scenario: Upload fails due to missing required field in one or more rows + Given my CSV file contains one or more rows with missing values in the required field "well_name_point_id" + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with missing required fields + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected + + @negative @validation + Scenario: Upload fails due to duplicate well names in one or more rows + Given my CSV file contains one or more rows with duplicate values in the "well_name_point_id" field + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with duplicate well names + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected + + @negative @validation + Scenario: Upload fails due to invalid lexicon value in one or more rows + Given my CSV file contains one or more rows with an invalid value in the "contact_1_role" field that is not in the contact_role lexicon + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with invalid lexicon values + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected + + @negative @validation + Scenario: Upload fails due to invalid date format in one or more rows + Given my CSV file contains one or more rows with an invalid date format in the "date_time" field + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with invalid date formats + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected + + @negative @validation + Scenario: Upload fails due to invalid numeric value in one or more rows + Given my CSV file contains one or more rows with a value that cannot be parsed as a numeric value in the "utm_easting" field + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with invalid numeric values + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected + + @negative @validation + Scenario: Upload fails due to missing conditional field in one or more rows + Given my CSV file contains one or more rows that include "contact_1_address_2_line_1" but are missing the required conditional field "contact_1_address_2_city" + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response should include validation errors for all rows with missing conditional fields + And the response should indicate which row and field contains each error + And no wells should be imported + And all rows should be validated before the upload is rejected \ No newline at end of file From 8153d9899318d88a9df0d965d77884bf670ef03a Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 15:19:36 -0800 Subject: [PATCH 02/22] feat: add file format negative paths --- features/backend/well-inventory-csv.feature | 35 +++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index c8d39e0..1bde748 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -13,6 +13,8 @@ Feature: Upload a well inventory spreadsheet (CSV) # is provided means the field is required and must be filled out # is included if available means the field is optional and may be filled out + # FIELD NAMES ARE CSV FIELD NAMES, NOT API/DB FIELD NAMES + # Field Visit Event fields And the field "project" is provided And the field "well_name_point_id" is provided and unique per row @@ -111,7 +113,6 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with missing required fields And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected @negative @validation Scenario: Upload fails due to duplicate well names in one or more rows @@ -122,7 +123,6 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with duplicate well names And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected @negative @validation Scenario: Upload fails due to invalid lexicon value in one or more rows @@ -133,7 +133,6 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with invalid lexicon values And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected @negative @validation Scenario: Upload fails due to invalid date format in one or more rows @@ -144,7 +143,6 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with invalid date formats And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected @negative @validation Scenario: Upload fails due to invalid numeric value in one or more rows @@ -155,7 +153,6 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with invalid numeric values And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected @negative @validation Scenario: Upload fails due to missing conditional field in one or more rows @@ -166,4 +163,30 @@ Feature: Upload a well inventory spreadsheet (CSV) And the response should include validation errors for all rows with missing conditional fields And the response should indicate which row and field contains each error And no wells should be imported - And all rows should be validated before the upload is rejected \ No newline at end of file + +@negative @file_format +Scenario: Upload fails due to unsupported file type + Given I upload a file that is not a CSV file + When I upload the file to the bulk upload endpoint + Then the system should return a 400 Bad Request status code + And the system should return a response in JSON format + And the response should include an error message indicating the file type is not supported + And no wells should be imported + +@negative @file_format +Scenario: Upload fails due to empty file + Given my CSV file is empty + When I upload the file to the bulk upload endpoint + Then the system should return a 400 Bad Request status code + And the system should return a response in JSON format + And the response should include an error message indicating the file is empty + And no wells should be imported + +@negative @file_format + Scenario: Upload fails due to CSV with only headers and no data rows + Given my CSV file contains only column headers with no data rows + When I upload the CSV file to the bulk upload endpoint + Then the system should return a 400 Bad Request status code + And the system should return a response in JSON format + And the response should include an error indicating no data rows found + And no wells should be imported \ No newline at end of file From ff43c170f3d213d552382381fb25e46396f7370a Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 15:21:39 -0800 Subject: [PATCH 03/22] fix: change well purpose name --- features/backend/well-inventory-csv.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 1bde748..95209be 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -87,7 +87,7 @@ Feature: Upload a well inventory spreadsheet (CSV) And the field "casing_diameter_ft" is included if available as a numeric value in feet And the field "measuring_point_height_ft" is provided as a numeric value in feet And the field "measuring_point_description" is included if available - And the field "well_use_purpose" is included if available and one of the well_use_purpose lexicon values + And the field "well_purpose" is included if available and one of the well_purpose lexicon values And the field "well_hole_status" is included if available and one of the well_hole_status lexicon values And the field "monitoring_frequency" is included if available and one of the monitoring_frequency lexicon values From 23eced1f6351866e8c4705dfd5883d4231f8c39c Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 15:25:24 -0800 Subject: [PATCH 04/22] fix: timezone offset --- features/backend/well-inventory-csv.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 95209be..5e32c54 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -19,7 +19,7 @@ Feature: Upload a well inventory spreadsheet (CSV) And the field "project" is provided And the field "well_name_point_id" is provided and unique per row And the field "site_name" is provided - And the field "date_time" is provided as a valid timestamp in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00Z-08:00" + And the field "date_time" is provided as a valid timestamp in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00-08:00" And the field "field_staff" is provided and contains the first and last name of the primary person who measured or logged the data And the field "field_staff_2" is included if available And the field "field_staff_3" is included if available @@ -75,10 +75,10 @@ Feature: Upload a well inventory spreadsheet (CSV) # Well attributes And the field "ose_well_record_id" is included if available - And the field "date_drilled" is included if available as a valid date in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00Z-08:00" + And the field "date_drilled" is included if available as a valid date in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00-08:00" And the field "completion_source" is included if available And the field "total_well_depth_ft" is included if available as a numeric value in feet - And the field "static_water_depth_ft" is included if available as a numeric value + And the field "historic_depth_to_water_ft" is included if available as a numeric value in feet And the field "depth_source" is included if available And the field "well_pump_type" is included if available and one of the well_pump_type lexicon values And the field "well_pump_depth_ft" is included if available as a numeric value in feet From 1888c7a786bb54c48ea8b733270015bf23476609 Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 15:38:10 -0800 Subject: [PATCH 05/22] fix: use a single contact for now until multiple is needed by users --- features/backend/well-inventory-csv.feature | 54 ++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 5e32c54..c8fe3c9 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -7,16 +7,16 @@ Feature: Upload a well inventory spreadsheet (CSV) Background: Given a functioning api And my CSV file is encoded in UTF-8 and uses commas as separators + And the system has valid lexicon values for contact_role, contact_type, phone_type, email_type, address_type, elevation_method, well_pump_type, well_purpose, well_hole_status, and monitoring_frequency @positive @happy_path Scenario: Upload a well inventory CSV with all required and optional fields correctly filled out - # is provided means the field is required and must be filled out + # is provided means the field is required # is included if available means the field is optional and may be filled out - # FIELD NAMES ARE CSV FIELD NAMES, NOT API/DB FIELD NAMES # Field Visit Event fields - And the field "project" is provided + Given the field "project" is provided And the field "well_name_point_id" is provided and unique per row And the field "site_name" is provided And the field "date_time" is provided as a valid timestamp in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00-08:00" @@ -25,34 +25,34 @@ Feature: Upload a well inventory spreadsheet (CSV) And the field "field_staff_3" is included if available # Well Contact (Owner) fields - And the field "contact_1_name" is provided - And the field "contact_1_organization" is included if available - And the field "contact_1_role" is provided and one of the contact_role lexicon values - And the field "contact_1_type" is provided and one of the contact_type lexicon values + And the field "contact_name" is provided + And the field "contact_organization" is included if available + And the field "contact_role" is provided and one of the contact_role lexicon values + And the field "contact_type" is provided and one of the contact_type lexicon values # Phone and Email fields are optional - And the field "contact_1_phone_1" is included if available - And the field "contact_1_phone__1_type" is included if contact_1_phone_1 is provided and is one of the phone_type lexicon values - And the field "contact_1_phone_2" is included if available - And the field "contact_1_phone_2_type" is included if contact_1_phone_2 is provided and is one of the phone_type lexicon values - And the field "contact_1_email_1" is included if available - And the field "contact_1_email_1_type" is included if contact_1_email_1 is provided and is one of the email_type lexicon values - And the field "contact_1_email_2" is included if available - And the field "contact_1_email_2_type" is included if contact_1_email_2 is provided and is one of the email_type lexicon values + And the field "contact_phone_1" is included if available + And the field "contact_phone_1_type" is included if contact_phone_1 is provided and is one of the phone_type lexicon values + And the field "contact_phone_2" is included if available + And the field "contact_phone_2_type" is included if contact_phone_2 is provided and is one of the phone_type lexicon values + And the field "contact_email_1" is included if available + And the field "contact_email_1_type" is included if contact_email_1 is provided and is one of the email_type lexicon values + And the field "contact_email_2" is included if available + And the field "contact_email_2_type" is included if contact_email_2 is provided and is one of the email_type lexicon values # Address fields are optional - And the field "contact_1_address_1_line_1" is provided - And the field "contact_1_address_1_line_2" is included if available - And the field "contact_1_address_1_type" is provided and one of the address_type lexicon values - And the field "contact_1_address_1_state" is provided - And the field "contact_1_address_1_city" is provided - And the field "contact_1_address_1_postal_code" is provided - And the field "contact_1_address_2_line_1" is included if available - And the field "contact_1_address_2_line_2" is included if available - And the field "contact_1_address_2_type" is included if contact_1_address_2_line_1 is provided and is one of the address_type lexicon values - And the field "contact_1_address_2_state" is included if contact_1_address_2_line_1 is provided - And the field "contact_1_address_2_city" is included if contact_1_address_2_line_1 is provided - And the field "contact_1_address_2_postal_code" is included if contact_1_address_2_line_1 is provided + And the field "contact_address_1_line_1" is included if available + And the field "contact_address_1_line_2" is included if available + And the field "contact_address_1_type" is included if contact_address_1_line_1 is provided and is one of the address_type lexicon values + And the field "contact_address_1_state" is included if contact_address_1_line_1 is provided + And the field "contact_address_1_city" is included if contact_address_1_line_1 is provided + And the field "contact_address_1_postal_code" is included if contact_address_1_line_1 is provided + And the field "contact_address_2_line_1" is included if available + And the field "contact_address_2_line_2" is included if available + And the field "contact_address_2_type" is included if contact_address_2_line_1 is provided and is one of the address_type lexicon values + And the field "contact_address_2_state" is included if contact_address_2_line_1 is provided + And the field "contact_address_2_city" is included if contact_address_2_line_1 is provided + And the field "contact_address_2_postal_code" is included if contact_address_2_line_1 is provided # Location notes And the field "directions_to_site" is included if available From a07e4bbd8da22406dac88fedbc00466244e3258d Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 7 Nov 2025 16:13:43 -0800 Subject: [PATCH 06/22] fix: add utm_zone --- features/backend/well-inventory-csv.feature | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index c8fe3c9..d13ff80 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -68,8 +68,9 @@ Feature: Upload a well inventory spreadsheet (CSV) And the field "special_requests" is included if available # Location fields - And the field "utm_easting" is provided as a numeric value in NAD83 UTM Zone 13 - And the field "utm_northing" is provided as a numeric value in NAD83 UTM Zone 13 + And the field "utm_easting" is provided as a numeric value in NAD83 + And the field "utm_northing" is provided as a numeric value in NAD83 + And the field "utm_zone" is provided as a numeric value And the field "elevation_ft" is provided as a numeric value in NAVD88 And the field "elevation_method" is provided and one of the elevation_method lexicon values From 38b77363f0dfce441868c60a3367b920501a3c6f Mon Sep 17 00:00:00 2001 From: jakeross Date: Fri, 14 Nov 2025 09:27:36 -0700 Subject: [PATCH 07/22] feat: enhance well inventory CSV upload feature with improved scenarios and validation --- features/backend/well-inventory-csv.feature | 337 ++++++++++---------- 1 file changed, 165 insertions(+), 172 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index d13ff80..adea46f 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -1,193 +1,186 @@ -@backend @BDMS-?? @production -Feature: Upload a well inventory spreadsheet (CSV) +@backend +@BDMS-?? +@production +Feature: Bulk upload well inventory from CSV As a hydrogeologist or data specialist I want to upload a CSV file containing well inventory data for multiple wells - So that many wells can be imported quickly and accurately into the system - - Background: - Given a functioning api - And my CSV file is encoded in UTF-8 and uses commas as separators - And the system has valid lexicon values for contact_role, contact_type, phone_type, email_type, address_type, elevation_method, well_pump_type, well_purpose, well_hole_status, and monitoring_frequency - - @positive @happy_path - Scenario: Upload a well inventory CSV with all required and optional fields correctly filled out - # is provided means the field is required - # is included if available means the field is optional and may be filled out - # FIELD NAMES ARE CSV FIELD NAMES, NOT API/DB FIELD NAMES - - # Field Visit Event fields - Given the field "project" is provided - And the field "well_name_point_id" is provided and unique per row - And the field "site_name" is provided - And the field "date_time" is provided as a valid timestamp in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00-08:00" - And the field "field_staff" is provided and contains the first and last name of the primary person who measured or logged the data - And the field "field_staff_2" is included if available - And the field "field_staff_3" is included if available - - # Well Contact (Owner) fields - And the field "contact_name" is provided - And the field "contact_organization" is included if available - And the field "contact_role" is provided and one of the contact_role lexicon values - And the field "contact_type" is provided and one of the contact_type lexicon values - - # Phone and Email fields are optional - And the field "contact_phone_1" is included if available - And the field "contact_phone_1_type" is included if contact_phone_1 is provided and is one of the phone_type lexicon values - And the field "contact_phone_2" is included if available - And the field "contact_phone_2_type" is included if contact_phone_2 is provided and is one of the phone_type lexicon values - And the field "contact_email_1" is included if available - And the field "contact_email_1_type" is included if contact_email_1 is provided and is one of the email_type lexicon values - And the field "contact_email_2" is included if available - And the field "contact_email_2_type" is included if contact_email_2 is provided and is one of the email_type lexicon values - - # Address fields are optional - And the field "contact_address_1_line_1" is included if available - And the field "contact_address_1_line_2" is included if available - And the field "contact_address_1_type" is included if contact_address_1_line_1 is provided and is one of the address_type lexicon values - And the field "contact_address_1_state" is included if contact_address_1_line_1 is provided - And the field "contact_address_1_city" is included if contact_address_1_line_1 is provided - And the field "contact_address_1_postal_code" is included if contact_address_1_line_1 is provided - And the field "contact_address_2_line_1" is included if available - And the field "contact_address_2_line_2" is included if available - And the field "contact_address_2_type" is included if contact_address_2_line_1 is provided and is one of the address_type lexicon values - And the field "contact_address_2_state" is included if contact_address_2_line_1 is provided - And the field "contact_address_2_city" is included if contact_address_2_line_1 is provided - And the field "contact_address_2_postal_code" is included if contact_address_2_line_1 is provided - - # Location notes - And the field "directions_to_site" is included if available - And the field "specific_location_of_well" is included if available - - # Permissions - And the field "repeat_measurement_permission" is included if available as true or false - And the field "sampling_permission" is included if available as true or false - And the field "datalogger_installation_permission" is included if available as true or false - And the field "public_availability_acknowledgement" is included if available as true or false - - # Special requests - And the field "special_requests" is included if available - - # Location fields - And the field "utm_easting" is provided as a numeric value in NAD83 - And the field "utm_northing" is provided as a numeric value in NAD83 - And the field "utm_zone" is provided as a numeric value - And the field "elevation_ft" is provided as a numeric value in NAVD88 - And the field "elevation_method" is provided and one of the elevation_method lexicon values - - # Well attributes - And the field "ose_well_record_id" is included if available - And the field "date_drilled" is included if available as a valid date in ISO 8601 format with timezone offset (UTC-8) such as "2025-02-15T10:30:00-08:00" - And the field "completion_source" is included if available - And the field "total_well_depth_ft" is included if available as a numeric value in feet - And the field "historic_depth_to_water_ft" is included if available as a numeric value in feet - And the field "depth_source" is included if available - And the field "well_pump_type" is included if available and one of the well_pump_type lexicon values - And the field "well_pump_depth_ft" is included if available as a numeric value in feet - And the field "is_open" is included if available as true or false - And the field "datalogger_possible" is included if available as true or false - And the field "casing_diameter_ft" is included if available as a numeric value in feet - And the field "measuring_point_height_ft" is provided as a numeric value in feet - And the field "measuring_point_description" is included if available - And the field "well_purpose" is included if available and one of the well_purpose lexicon values - And the field "well_hole_status" is included if available and one of the well_hole_status lexicon values - And the field "monitoring_frequency" is included if available and one of the monitoring_frequency lexicon values + So that well records can be created efficiently and accurately in the system + + Background: + Given my CSV file is encoded in UTF-8 and uses commas as separators + And valid lexicon values exist for: + | contact_role | + | contact_type | + | phone_type | + | email_type | + | address_type | + | elevation_method | + | well_pump_type | + | well_purpose | + | well_hole_status | + | monitoring_frequency | +# + @positive @happy_path @BDMS-?? + Scenario: Uploading a valid well inventory CSV containing required and optional fields + Given my CSV file contains multiple rows of well inventory data + And the CSV includes required fields: + | project | + | well_name_point_id | + | site_name | + | date_time | + | field_staff | + | utm_easting | + | utm_northing | + | utm_zone | + | elevation_ft | + | elevation_method | + | measuring_point_height_ft | + And each "well_name_point_id" value is unique per row + And "date_time" values are valid ISO 8601 timestamps with timezone offsets (e.g. "2025-02-15T10:30:00-08:00") + And the CSV includes optional fields when available: + | field_staff_2 | + | field_staff_3 | + | contact_name | + | contact_organization | + | contact_role | + | contact_type | + | contact_phone_1 | + | contact_phone_1_type | + | contact_phone_2 | + | contact_phone_2_type | + | contact_email_1 | + | contact_email_1_type | + | contact_email_2 | + | contact_email_2_type | + | contact_address_1_line_1 | + | contact_address_1_line_2 | + | contact_address_1_type | + | contact_address_1_state | + | contact_address_1_city | + | contact_address_1_postal_code | + | contact_address_2_line_1 | + | contact_address_2_line_2 | + | contact_address_2_type | + | contact_address_2_state | + | contact_address_2_city | + | contact_address_2_postal_code | + | directions_to_site | + | specific_location_of_well | + | repeat_measurement_permission | + | sampling_permission | + | datalogger_installation_permission | + | public_availability_acknowledgement | + | special_requests | + | ose_well_record_id | + | date_drilled | + | completion_source | + | total_well_depth_ft | + | historic_depth_to_water_ft | + | depth_source | + | well_pump_type | + | well_pump_depth_ft | + | is_open | + | datalogger_possible | + | casing_diameter_ft | + | measuring_point_description | + | well_purpose | + | well_hole_status | + | monitoring_frequency | +# And all optional lexicon fields contain valid lexicon values when provided +# And all optional numeric fields contain valid numeric values when provided +# And all optional date fields contain valid ISO 8601 timestamps when provided When I upload the CSV file to the bulk upload endpoint - Then the system should return a 201 Created status code + Then the system returns a 201 Created status code And the system should return a response in JSON format - And null values in the response should be represented as JSON null (not placeholder strings) - - # Upload Summary - And the response should include a summary with total rows processed - And the response should include a summary with total rows successfully imported - And the response should include a summary with any validation errors or warnings - - # Created Well Objects - And the response should include an array of created water well objects +# And null values in the response are represented as JSON null + And the response includes a summary containing: + | total_rows_processed | 10 | + | total_rows_imported | 10 | + | validation_errors_or_warnings | 0 | + And the response includes an array of created well objects - @negative @validation - Scenario: Upload fails due to missing required field in one or more rows - Given my CSV file contains one or more rows with missing values in the required field "well_name_point_id" - When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response should include validation errors for all rows with missing required fields - And the response should indicate which row and field contains each error - And no wells should be imported - @negative @validation - Scenario: Upload fails due to duplicate well names in one or more rows - Given my CSV file contains one or more rows with duplicate values in the "well_name_point_id" field - When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response should include validation errors for all rows with duplicate well names - And the response should indicate which row and field contains each error - And no wells should be imported + ########################################################################### + # NEGATIVE VALIDATION SCENARIOS + ########################################################################### - @negative @validation - Scenario: Upload fails due to invalid lexicon value in one or more rows - Given my CSV file contains one or more rows with an invalid value in the "contact_1_role" field that is not in the contact_role lexicon + @negative @validation @BDMS-?? + Scenario: Upload fails when required fields are missing + Given my CSV file contains rows missing a required field "well_name_point_id" When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code + Then the system returns a 422 Unprocessable Entity status code And the system should return a response in JSON format - And the response should include validation errors for all rows with invalid lexicon values - And the response should indicate which row and field contains each error - And no wells should be imported + And the response includes validation errors for all rows missing required fields + And the response identifies the row and field for each error + And no wells are imported - @negative @validation - Scenario: Upload fails due to invalid date format in one or more rows - Given my CSV file contains one or more rows with an invalid date format in the "date_time" field + @negative @validation @BDMS-?? + Scenario: Upload fails when duplicate well_name_point_id values are present + Given my CSV file contains one or more duplicate "well_name_point_id" values When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response should include validation errors for all rows with invalid date formats - And the response should indicate which row and field contains each error - And no wells should be imported - - @negative @validation - Scenario: Upload fails due to invalid numeric value in one or more rows - Given my CSV file contains one or more rows with a value that cannot be parsed as a numeric value in the "utm_easting" field + Then the system returns a 422 Unprocessable Entity status code + And the response includes validation errors indicating duplicated values + And each error identifies the row and field + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails due to invalid lexicon values + Given my CSV file contains invalid lexicon values for "contact_role" or other lexicon fields When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response should include validation errors for all rows with invalid numeric values - And the response should indicate which row and field contains each error - And no wells should be imported + Then the system returns a 422 Unprocessable Entity status code + And the response includes validation errors identifying the invalid field and row + And no wells are imported - @negative @validation - Scenario: Upload fails due to missing conditional field in one or more rows - Given my CSV file contains one or more rows that include "contact_1_address_2_line_1" but are missing the required conditional field "contact_1_address_2_city" + @negative @validation @BDMS-?? + Scenario: Upload fails due to invalid date formats + Given my CSV file contains invalid ISO 8601 date values in the "date_time" field When I upload the CSV file to the bulk upload endpoint - Then the system should return a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response should include validation errors for all rows with missing conditional fields - And the response should indicate which row and field contains each error - And no wells should be imported + Then the system returns a 422 Unprocessable Entity status code + And the response includes validation errors identifying the invalid field and row + And no wells are imported -@negative @file_format -Scenario: Upload fails due to unsupported file type - Given I upload a file that is not a CSV file + @negative @validation @BDMS-?? + Scenario: Upload fails due to invalid numeric fields + Given my CSV file contains values that cannot be parsed as numeric in numeric-required fields such as "utm_easting" + When I upload the CSV file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the response includes validation errors identifying the invalid field and row + And no wells are imported +# +# @negative @validation @BDMS-?? +# Scenario: Upload fails when conditional address fields are incomplete +# Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" +# When I upload the CSV file to the bulk upload endpoint +# Then the system returns a 422 Unprocessable Entity status code +# And the response lists conditional field validation errors per row +# And no wells are imported +# +# +# ########################################################################### +# # FILE FORMAT SCENARIOS +# ########################################################################### +# + @negative @file_format @BDMS-?? + Scenario: Upload fails when file type is unsupported + Given I attempt to upload a non-CSV file When I upload the file to the bulk upload endpoint - Then the system should return a 400 Bad Request status code - And the system should return a response in JSON format - And the response should include an error message indicating the file type is not supported - And no wells should be imported + Then the system returns a 400 status code + And the response includes an error message indicating unsupported file type + And no wells are imported -@negative @file_format -Scenario: Upload fails due to empty file + @negative @file_format @BDMS-?? + Scenario: Upload fails when the CSV file is empty Given my CSV file is empty When I upload the file to the bulk upload endpoint - Then the system should return a 400 Bad Request status code - And the system should return a response in JSON format - And the response should include an error message indicating the file is empty - And no wells should be imported + Then the system returns a 400 status code + And the response includes an error message indicating an empty file + And no wells are imported -@negative @file_format - Scenario: Upload fails due to CSV with only headers and no data rows - Given my CSV file contains only column headers with no data rows - When I upload the CSV file to the bulk upload endpoint - Then the system should return a 400 Bad Request status code - And the system should return a response in JSON format - And the response should include an error indicating no data rows found - And no wells should be imported \ No newline at end of file + @negative @file_format @BDMS-?? + Scenario: Upload fails when CSV contains only headers + Given my CSV file contains column headers but no data rows + When I upload the file to the bulk upload endpoint + Then the system returns a 400 status code + And the response includes an error indicating that no data rows were found + And no wells are imported From 85aea385e17ef983487565709f62ebabf704916c Mon Sep 17 00:00:00 2001 From: jakeross Date: Fri, 14 Nov 2025 15:19:34 -0700 Subject: [PATCH 08/22] feat: update well inventory CSV upload scenarios for clarity and consistency --- features/backend/well-inventory-csv.feature | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index adea46f..3e855bd 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -90,7 +90,7 @@ Feature: Bulk upload well inventory from CSV # And all optional numeric fields contain valid numeric values when provided # And all optional date fields contain valid ISO 8601 timestamps when provided - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 201 Created status code And the system should return a response in JSON format # And null values in the response are represented as JSON null @@ -108,7 +108,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails when required fields are missing Given my CSV file contains rows missing a required field "well_name_point_id" - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the system should return a response in JSON format And the response includes validation errors for all rows missing required fields @@ -118,7 +118,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails when duplicate well_name_point_id values are present Given my CSV file contains one or more duplicate "well_name_point_id" values - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors indicating duplicated values And each error identifies the row and field @@ -127,7 +127,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails due to invalid lexicon values Given my CSV file contains invalid lexicon values for "contact_role" or other lexicon fields - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors identifying the invalid field and row And no wells are imported @@ -135,7 +135,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails due to invalid date formats Given my CSV file contains invalid ISO 8601 date values in the "date_time" field - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors identifying the invalid field and row And no wells are imported @@ -143,7 +143,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails due to invalid numeric fields Given my CSV file contains values that cannot be parsed as numeric in numeric-required fields such as "utm_easting" - When I upload the CSV file to the bulk upload endpoint + When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors identifying the invalid field and row And no wells are imported @@ -151,7 +151,7 @@ Feature: Bulk upload well inventory from CSV # @negative @validation @BDMS-?? # Scenario: Upload fails when conditional address fields are incomplete # Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" -# When I upload the CSV file to the bulk upload endpoint +# When I upload the file to the bulk upload endpoint # Then the system returns a 422 Unprocessable Entity status code # And the response lists conditional field validation errors per row # And no wells are imported @@ -163,7 +163,7 @@ Feature: Bulk upload well inventory from CSV # @negative @file_format @BDMS-?? Scenario: Upload fails when file type is unsupported - Given I attempt to upload a non-CSV file + Given I have a non-CSV file When I upload the file to the bulk upload endpoint Then the system returns a 400 status code And the response includes an error message indicating unsupported file type From 0d15ebeff4ae274b64c3fefbffd5a4780bb6b288 Mon Sep 17 00:00:00 2001 From: jakeross Date: Sat, 15 Nov 2025 08:52:54 -0700 Subject: [PATCH 09/22] feat: refine well inventory CSV upload scenarios for improved clarity and accuracy --- features/backend/well-inventory-csv.feature | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 3e855bd..4447920 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -7,7 +7,7 @@ Feature: Bulk upload well inventory from CSV So that well records can be created efficiently and accurately in the system Background: - Given my CSV file is encoded in UTF-8 and uses commas as separators + Given a functioning api And valid lexicon values exist for: | contact_role | | contact_type | @@ -19,10 +19,12 @@ Feature: Bulk upload well inventory from CSV | well_purpose | | well_hole_status | | monitoring_frequency | -# + @positive @happy_path @BDMS-?? Scenario: Uploading a valid well inventory CSV containing required and optional fields - Given my CSV file contains multiple rows of well inventory data + Given a valid CSV file for bulk well inventory upload + And my CSV file is encoded in UTF-8 and uses commas as separators + And my CSV file contains multiple rows of well inventory data And the CSV includes required fields: | project | | well_name_point_id | @@ -95,8 +97,8 @@ Feature: Bulk upload well inventory from CSV And the system should return a response in JSON format # And null values in the response are represented as JSON null And the response includes a summary containing: - | total_rows_processed | 10 | - | total_rows_imported | 10 | + | total_rows_processed | 2 | + | total_rows_imported | 2 | | validation_errors_or_warnings | 0 | And the response includes an array of created well objects From c01d01bd35eb7376e0c73aa3c596f7ccc9b54ce5 Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Mon, 17 Nov 2025 13:19:11 -0800 Subject: [PATCH 10/22] feat: add two potential contacts and additional requested notes/communication preference fields --- features/backend/well-inventory-csv.feature | 77 ++++++++++++++------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 4447920..2f0ec58 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -42,37 +42,62 @@ Feature: Bulk upload well inventory from CSV And the CSV includes optional fields when available: | field_staff_2 | | field_staff_3 | - | contact_name | - | contact_organization | - | contact_role | - | contact_type | - | contact_phone_1 | - | contact_phone_1_type | - | contact_phone_2 | - | contact_phone_2_type | - | contact_email_1 | - | contact_email_1_type | - | contact_email_2 | - | contact_email_2_type | - | contact_address_1_line_1 | - | contact_address_1_line_2 | - | contact_address_1_type | - | contact_address_1_state | - | contact_address_1_city | - | contact_address_1_postal_code | - | contact_address_2_line_1 | - | contact_address_2_line_2 | - | contact_address_2_type | - | contact_address_2_state | - | contact_address_2_city | - | contact_address_2_postal_code | + | contact_1_name | + | contact_1_organization | + | contact_1_role | + | contact_1_type | + | contact_1_phone_1 | + | contact_1_phone_1_type | + | contact_1_phone_2 | + | contact_1_phone_2_type | + | contact_1_email_1 | + | contact_1_email_1_type | + | contact_1_email_2 | + | contact_1_email_2_type | + | contact_1_address_1_line_1 | + | contact_1_address_1_line_2 | + | contact_1_address_1_type | + | contact_1_address_1_state | + | contact_1_address_1_city | + | contact_1_address_1_postal_code | + | contact_1_address_2_line_1 | + | contact_1_address_2_line_2 | + | contact_1_address_2_type | + | contact_1_address_2_state | + | contact_1_address_2_city | + | contact_1_address_2_postal_code | + | contact_2_name | + | contact_2_organization | + | contact_2_role | + | contact_2_type | + | contact_2_phone_1 | + | contact_2_phone_1_type | + | contact_2_phone_2 | + | contact_2_phone_2_type | + | contact_2_email_1 | + | contact_2_email_1_type | + | contact_2_email_2 | + | contact_2_email_2_type | + | contact_2_address_1_line_1 | + | contact_2_address_1_line_2 | + | contact_2_address_1_type | + | contact_2_address_1_state | + | contact_2_address_1_city | + | contact_2_address_1_postal_code | + | contact_2_address_2_line_1 | + | contact_2_address_2_line_2 | + | contact_2_address_2_type | + | contact_2_address_2_state | + | contact_2_address_2_city | + | contact_2_address_2_postal_code | | directions_to_site | | specific_location_of_well | | repeat_measurement_permission | | sampling_permission | | datalogger_installation_permission | | public_availability_acknowledgement | - | special_requests | + | result_communication_preference | + | contact_special_requests_notes | | ose_well_record_id | | date_drilled | | completion_source | @@ -88,6 +113,8 @@ Feature: Bulk upload well inventory from CSV | well_purpose | | well_hole_status | | monitoring_frequency | + | sampling_scenario_notes | + | well_measurment_notes | # And all optional lexicon fields contain valid lexicon values when provided # And all optional numeric fields contain valid numeric values when provided # And all optional date fields contain valid ISO 8601 timestamps when provided From 6a295dedb112b8f0be9e63d0f45f0fbbc737b478 Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Mon, 17 Nov 2025 13:20:22 -0800 Subject: [PATCH 11/22] fix: typo --- features/backend/well-inventory-csv.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 2f0ec58..b907d51 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -114,7 +114,7 @@ Feature: Bulk upload well inventory from CSV | well_hole_status | | monitoring_frequency | | sampling_scenario_notes | - | well_measurment_notes | + | well_measurement_notes | # And all optional lexicon fields contain valid lexicon values when provided # And all optional numeric fields contain valid numeric values when provided # And all optional date fields contain valid ISO 8601 timestamps when provided From d470b74192fd33387853023f5c35177456137cda Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Mon, 17 Nov 2025 13:22:05 -0800 Subject: [PATCH 12/22] fix: well measuring notes verbage --- features/backend/well-inventory-csv.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index b907d51..cce3ccb 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -114,7 +114,7 @@ Feature: Bulk upload well inventory from CSV | well_hole_status | | monitoring_frequency | | sampling_scenario_notes | - | well_measurement_notes | + | well_measuring_notes | # And all optional lexicon fields contain valid lexicon values when provided # And all optional numeric fields contain valid numeric values when provided # And all optional date fields contain valid ISO 8601 timestamps when provided From d2135dee782cf2429c5a9ec92113a71e28c0248d Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Wed, 19 Nov 2025 14:25:25 -0800 Subject: [PATCH 13/22] feat: add sample_possible true/false to the csv --- features/backend/well-inventory-csv.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index cce3ccb..7744f52 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -115,6 +115,7 @@ Feature: Bulk upload well inventory from CSV | monitoring_frequency | | sampling_scenario_notes | | well_measuring_notes | + | sample_possible | # And all optional lexicon fields contain valid lexicon values when provided # And all optional numeric fields contain valid numeric values when provided # And all optional date fields contain valid ISO 8601 timestamps when provided From 8e5829f8134c45968a0ba014dc1c62a7b0be48ea Mon Sep 17 00:00:00 2001 From: jakeross Date: Thu, 20 Nov 2025 07:59:23 -0700 Subject: [PATCH 14/22] feat: add negative validation scenarios for CSV upload errors --- features/backend/well-inventory-csv.feature | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 7744f52..a835378 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -134,6 +134,24 @@ Feature: Bulk upload well inventory from CSV ########################################################################### # NEGATIVE VALIDATION SCENARIOS ########################################################################### + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has an invalid postal code format + Given my CSV file contains a row that has an invalid postal code format in contact_1_address_1_postal_code + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the invalid postal code format + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has contact without a contact_role + Given my CSV file contains a row with a contact but is missing the required "contact_role" field for that contact + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "contact_role" field + And no wells are imported + @negative @validation @BDMS-?? Scenario: Upload fails when required fields are missing From e03be39279a745087e1cd440cdbf99b6359201be Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Thu, 20 Nov 2025 12:11:21 -0800 Subject: [PATCH 15/22] feat: add more negative scenarios for contact and state --- features/backend/well-inventory-csv.feature | 64 ++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index a835378..aa1501e 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -143,6 +143,24 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the invalid postal code format And no wells are imported + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has a contact with a invalid phone number format + Given my CSV file contains a row with a contact with a phone number that is not in the valid format + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the invalid phone number format + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has a contact with a invalid email format + Given my CSV file contains a row with a contact with an email that is not in the valid format + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the invalid email format + And no wells are imported + @negative @validation @BDMS-?? Scenario: Upload fails when a row has contact without a contact_role Given my CSV file contains a row with a contact but is missing the required "contact_role" field for that contact @@ -152,6 +170,50 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the missing "contact_role" field And no wells are imported + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has contact without a "contact_type" + Given my CSV file contains a row with a contact but is missing the required "contact_type" field for that contact + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "contact_type" value + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has contact with an email without an email_type + Given my CSV file contains a row with a contact with an email but is missing the required "email_type" field for that email + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "email_type" value + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has contact with a phone without a phone_type + Given my CSV file contains a row with a contact with a phone but is missing the required "phone_type" field for that phone + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "phone_type" value + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has contact with an address without an address_type + Given my CSV file contains a row with a contact with an address but is missing the required "address_type" field for that address + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "address_type" value + And no wells are imported + + @negative @validation @BDMS-?? + Scenario: Upload fails when a row has utm_easting utm_northing and utm_zone values that are not within New Mexico + Given my CSV file contains a row with utm_easting utm_northing and utm_zone values that are not within New Mexico + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the invalid UTM coordinates + And no wells are imported @negative @validation @BDMS-?? Scenario: Upload fails when required fields are missing @@ -182,7 +244,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @BDMS-?? Scenario: Upload fails due to invalid date formats - Given my CSV file contains invalid ISO 8601 date values in the "date_time" field + Given my CSV file contains invalid ISO 8601 date values in the "date_time" or "date_drilled" field When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors identifying the invalid field and row From 63ecc67a21bea63b5395759e88abcf8d981ef871 Mon Sep 17 00:00:00 2001 From: jakeross Date: Thu, 20 Nov 2025 21:12:35 -0700 Subject: [PATCH 16/22] feat: update well inventory CSV upload scenarios with consistent tagging and additional negative validation cases --- features/backend/well-inventory-csv.feature | 105 +++++++++++--------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index aa1501e..9714f12 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -1,5 +1,5 @@ @backend -@BDMS-?? +@BDMS-TBD @production Feature: Bulk upload well inventory from CSV As a hydrogeologist or data specialist @@ -20,7 +20,7 @@ Feature: Bulk upload well inventory from CSV | well_hole_status | | monitoring_frequency | - @positive @happy_path @BDMS-?? + @positive @happy_path @BDMS-TBD Scenario: Uploading a valid well inventory CSV containing required and optional fields Given a valid CSV file for bulk well inventory upload And my CSV file is encoded in UTF-8 and uses commas as separators @@ -134,7 +134,7 @@ Feature: Bulk upload well inventory from CSV ########################################################################### # NEGATIVE VALIDATION SCENARIOS ########################################################################### - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has an invalid postal code format Given my CSV file contains a row that has an invalid postal code format in contact_1_address_1_postal_code When I upload the file to the bulk upload endpoint @@ -143,7 +143,7 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the invalid postal code format And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has a contact with a invalid phone number format Given my CSV file contains a row with a contact with a phone number that is not in the valid format When I upload the file to the bulk upload endpoint @@ -152,7 +152,7 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the invalid phone number format And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has a contact with a invalid email format Given my CSV file contains a row with a contact with an email that is not in the valid format When I upload the file to the bulk upload endpoint @@ -161,7 +161,7 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the invalid email format And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has contact without a contact_role Given my CSV file contains a row with a contact but is missing the required "contact_role" field for that contact When I upload the file to the bulk upload endpoint @@ -170,43 +170,52 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the missing "contact_role" field And no wells are imported - @negative @validation @BDMS-?? - Scenario: Upload fails when a row has contact without a "contact_type" - Given my CSV file contains a row with a contact but is missing the required "contact_type" field for that contact - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating the missing "contact_type" value - And no wells are imported + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has contact without a "contact_type" + Given my CSV file contains a row with a contact but is missing the required "contact_type" field for that contact + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "contact_type" value + And no wells are imported - @negative @validation @BDMS-?? - Scenario: Upload fails when a row has contact with an email without an email_type - Given my CSV file contains a row with a contact with an email but is missing the required "email_type" field for that email - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating the missing "email_type" value - And no wells are imported + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has contact with an invalid "contact_type" + Given my CSV file contains a row with a contact_type value that is not in the valid lexicon for "contact_type" + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating an invalid "contact_type" value + And no wells are imported - @negative @validation @BDMS-?? - Scenario: Upload fails when a row has contact with a phone without a phone_type - Given my CSV file contains a row with a contact with a phone but is missing the required "phone_type" field for that phone - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating the missing "phone_type" value - And no wells are imported + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has contact with an email without an email_type + Given my CSV file contains a row with a contact with an email but is missing the required "email_type" field for that email + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "email_type" value + And no wells are imported + + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has contact with a phone without a phone_type + Given my CSV file contains a row with a contact with a phone but is missing the required "phone_type" field for that phone + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "phone_type" value + And no wells are imported - @negative @validation @BDMS-?? - Scenario: Upload fails when a row has contact with an address without an address_type - Given my CSV file contains a row with a contact with an address but is missing the required "address_type" field for that address - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating the missing "address_type" value - And no wells are imported + @negative @validation @BDMS-TBD + Scenario: Upload fails when a row has contact with an address without an address_type + Given my CSV file contains a row with a contact with an address but is missing the required "address_type" field for that address + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating the missing "address_type" value + And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has utm_easting utm_northing and utm_zone values that are not within New Mexico Given my CSV file contains a row with utm_easting utm_northing and utm_zone values that are not within New Mexico When I upload the file to the bulk upload endpoint @@ -215,7 +224,7 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating the invalid UTM coordinates And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when required fields are missing Given my CSV file contains rows missing a required field "well_name_point_id" When I upload the file to the bulk upload endpoint @@ -225,7 +234,7 @@ Feature: Bulk upload well inventory from CSV And the response identifies the row and field for each error And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails when duplicate well_name_point_id values are present Given my CSV file contains one or more duplicate "well_name_point_id" values When I upload the file to the bulk upload endpoint @@ -234,7 +243,7 @@ Feature: Bulk upload well inventory from CSV And each error identifies the row and field And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails due to invalid lexicon values Given my CSV file contains invalid lexicon values for "contact_role" or other lexicon fields When I upload the file to the bulk upload endpoint @@ -242,7 +251,7 @@ Feature: Bulk upload well inventory from CSV And the response includes validation errors identifying the invalid field and row And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails due to invalid date formats Given my CSV file contains invalid ISO 8601 date values in the "date_time" or "date_drilled" field When I upload the file to the bulk upload endpoint @@ -250,7 +259,7 @@ Feature: Bulk upload well inventory from CSV And the response includes validation errors identifying the invalid field and row And no wells are imported - @negative @validation @BDMS-?? + @negative @validation @BDMS-TBD Scenario: Upload fails due to invalid numeric fields Given my CSV file contains values that cannot be parsed as numeric in numeric-required fields such as "utm_easting" When I upload the file to the bulk upload endpoint @@ -258,7 +267,7 @@ Feature: Bulk upload well inventory from CSV And the response includes validation errors identifying the invalid field and row And no wells are imported # -# @negative @validation @BDMS-?? +# @negative @validation @BDMS-TBD # Scenario: Upload fails when conditional address fields are incomplete # Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" # When I upload the file to the bulk upload endpoint @@ -271,7 +280,7 @@ Feature: Bulk upload well inventory from CSV # # FILE FORMAT SCENARIOS # ########################################################################### # - @negative @file_format @BDMS-?? + @negative @file_format @BDMS-TBD Scenario: Upload fails when file type is unsupported Given I have a non-CSV file When I upload the file to the bulk upload endpoint @@ -279,7 +288,7 @@ Feature: Bulk upload well inventory from CSV And the response includes an error message indicating unsupported file type And no wells are imported - @negative @file_format @BDMS-?? + @negative @file_format @BDMS-TBD Scenario: Upload fails when the CSV file is empty Given my CSV file is empty When I upload the file to the bulk upload endpoint @@ -287,7 +296,7 @@ Feature: Bulk upload well inventory from CSV And the response includes an error message indicating an empty file And no wells are imported - @negative @file_format @BDMS-?? + @negative @file_format @BDMS-TBD Scenario: Upload fails when CSV contains only headers Given my CSV file contains column headers but no data rows When I upload the file to the bulk upload endpoint From 7bc5fb25bb38f76a00f0353a6ecbdb29699ae9e8 Mon Sep 17 00:00:00 2001 From: jakeross Date: Thu, 20 Nov 2025 22:48:55 -0700 Subject: [PATCH 17/22] feat: enhance well inventory CSV upload scenarios with additional lexicon and field requirements --- features/backend/well-inventory-csv.feature | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 9714f12..1ee62d9 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -9,6 +9,7 @@ Feature: Bulk upload well inventory from CSV Background: Given a functioning api And valid lexicon values exist for: + | lexicon category | | contact_role | | contact_type | | phone_type | @@ -26,6 +27,7 @@ Feature: Bulk upload well inventory from CSV And my CSV file is encoded in UTF-8 and uses commas as separators And my CSV file contains multiple rows of well inventory data And the CSV includes required fields: + | required field name | | project | | well_name_point_id | | site_name | @@ -40,6 +42,7 @@ Feature: Bulk upload well inventory from CSV And each "well_name_point_id" value is unique per row And "date_time" values are valid ISO 8601 timestamps with timezone offsets (e.g. "2025-02-15T10:30:00-08:00") And the CSV includes optional fields when available: + | optional field name | | field_staff_2 | | field_staff_3 | | contact_1_name | @@ -125,6 +128,7 @@ Feature: Bulk upload well inventory from CSV And the system should return a response in JSON format # And null values in the response are represented as JSON null And the response includes a summary containing: + | summary_field | value | | total_rows_processed | 2 | | total_rows_imported | 2 | | validation_errors_or_warnings | 0 | From a9a899c149a0d75a9ad47c76e3902eeac01d1269 Mon Sep 17 00:00:00 2001 From: Chase Martin Date: Fri, 21 Nov 2025 10:52:33 -0800 Subject: [PATCH 18/22] feat: add 2nd well purpose column --- features/backend/well-inventory-csv.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 1ee62d9..f1acca1 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -114,6 +114,7 @@ Feature: Bulk upload well inventory from CSV | casing_diameter_ft | | measuring_point_description | | well_purpose | + | well_purpose_2 | | well_hole_status | | monitoring_frequency | | sampling_scenario_notes | From c5402c0d03f1bd43b836c620ec60449d04c4f7d7 Mon Sep 17 00:00:00 2001 From: jakeross Date: Fri, 21 Nov 2025 12:53:09 -0700 Subject: [PATCH 19/22] feat: expand well inventory CSV upload scenarios with additional positive and negative validation cases --- features/backend/well-inventory-csv.feature | 177 +++++++++++++++++++- 1 file changed, 169 insertions(+), 8 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index f1acca1..9484553 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -135,10 +135,40 @@ Feature: Bulk upload well inventory from CSV | validation_errors_or_warnings | 0 | And the response includes an array of created well objects + @positive @validation @column_order @BDMS-TBD + Scenario: Upload succeeds when required columns are present but in a different order + Given my CSV file contains all required headers but in a different column order + And all required fields are populated with valid values + When I upload the file to the bulk upload endpoint + Then the system returns a 201 Created status code + And the system should return a response in JSON format + And all wells are imported + + @positive @validation @extra_columns @BDMS-TBD + Scenario: Upload succeeds when CSV contains extra, unknown columns + Given my CSV file contains all required headers + And my CSV file also contains additional columns not recognized by the system + And all required fields are populated with valid values + When I upload the file to the bulk upload endpoint + Then the system returns a 201 Created status code + And the system should return a response in JSON format + And all wells are imported + And the extra, unknown columns are ignored by the system ########################################################################### # NEGATIVE VALIDATION SCENARIOS ########################################################################### + @negative @validation @transactional_import @BDMS-TBD + Scenario: No wells are imported when any row fails validation + Given my CSV file contains 3 rows of well inventory data + And 2 rows are fully valid + And 1 row is missing the required "well_name_point_id" field + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error for the row missing "well_name_point_id" + And no wells are imported + @negative @validation @BDMS-TBD Scenario: Upload fails when a row has an invalid postal code format Given my CSV file contains a row that has an invalid postal code format in contact_1_address_1_postal_code @@ -239,6 +269,39 @@ Feature: Bulk upload well inventory from CSV And the response identifies the row and field for each error And no wells are imported + @negative @validation @required_fields @BDMS-TBD + Scenario Outline: Upload fails when a required field is missing + Given my CSV file contains a row missing the required "" field + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error for the "" field + And no wells are imported + + Examples: + | required_field | + | project | + | well_name_point_id | + | site_name | + | date_time | + | field_staff | + | utm_easting | + | utm_northing | + | utm_zone | + | elevation_ft | + | elevation_method | + | measuring_point_height_ft | + + @negative @validation @boolean_fields @BDMS-TBD + Scenario: Upload fails due to invalid boolean field values + Given my CSV file contains a row with an invalid boolean value "maybe" in the "is_open" field +# And my CSV file contains other boolean fields such as "sample_possible" with valid boolean values + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating an invalid boolean value for the "is_open" field + And no wells are imported + @negative @validation @BDMS-TBD Scenario: Upload fails when duplicate well_name_point_id values are present Given my CSV file contains one or more duplicate "well_name_point_id" values @@ -271,20 +334,29 @@ Feature: Bulk upload well inventory from CSV Then the system returns a 422 Unprocessable Entity status code And the response includes validation errors identifying the invalid field and row And no wells are imported -# -# @negative @validation @BDMS-TBD -# Scenario: Upload fails when conditional address fields are incomplete -# Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" -# When I upload the file to the bulk upload endpoint -# Then the system returns a 422 Unprocessable Entity status code + + @negative @validation @BDMS-TBD + Scenario: Upload fails when conditional address fields are incomplete + Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code # And the response lists conditional field validation errors per row -# And no wells are imported + And no wells are imported # # # ########################################################################### # # FILE FORMAT SCENARIOS # ########################################################################### -# + + @negative @file_format @limits @BDMS-TBD + Scenario: Upload fails when the CSV exceeds the maximum allowed number of rows + Given my CSV file contains more rows than the configured maximum for bulk upload + When I upload the file to the bulk upload endpoint + Then the system returns a 400 status code + And the system should return a response in JSON format + And the response includes an error message indicating the row limit was exceeded + And no wells are imported + @negative @file_format @BDMS-TBD Scenario: Upload fails when file type is unsupported Given I have a non-CSV file @@ -308,3 +380,92 @@ Feature: Bulk upload well inventory from CSV Then the system returns a 400 status code And the response includes an error indicating that no data rows were found And no wells are imported + + ########################################################################### + # HEADER & SCHEMA INTEGRITY SCENARIOS + ########################################################################### + + @negative @validation @header_row @BDMS-TBD + Scenario: Upload fails when a header row is repeated in the middle of the file + Given my CSV file contains a valid header row + And my CSV file contains data rows after the header + And a duplicate header row appears again after one or more data rows + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating a repeated header row + And no wells are imported + + @negative @validation @header_row @BDMS-TBD + Scenario: Upload fails when a required header name is misspelled + Given my CSV file header row contains a column "well_name_pointID" instead of "well_name_point_id" + And all other required headers are present and correctly spelled + And my CSV file contains data rows under these headers + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating a missing required header "well_name_point_id" + And no wells are imported + + @negative @validation @header_row @BDMS-TBD + Scenario: Upload fails when the header row contains duplicate column names + Given my CSV file header row contains the "contact_1_email_1" column name more than once + And my CSV file contains data rows under these duplicate columns + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating duplicate header names + And no wells are imported + + + ########################################################################### + # DELIMITER & QUOTING / EXCEL-RELATED SCENARIOS + ########################################################################### + + @negative @file_format @delimiter @BDMS-TBD + Scenario Outline: Upload fails when CSV uses an unsupported delimiter + Given my file is named with a .csv extension + And my file uses "" as the field delimiter instead of commas + And the header and data rows are otherwise valid + When I upload the file to the bulk upload endpoint + Then the system returns a 400 status code + And the system should return a response in JSON format + And the response includes an error message indicating an unsupported delimiter + And no wells are imported + + Examples: + | delimiter_description | + | semicolons | + | tab characters | + + @negative @file_format @quoting @BDMS-TBD + Scenario: Upload fails when CSV contains mismatched or unbalanced quotes + Given my CSV file contains a header row with valid column names + And my CSV file contains a data row where a field begins with a quote but does not have a matching closing quote + When I upload the file to the bulk upload endpoint + Then the system returns a 400 status code + And the system should return a response in JSON format + And the response includes an error message indicating malformed CSV due to unbalanced quotes + And no wells are imported + + @positive @file_format @quoting @BDMS-TBD + Scenario: Upload succeeds when fields contain commas inside properly quoted values + Given my CSV file header row contains all required columns + And my CSV file contains a data row where the "site_name" field value includes a comma and is enclosed in quotes + | site_name | + | "New Mexico Institute, Dept." | + And all other required fields are populated with valid values + When I upload the file to the bulk upload endpoint + Then the system returns a 201 Created status code + And the system should return a response in JSON format + And all wells are imported successfully + + @negative @validation @numeric @excel @BDMS-TBD + Scenario: Upload fails when numeric fields are provided in Excel scientific notation format + Given my CSV file contains a numeric-required field such as "utm_easting" + And Excel has exported the "utm_easting" value in scientific notation (for example "1.2345E+06") + When I upload the file to the bulk upload endpoint + Then the system returns a 422 Unprocessable Entity status code + And the system should return a response in JSON format + And the response includes a validation error indicating an invalid numeric format for "utm_easting" + And no wells are imported \ No newline at end of file From e310e6c9e2c728d3a16620da6b79cee1cf862600 Mon Sep 17 00:00:00 2001 From: jross Date: Fri, 21 Nov 2025 16:50:35 -0700 Subject: [PATCH 20/22] feat: enhance well inventory CSV upload scenarios with detailed required fields and improved negative validation cases --- features/backend/well-inventory-csv.feature | 38 +++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 9484553..80a2484 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -138,7 +138,19 @@ Feature: Bulk upload well inventory from CSV @positive @validation @column_order @BDMS-TBD Scenario: Upload succeeds when required columns are present but in a different order Given my CSV file contains all required headers but in a different column order - And all required fields are populated with valid values + And the CSV includes required fields: + | required field name | + | project | + | well_name_point_id | + | site_name | + | date_time | + | field_staff | + | utm_easting | + | utm_northing | + | utm_zone | + | elevation_ft | + | elevation_method | + | measuring_point_height_ft | When I upload the file to the bulk upload endpoint Then the system returns a 201 Created status code And the system should return a response in JSON format @@ -146,23 +158,18 @@ Feature: Bulk upload well inventory from CSV @positive @validation @extra_columns @BDMS-TBD Scenario: Upload succeeds when CSV contains extra, unknown columns - Given my CSV file contains all required headers - And my CSV file also contains additional columns not recognized by the system - And all required fields are populated with valid values + Given my CSV file contains extra columns but is otherwise valid When I upload the file to the bulk upload endpoint Then the system returns a 201 Created status code And the system should return a response in JSON format And all wells are imported - And the extra, unknown columns are ignored by the system ########################################################################### # NEGATIVE VALIDATION SCENARIOS ########################################################################### @negative @validation @transactional_import @BDMS-TBD Scenario: No wells are imported when any row fails validation - Given my CSV file contains 3 rows of well inventory data - And 2 rows are fully valid - And 1 row is missing the required "well_name_point_id" field + Given my CSV file contains 3 rows of data with 2 valid rows and 1 row missing the required "well_name_point_id" When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the system should return a response in JSON format @@ -335,15 +342,7 @@ Feature: Bulk upload well inventory from CSV And the response includes validation errors identifying the invalid field and row And no wells are imported - @negative @validation @BDMS-TBD - Scenario: Upload fails when conditional address fields are incomplete - Given my CSV file includes "contact_address_2_line_1" but omits required conditional fields such as "contact_address_2_city" - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code -# And the response lists conditional field validation errors per row - And no wells are imported -# -# + # ########################################################################### # # FILE FORMAT SCENARIOS # ########################################################################### @@ -387,9 +386,7 @@ Feature: Bulk upload well inventory from CSV @negative @validation @header_row @BDMS-TBD Scenario: Upload fails when a header row is repeated in the middle of the file - Given my CSV file contains a valid header row - And my CSV file contains data rows after the header - And a duplicate header row appears again after one or more data rows + Given my CSV file contains a valid but duplicate header row When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the system should return a response in JSON format @@ -410,7 +407,6 @@ Feature: Bulk upload well inventory from CSV @negative @validation @header_row @BDMS-TBD Scenario: Upload fails when the header row contains duplicate column names Given my CSV file header row contains the "contact_1_email_1" column name more than once - And my CSV file contains data rows under these duplicate columns When I upload the file to the bulk upload endpoint Then the system returns a 422 Unprocessable Entity status code And the system should return a response in JSON format From f3018eba572088530d7dbb590801df6e91cc6b77 Mon Sep 17 00:00:00 2001 From: jakeross Date: Fri, 21 Nov 2025 21:15:51 -0700 Subject: [PATCH 21/22] feat: remove redundant negative validation scenarios for CSV upload and improve clarity --- features/backend/well-inventory-csv.feature | 47 ++++++--------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index 80a2484..d335ea4 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -393,16 +393,6 @@ Feature: Bulk upload well inventory from CSV And the response includes a validation error indicating a repeated header row And no wells are imported - @negative @validation @header_row @BDMS-TBD - Scenario: Upload fails when a required header name is misspelled - Given my CSV file header row contains a column "well_name_pointID" instead of "well_name_point_id" - And all other required headers are present and correctly spelled - And my CSV file contains data rows under these headers - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating a missing required header "well_name_point_id" - And no wells are imported @negative @validation @header_row @BDMS-TBD Scenario: Upload fails when the header row contains duplicate column names @@ -422,7 +412,6 @@ Feature: Bulk upload well inventory from CSV Scenario Outline: Upload fails when CSV uses an unsupported delimiter Given my file is named with a .csv extension And my file uses "" as the field delimiter instead of commas - And the header and data rows are otherwise valid When I upload the file to the bulk upload endpoint Then the system returns a 400 status code And the system should return a response in JSON format @@ -434,34 +423,22 @@ Feature: Bulk upload well inventory from CSV | semicolons | | tab characters | - @negative @file_format @quoting @BDMS-TBD - Scenario: Upload fails when CSV contains mismatched or unbalanced quotes - Given my CSV file contains a header row with valid column names - And my CSV file contains a data row where a field begins with a quote but does not have a matching closing quote - When I upload the file to the bulk upload endpoint - Then the system returns a 400 status code - And the system should return a response in JSON format - And the response includes an error message indicating malformed CSV due to unbalanced quotes - And no wells are imported - @positive @file_format @quoting @BDMS-TBD Scenario: Upload succeeds when fields contain commas inside properly quoted values Given my CSV file header row contains all required columns And my CSV file contains a data row where the "site_name" field value includes a comma and is enclosed in quotes - | site_name | - | "New Mexico Institute, Dept." | - And all other required fields are populated with valid values +# And all other required fields are populated with valid values When I upload the file to the bulk upload endpoint Then the system returns a 201 Created status code And the system should return a response in JSON format - And all wells are imported successfully - - @negative @validation @numeric @excel @BDMS-TBD - Scenario: Upload fails when numeric fields are provided in Excel scientific notation format - Given my CSV file contains a numeric-required field such as "utm_easting" - And Excel has exported the "utm_easting" value in scientific notation (for example "1.2345E+06") - When I upload the file to the bulk upload endpoint - Then the system returns a 422 Unprocessable Entity status code - And the system should return a response in JSON format - And the response includes a validation error indicating an invalid numeric format for "utm_easting" - And no wells are imported \ No newline at end of file + And all wells are imported +# +# @negative @validation @numeric @excel @BDMS-TBD +# Scenario: Upload fails when numeric fields are provided in Excel scientific notation format +# Given my CSV file contains a numeric-required field such as "utm_easting" +# And Excel has exported the "utm_easting" value in scientific notation (for example "1.2345E+06") +# When I upload the file to the bulk upload endpoint +# Then the system returns a 422 Unprocessable Entity status code +# And the system should return a response in JSON format +# And the response includes a validation error indicating an invalid numeric format for "utm_easting" +# And no wells are imported \ No newline at end of file From dce035a2f7b3b7553acd5dd3db8afdd10ffa2b15 Mon Sep 17 00:00:00 2001 From: jakeross Date: Sat, 22 Nov 2025 17:43:39 -0700 Subject: [PATCH 22/22] feat: add scenario for successful upload with auto-generated well_name_point_id using "XY-" prefix --- features/backend/well-inventory-csv.feature | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/backend/well-inventory-csv.feature b/features/backend/well-inventory-csv.feature index d335ea4..f773896 100644 --- a/features/backend/well-inventory-csv.feature +++ b/features/backend/well-inventory-csv.feature @@ -164,6 +164,14 @@ Feature: Bulk upload well inventory from CSV And the system should return a response in JSON format And all wells are imported + @positive @validation @autogenerate_ids @BDMS-TBD + Scenario: Upload succeeds and system auto-generates well_name_point_id when prefixed with "XY- + Given my CSV file contains all valid columns but uses "XY-" prefix for well_name_point_id values + When I upload the file to the bulk upload endpoint + Then the system returns a 201 Created status code + And the system should return a response in JSON format + And all wells are imported with system-generated unique well_name_point_id values + ########################################################################### # NEGATIVE VALIDATION SCENARIOS ###########################################################################