diff --git a/Online-Banking-App-Spring-Boot/.roost/knowledge.json b/Online-Banking-App-Spring-Boot/.roost/knowledge.json new file mode 100644 index 0000000..3c00682 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/.roost/knowledge.json @@ -0,0 +1,575 @@ +{ + "endpoints": [ + { + "controller": "AccountController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/account\")" + ], + "method": "POST", + "path": "/account/create_account", + "handler": "createAccount", + "parameters": [ + { + "in": "body", + "name": "requestMap", + "type": "Map", + "description": "Expected keys: account_name, account_type" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with user accounts, 400 Bad Request if missing fields, 401 Unauthorized if not logged in", + "responseType": "ResponseEntity" + }, + { + "controller": "AppController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/app\")" + ], + "method": "GET", + "path": "/app/dashboard", + "handler": "getDashboard", + "parameters": [ + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with userAccounts and totalBalance in JSON", + "responseType": "ResponseEntity>" + }, + { + "controller": "AppController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/app\")" + ], + "method": "GET", + "path": "/app/payment_history", + "handler": "getPaymentHistory", + "parameters": [ + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with payment_history array in JSON", + "responseType": "ResponseEntity>" + }, + { + "controller": "AppController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/app\")" + ], + "method": "GET", + "path": "/app/transaction_history", + "handler": "getTransactiontHistory", + "parameters": [ + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with transaction_history array in JSON", + "responseType": "ResponseEntity>" + }, + { + "controller": "AppController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/app\")" + ], + "method": "POST", + "path": "/app/account_transaction_history", + "handler": "getAccountTransactiontHistory", + "parameters": [ + { + "in": "body", + "name": "requestMap", + "type": "Map", + "description": "Expected key: account_id" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session (not explicitly used in handler, but consistent with other endpoints)" + } + ], + "response": "200 OK with transaction_history array in JSON", + "responseType": "ResponseEntity>" + }, + { + "controller": "AuthController", + "classAnnotations": [ + "@Controller" + ], + "method": "POST", + "path": "/login", + "handler": "login", + "parameters": [ + { + "in": "body", + "name": "requestMap", + "type": "Map", + "description": "Expected keys: email, password" + }, + { + "in": "session", + "name": "session", + "type": "HttpSession", + "description": "Session object for user login state" + } + ], + "response": "200 OK with access_token and message; 400 if missing fields; 401 Unauthorized if bad credentials; 403 if account not verified; 500 if email not found", + "responseType": "ResponseEntity>" + }, + { + "controller": "AuthController", + "classAnnotations": [ + "@Controller" + ], + "method": "GET", + "path": "/logout", + "handler": "logout", + "parameters": [ + { + "in": "session", + "name": "session", + "type": "HttpSession", + "description": "Session object for user." + } + ], + "response": "200 OK with logout confirmation message.", + "responseType": "ResponseEntity" + }, + { + "controller": "IndexController", + "classAnnotations": [ + "@RestController" + ], + "method": "GET", + "path": "/", + "handler": "getIndex", + "parameters": [], + "response": "200 OK with welcome string message", + "responseType": "String" + }, + { + "controller": "IndexController", + "classAnnotations": [ + "@RestController" + ], + "method": "GET", + "path": "/verify", + "handler": "getVerify", + "parameters": [ + { + "in": "query", + "name": "token", + "type": "String", + "description": "Verification token" + }, + { + "in": "query", + "name": "code", + "type": "String", + "description": "Verification code" + } + ], + "response": "200 OK with verification success JSON; 400 if token invalid", + "responseType": "ResponseEntity>" + }, + { + "controller": "RegisterController", + "classAnnotations": [ + "@RestController" + ], + "method": "POST", + "path": "/register", + "handler": "registerUser", + "parameters": [ + { + "in": "body", + "name": "user", + "type": "User", + "description": "User registration object, must have first_name, last_name, email, password" + }, + { + "in": "query", + "name": "confirm_password", + "type": "String", + "description": "Repeat of password for confirmation" + } + ], + "response": "200 OK with message and user; 400 for validation errors or password mismatch", + "responseType": "ResponseEntity or List>" + }, + { + "controller": "TransactController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/transact\")" + ], + "method": "POST", + "path": "/transact/deposit", + "handler": "deposit", + "parameters": [ + { + "in": "body", + "name": "requestMap", + "type": "Map", + "description": "Expected keys: deposit_amount, account_id" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with message and user accounts; 400 for missing/zero fields; 401 if not logged in", + "responseType": "ResponseEntity>" + }, + { + "controller": "TransactController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/transact\")" + ], + "method": "POST", + "path": "/transact/transfer", + "handler": "transfer", + "parameters": [ + { + "in": "body", + "name": "request", + "type": "TransferRequest", + "description": "Source and target account and amount" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with message and user accounts; 400 for invalid/insufficient/missing fields; failed logs on insufficient funds", + "responseType": "ResponseEntity>" + }, + { + "controller": "TransactController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/transact\")" + ], + "method": "POST", + "path": "/transact/withdraw", + "handler": "transfer", + "parameters": [ + { + "in": "body", + "name": "requestMap", + "type": "Map", + "description": "Expected keys: withdrawal_amount, account_id" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with message and user accounts; 400 for missing/zero/insufficient fields/funds", + "responseType": "ResponseEntity>" + }, + { + "controller": "TransactController", + "classAnnotations": [ + "@Controller", + "@RequestMapping(\"/transact\")" + ], + "method": "POST", + "path": "/transact/payment", + "handler": "transfer", + "parameters": [ + { + "in": "body", + "name": "request", + "type": "PaymentRequest", + "description": "Expected: beneficiary, account_number, account_id, payment_amount, reference" + }, + { + "in": "session", + "name": "user", + "type": "User", + "description": "Retrieved from session attribute" + } + ], + "response": "200 OK with message and user accounts; 400 for missing/zero/insufficient fields/funds; failed logs on insufficient funds", + "responseType": "ResponseEntity>" + } + ], + "models": [ + { + "name": "Account", + "annotations": [ + "@Entity" + ], + "fields": [ + { + "name": "account_id", + "type": "int", + "annotations": [ + "@Id" + ] + }, + { + "name": "user_id", + "type": "int" + }, + { + "name": "account_number", + "type": "String" + }, + { + "name": "account_name", + "type": "String" + }, + { + "name": "account_type", + "type": "String" + }, + { + "name": "balance", + "type": "BigDecimal" + }, + { + "name": "create_at", + "type": "LocalDateTime" + }, + { + "name": "updated_at", + "type": "LocalDateTime" + } + ] + }, + { + "name": "User", + "annotations": [ + "@Entity" + ], + "fields": [ + { + "name": "user_id", + "type": "String", + "annotations": [ + "@Id" + ] + }, + { + "name": "first_name", + "type": "String", + "annotations": [ + "@NotEmpty", + "@Size(min=3)" + ] + }, + { + "name": "last_name", + "type": "String", + "annotations": [ + "@NotEmpty", + "@Size(min=3)" + ] + }, + { + "name": "email", + "type": "String", + "annotations": [ + "@Email", + "@NotEmpty", + "@Pattern" + ] + }, + { + "name": "password", + "type": "String", + "annotations": [ + "@NotEmpty", + "@NotNull" + ] + }, + { + "name": "token", + "type": "String" + }, + { + "name": "code", + "type": "String" + }, + { + "name": "verified", + "type": "int" + }, + { + "name": "verified_at", + "type": "LocalDate" + }, + { + "name": "create_at", + "type": "LocalDateTime" + }, + { + "name": "updated_at", + "type": "LocalDateTime" + } + ], + "validation": { + "first_name": "Not empty, min 3 chars", + "last_name": "Not empty, min 3 chars", + "email": "Valid email address, not empty, valid pattern", + "password": "Not empty" + } + }, + { + "name": "Payment", + "annotations": [ + "@Entity" + ], + "fields": [ + { + "name": "payment_id", + "type": "int", + "annotations": [ + "@Id" + ] + }, + { + "name": "account_id", + "type": "int" + }, + { + "name": "beneficiary", + "type": "String" + }, + { + "name": "beneficiary_acc_no", + "type": "String" + }, + { + "name": "amount", + "type": "double" + }, + { + "name": "reference_no", + "type": "String" + }, + { + "name": "status", + "type": "String" + }, + { + "name": "reason_code", + "type": "String" + }, + { + "name": "created_at", + "type": "LocalDateTime" + } + ] + }, + { + "name": "PaymentHistory", + "annotations": [ + "@Entity", + "@Table(name =\"v_payments\")" + ], + "fields": [ + { + "name": "payment_id", + "type": "int", + "annotations": [ + "@Id" + ] + }, + { + "name": "account_id", + "type": "int" + }, + { + "name": "beneficiary", + "type": "String" + }, + { + "name": "beneficiary_acc_no", + "type": "String" + }, + { + "name": "amount", + "type": "double" + }, + { + "name": "reference_no", + "type": "String" + }, + { + "name": "status", + "type": "String" + }, + { + "name": "reason_code", + "type": "String" + }, + { + "name": "created_at", + "type": "LocalDateTime" + } + ] + } + ], + "dependencies": [], + "businessFlows": [], + "language": { + "language": "java" + }, + "buildTool": { + "buildTool": "maven" + }, + "framework": { + "framework": "spring-boot" + }, + "projectStructure": { + "structure": [ + ".mvn/wrapper/", + "src/main/java/com/beko/DemoBank_v1/config/", + "src/main/java/com/beko/DemoBank_v1/controller_advisor/", + "src/main/java/com/beko/DemoBank_v1/controllers/", + "src/main/java/com/beko/DemoBank_v1/exception/", + "src/main/java/com/beko/DemoBank_v1/helpers/", + "src/main/java/com/beko/DemoBank_v1/interceptors/", + "src/main/java/com/beko/DemoBank_v1/mailMessenger/", + "src/main/java/com/beko/DemoBank_v1/models/", + "src/main/java/com/beko/DemoBank_v1/repository/", + "src/main/java/com/beko/DemoBank_v1/DemoBankV1Application.java", + "src/main/resources/application.properties", + "src/main/webapp/WEB-INF/jsp/index.jsp", + "src/test/java/com/beko/DemoBank_v1/DemoBankV1ApplicationTests.java", + "pom.xml", + "README.md" + ] + } +} \ No newline at end of file diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account.feature new file mode 100644 index 0000000..ee63569 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account.feature @@ -0,0 +1,105 @@ +Feature: Create Bank Account via REST API + + As a logged-in user, + I want to create a new bank account with a valid name and account type, + So that I can manage multiple accounts in my banking application. + + Background: + Given the API endpoint "/account/create_account" is available + And a user with id "12345" exists in the system + + @smoke + Scenario: Successful account creation with valid data + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | "Savings" | "Checking" | + When I POST to "/account/create_account" + Then the response status should be 200 + And the response body should contain a list of accounts including an account with: + | account_name | account_type | + | "Savings" | "Checking" | + + @regression + Scenario: Create account with missing account_name + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_type | + | "Checking" | + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating account_name is required + + @regression + Scenario: Create account with missing account_type + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | + | "Personal" | + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating account_type is required + + @regression + Scenario: Create account with completely missing body + Given the user is authenticated with session user id "12345" + And the request body is empty + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating required fields are missing + + @regression + Scenario: Create account when not authenticated + Given the user is not authenticated (no session user) + And the request body contains: + | account_name | account_type | + | "Savings" | "Checking" | + When I POST to "/account/create_account" + Then the response status should be 401 + And the response body should include an error message indicating authentication is required + + @regression + Scenario: Create account with account_name at boundary length (min/max) + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | "A" | "Checking" | + When I POST to "/account/create_account" + Then the response status should be 200 + And the response body should contain an account with account_name "A" + + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" | "Savings" | + When I POST to "/account/create_account" + Then the response status should be 200 + And the response body should contain an account with account_name "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" + + @regression + Scenario: Create account with account_name or account_type as whitespace + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | " " | "Checking" | + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating account_name is invalid + + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | "Home" | " " | + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating account_type is invalid + + @regression + Scenario: Create account with invalid account_type value + Given the user is authenticated with session user id "12345" + And the request body contains: + | account_name | account_type | + | "Investment" | "InvalidType" | + When I POST to "/account/create_account" + Then the response status should be 400 + And the response body should include an error message indicating account_type is invalid diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account_transaction_history.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account_transaction_history.feature new file mode 100644 index 0000000..3cb80c3 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_account_transaction_history.feature @@ -0,0 +1,51 @@ +Feature: Account Transaction History API + + The POST /app/account_transaction_history endpoint returns the transaction history for a specified account. + It requires authentication and a valid account_id in the request body. + + @smoke + Scenario: Successful retrieval of transaction history for an existing account + Given a logged-in user with session "valid_session_token" + And the user owns an account with account_id "ACC123" + And the account "ACC123" has transactions + When the user sends a POST request to "/app/account_transaction_history" with JSON body: + | account_id | ACC123 | + Then the response status should be 200 + And the response body should contain a "transaction_history" array + And the "transaction_history" array should have at least one transaction + + @regression + Scenario: Unauthorized access when session is missing + Given no session is present + When the user sends a POST request to "/app/account_transaction_history" with JSON body: + | account_id | ACC123 | + Then the response status should be 401 + And the response body should contain an error message "Unauthorized" + + @regression + Scenario: Missing account_id in request body + Given a logged-in user with session "valid_session_token" + When the user sends a POST request to "/app/account_transaction_history" with JSON body: + | account_id | | + Then the response status should be 400 + And the response body should contain an error message "Missing account_id" + + @regression + Scenario: Invalid account_id not owned by user + Given a logged-in user with session "valid_session_token" + And the account_id "ACC999" exists but is not owned by the user + When the user sends a POST request to "/app/account_transaction_history" with JSON body: + | account_id | ACC999 | + Then the response status should be 400 + And the response body should contain an error message "Invalid account_id" + + @regression + Scenario: Account with no transactions + Given a logged-in user with session "valid_session_token" + And the user owns an account with account_id "ACC456" + And the account "ACC456" has no transactions + When the user sends a POST request to "/app/account_transaction_history" with JSON body: + | account_id | ACC456 | + Then the response status should be 200 + And the response body should contain a "transaction_history" array + And the "transaction_history" array should be empty diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_app.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_app.feature new file mode 100644 index 0000000..4d275b8 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_app.feature @@ -0,0 +1,70 @@ +Feature: Account Data Retrieval + As an authenticated user + I want to retrieve my dashboard, payment history, and transaction history + So that I can view my financial data securely + + @smoke + Scenario: Successful dashboard retrieval + Given I am an authenticated user with account data + When I send a GET request to "/app/dashboard" + Then the response status should be 200 + And the response should contain "userAccounts" as a non-empty array + And the response should contain "totalBalance" as a number + + @regression + Scenario: Unauthorized dashboard retrieval + Given I am not authenticated + When I send a GET request to "/app/dashboard" + Then the response status should be 401 + And the response should not contain "userAccounts" + And the response should not contain "totalBalance" + + @regression + Scenario: Dashboard with no accounts + Given I am an authenticated user with no account data + When I send a GET request to "/app/dashboard" + Then the response status should be 200 + And the response should contain "userAccounts" as an empty array + And the response should contain "totalBalance" as 0 + + @smoke + Scenario: Payment history with data + Given I am an authenticated user with payment history data + When I send a GET request to "/app/payment_history" + Then the response status should be 200 + And the response should contain "payment_history" as a non-empty array + + @regression + Scenario: Payment history with no data + Given I am an authenticated user with no payment history data + When I send a GET request to "/app/payment_history" + Then the response status should be 200 + And the response should contain "payment_history" as an empty array + + @regression + Scenario: Unauthorized payment history retrieval + Given I am not authenticated + When I send a GET request to "/app/payment_history" + Then the response status should be 401 + And the response should not contain "payment_history" + + @smoke + Scenario: Transaction history with data + Given I am an authenticated user with transaction history data + When I send a GET request to "/app/transaction_history" + Then the response status should be 200 + And the response should contain "transaction_history" as a non-empty array + + @regression + Scenario: Transaction history with no data + Given I am an authenticated user with no transaction history data + When I send a GET request to "/app/transaction_history" + Then the response status should be 200 + And the response should contain "transaction_history" as an empty array + + @regression + Scenario: Unauthorized transaction history retrieval + Given I am not authenticated + When I send a GET request to "/app/transaction_history" + Then the response status should be 401 + And the response should not contain "transaction_history" \ No newline at end of file diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_auth.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_auth.feature new file mode 100644 index 0000000..bed97c5 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_auth.feature @@ -0,0 +1,111 @@ +Feature: User Login + + Background: + Given the API is available + + @smoke + Scenario: Successful login with valid credentials + Given a registered user with email "test.user@example.com" and password "ValidPassword123" + When the user logs in with email "test.user@example.com" and password "ValidPassword123" + Then the response status should be 200 + And the response should contain an access_token and a message + + @regression + Scenario: Login with missing email + When the user logs in with email "" and password "ValidPassword123" + Then the response status should be 400 + And the response should indicate that the email field is missing + + @regression + Scenario: Login with missing password + When the user logs in with email "test.user@example.com" and password "" + Then the response status should be 400 + And the response should indicate that the password field is missing + + @regression + Scenario: Login with both fields missing + When the user logs in with email "" and password "" + Then the response status should be 400 + And the response should indicate that email and password fields are missing + + @regression + Scenario: Login with invalid email format + When the user logs in with email "invalid-email-format" and password "ValidPassword123" + Then the response status should be 400 + And the response should indicate that the email format is invalid + + @regression + Scenario: Login with invalid credentials + When the user logs in with email "test.user@example.com" and password "WrongPassword" + Then the response status should be 401 + And the response should indicate bad credentials + + @regression + Scenario: Login with unverified account + Given the user account is registered but not verified + When the user logs in with email "test.unverified@example.com" and password "ValidPassword123" + Then the response status should be 403 + And the response should indicate the account is not verified + + @regression + Scenario: Login with unknown email + When the user logs in with email "unknown@example.com" and password "AnyPassword" + Then the response status should be 500 + And the response should indicate that the email was not found + + @regression + Scenario: Login with blank spaces in email and password fields + When the user logs in with email " " and password " " + Then the response status should be 400 + And the response should indicate that email and password fields are missing + + @regression + Scenario: Login without authentication header + When the user logs in with email "test.user@example.com" and password "ValidPassword123" but without authentication header + Then the response status should be 401 + And the response should indicate missing or invalid authentication + + @regression + Scenario: Login with excessively long email and password fields + When the user logs in with email "longemailuser12345678901234567890123456789012345678901234567890@example.com" and password "VeryLongPasswordThatExceedsMaxLimit12345678901234567890" + Then the response status should be 400 + And the response should indicate field length validation errors + + @regression + Scenario: Login with SQL injection attempt in email and password + When the user logs in with email "' OR 1=1; -- " and password "' OR 1=1; -- " + Then the response status should be 401 + And the response should indicate bad credentials + +Feature: Logout Functionality + + The /logout endpoint allows users to end their session. + These scenarios cover successful and unsuccessful logout attempts under different authentication conditions. + + @smoke @logout + Scenario: Successful logout when logged in + Given the user is authenticated with a valid session token + When the user sends a GET request to /logout with the session token + Then the response status should be 200 + And the response body should contain a confirmation message "You have been logged out successfully." + + @regression @logout + Scenario: Logout attempt with no active session + Given the user does not have any session token + When the user sends a GET request to /logout without authentication headers + Then the response status should be 401 + And the response body should contain an error message "No active session found." + + @regression @logout + Scenario: Logout attempt with expired session + Given the user is authenticated with an expired session token + When the user sends a GET request to /logout with the expired session token + Then the response status should be 401 + And the response body should contain an error message "Session has expired. Please log in again." + + @regression @logout + Scenario: Logout attempt with invalid session token + Given the user is authenticated with an invalid session token + When the user sends a GET request to /logout with the invalid session token + Then the response status should be 401 + And the response body should contain an error message "Invalid session token." diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_register.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_register.feature new file mode 100644 index 0000000..f545c2b --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_register.feature @@ -0,0 +1,79 @@ +Feature: User Registration API + + The POST /register endpoint allows new users to register. + The endpoint validates field presence, length, correctness, and password confirmation. + + @smoke + Scenario: Successful registration with valid data + Given the following user registration payload: + | first_name | last_name | email | password | + | Alice | Johnson | alice@example.com | Secret123 | + And the confirm_password query parameter is "Secret123" + When I send a POST request to /register + Then the response status should be 200 + And the response body should contain "User registered successfully" + And the response body should include the user: + | first_name | last_name | email | + | Alice | Johnson | alice@example.com | + + @regression + Scenario Outline: Field validation - missing or invalid fields + Given the following user registration payload: + | first_name | last_name | email | password | + | | | | | + And the confirm_password query parameter is "" + When I send a POST request to /register + Then the response status should be 400 + And the response body should contain "" + + Examples: + | first_name | last_name | email | password | confirm_password | error_message | + | | Smith | smith@example.com | Pass123! | Pass123! | "first_name cannot be empty" | + | Jo | Doe | joe@example.com | MySecret | MySecret | "first_name must be at least 3 characters" | + | Jane | | jane@example.com | Secretp@ss | Secretp@ss | "last_name cannot be empty" | + | Jenna | Li | jen.com | p@ssw0rd | p@ssw0rd | "email is not a valid email address" | + | Tom | Stark | tom@example.com | | | "password cannot be empty" | + | Emma | Stone | emma@example.com | StonePwd | | "confirm_password cannot be empty" | + + @regression + Scenario: Password confirmation mismatch + Given the following user registration payload: + | first_name | last_name | email | password | + | Mark | Hill | mark@example.com | MyPass123 | + And the confirm_password query parameter is "WrongPass123" + When I send a POST request to /register + Then the response status should be 400 + And the response body should contain "Password and confirm_password do not match" + + @regression + Scenario: Registration with already existing email + Given the user with email "existing@example.com" has already registered + And the following user registration payload: + | first_name | last_name | email | password | + | Grace | Lee | existing@example.com | GracePwd1 | + And the confirm_password query parameter is "GracePwd1" + When I send a POST request to /register + Then the response status should be 400 + And the response body should contain "Email already exists" + + @regression + Scenario Outline: Edge cases for field boundaries and whitespace + Given the following user registration payload: + | first_name | last_name | email | password | + | | | | | + And the confirm_password query parameter is "" + When I send a POST request to /register + Then the response status should be + And the response body should contain "" + + Examples: + | first_name | last_name | email | password | confirm_password | status | error_or_success_message | + | Ana | Li | ana.li@example.com | Pass@123 | Pass@123 | 200 | "User registered successfully" | + | Ana | Li | ana.li@example.com | Pass@123 | Pass@123 | 400 | "first_name cannot start or end with whitespace" | + | Ana | Li | ana.li@example.com | Pass@123 | Pass@123 | 400 | "last_name cannot start or end with whitespace" | + | Ann | Lee | ann@example.com | Pass123 | Pass123 | 400 | "password cannot start or end with whitespace" | + | Jo3 | Doe | jo3@example.com | pass123 | pass123 | 200 | "User registered successfully" | + | | Lee | lee@example.com | 12345678 | 12345678 | 400 | "first_name cannot be empty" | + | Max | | max@example.com | maxpwd123 | maxpwd123 | 400 | "last_name cannot be empty" | + | Alice | Johnson | | alicepwd | alicepwd | 400 | "email cannot be empty" | + | Sam | White | sam@example.com | | | 400 | "password cannot be empty" | \ No newline at end of file diff --git a/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_transact.feature b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_transact.feature new file mode 100644 index 0000000..deb7c17 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/gherkin_scenarios/gherkin_transact.feature @@ -0,0 +1,167 @@ +Feature: Transaction API Endpoints - Deposit, Withdraw, Transfer, and Payment + + Comprehensive tests for core transaction actions under TransactController. + Covers happy paths, validation, authentication, and edge cases. + All endpoints require an authenticated user session. + + Background: + Given a user with valid credentials is authenticated + And the user has an account with id "ACC123" and a balance of 1000.00 + And another valid account with id "ACC456" + And the system accepts decimal amounts up to two places + + #---------------------- DEPOSIT ENDPOINT TESTS --------------------------- + + @smoke + Scenario: Successful deposit to an account + When the user sends a POST request to /transact/deposit with: + | deposit_amount | account_id | + | 150.50 | ACC123 | + Then the response status should be 200 + And the response should contain a success message + And the account "ACC123" balance should increase by 150.50 + + @regression + Scenario Outline: Deposit with missing or invalid amount or account_id + When the user sends a POST request to /transact/deposit with: + | deposit_amount | account_id | + | | | + Then the response status should be 400 + And the error message should indicate "" + + Examples: + | amount | account | error | + | | ACC123 | deposit_amount is required | + | 0 | ACC123 | deposit_amount must be greater than 0 | + | -50 | ACC123 | deposit_amount must be greater than 0 | + | 200 | | account_id is required | + | | | deposit_amount and account_id required| + | abc | ACC123 | deposit_amount is not a valid number | + | 1e9 | ACC123 | deposit_amount exceeds allowed limit | + + @regression + Scenario: Deposit when unauthenticated + Given the user is not authenticated + When the user sends a POST request to /transact/deposit with: + | deposit_amount | account_id | + | 100 | ACC123 | + Then the response status should be 401 + And the error message should indicate authentication is required + + @regression + Scenario Outline: Deposit with edge/boundary values for amount or account_id + When the user sends a POST request to /transact/deposit with: + | deposit_amount | account_id | + | | | + Then the response status should be 400 + And the error message should indicate "" + + Examples: + | amount | account | error | + | 0.0001 | ACC123 | deposit_amount must be greater than 0 | + | 1000000000 | ACC123 | deposit_amount exceeds allowed limit | + | 50 | | account_id is required | + | 100 | " " | account_id cannot be blank or whitespace | + + + #---------------------- WITHDRAW ENDPOINT TESTS --------------------------- + + @smoke + Scenario: Successful withdrawal from an account + When the user sends a POST request to /transact/withdraw with: + | withdrawal_amount | account_id | + | 200.00 | ACC123 | + Then the response status should be 200 + And the response should contain a success message + And the account "ACC123" balance should decrease by 200.00 + + @regression + Scenario Outline: Withdraw with insufficient funds, missing, or invalid amount + When the user sends a POST request to /transact/withdraw with: + | withdrawal_amount | account_id | + | | | + Then the response status should be 400 + And the error message should indicate "" + + Examples: + | amount | account | error | + | 0 | ACC123 | withdrawal_amount must be greater than 0 | + | -10 | ACC123 | withdrawal_amount must be greater than 0 | + | 2000 | ACC123 | insufficient funds | + | | ACC123 | withdrawal_amount is required | + | 50 | | account_id is required | + | abc | ACC123 | withdrawal_amount is not a valid number | + | 100 | " " | account_id cannot be blank or whitespace | + + #----------------------- TRANSFER ENDPOINT TESTS --------------------------- + + @smoke + Scenario: Successful transfer between two accounts + When the user sends a POST request to /transact/transfer with: + | source_account_id | target_account_id | amount | + | ACC123 | ACC456 | 300.00 | + Then the response status should be 200 + And the response should contain a success message + And the account "ACC123" balance should decrease by 300.00 + And the account "ACC456" balance should increase by 300.00 + + @regression + Scenario Outline: Transfer with insufficient funds, invalid account IDs, or amounts + When the user sends a POST request to /transact/transfer with: + | source_account_id | target_account_id | amount | + | | | | + Then the response status should be 400 + And the error message should indicate "" + + Examples: + | source | target | amt | error | + | ACC123 | ACC456 | 0 | amount must be greater than 0 | + | ACC123 | ACC456 | -100 | amount must be greater than 0 | + | ACC123 | ACC456 | 5000 | insufficient funds | + | ACC999 | ACC456 | 100 | invalid source_account_id | + | ACC123 | ACC999 | 100 | invalid target_account_id | + | | ACC456 | 100 | source_account_id is required | + | ACC123 | | 100 | target_account_id is required | + | ACC123 | ACC456 | abc | amount is not a valid number | + | ACC123 | ACC123 | 100 | source and target accounts must be different | + | " " | ACC456 | 100 | source_account_id cannot be blank/whitespace | + + #------------------------ PAYMENT ENDPOINT TESTS --------------------------- + + @smoke + Scenario: Successful payment to a beneficiary + When the user sends a POST request to /transact/payment with: + | beneficiary | account_number | account_id | payment_amount | reference | + | "John Doe" | "98765432" | ACC123 | 250.00 | "INVOICE1" | + Then the response status should be 200 + And the response should contain a success message + And the account "ACC123" balance should decrease by 250.00 + And a Payment record should be created for "John Doe", "98765432", and 250.00 + + @regression + Scenario Outline: Payment with missing, zero, or invalid fields or insufficient funds + When the user sends a POST request to /transact/payment with: + | beneficiary | account_number | account_id | payment_amount | reference | + | | | | | | + Then the response status should be 400 + And the error message should indicate "" + + Examples: + | benef | accno | aid | amt | ref | error | + | | 98765432 | ACC123 | 100 | REF1 | beneficiary is required | + | John Doe | | ACC123 | 100 | REF1 | account_number is required | + | John Doe | 98765432 | | 100 | REF1 | account_id is required | + | John Doe | 98765432 | ACC123 | 0 | REF1 | payment_amount must be > 0 | + | John Doe | 98765432 | ACC123 | -50 | REF1 | payment_amount must be > 0 | + | John Doe | 98765432 | ACC123 | 1200 | REF1 | insufficient funds | + | John Doe | 98765432 | ACC123 | abc | REF1 | payment_amount is not a valid number | + | John Doe | 98765432 | ACC123 | 100 | | reference is required | + | John Doe | 98765432 | " " | 100 | REF1 | account_id cannot be blank/whitespace | + + @regression + Scenario: Payment with very large amount + When the user sends a POST request to /transact/payment with: + | beneficiary | account_number | account_id | payment_amount | reference | + | John Doe | 98765432 | ACC123 | 1000000000 | REF2 | + Then the response status should be 400 + And the error message should indicate payment_amount exceeds allowed limit diff --git a/Online-Banking-App-Spring-Boot/test_docs/business_use_cases.md b/Online-Banking-App-Spring-Boot/test_docs/business_use_cases.md new file mode 100644 index 0000000..66a3fd7 --- /dev/null +++ b/Online-Banking-App-Spring-Boot/test_docs/business_use_cases.md @@ -0,0 +1,222 @@ +# Business Use Case Documentation + +## Contents +- [Account Management](#account-management) +- [Transactions](#transactions) +- [Authentication](#authentication) +- [Registration](#registration) +- [Data Retrieval](#data-retrieval) + +--- + +## Account Management + +### Main Flows +- Create a bank account + +### User Stories +| ID | Scenario | Description | Tags | +|----|----------|-------------|------| +| AM-01 | As a user, I want to create a new account so I can manage my finances. | Users can open an account. | `@smoke`, `@regression` | + +*Scenario coverage from [gherkin_account.feature](../gherkin_scenarios/gherkin_account.feature)* + +### Acceptance Criteria +- Account can be created with account_name and account_type present and valid +- 400 error for missing/invalid fields +- 401 error if user is not authenticated +- Account name boundaries and invalid types are handled + +| Scenario Title | Endpoint | Criteria | Tag | +|---------------|----------|----------|-----| +| Successful account creation | POST `/account/create_account` | 200 OK, account appears in returned list | `@smoke` | +| Missing account_name/type | POST `/account/create_account` | 400, error message for field presence | `@regression` | +| Non-authenticated user | POST `/account/create_account` | 401, error message for authentication | `@regression` | +| Boundary values | POST `/account/create_account` | 200 or 400, depending on value | `@regression` | + +### Business Rules & Constraints +- Only authenticated users (session User) can create accounts +- Required fields: account_name, account_type (validated) +- Account model must include fields as per discovered schema + +### Actor Descriptions +- **User:** End customer creating and managing their accounts + +--- + +## Transactions + +### Main Flows +- Deposit, withdraw, transfer between accounts, make a payment + +### User Stories +| ID | Scenario | Description | Tags | +|----|----------|-------------|------| +| TR-01 | As a user, I want to deposit funds. | Add money to my account | `@smoke`, `@regression` | +| TR-02 | As a user, I want to withdraw funds. | Remove money from my account | `@smoke`, `@regression` | +| TR-03 | As a user, I want to transfer funds. | Move money between accounts | `@smoke`, `@regression` | +| TR-04 | As a user, I want to pay a beneficiary. | Make payments to others | `@smoke`, `@regression` | + +*Scenario coverage from [gherkin_transact.feature](../gherkin_scenarios/gherkin_transact.feature)* + +### Acceptance Criteria +- Deposit/withdraw/transfer/payment validate amounts, accounts, sufficient funds +- 400 error for invalid/missing data +- 401 error for unauthenticated actions +- Out-of-bound values and whitespace handled + +| Scenario Title | Endpoint | Criteria | Tag | +|---------------|----------|----------|-----| +| Successful deposit | POST `/transact/deposit` | 200 OK, balance increases | `@smoke` | +| Successful withdraw | POST `/transact/withdraw` | 200 OK, balance decreases | `@smoke` | +| Successful transfer | POST `/transact/transfer` | 200 OK, balances updated | `@smoke` | +| Successful payment | POST `/transact/payment` | 200 OK, balance decreases, payment record | `@smoke` | +| Invalid/missing fields | Various | 400, error message | `@regression` | +| Insufficient funds | Various | 400, error message | `@regression` | +| Unauthorized actions | Various | 401, error message | `@regression` | + +### Business Rules & Constraints +- Only authenticated users can transact +- Amounts must be positive and within allowed limits +- Source/target accounts must be valid and not identical (for transfer) +- All transaction actions update account models and create transaction/payment entities + +### Actor Descriptions +- **User:** Account holder initiating transactions +- **System:** Validates, updates balances, creates records + +--- + +## Authentication + +### Main Flows +- Log in, log out + +### User Stories +| ID | Scenario | Description | Tags | +|----|----------|-------------|------| +| AU-01 | As a user, I want to log in securely. | Authenticate to access services | `@smoke`, `@regression` | +| AU-02 | As a user, I want to log out of my session. | End my session | `@smoke`, `@regression`, `@logout` | + +*Scenario coverage from [gherkin_auth.feature](../gherkin_scenarios/gherkin_auth.feature)* + +### Acceptance Criteria +- Login requires email and password, verified account +- 400 for missing/invalid fields, 401/403/500 for various fail states +- Logout succeeds with valid session, errors for expired/invalid/no session + +| Scenario Title | Endpoint | Criteria | Tag | +|---------------|----------|----------|-----| +| Successful login | POST `/login` | 200 OK, access_token returned | `@smoke` | +| Successful logout | GET `/logout` | 200 OK, confirmation message | `@smoke` | +| Invalid login | POST `/login` | 400/401/403/500, error messages | `@regression` | +| Invalid logout | GET `/logout` | 401, error messages | `@regression` | + +### Business Rules & Constraints +- Only registered, verified users can log in +- Sessions managed via tokens +- Account models enforce validation on credentials + +### Actor Descriptions +- **User:** Logs in/out, receives tokens +- **System:** Verifies credentials, issues tokens, manages session + +--- + +## Registration + +### Main Flows +- Sign up, password confirmation, handle duplicate emails, validate fields + +### User Stories +| ID | Scenario | Description | Tags | +|----|----------|-------------|------| +| RG-01 | As a new user, I want to register using valid information. | Sign up as customer | `@smoke`, `@regression` | +| RG-02 | As a user, I want my password to be confirmed. | Avoid mistakes in password entry | `@regression` | +| RG-03 | As a user, I want to avoid duplicate account registration. | Register with a unique email | `@regression` | + +*Scenario coverage from [gherkin_register.feature](../gherkin_scenarios/gherkin_register.feature)* + +### Acceptance Criteria +- Registration requires first_name, last_name, email, password, confirm_password +- Validation enforces presence, length, format +- Duplicate emails rejected +- Password & confirm_password must match + +| Scenario Title | Endpoint | Criteria | Tag | +|---------------|----------|----------|-----| +| Successful registration | POST `/register` | 200 OK, confirmation, user returned | `@smoke` | +| Invalid fields | POST `/register` | 400, error messages | `@regression` | +| Password mismatch | POST `/register` | 400, error message | `@regression` | +| Duplicate email | POST `/register` | 400, error message | `@regression` | + +### Business Rules & Constraints +- User fields validated as per discovered User model +- Only non-empty, correctly formatted data allowed +- Passwords must match confirm_password + +### Actor Descriptions +- **Visitor/User:** Registers account +- **System:** Validates input, stores user + +--- + +## Data Retrieval + +### Main Flows +- Dashboard, payment history, transaction history, per-account transactions + +### User Stories +| ID | Scenario | Description | Tags | +|----|----------|-------------|------| +| DR-01 | As a user, I want to view my dashboard summary. | Access accounts and total balance | `@smoke`, `@regression` | +| DR-02 | As a user, I want to see my payment history. | Track payments | `@smoke`, `@regression` | +| DR-03 | As a user, I want to see my transaction history. | Review transactions | `@smoke`, `@regression` | +| DR-04 | As a user, I want to view my account's transaction history. | See transactions for a given account | `@smoke`, `@regression` | + +*Scenario coverage from [gherkin_app.feature](../gherkin_scenarios/gherkin_app.feature), [gherkin_account_transaction_history.feature](../gherkin_scenarios/gherkin_account_transaction_history.feature)* + +### Acceptance Criteria +- Authentication required for all data retrieval +- 200 OK with correct data arrays for valid requests +- 401 for unauthenticated, 400 for invalid/missing account_id +- Empty arrays returned for no data + +| Scenario Title | Endpoint | Criteria | Tag | +|---------------|----------|----------|-----| +| Dashboard retrieval | GET `/app/dashboard` | 200, userAccounts & totalBalance returned | `@smoke`, `@regression` | +| Payment history | GET `/app/payment_history` | 200, payment_history returned | `@smoke`, `@regression` | +| Transaction history | GET `/app/transaction_history` | 200, transaction_history returned | `@smoke`, `@regression` | +| Account transaction history | POST `/app/account_transaction_history` | 200/400/401, transaction history/results | `@smoke`, `@regression` | + +### Business Rules & Constraints +- Only authenticated users can access their data +- Account IDs validated for ownership +- Models: Account, Payment, PaymentHistory + +### Actor Descriptions +- **User:** Consumes dashboard, history APIs +- **System:** Serves filtered, secure data + +--- + +## Cross-Reference Index + +| Feature Tag | Endpoint Path | Business Flow | Scenario File | +|-------------|-------------------------|---------------|---------------------------| +| `@smoke`/`@regression` | POST `/account/create_account` | Account Management | gherkin_account.feature | +| `@smoke`/`@regression` | POST `/transact/deposit` | Transactions | gherkin_transact.feature | +| `@smoke`/`@regression` | GET `/app/dashboard` | Data Retrieval | gherkin_app.feature | +| `@smoke`/`@regression` | POST `/register` | Registration | gherkin_register.feature | +| `@smoke`/`@regression` | POST `/login`/GET `/logout` | Authentication | gherkin_auth.feature | +| `@smoke`/`@regression` | POST `/app/account_transaction_history` | Data Retrieval | gherkin_account_transaction_history.feature | + +--- + +## Traceability Links + +- All test scenarios are linked to business flows via scenario tags. +- Endpoints are mapped to each user story and acceptance criteria. +- Models referenced per flow are validated in feature files and reflected in request/response validations. + +--- \ No newline at end of file