# Configuration

Consumer applications preferably configure the package with `resources/4-config/bdd-ui.config.json`.
The loader also accepts a root-level `bdd-ui.config.json` or a `BDD_UI_CONFIG_PATH` override, but the
recommended project structure is:

You can scaffold that structure with:

```bash
npx bdd-ui-init-resources
```

or include starter sample files with:

```bash
npx bdd-ui-init-resources --include-samples
```

```text
resources/
  1-payload/
  2-actual/
  3-expected/
  4-config/
  5-input/
  features/
```

The scaffolded `resources/4-config/bdd-ui.config.json` created by `npx bdd-ui-init-resources` includes a starter
`jsonComparison` section:

```json
{
  "jsonComparison": {
    "engine": "jar",
    "output": "json"
  }
}
```

Keep the structure flat inside each feature-name folder. For example:

```text
resources/features/
  login.feature
  extract-visible-grid.feature
  qte-acceptance-criteria.feature

resources/5-input/
  qte-acceptance-criteria/
    qte-ac-core-valid.json
    qte-ac-premium-valid.json
  qte-global-field-synchronization/
    qte-global-sync.json

resources/3-expected/
  extract-visible-grid/
    qte-grid-list.json
  qte-acceptance-criteria/
    qte-created.json
    qte-success.json

resources/2-actual/
  extract-visible-grid/
    qte-grid-list.json
  qte-acceptance-criteria/
    qte-created.json
```

```json
{
  "baseUrl": "https://qa.example.com",
  "browser": "chromium",
  "headless": true,
  "timeout": 30000,
  "trace": true,
  "screenshotOnFailure": true,
  "viewport": {
    "width": 1440,
    "height": 900
  },
  "resourcePaths": {
    "payload": "resources/1-payload",
    "actual": "resources/2-actual",
    "expected": "resources/3-expected",
    "config": "resources/4-config",
    "input": "resources/5-input",
    "features": "resources/features"
  },
  "grids": {
    "trade": "[data-testid=\"trade-grid\"]"
  },
  "selectors": {
    "login-form": "[data-test-id=\"login-form\"]",
    "qte-form": "[data-test-id=\"qte-form\"]",
    "open-full-ticket-button": "[data-test-id=\"open-full-ticket-button\"]"
  },
  "uiScanner": {
    "language": "react-tsx",
    "include": [".tsx", ".ts"],
    "exclude": [".test.", ".spec.", ".stories.", "node_modules"]
  },
  "screenshots": {
    "expectedDir": "resources/3-expected/screenshots",
    "actualDir": "resources/2-actual/screenshots",
    "diffDir": "resources/2-actual/screenshots-diff",
    "mode": "compare",
    "threshold": 0.1,
    "maxDiffPixels": 0
  },
  "fieldVerification": {
    "Notional": {
      "mode": "normalized"
    },
    "Counterparty": {
      "mode": "contains"
    },
    "Premium BPS": {
      "mode": "pattern",
      "expectedPattern": "^\\d+\\.\\d{2}$"
    },
    "Trade Date": {
      "mode": "formatted",
      "expectedPattern": "^\\d{2}/\\d{2}/\\d{4}$"
    },
    "Internal Notes": {
      "mode": "none"
    }
  },
  "auth": {
    "loginPath": "/login",
    "successUrlContains": "/home"
  },
  "credentials": {
    "standardUser": {
      "username": "qa-user",
      "password": "secret"
    }
  }
}
```

The optional `grids` section maps readable grid names from feature files to stable selectors in the consumer app.
For example, `"trade"` can point to a `data-testid`, id, or another selector that resolves to the grid or a visible
container that contains the grid.

The `screenshotOnFailure` flag controls failure evidence capture. When enabled, the framework attaches a full-page
screenshot only for steps that fail. It does not attach screenshots for passing steps.

The optional `selectors` section maps readable names to stable selectors for non-grid elements. These aliases can be
used with existing visibility, enabled-state, button-click, checkbox, and scoped-form steps.

```gherkin
Then "qte-form" should be visible
When I click the "open-full-ticket-button" button
When I fill the form "qte-form" from "qte-ac-core-valid.json"
```

They also work with the newer custom-control steps:

```gherkin
When I choose "Ireland" from "country-dropdown"
When I scroll to element "roll-field"
When I open the "main-tab" tab
When I open the "main-tab" tab in "workspace-panel"
Then "country-dropdown" should have value "Ireland"
Then "country-dropdown" should contain value "Ire"
Then the "main-tab" tab should be active
```

The dropdown content assertion steps reuse the same alias support. For example:

```gherkin
Then the dropdown "country-dropdown" should contain exactly:
  | Ireland |
  | France  |
```

A consumer app with stable custom-control hooks can configure them like this:

```json
{
  "selectors": {
    "country-dropdown": "[data-test-id=\"country-dropdown\"]",
    "main-tab": "[data-test-id=\"main-tab\"]",
    "roll-field": "[data-test-id=\"ROLL\"]",
    "workspace-panel": "[data-test-id=\"workspace-panel\"]"
  }
}
```

For long-term maintainability, prefer selector aliases over hardcoded raw selectors in feature files. A selector alias
can point to a stable `data-test-id`, `data-testid`, `id`, class selector, or another supported locator:

```json
{
  "selectors": {
    "save-button": "[data-test-id=\"save-button\"]",
    "primary-cta": ".primary-cta",
    "main-tab": "[data-test-id=\"main-tab\"]"
  }
}
```

Then the same aliases can be reused across generic steps:

```gherkin
When I click "save-button"
When I click "primary-cta"
When I open the "main-tab" tab
When I open the "main-tab" tab in "workspace-panel"
Then "save-button" should be visible
```

The same `selectors` map can also provide panel/container aliases for scoped tab lookup when duplicate tab names appear
in different parts of the page.

If the same target appears more than once, use the indexed variants:

```gherkin
When I click ".primary-cta" at index 1
Then "Country" at index 1 should have value "Ireland"
```

The optional `uiScanner` section configures the selector generator CLI. Today the generator supports
`"language": "react-tsx"` and scans `.tsx` / `.ts` files for stable `data-test-id` and `data-testid` values.
Future languages can be added under the same config shape without changing the command interface.

The optional `resourcePaths` section controls where feature-scoped resources are resolved from:

```json
{
  "resourcePaths": {
    "payload": "resources/1-payload",
    "actual": "resources/2-actual",
    "expected": "resources/3-expected",
    "config": "resources/4-config",
    "input": "resources/5-input",
    "features": "resources/features"
  }
}
```

These roots are intended to mirror the API automation project structure:
- `1-payload` for request or event payloads
- `2-actual` for generated artifacts
- `3-expected` for baselines
- `4-config` for configuration
- `5-input` for UI test inputs such as form JSON
- `features` for feature files

File-based UI steps resolve relative to the appropriate root and the current feature name. For example:

```gherkin
When I fill the form from "qte-global-sync.json"
```

resolves under:

```text
resources/5-input/<feature-name>/qte-global-sync.json
```

The optional `viewport` section controls the browser context viewport. If the consumer project does not set a viewport,
the framework defaults to:

```json
{
  "viewport": {
    "width": 1440,
    "height": 900
  }
}
```

This keeps visual behavior stable across CI and local runs unless a consumer explicitly opts into another viewport.

The optional `screenshots` section controls screenshot baseline and artifact folders:

```json
{
  "screenshots": {
    "expectedDir": "resources/3-expected/screenshots",
    "actualDir": "resources/2-actual/screenshots",
    "diffDir": "resources/2-actual/screenshots-diff",
    "mode": "compare",
    "threshold": 0.1,
    "maxDiffPixels": 0
  }
}
```

These directories are intended for nested relative screenshot paths. For example, a logical screenshot id such as
`home/blotter/trade-grid` resolves to:

```text
resources/3-expected/screenshots/home/blotter/trade-grid.png
resources/2-actual/screenshots/home/blotter/trade-grid.png
resources/2-actual/screenshots-diff/home/blotter/trade-grid.png
```

The screenshot runtime rejects absolute paths and `..` traversal, creates nested folders automatically, and supports
alias-based masking through the `selectors` map. Screenshot-compare steps attach the actual screenshot to the
Cucumber/Allure report and attach the diff image when a mismatch generates one.

The optional `jsonComparison` section defines how the planned backend response comparison integration should resolve
the comparator runtime:

```json
{
  "jsonComparison": {
    "engine": "jar",
    "output": "json"
  }
}
```

The clean design assumes the comparator JAR is bundled inside the published `@genesislcap/bdd-ui-automation`
package. In that mode, consumer projects do not need Gradle or a populated `.m2` cache at runtime. The framework
should resolve the comparator in this order:
- `jsonComparison.jarPath` when a consumer explicitly overrides it
- the bundled package path for the comparator JAR
- fail clearly if neither exists

An explicit override can still be provided when needed:

```json
{
  "jsonComparison": {
    "engine": "jar",
    "jarPath": "tools/custom-bdd-comparator.jar",
    "output": "json"
  }
}
```

The bundled comparator CLI supports these options for JSON comparison:
- `--expected <path>`
- `--actual <path>`
- `--output <text|json>`
- `--parent-object <nameOrPath>`
- `--primary-key <field[,field2]>`
- `--ignore <field[,field2]>`
- `--fields <field[,field2]>`
- `--threshold-config <path>`
- `--health-check`
- `--fail-on-extra <true|false>`

When `--fields` is used, keep the selected fields within the same parent context. For nested JSON, the recommended
shape is to pair `for specific fields` with `with Parent Object "..."`, and optionally `with Primary Key "..."` when
the nested data is record-oriented.

The planned UI response-comparison steps use those options to compare:
- expected files from `resources/3-expected/<feature-name>/<file>`
- actual captured responses written to `resources/2-actual/<feature-name>/<file>`

The intended runtime behavior is:
- write the captured response JSON before invoking the comparator
- delete the actual file when comparison passes
- keep the actual file when comparison fails
- surface comparator exit codes clearly in the Cucumber failure

Comparator exit codes are:
- `0` pass
- `1` comparison failed
- `2` extra-only differences when `--fail-on-extra true`
- `3` invalid CLI usage
- `4` input missing or unreadable
- `5` internal comparator error

The optional `fieldVerification` section controls how the framework validates readback after `fill` steps and JSON
form fills:

```json
{
  "fieldVerification": {
    "Notional": {
      "mode": "normalized"
    },
    "Counterparty": {
      "mode": "contains"
    },
    "Premium BPS": {
      "mode": "pattern",
      "expectedPattern": "^\\d+\\.\\d{2}$"
    },
    "Trade Date": {
      "mode": "formatted",
      "expectedPattern": "^\\d{2}/\\d{2}/\\d{4}$"
    },
    "Internal Notes": {
      "mode": "none"
    }
  }
}
```

Supported modes are:
- default exact verification when the field is not listed
- `normalized` for values like `1000` vs `1,000`
- `contains` when the UI expands the value and the expected input should appear within it
- `pattern` for regex-based verification; requires `expectedPattern`
- `formatted` for transformed display values validated by regex; requires `expectedPattern`
- `none` to skip readback verification for a field entirely

Generate selectors with:

```text
npx bdd-ui-init-selectors --ui-path "<path-to-ui-project>" --config-path "<path-to-consumer>\\resources\\4-config\\bdd-ui.config.json" --write
```

For consumers using the recommended numbered `resources/...` layout, `--config-path` should usually point at:

```text
resources/4-config/bdd-ui.config.json
```

If `--config-path` is omitted, the command defaults to updating the current project's root-level
`bdd-ui.config.json`. When the target config already exists and `--write` is used, the command creates a timestamped
backup before writing the merged config.

Environment variables override file values:

```text
BDD_UI_BASE_URL
BDD_UI_BROWSER
BDD_UI_HEADLESS
BDD_UI_TIMEOUT
BDD_UI_TRACE
BDD_UI_SCREENSHOT_ON_FAILURE
```

Credentials are referenced from feature files by profile and field:

```gherkin
When I fill "Username" with credential "standardUser.username"
When I fill "Password" with credential "standardUser.password"
Given I log in as "standardUser"
```

Do not commit real passwords or secrets in `bdd-ui.config.json`. Consumer applications should inject secrets through their pipeline or secret-management tooling.
