From 9ca47dbdea2ad2fcd0bb4491bf377d8665abc0d2 Mon Sep 17 00:00:00 2001 From: roost-io Date: Sun, 9 Nov 2025 18:19:40 +0530 Subject: [PATCH] Functional test generated by RoostGPT Using AI Model eu.anthropic.claude-3-7-sonnet-20250219-v1:0 --- functional_tests/README.md | 16 + .../ZBIO-5136/.roost/roost_metadata.json | 8 +- functional_tests/ZBIO-5136/ZBIO-5136.csv | 34 +- functional_tests/ZBIO-5136/ZBIO-5136.feature | 395 +++++++++--------- functional_tests/ZBIO-5136/ZBIO-5136.json | 10 - functional_tests/ZBIO-5136/ZBIO-5136.xlsx | Bin 10466 -> 10185 bytes functional_tests/ZBIO-5136/ZBIO-5136.yaml | 9 +- 7 files changed, 236 insertions(+), 236 deletions(-) diff --git a/functional_tests/README.md b/functional_tests/README.md index 1c972b2..e22daf1 100644 --- a/functional_tests/README.md +++ b/functional_tests/README.md @@ -65,3 +65,19 @@ --- +**Execution Date:** 11/9/2025, 6:19:39 PM + +**Test Unique Identifier:** "ZBIO-5136" + +**Input(s):** + 1. JIRA ID: ZBIO-5136 + +**Test Output Folder:** + 1. [ZBIO-5136.json](ZBIO-5136/ZBIO-5136.json) + 2. [ZBIO-5136.feature](ZBIO-5136/ZBIO-5136.feature) + 3. [ZBIO-5136.csv](ZBIO-5136/ZBIO-5136.csv) + 4. [ZBIO-5136.xlsx](ZBIO-5136/ZBIO-5136.xlsx) + 5. [ZBIO-5136.yaml](ZBIO-5136/ZBIO-5136.yaml) + +--- + diff --git a/functional_tests/ZBIO-5136/.roost/roost_metadata.json b/functional_tests/ZBIO-5136/.roost/roost_metadata.json index 2193f15..0cd75ef 100644 --- a/functional_tests/ZBIO-5136/.roost/roost_metadata.json +++ b/functional_tests/ZBIO-5136/.roost/roost_metadata.json @@ -1,15 +1,15 @@ { "project": { "name": "ZBIO-5136", - "created_at": "2025-11-09T12:36:25.607Z", - "updated_at": "2025-11-09T12:36:25.607Z" + "created_at": "2025-11-09T12:49:39.400Z", + "updated_at": "2025-11-09T12:49:39.400Z" }, "files": { "input_files": [ { "fileName": "ZBIO-5136.txt", - "fileURI": "/var/tmp/Roost/RoostGPT/systemAnalysis_clone/1762691541/functional_tests/ZBIO-5136/ZBIO-5136.txt", - "fileSha": "76dbce7dd3" + "fileURI": "/var/tmp/Roost/RoostGPT/systemAnalysis_clone/1762692371/functional_tests/ZBIO-5136/ZBIO-5136.txt", + "fileSha": "7ce40466de" } ] }, diff --git a/functional_tests/ZBIO-5136/ZBIO-5136.csv b/functional_tests/ZBIO-5136/ZBIO-5136.csv index 77c053a..be4f726 100644 --- a/functional_tests/ZBIO-5136/ZBIO-5136.csv +++ b/functional_tests/ZBIO-5136/ZBIO-5136.csv @@ -1,17 +1,17 @@ -"Scenario: Retrieve card balance for an account with an outstanding amount" -"Scenario Outline: Retrieve zero balance for new or fully paid cards" -"Scenario: Successfully make a full payment via API" -"Scenario: Successfully make a partial payment via API" -"Scenario: Handle an overpayment via API" -"Scenario: Fail a payment with invalid card details via API" -"Scenario: Fail a payment attempt for a non-existent card" -"Scenario: Trigger automated collection call for a past-due account" -"Scenario: Ensure no collection call is triggered for a fully paid account" -"Scenario: Ensure payment API endpoint requires authentication" -"Scenario: Display unpaid balance and due date on the account summary page" -"Scenario Outline: Display zero balance for new or fully paid cards" -"Scenario: User successfully pays the full unpaid balance" -"Scenario: User successfully makes a partial payment" -"Scenario: User makes an overpayment and sees a credit balance" -"Scenario: User attempts a payment with invalid card details" -"Scenario: User attempts to submit a payment form with an empty amount" \ No newline at end of file +"Retrieve card balance for an account with an outstanding amount" +"Retrieve zero balance for new or fully paid cards" +"Successfully make a full payment via API" +"Successfully make a partial payment via API" +"Handle an overpayment via API" +"Fail a payment with invalid card details via API" +"Fail a payment attempt for a non-existent card" +"Trigger automated collection call for a past-due account" +"Ensure no collection call is triggered for a fully paid account" +"Ensure payment API endpoint requires authentication" +"Display unpaid balance and due date on the account summary page" +"Display zero balance for new or fully paid cards" +"User successfully pays the full unpaid balance" +"User successfully makes a partial payment" +"User makes an overpayment and sees a credit balance" +"User attempts a payment with invalid card details" +"User attempts to submit a payment form with an empty amount" diff --git a/functional_tests/ZBIO-5136/ZBIO-5136.feature b/functional_tests/ZBIO-5136/ZBIO-5136.feature index 7e55a69..1ea6a1d 100644 --- a/functional_tests/ZBIO-5136/ZBIO-5136.feature +++ b/functional_tests/ZBIO-5136/ZBIO-5136.feature @@ -1,199 +1,198 @@ Feature: Credit Card Balance and Payment Management - This feature covers viewing credit card balances, making payments, and system processes for overdue accounts, for both UI and API interfaces. - - Background: - Given the API base URL is set from environment variable 'BASE_URL' - And the content type is 'application/json' - - # API Test Scenarios - @api - Scenario: Retrieve card balance for an account with an outstanding amount - Given the authorization header is set for user 'user-001' with card 'card-123' - When I send a GET request to '/api/v1/cards/card-123/balance' - Then the response status should be 200 - And the response body should contain a 'unpaidBalance' of 150.75 - And the response body should contain a 'dueDate' with a valid date format - - @api - Scenario Outline: Retrieve zero balance for new or fully paid cards - Given the authorization header is set for user '' with card '' - When I send a GET request to '/api/v1/cards//balance' - Then the response status should be 200 - And the response body should contain a 'unpaidBalance' of 0.00 - And the response body 'dueDate' should be null or not present - - Examples: - | user_id | card_id | description | - | user-002 | card-new | new card | - | user-003 | card-paid | fully paid card | - - @api - Scenario: Successfully make a full payment via API - Given the authorization header is set for user 'user-005' with card 'card-250' which has a balance of 250.00 - And the request body: - ''' - { - "amount": 250.00, - "paymentMethodId": "pm_valid_source", - "currency": "USD" - } - ''' - When I send a POST request to '/api/v1/cards/card-250/payments' - Then the response status should be 201 - And the response body 'status' should be 'succeeded' - And the response body should contain a 'transactionId' - - @api - Scenario: Successfully make a partial payment via API - Given the authorization header is set for user 'user-006' with card 'card-500' which has a balance of 500.00 - And the request body: - ''' - { - "amount": 200.00, - "paymentMethodId": "pm_valid_source", - "currency": "USD" - } - ''' - When I send a POST request to '/api/v1/cards/card-500/payments' - Then the response status should be 201 - And the response body 'status' should be 'succeeded' - And a subsequent GET request to '/api/v1/cards/card-500/balance' should have 'unpaidBalance' of 300.00 - - @api - Scenario: Handle an overpayment via API - Given the authorization header is set for user 'user-007' with card 'card-100' which has a balance of 100.00 - And the request body: - ''' - { - "amount": 120.00, - "paymentMethodId": "pm_valid_source", - "currency": "USD" - } - ''' - When I send a POST request to '/api/v1/cards/card-100/payments' - Then the response status should be 201 - And a subsequent GET request to '/api/v1/cards/card-100/balance' should have 'unpaidBalance' of 0.00 - And the same response should have 'creditBalance' of 20.00 - - @api - Scenario: Fail a payment with invalid card details via API - Given the authorization header is set for user 'user-008' with card 'card-fail' - And the request body: - ''' - { - "amount": 75.00, - "paymentMethodId": "pm_invalid_cvc", - "currency": "USD" - } - ''' - When I send a POST request to '/api/v1/cards/card-fail/payments' - Then the response status should be 400 - And the response body should contain an 'errorCode' of 'payment_details_invalid' - And the response body should contain an 'errorMessage' of 'Your card details are incorrect.' - - @api - Scenario: Fail a payment attempt for a non-existent card - Given the authorization header is set for user 'user-008' - And the request body: - ''' - { - "amount": 50.00, - "paymentMethodId": "pm_valid_source", - "currency": "USD" - } - ''' - When I send a POST request to '/api/v1/cards/card-nonexistent/payments' - Then the response status should be 404 - And the response body should contain an 'errorMessage' of 'Card not found.' - - @api - Scenario: Trigger automated collection call for a past-due account - Given an admin authorization header is set - And a user 'user-past-due' has a card with an unpaid balance and a past due date - When I send a POST request to '/api/v1/admin/batch/check-past-due' - Then the response status should be 202 - And a subsequent GET request to '/api/v1/admin/call-logs?userId=user-past-due' should return a log entry with status 'TRIGGERED' - And the log entry must show the credit card number masked to the last 4 digits - - @api - Scenario: Ensure no collection call is triggered for a fully paid account - Given an admin authorization header is set - And a user 'user-paid-up' has a card with a zero balance - When I send a POST request to '/api/v1/admin/batch/check-past-due' - Then the response status should be 202 - And a subsequent GET request to '/api/v1/admin/call-logs?userId=user-paid-up' should return an empty list - - @api - Scenario: Ensure payment API endpoint requires authentication - Given the authorization header is not set - When I send a POST request to '/api/v1/cards/card-any/payments' with an empty body - Then the response status should be 401 - And the response body should contain an 'error' of 'Authentication required' - - # UI Test Scenarios - @ui - Scenario: Display unpaid balance and due date on the account summary page - Given I am logged in as a user with an unpaid balance of '$150.75' - When I navigate to the 'Account Summary' page - Then I should see the unpaid balance is '$150.75' - And I should see the payment due date is displayed - - @ui - Scenario Outline: Display zero balance for new or fully paid cards - Given I am logged in as a user with a - When I navigate to the 'Account Summary' page - Then I should see the unpaid balance is '$0.00' - - Examples: - | card_status | - | new card | - | fully paid off card | - - @ui - Scenario: User successfully pays the full unpaid balance - Given I am logged in as a user with an unpaid balance of '$250.00' - When I navigate to the 'Make a Payment' page - And I select the option to pay the 'Full Balance' - And the payment amount field is pre-filled with '250.00' - And I enter valid payment details and click 'Confirm Payment' - Then I should see a success message 'Payment Successful' - And I should be redirected to the 'Account Summary' page - And the unpaid balance should now be '$0.00' - - @ui - Scenario: User successfully makes a partial payment - Given I am logged in as a user with an unpaid balance of '$500.00' - When I navigate to the 'Make a Payment' page - And I select the option to pay a 'Custom Amount' - And I enter '200.00' into the payment amount field - And I enter valid payment details and click 'Confirm Payment' - Then I should see a success message 'Payment Successful' - And on the 'Account Summary' page, the unpaid balance should now be '$300.00' - - @ui - Scenario: User makes an overpayment and sees a credit balance - Given I am logged in as a user with an unpaid balance of '$100.00' - When I navigate to the 'Make a Payment' page - And I enter '120.00' into the custom payment amount field - And I complete the payment successfully - Then I should see a success message 'Payment Successful' - And on the 'Account Summary' page, the unpaid balance should be '$0.00' - And I should see a credit balance of '$20.00' - - @ui - Scenario: User attempts a payment with invalid card details - Given I am logged in as a user with an unpaid balance of '$80.00' - When I navigate to the 'Make a Payment' page - And I enter '80.00' into the payment amount field - And I enter an expired card date in the payment details form - And I click the 'Confirm Payment' button - Then I should see an error message 'Payment failed. Please check your card details and try again.' - And my unpaid balance on the page should still be '$80.00' - - @ui - Scenario: User attempts to submit a payment form with an empty amount - Given I am logged in and on the 'Make a Payment' page - When I leave the payment amount field empty - And I click the 'Confirm Payment' button - Then I should see a validation error message 'Payment amount is required' next to the amount field - And the payment should not be processed \ No newline at end of file +This feature covers viewing credit card balances, making payments, and system processes for overdue accounts, for both UI and API interfaces. + +Background: + Given the API base URL is set from environment variable 'BASE_URL' + And the content type is 'application/json' + +# API Test Scenarios +@api +Scenario: Retrieve card balance for an account with an outstanding amount + Given the authorization header is set for user 'user-001' with card 'card-123' + When I send a GET request to '/api/v1/cards/card-123/balance' + Then the response status should be 200 + And the response body should contain a 'unpaidBalance' of 150.75 + And the response body should contain a 'dueDate' with a valid date format + +@api +Scenario Outline: Retrieve zero balance for new or fully paid cards + Given the authorization header is set for user '' with card '' + When I send a GET request to '/api/v1/cards//balance' + Then the response status should be 200 + And the response body should contain a 'unpaidBalance' of 0.00 + And the response body 'dueDate' should be null or not present + + Examples: + | user_id | card_id | description | + | user-002 | card-new | new card | + | user-003 | card-paid | fully paid card | + +@api +Scenario: Successfully make a full payment via API + Given the authorization header is set for user 'user-005' with card 'card-250' which has a balance of 250.00 + And the request body: + ''' + { + "amount": 250.00, + "paymentMethodId": "pm_valid_source", + "currency": "USD" + } + ''' + When I send a POST request to '/api/v1/cards/card-250/payments' + Then the response status should be 201 + And the response body 'status' should be 'succeeded' + And the response body should contain a 'transactionId' + +@api +Scenario: Successfully make a partial payment via API + Given the authorization header is set for user 'user-006' with card 'card-500' which has a balance of 500.00 + And the request body: + ''' + { + "amount": 200.00, + "paymentMethodId": "pm_valid_source", + "currency": "USD" + } + ''' + When I send a POST request to '/api/v1/cards/card-500/payments' + Then the response status should be 201 + And the response body 'status' should be 'succeeded' + And a subsequent GET request to '/api/v1/cards/card-500/balance' should have 'unpaidBalance' of 300.00 + +@api +Scenario: Handle an overpayment via API + Given the authorization header is set for user 'user-007' with card 'card-100' which has a balance of 100.00 + And the request body: + ''' + { + "amount": 120.00, + "paymentMethodId": "pm_valid_source", + "currency": "USD" + } + ''' + When I send a POST request to '/api/v1/cards/card-100/payments' + Then the response status should be 201 + And a subsequent GET request to '/api/v1/cards/card-100/balance' should have 'unpaidBalance' of 0.00 + And the same response should have 'creditBalance' of 20.00 + +@api +Scenario: Fail a payment with invalid card details via API + Given the authorization header is set for user 'user-008' with card 'card-fail' + And the request body: + ''' + { + "amount": 75.00, + "paymentMethodId": "pm_invalid_cvc", + "currency": "USD" + } + ''' + When I send a POST request to '/api/v1/cards/card-fail/payments' + Then the response status should be 400 + And the response body should contain an 'errorCode' of 'payment_details_invalid' + And the response body should contain an 'errorMessage' of 'Your card details are incorrect.' + +@api +Scenario: Fail a payment attempt for a non-existent card + Given the authorization header is set for user 'user-008' + And the request body: + ''' + { + "amount": 50.00, + "paymentMethodId": "pm_valid_source", + "currency": "USD" + } + ''' + When I send a POST request to '/api/v1/cards/card-nonexistent/payments' + Then the response status should be 404 + And the response body should contain an 'errorMessage' of 'Card not found.' + +@api +Scenario: Trigger automated collection call for a past-due account + Given an admin authorization header is set + And a user 'user-past-due' has a card with an unpaid balance and a past due date + When I send a POST request to '/api/v1/admin/batch/check-past-due' + Then the response status should be 202 + And a subsequent GET request to '/api/v1/admin/call-logs?userId=user-past-due' should return a log entry with status 'TRIGGERED' + +@api +Scenario: Ensure no collection call is triggered for a fully paid account + Given an admin authorization header is set + And a user 'user-paid-up' has a card with a zero balance + When I send a POST request to '/api/v1/admin/batch/check-past-due' + Then the response status should be 202 + And a subsequent GET request to '/api/v1/admin/call-logs?userId=user-paid-up' should return an empty list + +@api +Scenario: Ensure payment API endpoint requires authentication + Given the authorization header is not set + When I send a POST request to '/api/v1/cards/card-any/payments' with an empty body + Then the response status should be 401 + And the response body should contain an 'error' of 'Authentication required' + +# UI Test Scenarios +@ui +Scenario: Display unpaid balance and due date on the account summary page + Given I am logged in as a user with an unpaid balance of '$150.75' + When I navigate to the 'Account Summary' page + Then I should see the unpaid balance is '$150.75' + And I should see the payment due date is displayed + +@ui +Scenario Outline: Display zero balance for new or fully paid cards + Given I am logged in as a user with a + When I navigate to the 'Account Summary' page + Then I should see the unpaid balance is '$0.00' + + Examples: + | card_status | + | new card | + | fully paid off card | + +@ui +Scenario: User successfully pays the full unpaid balance + Given I am logged in as a user with an unpaid balance of '$250.00' + When I navigate to the 'Make a Payment' page + And I select the option to pay the 'Full Balance' + And the payment amount field is pre-filled with '250.00' + And I enter valid payment details and click 'Confirm Payment' + Then I should see a success message 'Payment Successful' + And I should be redirected to the 'Account Summary' page + And the unpaid balance should now be '$0.00' + +@ui +Scenario: User successfully makes a partial payment + Given I am logged in as a user with an unpaid balance of '$500.00' + When I navigate to the 'Make a Payment' page + And I select the option to pay a 'Custom Amount' + And I enter '200.00' into the payment amount field + And I enter valid payment details and click 'Confirm Payment' + Then I should see a success message 'Payment Successful' + And on the 'Account Summary' page, the unpaid balance should now be '$300.00' + +@ui +Scenario: User makes an overpayment and sees a credit balance + Given I am logged in as a user with an unpaid balance of '$100.00' + When I navigate to the 'Make a Payment' page + And I enter '120.00' into the custom payment amount field + And I complete the payment successfully + Then I should see a success message 'Payment Successful' + And on the 'Account Summary' page, the unpaid balance should be '$0.00' + And I should see a credit balance of '$20.00' + +@ui +Scenario: User attempts a payment with invalid card details + Given I am logged in as a user with an unpaid balance of '$80.00' + When I navigate to the 'Make a Payment' page + And I enter '80.00' into the payment amount field + And I enter an expired card date in the payment details form + And I click the 'Confirm Payment' button + Then I should see an error message 'Payment failed. Please check your card details and try again.' + And my unpaid balance on the page should still be '$80.00' + +@ui +Scenario: User attempts to submit a payment form with an empty amount + Given I am logged in and on the 'Make a Payment' page + When I leave the payment amount field empty + And I click the 'Confirm Payment' button + Then I should see a validation error message 'Payment amount is required' next to the amount field + And the payment should not be processed diff --git a/functional_tests/ZBIO-5136/ZBIO-5136.json b/functional_tests/ZBIO-5136/ZBIO-5136.json index 66b819d..54e16db 100644 --- a/functional_tests/ZBIO-5136/ZBIO-5136.json +++ b/functional_tests/ZBIO-5136/ZBIO-5136.json @@ -109,16 +109,6 @@ "prerequisites": "Access to the application in a test environment. Security scanning tools like OWASP ZAP or Burp Suite.", "stepsToPerform": "1. Intercept the network traffic when submitting a payment.\n2. Verify that the connection is encrypted using a valid TLS/SSL certificate.\n3. Confirm that sensitive data like the full card number and CVC are not logged in plain text on the client or server.\n4. Attempt to inject malicious scripts (XSS) or SQL commands (SQLi) into the payment form fields.", "expectedResult": "All communication must be over HTTPS. No sensitive payment details should be stored or logged insecurely. The application must properly sanitize all inputs to prevent injection attacks." - }, - { - "type": "non-functional", - "title": "Verify Masking of Credit Card Number in Collection Documentation", - "description": "To ensure that any logs or documentation generated during the automated payment collection process do not expose the full credit card number, in compliance with security policies.", - "testId": "TC-012", - "testDescription": "This security test verifies that when the system logs an activity for the collection process (e.g., a triggered call), the associated credit card number is properly masked.", - "prerequisites": "A user account with a past-due balance exists. The system's collection process is about to be triggered. Access to system logs is available.", - "stepsToPerform": "1. Trigger the daily batch process that checks for past-due accounts.\n2. Access the system logs or a dedicated call-log table in the database.\n3. Locate the log entry corresponding to the test user's collection activity.\n4. Inspect the log entry for any mention of the user's credit card number.", - "expectedResult": "The log entry must not contain the full credit card number in plain text. If the card number is referenced, it must be masked to show only the last 4 digits (e.g., '************1234')." } ] } diff --git a/functional_tests/ZBIO-5136/ZBIO-5136.xlsx b/functional_tests/ZBIO-5136/ZBIO-5136.xlsx index cdce5b7797d391f19e69b7c948dc18de584caba3..a424781e6d5d710820e055ddc35cf43586144910 100644 GIT binary patch delta 5202 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