# Reusable Step Reference

## Navigation

```gherkin
Given I open the application
Given I navigate to "/login"
Then the current URL should contain "/dashboard"
```

## Authentication

```gherkin
Given I log in as "standardUser"
Given I log in as "standardUser" from "/login"
```

The login steps read `standardUser.username` and `standardUser.password` from `bdd-ui.config.json`.
By default they use the Genesis/Foundation login shape: `/login`, username/password inputs, and a
`Login` or `Sign in` button. Override `auth` selectors in config when a consumer app has custom markup.

## Interaction

```gherkin
When I click "Sign in"
When I click "Sign in" at index 1
When I click "Forgot password?"
When I click "Username"
When I click "submit-btn"    # id/class/test-id style target (no # needed)
When I click "primary-cta"   # class token target (no . needed)
When I click the "Sign in" button
When I click the "Sign in" button at index 1
When I click text "Forgot password?"
When I click text "Forgot password?" at index 1
When I check "Remember me"
When I check "Remember me" at index 1
When I uncheck "Remember me"
When I uncheck "Remember me" at index 1
When I choose "Ireland" from "Country"
When I choose "Spot" from "Tenor Type" at index 1
When I scroll to element "ROLL"
When I scroll to element "ROLL" at index 1
When I open the "Main" tab
When I open the "Detailed" tab at index 1
When I open the "Main" tab in "workspace-panel"
When I open the "Detailed" tab in "workspace-panel" at index 1
```

`When I click {string}` is an additive convenience step. It can match selector aliases from config, accessible labels,
placeholder text, exact text, common attributes such as `data-test-id`, id/class selectors (with or without `#`/`.`),
links, and buttons. The existing `button` and `click text` steps remain supported for backward compatibility. Use
`at index N` when the same target appears more than once; indexes are zero-based.

In practice that means a target such as `"save-button"` or `"primary-cta"` can resolve through:
- a selector alias from `bdd-ui.config.json`
- `data-test-id` / `data-testid`
- accessible label or exact text
- `name`, `aria-label`, `col-id`, or `row-id`
- `id` or `class`
- a raw CSS selector such as `".primary-cta"`

Class selectors are supported, but they are a fallback. Prefer stable `data-test-id` hooks mapped through config
aliases when possible.

`When I choose {string} from {string}` is the custom-dropdown companion to the native-select `When I select ... from ...`
step. Use `choose` for component wrappers such as `rapid-combobox` where the field must be opened and an option clicked.
`When I scroll to element {string}` scrolls a matched target into view before later interaction. `When I open the {string}
tab` prefers tab semantics and falls back to the framework's standard locator strategies. If the tab is already active,
the framework skips the click. After a click, it waits for that same tab to become active before continuing. The scoped
tab variants resolve the second string through the normal selector-alias rules so repeated tab names can be targeted
within a specific panel or container.

## Forms

```gherkin
When I fill "Username" with "test.user"
When I fill "Username" at index 1 with "test.user"
When I fill "Username" with credential "standardUser.username"
When I fill "Username" at index 1 with credential "standardUser.username"
When I clear "Search"
When I clear "Search" at index 1
When I select "Ireland" from "Country"
When I select "Ireland" from "Country" at index 1
When I fill the form from "qte-ac-core-valid.json"
When I fill the form "qte-form" from "qte-ac-core-valid.json"
```

The form JSON steps read a flat JSON object from the configured input root for the current feature.
Keys can be visible field labels such as `Instrument` or schema-style field names such as `INSTRUMENT`.
The scoped variant first finds a form/container by `data-test-id`, id, or selector. For example, the Sales
Trader Hub QTE form can use `qte-form`.

With the default `resourcePaths` configuration, each feature file lives directly under `resources/features`, and the
input/expected/actual folders are flat inside each feature-name folder. A step such as:

```gherkin
When I fill the form from "qte-ac-core-valid.json"
```

resolves to:

```text
resources/5-input/<feature-name>/qte-ac-core-valid.json
```

Example JSON:

```json
{
  "Instrument": "IRG",
  "Ccy": "EUR",
  "Product": "OUTRIGHT_CAP",
  "Index": "EURIBOR",
  "Maturity": "6M",
  "Notional": "850T",
  "Quote Type": "Premium",
  "Premium BPS": "12.5",
  "Counterparty": "CP_HSBC"
}
```

The runtime tries text inputs, text areas, selects, Foundation/Fast controls, segmented/radio options,
boolean controls, and the common counterparty picker pattern. For Foundation/JSON Forms controls, labels such
as `Product` can map to schema-style controls such as `PRODUCT`, and field labels ending in `*` are handled
without requiring the `*` in the JSON key. If a label resolves to a non-fillable wrapper, the runtime continues
to the next candidate input instead of failing immediately. It also supports Foundation custom controls used by
full-ticket forms, including `rapid-text-field`, `rapid-combobox`, `rapid-switch`, date/tenor pair fields, and
switch/dropdown or roll/roll-day pairs when the JSON key matches the visible label or schema field name. It
attaches the JSON data to the Cucumber report.

The plain `fill` steps and the JSON form-fill steps also verify readback for input-style controls. After the
framework fills a field, it reads the value back from the control and fails fast if the control still reports a
different value. That reduces false positives where the UI accepts the interaction event but silently keeps the
old value.

Consumer projects can override that verification per field through `fieldVerification` in `bdd-ui.config.json`.
Fields not listed there use exact verification by default. Supported override modes are:
- `normalized`
- `contains`
- `pattern` with `expectedPattern`
- `formatted` with `expectedPattern`
- `none`

## Assertions

```gherkin
Then I should see text "Dashboard"
Then I should see text "Premium Amount" at index 1
Then I should not see text "Invalid password"
Then I should not see text "Validation failed" at index 0
Then "Username" should be visible
Then "Username" at index 1 should be visible
Then "Username" should be enabled
Then "Username" at index 1 should be enabled
Then "Premium Amount" should be read only
Then "Premium Amount" at index 1 should be read only
Then the "Submit" button should be enabled
Then the "Submit" button at index 1 should be enabled
Then "Country" should have value "Ireland"
Then "Country" should contain value "Ire"
Then "Roll" at index 1 should have value "Forward"
Then "Desk" at index 1 should contain value "LDN"
Then the "Main" tab should be active
Then the "Detailed" tab at index 1 should be active
Then the dropdown "Country" should contain exactly:
  | Ireland |
  | France  |
Then the dropdown "Country" should contain values:
  | France  |
  | Ireland |
Then the dropdown "Country" at index 1 should contain exactly:
  | Ireland |
  | France  |
Given User check if element "Username" is "visible"
Given User check if element "Status,Amount" is "visible,notVisible" at index "0,1"
```

The `User check if element` step is available for compatibility with the previous BDD UI step vocabulary.
Use `visible` when the element must be displayed and `notVisible` when the element should be hidden or absent.
The field, visibility, and index arguments can be comma-separated. If a single visibility is supplied, it is applied
to every field. If no index is supplied, index `0` is used.

The step tries common product-neutral locator strategies including accessible labels, exact text, `data-test-id`,
`name`, `aria-label`, `col-id`, `row-id`, id, and class selectors.

The text assertions also support zero-based indexes, which is useful when the same text appears in multiple cards,
tables, or repeated form sections and you want to assert a specific occurrence.

`should have value` reads native field values first, then common value-like attributes and visible text, which makes it
usable for custom web-component wrappers as well as plain inputs. `tab should be active` checks standard active-state
markers such as `aria-selected`, `data-active`, `data-selected`, `selected`, and common active/selected/current classes.
The dropdown content steps open the dropdown when needed, read visible option text from native selects or custom
listbox/option controls, and compare either exact ordered values (`contain exactly`) or the same values ignoring order
(`contain values`). They also support selector aliases and zero-based indexed dropdowns. `should be read only` checks
whether the resolved control is visible but not editable, covering native `readonly` or disabled states as well as
common component wrappers that expose the same behavior through ARIA or container attributes. `should contain value`
uses the same control-value reader as `should have value`, but checks for substring containment instead of strict
equality. This is useful when the UI formats or expands the displayed value.

## Screenshot Comparison

```gherkin
Then the screen should match screenshot "dashboard/home-default"
Then element "qte-form" should match screenshot "qte-acceptance-criteria/qte-form-default"
Then element "tile" at index 1 should match screenshot "dashboard/tiles/second-tile"
Then element "qte-grid-list" should match screenshot "extract-visible-grid/qte-grid-list" masking "price-ticker,clock"
Then element "tile" at index 1 should match screenshot "dashboard/tiles/second-tile" masking "live-price,badge"
```

The screenshot steps use the configured screenshot roots:
- expected baselines from `resources/3-expected/screenshots/...`
- actual captures in `resources/2-actual/screenshots/...`
- diff images in `resources/2-actual/screenshots-diff/...`

The screenshot path passed in the step is a nested relative path. For example:

```gherkin
Then element "qte-form" should match screenshot "qte-acceptance-criteria/qte-form-default"
```

resolves its baseline to:

```text
resources/3-expected/screenshots/qte-acceptance-criteria/qte-form-default.png
```

`element ... masking "a,b"` resolves each mask target through the same selector alias logic used by the rest of the
framework. The screen-level step does not currently support masking; masking is available only for element screenshots.
The screenshot comparison steps attach the actual screenshot to the Cucumber/Allure report on pass or failure, and also
attach the diff image when a mismatch produces one.

## Grid

These steps use generic BDD wording. The framework implementation targets AG Grid.

Named grid steps read selectors from `bdd-ui.config.json`:

```json
{
  "grids": {
    "trade": "[data-testid=\"trade-grid\"]"
  }
}
```

```gherkin
Then the grid should be visible
Then the grid 1 should be visible
Then the "trade" grid should be visible
Then the grid should have 10 rows
Then the "trade" grid should have 10 rows
Then the grid should have at least 1 row
Then the "trade" grid should have at least 1 row
Then the grid column "Status" should be visible
Then the "trade" grid column "Status" should be visible

Then the grid cell in row 0 and column "Status" should contain "Active"
Then the "trade" grid cell in row 0 and column "Status" should contain "Active"
Then the grid cell in row 0 and column "Status" should equal "Active"
Then the "trade" grid cell in row 0 and column "Status" should equal "Active"
Then the grid row where column "Trade ID" is "T-123" should have column "Status" containing "Booked"
Then the "trade" grid row where column "Trade ID" is "T-123" should have column "Status" containing "Booked"
Then the grid row where column "Trade ID" is "T-123" should have column "Status" equal to "Booked"
Then the "trade" grid row where column "Trade ID" is "T-123" should have column "Status" equal to "Booked"

When I click on the grid cell in row 0 and column "Status"
When I click on the "trade" grid cell in row 0 and column "Status"
When I double click on the grid cell in row 0 and column "Status"
When I double click on the "trade" grid cell in row 0 and column "Status"
When I right click on the grid cell in row 0 and column "Status"
When I right click on the "trade" grid cell in row 0 and column "Status"
When I click on the grid cell where column "Trade ID" is "T-123" in column "Status"
When I click on the "trade" grid cell where column "Trade ID" is "T-123" in column "Status"
When I double click on the grid cell where column "Trade ID" is "T-123" in column "Status"
When I double click on the "trade" grid cell where column "Trade ID" is "T-123" in column "Status"
When I right click on the grid cell where column "Trade ID" is "T-123" in column "Status"
When I right click on the "trade" grid cell where column "Trade ID" is "T-123" in column "Status"
When I edit the grid cell in row 0 and column "Status" with "Active"
When I edit the "trade" grid cell in row 0 and column "Status" with "Active"

When I sort the grid column "Amount" ascending
When I sort the "trade" grid column "Amount" ascending
When I sort the grid column "Amount" descending
When I sort the "trade" grid column "Amount" descending
When I filter the grid column "Status" by "Active"
When I filter the "trade" grid column "Status" by "Active"
When I clear the grid column "Status" filter
When I clear the "trade" grid column "Status" filter
When I extract the grid as JSON
When I extract the "trade" grid as JSON
When I extract the grid as JSON to "reports/grid-data.json"
When I extract the "trade" grid as JSON to "reports/trade-grid-data.json"
```

Grid indexes are zero-based. If no grid index is supplied, the first grid is used.
Named grids use selectors from the `grids` config section, which keeps selectors out of feature files.
Columns can be referenced by visible header text or by AG Grid `col-id`.
Grid JSON extraction uses visible column headers as object keys and visible row values as strings. The plain
extraction step attaches JSON to the Cucumber report; the `to` variant writes the JSON file relative to the
consumer project's current working directory.

## JSON Comparison

Use keyed JSON comparison for grid exports when row order is not stable.

```gherkin
Then the JSON file "resources/2-actual/extract-visible-grid/qte-grid-list.json" should match "resources/3-expected/extract-visible-grid/qte-grid-list.json" using key "RFQ ID"
Then the JSON file "resources/2-actual/extract-visible-grid/qte-grid-list.json" should match "resources/3-expected/extract-visible-grid/qte-grid-list.json" using keys "Book,RFQ ID"
Then the JSON file "resources/2-actual/extract-visible-grid/qte-grid-list.json" should contain rows from "resources/3-expected/extract-visible-grid/qte-grid-list.json" using key "RFQ ID"
Then the JSON file "resources/2-actual/extract-visible-grid/qte-grid-list.json" should contain rows from "resources/3-expected/extract-visible-grid/qte-grid-list.json" using keys "Book,RFQ ID"
```

The `match` steps compare rows without relying on array order and fail when rows are missing, unexpected, or
different. The `contain rows from` steps ignore extra rows in the actual file, which is useful when a live grid
can include records beyond the baseline expected set. Key columns must uniquely identify each expected and actual
row in the selected comparison mode.

## Response capture and comparator design

The planned backend response-comparison workflow keeps capture and comparison as separate steps, mirroring the API
automation style while fitting the UI resource layout.

Capture steps:

```gherkin
When I submit the form and capture response matching "EVENT_RFQ_TRADE_INSERT"
When I click "save-button" and capture response matching "EVENT_RFQ_TRADE_INSERT"
When I click "save-button" at index 1 and capture response matching "EVENT_RFQ_TRADE_INSERT"
```

Comparison steps:

```gherkin
Then I compare response with expected result "qte-create-ack.json"
Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY"
Then I compare response with expected result "qte-create-ack.json" with Primary Key "TRADE_ID"
Then I compare response with expected result "qte-create-ack.json" and ignore "RFQ_ID,TIMESTAMP"
Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY" with Primary Key "ID" for specific fields "STATUS,ID"
Then I compare response with expected result "qte-create-ack.json" and fail on extra "true"
```

Example scenario:

```gherkin
Scenario: Submit QTE and compare backend response
  Given I log in as "standardUser"
  When I click "New RFQ"
  And I fill the form from "qte-ac-core-valid.json"
  And I submit the form and capture response matching "EVENT_RFQ_TRADE_INSERT"
  Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY" and ignore "RFQ_ID,TIMESTAMP"
```

With the flat consumer structure, a step such as:

```gherkin
Then I compare response with expected result "qte-create-ack.json"
```

inside `resources/features/qte-acceptance-criteria.feature` is intended to resolve to:

```text
resources/3-expected/qte-acceptance-criteria/qte-create-ack.json
resources/2-actual/qte-acceptance-criteria/qte-create-ack.json
```

The clean design assumes the comparator JAR is bundled inside the `@genesislcap/bdd-ui-automation` package and
invoked by the framework with `java -jar ... json ...`. The relevant comparator options are:
- `--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>`

`for specific fields` works best when all listed fields belong to the same parent context. For nested JSON, prefer
combining it with `with Parent Object "..."`, and when the nested data is record-oriented, also supply
`with Primary Key "..."`. For example:

```gherkin
Then I compare response with expected result "qte-create-ack.json" with Parent Object "REPLY" with Primary Key "ID" for specific fields "STATUS,ID"
```

The intended compare-step behavior is:
- require a previously captured response
- write the actual response JSON before compare
- delete the actual file on pass
- keep the actual file on failure
- fail clearly when the expected file is missing, the comparator is unavailable, or no response was captured

Comparator exit codes are expected to map as follows:
- `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

## Waits

```gherkin
When I wait for 2 seconds
When I wait for text "Dashboard"
When I wait for element "trade-grid"
When I wait for element "tile" at index 1
When I wait for URL containing "/dashboard"
```

`wait for text` is intentionally text-only. Use `wait for element` when you want the framework's generic locator
resolution, including selector aliases from `bdd-ui.config.json`, attributes such as `data-test-id`, and indexed matches.
