# PRD — katalon_tests

Evidence date: 2026-10-11.

Source: `git@bitbucket.org:overdrive/katalon_tests.git`, `main` at `7fa8653` (2025-08-21).

There is no prior PRD in Silicon Ark. Requirements below are recovered from `ShopFlow/README.md`, the four Markdown guides, the `.tc` tags, the Groovy scripts, the dynamic suites, and `Profiles/default.glbl`. Provenance is labelled. Secret values are omitted.

This document describes the test suite. Expected behaviour of the ShopFlow application is recorded only where a script asserts it, and those assertions are **Inferred** expectations of the system under test, not confirmed product requirements of ShopFlow.

## Product purpose

**Documented.** `TEST_COVERAGE.md` calls the target "the ShopFlow EDI application" and organises cases by authentication, commerce, user management, admin, price management, reports, and integration. `README.md` says IMAP credentials, user credentials, and the site URL live in `Profiles/default`, and that other tests should include the login case.

**Implemented.** A Katalon Studio Enterprise 10.3.0 Web UI project that opens Chrome against `GlobalVariable.url` and runs tagged Groovy cases.

**Discrepancy.** `README.md` tells the reader to include `Test Cases/Login/Login`. The case on disk is `Test Cases/01_Authentication/Login`. Only `Logout` and `Order_Management` call that case. The smoke and regression suite setup methods open a browser and navigate to `GlobalVariable.url`. They do not call Login.

## Users and roles

The repository does not define application roles. It defines one execution profile and the people who would run Katalon.

| Actor | Evidence | Status |
|---|---|---|
| Suite operator | Shell scripts and Katalon console flags | **Implemented** as the intended runner. No named owner beyond git author joshgatdew |
| Shared test user | `Profiles/default.glbl` variables `username` and `password` | **Implemented**. `username` is a Gmail address in clear text. `password` is protected and the committed value is empty |
| IMAP mailbox | `imap_user`, `imap_pass`, `imap_host`, `imap_port` | **Implemented**. Host `imap.gmail.com`, port `993`. `imap_user` matches `username`. `imap_pass` is protected and empty in git |
| System under test | `url` = `http://shopflow.io.dedi1534.jnb2.host-h.net` | **Implemented** as configuration |
| Application end users (buyer, admin, seller) | Exercised only as UI flows inside scripts | **Inferred** from page paths. No role matrix is in this repository |

`TEST_COVERAGE.md` lists Chrome as primary, Firefox as secondary, and Safari "if needed". The runners and the test-suite collection request Chrome only.

## Actors inside the scripts

Login treats a single account. It does not switch roles. Admin cases navigate to admin paths with that same session only if some earlier step has logged in. Most cases do not log in themselves.

## Systems the suite talks to

1. The HTTP host in `GlobalVariable.url`. Provenance: **Implemented**. Whether that host still serves ShopFlow is **Unknown**.
2. Gmail over IMAPS on port 993, from `Scripts/01_Authentication/Read GMail 2fa Code/Script1755182083194.groovy`. The script sets `mail.imaps.ssl.trust` to `*` and `mail.imaps.ssl.checkserveridentity` to `false`. Provenance: **Implemented**.
3. Katalon Runtime at `/opt/katalon/katalon`, invoked by the shell scripts, with a placeholder `-apiKey`. Provenance: **Documented** in the scripts. A successful run from this repository was not observed.
4. REST paths on the same host, from `API_Integration` via Katalon `WS.sendRequest` and objects under `Object Repository/API/`. Provenance: **Implemented** as requests. Whether those paths exist on the host is **Unknown**.

`console.properties` leaves TestOps, TestCloud, Kobiton, qTest, and Azure DevOps identifiers empty. No monitoring, queue, or database client is configured.

`playwright_tests` in Silicon Ark documents a different ShopFlow base URL (`https://shopflow.php8` or the QA hostname). That is a separate suite. It is not a dependency of this repository.

## Major workflows

### WF-1 — Run the smoke suite

**Trigger:** operator runs `ShopFlow/run_smoke_tests.sh` from the project directory, or the equivalent `katalonc` command in `DYNAMIC_TEST_SUITES.md`.

**Inputs:** Katalon binary at `/opt/katalon/katalon`, project path `.`, suite `Test Suites/suites/Smoke_Tests_Dynamic`, browser Chrome, profile `default`, retry 1, and the literal API key `your-api-key-here`.

**Behaviour:** `Smoke_Tests_Dynamic.ts` is a `FilteringTestSuiteEntity` using `com.kms.katalon.execution.platform.DynamicBuiltInSearch`. Filter text is two lines: `tag=(P1)` and `tag=(SMOKE)`. `DYNAMIC_TEST_SUITES.md` describes that pair as the inclusion rule. Suite Groovy `@SetUp` opens and maximises a browser, zeroes `smokeTestPassCount`, `smokeTestFailCount`, and `smokeTestSkipCount`, and `@SetupTestCase` navigates to `GlobalVariable.url`. `@TearDown` prints those counters and closes the browser.

**Output:** Katalon report for the cases whose `.tc` tags contain both `P1` and `SMOKE`. Those cases are Login, Logout, Dashboard, Add_To_Cart, Product_Catalog_Browse, Order_Management, and Product_Catalog_Management.

**Errors:** the shell script does not check the Katalon exit code. The placeholder API key will fail a run that requires a real Runtime Engine licence. **Requires Confirmation** of how this team licenses console runs.

**Gap:** the counters are assigned `0` in setup and never incremented. The printed summary is therefore always zero unless another script writes them. No such write was found.

### WF-2 — Run the regression suite

**Trigger:** `run_regression_tests.sh`.

**Inputs:** same binary and profile, suite `Test Suites/suites/Regression_Tests_Dynamic`, retry 2.

**Behaviour:** filter text is `tag=(REGRESSION)`. Page-load timeout on the suite entity is 60 seconds. Number of reruns is 2. `@SetUp` opens Chrome and calls `setupTestData()`, which calls `createTestUsers`, `createTestProducts`, and `createTestOrders`. Each of those functions only prints a line. Teardown prints counters and calls the matching remove functions, which also only print.

**Output:** cases whose tags include `REGRESSION`. That set is Invalid_Login, Cart_Management, Order_Scheduling, User_Profile_View, the six admin cases, Price_File_Management, Pricing_Rules_Management, Price_File_Upload, and Sales_Report_Generation (tag `SHOPFLOW_REPORTS`, not `REPORTS`).

**Errors:** `TAG_STRATEGY.md` says regression runs in parallel where possible. The only suite collection, `Test Suites/main/Tag_Based_Execution.ts`, sets `executionMode` SEQUENTIAL and includes only `Regression_Tests_Dynamic`. It does not include the smoke suite.

### WF-3 — Log in, with optional email 2FA

**Trigger:** test case `01_Authentication/Login`, or `WebUI.callTestCase` of that case from Logout and Order_Management.

**Inputs:** `GlobalVariable.username`, `GlobalVariable.password`, and, when a 2FA field is present, IMAP settings plus `GlobalVariable.LoginDate`.

**Behaviour:**

1. `WebUI.openBrowser('')`, maximise, navigate to `GlobalVariable.url`, wait up to 10 seconds.
2. Fail the test if the window title is empty or if email, password, or the login button object is absent. Objects live under `Object Repository/Page_Login  Transactflow/`. The email object uses XPath `//input[@id='inputEmail']` (CSS `#inputEmail` is also stored). Smart locators are disabled.
3. Remember-me and forgot-password objects are checked with `FailureHandling.OPTIONAL`. Absence prints a warning and does not fail the test.
4. Clear and set email and password. Fail if the email attribute does not equal `GlobalVariable.username`.
5. Store `LoginDate` as `yyyy/MM/dd HH:mm:ss` immediately before the click.
6. Click the login button and delay 3 seconds.
7. If `Page_Transactflow/input_Remember this device for 30 days_inpu_99772f` is present, call `Read GMail 2fa Code`. If that returns a non-empty string, type it and click `button_Remember this device for 30 days_ver_bfc570`. If it returns empty, or the call throws, the test fails. If the 2FA field is absent, the script logs that it is proceeding without 2FA.
8. After load, treat login as successful when the window title and the URL both differ from the pre-submit values. Dashboard, home, welcome, logout, and profile objects are optional checks.

**Output:** a browser session on a URL other than the original login URL, or a failed test.

**2FA read (`Read GMail 2fa Code`):** connect with JavaMail store `imaps`, open INBOX read-only, search subject `2FA Validation`, retry for 30 seconds every 5 seconds. Prefer a message whose sent date is after `LoginDate`. If none, use the newest message with that subject. Extract the text after `Your 2FA code is:`. The `.tc` file for this case has an empty `<tag>`, so the dynamic suites do not select it on its own. Login calls it.

**Errors:** empty protected password means step 4 submits an empty password unless a runtime override exists. IMAP failure is printed and the case returns no code, which makes Login fail when the 2FA field was shown. The script logs the verification code with `println`.

### WF-4 — Reject invalid login input

**Trigger:** `01_Authentication/Invalid_Login`, selected by the regression filter (`AUTH,P2,REGRESSION,UI,SECURITY`).

**Inputs:** the login form. This script does not call `openBrowser`. It navigates to `GlobalVariable.url` and stops if the form is missing.

**Behaviour:** the script submits empty credentials, a list of malformed email strings, wrong-password and unknown-user attempts, SQL-injection-shaped strings, and XSS-shaped strings. It then looks at page source and an `errorMessageText` object. Many checks call `KeywordUtil.markFailed` instead of stopping. Account lockout is named in the script header. The assertions that follow are string searches in the page, not a lockout counter.

**Output:** a Katalon failure when a `markFailed` or `WebUI.fail` path runs.

**Constraint:** this encodes what the test hopes the login page will do. It is not evidence that the application blocks injection.

### WF-5 — Shop and cart

**Trigger:** `02_Core_Commerce/Add_To_Cart` (smoke) and `Cart_Management` (regression).

**Inputs:** an already open browser. `Add_To_Cart` comments say login should be handled by suite setup. Suite setup does not log in. The script navigates to `GlobalVariable.url + '/shop'`.

**Behaviour:** wait for the shop URL, then interact with objects such as `#productsTable`, quantity inputs `input[type="text"][data-quantity]`, and a button whose locator is tied to `onclick` containing `addProductToTable`. `ADD_TO_CART_TEST_FIXES.md` says styling classes were removed from several locators after they broke. Many steps use `FailureHandling.OPTIONAL`. A local function `isValidPriceFormat` accepts a number after stripping `$`, `R`, and commas, and requires the value to be `>= 0`.

**Output:** pass or `KeywordUtil.markFailed` depending on which checks are strict.

**Last change:** commits `9af7ea3`, `c8debfd`, and `7fa8653` are the add-to-cart fix series.

### WF-6 — Other UI modules

Each remaining UI case navigates to a path on `GlobalVariable.url` and checks objects under `Page_Transactflow`. Paths found in the scripts:

| Case | Path | Suite |
|---|---|---|
| Dashboard | `/home` | Smoke |
| Product_Catalog_Browse | `/shop`, and later `/products` | Smoke |
| Order_Management | `/dashboard` then `/orders`. Calls Login | Smoke |
| Logout | `/products`, `/Welcome/logout`, `/dashboard`, `/admin` | Smoke |
| Cart_Management | `/carts` | Regression |
| Order_Scheduling | `/orders` | Regression |
| User_Profile_View | `/users/userProfile` | Regression |
| Seller_Management | `/seller-management` | Regression |
| Store_Management | `/storemanagement` | Regression |
| Seller_Groups | `/sellergroups` | Regression |
| Buying_Groups | `/admin/buying-groups` | Regression |
| Company_Management | `/companymanagement` | Regression |
| Company_User_Management | `/admin/company-users` | Regression |
| Price_File_Upload | `/productmanagement/pricefiles` | Regression |
| Price_File_Management | `/pricefiles` | Regression |
| Product_Catalog_Management | `/productmanagement` | Smoke |
| Pricing_Rules_Management | `/pricefilemappingrules` | Regression |
| Sales_Report_Generation | `/reports` | Regression |

`TEST_COVERAGE.md` describes create, edit, deactivate, tax, shipping, permissions, and chart interactions for these modules. The scripts navigate and look for objects. They were not re-traced line by line. Treat the coverage document's feature lists as **Documented** intent. Treat a path plus an object check as **Implemented** navigation.

`08_Multipath_Regressions/placeholder` has an empty tag. Its script still walks `/products`, `/carts`, `/orders`, `/seller-management`, `/company-management`, `/reports`, `/pricefiles`, and `/invalid-page`. The dynamic suites do not select it.

### WF-7 — API integration case

**Trigger:** only if an operator runs `07_Integration/API_Integration` directly. Tags on the `.tc` file are `INTEGRATION,P4,PLACEHOLDER,API`. It has neither `SMOKE` nor `REGRESSION`, so neither dynamic suite selects it.

**Discrepancy.** The Groovy header comment says tags `INTEGRATION, P1, API, AUTHENTICATION, REST` and "covers all available API endpoints". `TEST_COVERAGE.md` calls the same case a placeholder health check with integration coverage of 10%.

**Behaviour that is in the script:** a browser check for the login email field, then `WS.sendRequest` using REST objects. Paths include `POST /organisations/login` with a hard-coded example username and password (not `GlobalVariable`), `GET` and `POST /organisations`, get/update/delete of one organisation id when one was captured, `GET /store-api`, and `GET /api-simulation`. Further requests hit `/organisations` for invalid auth, invalid body, performance, consistency, security, rate limit, and error handling. A 401 response is passed to `KeywordUtil.markFailed` with text that says authentication is expected. A 401 therefore fails the case.

**Output:** Katalon WS results. No token is taken from the UI login.

## Functional requirements

### FR-001 — Default profile supplies the host and the mailbox

**Requirement:** A Katalon run with `-executionProfile=default` reads `url`, `username`, `password`, `imap_host`, `imap_user`, `imap_pass`, and `imap_port` from `Profiles/default.glbl`.

**Trigger:** any script that references `GlobalVariable`.

**Validation:** `password` and `imap_pass` are `protected` with empty `initValue`. A run without an external override submits an empty password and an empty IMAP password.

**Implementation:** Implemented.

**Evidence:** `Profiles/default.glbl`, both shell scripts.

**Confidence:** High for the file contents. Low for the live secret values.

### FR-002 — Smoke selection is the intersection of P1 and SMOKE

**Requirement:** The smoke suite includes a test case only when its `.tc` `<tag>` contains both `P1` and `SMOKE`.

**Implementation:** Implemented as two filter lines on `Smoke_Tests_Dynamic.ts`. Documented the same way in `DYNAMIC_TEST_SUITES.md`.

**Evidence:** the seven cases listed in WF-1 match that rule. `Read GMail 2fa Code` and `placeholder` have empty tags and are excluded. `API_Integration` is `P4` and excluded.

**Confidence:** High for the filter text. Katalon's exact AND/OR parsing of newline-separated `filteringText` was not executed. The project document states the intended AND.

### FR-003 — Regression selection is the REGRESSION tag

**Requirement:** The regression suite includes every case whose tag list contains `REGRESSION`, and continues after a case failure.

**Implementation:** Filter `tag=(REGRESSION)` is implemented. "Continue on failure" is **Documented** in `DYNAMIC_TEST_SUITES.md` and `TAG_STRATEGY.md`. The suite entity sets `numberOfRerun` to 2 and does not itself set a stop-on-failure flag. Individual scripts mix `STOP_ON_FAILURE`, `OPTIONAL`, and `KeywordUtil.markFailed`.

**Confidence:** High for membership. Medium for suite-level failure policy, because it depends on Katalon defaults plus per-step handling.

### FR-004 — Login fails closed when the form is missing, and 2FA fails closed only when the field is shown

**Requirement:** Missing email, password, or login button fails the login case. A visible 2FA field requires a code parsed from a message whose subject is `2FA Validation` and whose body contains `Your 2FA code is:`. A missing 2FA field does not fail the case.

**Implementation:** Implemented in `Script1755182083031.groovy` and `Script1755182083194.groovy`.

**Confidence:** High.

### FR-005 — Add-to-cart locators prefer stable attributes

**Requirement:** `ADD_TO_CART_TEST_FIXES.md` says selectors must not depend on styling classes such as `btn-success` or `text-end`, and should use ids, `data-*`, `onclick`, or structural positions.

**Implementation:** `productsTable.rs` selects `#productsTable` by CSS. The document lists other objects that were changed. Not every one of the 456 `Page_Transactflow` objects was checked against that rule.

**Confidence:** High for the written rule and for `productsTable`. Medium for the rest of the repository.

### FR-006 — Price-file fixtures exist for upload tests

**Requirement:** `TEST_COVERAGE.md` says `valid_price_file.csv`, `invalid_data_price_file.csv`, and `invalid_file.txt` are the upload fixtures.

**Inputs on disk:**

- Valid CSV header: `Product_ID,Product_Name,Category,Price,Currency,Effective_Date`, with five rows, prices such as `29.99`, currency `USD`, date `2024-12-31`.
- Invalid CSV: negative price `-29.99`, price text `invalid_price`, empty product name, date `invalid_date`, currency `INVALID_CURRENCY`.
- `invalid_file.txt` is plain text stating it should be rejected.
- `product_image.jpg` is also in `TestData/` and is not mentioned in the coverage doc.

**Implementation gap:** no Groovy file references those filenames or `findTestData(...)` with a data file id. `Price_File_Upload` waits for `uploadFileInput` and later reads `firstUploadFileName`, and it checks that a displayed name matches `csv`, `xlsx`, `xls`, or `txt`. It does not upload the fixtures.

**Confidence:** High that the files exist and are unreferenced.

### FR-007 — Tag helper does not discover cases

**Requirement:** `TAG_STRATEGY.md` shows command lines with `-includeTags` against suites named `All_Tests` and `API_Tests`, and a Groovy `@Tag` style.

**Implementation:** `Scripts/Include/TagBasedExecution.groovy` method `findTestCasesByTags` returns `[]`. `executeSmokeTests`, `executeCriticalTests`, `executeRegressionTests`, `executeAPITests`, and `executeUITests` therefore call nothing. Suites `All_Tests` and `API_Tests` are not in the tree. Katalon tags in this project are comma-separated strings inside `.tc` XML, not Spock `@Tag` annotations.

**Confidence:** High.

### FR-008 — API case is excluded from the packaged suites and uses example credentials

**Requirement:** Operators who run the dynamic suites do not run `API_Integration`. A direct run sends JSON to `/organisations/login` with a hard-coded example identity, not the profile user.

**Implementation:** Implemented. See WF-7.

**Confidence:** High.

## Important constraints

- Project type is WEBUI. Chrome arguments in `com.kms.katalon.core.webui.chrome.properties` are `start-maximized`, `ignore-certificate-errors`, `disable-popup-blocking`, and `auth-server-whitelist`.
- Default captured-object selector method is XPATH (`com.kms.katalon.execution.properties`). Individual objects can override it. `productsTable` uses CSS.
- Video recording is disabled in that same properties file.
- `pageLoadTimeout` on the project is `0` (`ShopFlow.prj`). The dynamic suites set their own page-load timeouts (30 seconds smoke, 60 seconds regression).
- Shell scripts are Bash and assume `/opt/katalon/katalon`. There is no Windows `.bat` runner in this revision.
- 25 `.groovy.backup` files are committed next to the scripts. They are not selected by Katalon.

## Non-requirements (claimed, not implemented)

The following appear in `TEST_COVERAGE.md` or `TAG_STRATEGY.md` and do not have a corresponding pipeline, suite, or tag on a `.tc` file:

- Environment tags `DEV`, `QA`, `STAGING`, `PROD`.
- Priority `P3`. The coverage doc says P3 count is 0 and also says P3 coverage is 100%.
- Tags `DATABASE`, `PERFORMANCE`, `REPORTS` (the reports case uses `SHOPFLOW_REPORTS`).
- Parallel regression, mail recipients, and immediate notification on P1 failure.
- Functional coverage of 99% and test-type coverage of 100%. No coverage tool output is in the repository.
- CI/CD, mobile, accessibility, visual regression, and load tests. Listed under "Planned Improvements" and "Future Enhancements".

## Unknown / Requires Confirmation

1. Whether `http://shopflow.io.dedi1534.jnb2.host-h.net` is still the intended target, and how it relates to the Playwright suite's `https://shopflow.php8` and `qa.shopflow.io.dedi1534.jnb2.host-h.net`.
2. Where the test-user password and the Gmail app password are stored for a real run.
3. Whether the 2FA mail subject is still `2FA Validation` and the body still contains `Your 2FA code is:`.
4. Whether `/organisations`, `/store-api`, and `/api-simulation` are real ShopFlow routes. The session path name includes `simulation`.
5. Whether the recorded titles Transactflow and AdminOverdrive are the current product name.
6. Whether Katalon Enterprise 10.3.0 is still the approved runner, and what replaces the placeholder API key.
7. Whether the sonar files named at onboarding discovery should be restored.
8. Whether empty-tag cases (`Read GMail 2fa Code`, `placeholder`) and the P4 API case are intentionally excluded from both suites.
