# Requirements: QSP-39305 — Unit Integration Testing E2E Tests

## Status

✅ Approved

## Summary

Add **20 new Playwright E2E tests** to the Scorecards app that run against a **mocked backend** to satisfy the "Unit Integration Testing" scorecard signal (grade A requires ≥ 20 passing tests with zero failures). The tests cover all 4 app pages (`/overview`, `/overview/aggregation`, `/components`, `/components/:name`) with both single-page and multi-page navigation flows, deepening coverage on existing pages and adding first-ever coverage for `AppScorePage` and `OverviewAggregationView`.

## Acceptance Criteria

- [ ] AC-1: At least **20 new passing E2E tests** are added in `e2e/tests/`.
- [ ] AC-2: Tests cover all 4 app pages: Overview, Overview Aggregation, Components, and AppScorePage.
- [ ] AC-3: Tests include both **single-page** (element visibility, filtering, URL state) and **multi-page** (navigation between pages) flows.
- [ ] AC-4: Tests use `FORCE_LOCAL_DEV_SERVER_IN_CI = 'true'` for mocked backend execution.
- [ ] AC-5: All tests use `Author.GERALD_SPENLINGWIMMER`, ticket `QSP-39305`, and `TestTag.E2E`.
- [ ] AC-6: New Page Objects and Assertion classes are created for untested pages (`AppScorePage`, `OverviewAggregationView`).
- [ ] AC-7: All tests pass with zero failures (`npm run test:e2e`).
- [ ] AC-8: TypeScript compiles cleanly (`npm run typecheck`).

## Key Decisions

| # | Decision | Rationale |
|---|---|---|
| D-1 | Run tests against mocked backend (`FORCE_LOCAL_DEV_SERVER_IN_CI`) | Required by "Unit Integration Testing" signal definition — tests verify components work together with mocked backend |
| D-2 | Add 20 new tests (not replace existing 7) | Existing tests test real environment; new tests are for the integration testing signal |
| D-3 | Place tests in `e2e/tests/` alongside existing E2E tests | Keeps tests co-located; same Playwright config and auth setup |
| D-4 | Cover all 4 pages with both single-page and multi-page flows | Maximises meaningful coverage and tests real user journeys |
| D-5 | Create new Page Objects for AppScorePage and OverviewAggregationView | These pages have no existing POs; follows the PO + Assertion pattern |
| D-6 | Use intercepted Grail data as ground truth where applicable | Ensures data-driven assertions match what the real API would return |

## Data Model

Not applicable — this ticket adds tests, not data model changes.

## UX / UI Specification

Not applicable — this ticket adds tests, not UI features.

## API Contracts

Not applicable — this ticket adds tests, not API changes.

## DQL Queries

Not applicable — this ticket adds tests, not DQL queries.

## Implementation Plan

### New Page Objects to create

#### 1. `e2e/src/page-objects/app-score-page/app-score-page.po.ts`

Locators:
- `PAGE` — root container
- `HEADING` — page title heading (the `name.toUpperCase()` text)
- `AVERAGE_GRADE_CONTAINER` — `data-testid="average-grade-container"`
- `GRADE_HISTORY_CONTAINER` — `data-testid="grade-history-container"`
- `SIGNAL_TILE_CONTAINER` — `data-testid="signal-tile-container"`
- `SIGNAL_TILES` — all signal tile elements (`[data-testid^="signal-tile-"]`)
- `signalTile(index)` — specific signal tile by index
- `SIGNAL_TILE_HEADERS` — `data-testid="signal-tile-header-title"` (all)
- `SIGNAL_TILE_MESSAGES` — `data-testid="signal-tile-message"` (all)
- `SIGNAL_DETAILS_BUTTONS` — `data-testid="signal-details-button"` (all)

#### 2. `e2e/src/page-objects/app-score-page/app-score-page.assertion.ts`

Methods:
- `verifyPageLoaded(name)` — heading visible and contains uppercase name, grade containers visible, signal container visible
- `verifySignalTilesDisplayed(count)` — expected number of signal tiles rendered

#### 3. `e2e/src/page-objects/overview-aggregation/overview-aggregation.po.ts`

Locators:
- `PAGE` — root container
- `TITLE` — page title
- `FILTER_CONTAINER` — `data-testid="filter-container"`
- `FILTER_FIELD` — `data-testid="overview-aggregation-filters"`
- `APPLY_BUTTON` — Button with text "Apply"
- `TABS` — `data-testid="aggregation-tabs"`
- `OVERVIEW_TAB` — `data-testid="overview-tab"`
- `COMPONENTS_TAB` — `data-testid="components-tab"`
- `COMPONENTS_TABLE` — `data-testid="overview-aggregation-components-table"`
- `TABLE_PAGINATION` — `data-testid="data-table-pagination"`

Methods:
- `applyFilter(query)` — fill FilterField and click Apply
- `switchToTab(tabName)` — click the specified tab

#### 4. `e2e/src/page-objects/overview-aggregation/overview-aggregation.assertion.ts`

Methods:
- `verifyPageLoaded()` — title, filter, tabs all visible
- `verifyComponentsTabHasData()` — components table is visible with at least one row

### Test Plan — 20 Tests

Tests are grouped by page and flow. Each test file uses `test.use` with `Author.GERALD_SPENLINGWIMMER`, `QSP-39305`, `TestTag.E2E`.

#### File 1: `e2e/tests/app-landing-page/app-header-navigation.spec.ts` (3 tests)

| # | Test name | What it verifies |
|---|---|---|
| 1 | `Header displays Overview and Components navigation links` | Both nav links are visible in the banner |
| 2 | `Clicking Overview navigation link navigates to overview page` | URL contains `/overview`, overview elements visible |
| 3 | `Clicking Components navigation link navigates to components page` | URL contains `/components`, components table visible |

#### File 2: `e2e/tests/overview-page/overview-page-elements.spec.ts` (4 tests)

| # | Test name | What it verifies |
|---|---|---|
| 4 | `Average grade container displays overall, quality, and security grades` | All 3 GradeBadges visible (`average-grade`, `quality-grade`, `security-grade`) |
| 5 | `Grade history container displays title, subtitle, and range labels` | Title "30-day trend", subtitle, "days ago" and "Today" text visible |
| 6 | `Overview table displays pagination controls` | Pagination element is visible |
| 7 | `Overview table has interactive rows` | At least one row exists in the table body |

#### File 3: `e2e/tests/overview-page/overview-to-aggregation-navigation.spec.ts` (2 tests)

| # | Test name | What it verifies |
|---|---|---|
| 8 | `Clicking a capability row navigates to aggregation view` | URL contains `/overview/aggregation`, `tab=components`, `query=` params present |
| 9 | `Aggregation view pre-fills filter from URL query parameter` | FilterField contains the query value from the URL |

#### File 4: `e2e/tests/components-page/components-page-elements.spec.ts` (3 tests)

| # | Test name | What it verifies |
|---|---|---|
| 10 | `Components page displays title` | "Components" title is visible |
| 11 | `Components page table has Name, Asset ID, Owner, Component type, and Grade columns` | All 5 column headers visible |
| 12 | `Clicking a component row navigates to app score page` | URL contains `/components/<name>`, AppScorePage heading visible |

#### File 5: `e2e/tests/app-score-page/app-score-page-elements.spec.ts` (3 tests)

| # | Test name | What it verifies |
|---|---|---|
| 13 | `App score page displays component name as heading` | Heading contains the URL param name in uppercase |
| 14 | `App score page displays average grade and grade history containers` | Both `average-grade-container` and `grade-history-container` visible |
| 15 | `App score page displays all signal tiles` | `signal-tile-container` visible, 7 signal tiles rendered |

#### File 6: `e2e/tests/app-score-page/app-score-page-signals.spec.ts` (3 tests)

| # | Test name | What it verifies |
|---|---|---|
| 16 | `Each signal tile displays header with title and description` | All signal tiles have `signal-tile-header-title` and `signal-tile-header-description` |
| 17 | `Each signal tile displays a status message` | All signal tiles have `signal-tile-message` element |
| 18 | `Each signal tile displays footer with timestamp and details button` | All signal tiles have `signal-tile-footer` and `signal-details-button` |

#### File 7: `e2e/tests/overview-aggregation/overview-aggregation-page.spec.ts` (2 tests)

| # | Test name | What it verifies |
|---|---|---|
| 19 | `Overview aggregation page displays filter, tabs, and components table` | Filter container, tabs, and components table all visible |
| 20 | `Switching to Components tab shows component data table with pagination` | Components tab selected, table and pagination visible |

### Consumer Impact Analysis

No existing interfaces are being modified — this ticket only adds test files and Page Objects.

| Artefact | Action |
|---|---|
| `e2e/src/page-objects/app-score-page/` | **Create** — new PO + assertion |
| `e2e/src/page-objects/overview-aggregation/` | **Create** — new PO + assertion |
| `e2e/tests/app-landing-page/app-header-navigation.spec.ts` | **Create** — new test file |
| `e2e/tests/overview-page/overview-page-elements.spec.ts` | **Create** — new test file |
| `e2e/tests/overview-page/overview-to-aggregation-navigation.spec.ts` | **Create** — new test file |
| `e2e/tests/components-page/components-page-elements.spec.ts` | **Create** — new test file |
| `e2e/tests/app-score-page/app-score-page-elements.spec.ts` | **Create** — new test file |
| `e2e/tests/app-score-page/app-score-page-signals.spec.ts` | **Create** — new test file |
| `e2e/tests/overview-aggregation/overview-aggregation-page.spec.ts` | **Create** — new test file |

### Implementation Steps

#### Step 1: Create AppScorePage Page Object and Assertion
- **Files**: `e2e/src/page-objects/app-score-page/app-score-page.po.ts`, `e2e/src/page-objects/app-score-page/app-score-page.assertion.ts`
- **Changes**: New PO with locators for heading, grade containers, signal tiles; assertion class with `verifyPageLoaded` and `verifySignalTilesDisplayed`.
- **Verification**: TypeScript compiles.

#### Step 2: Create OverviewAggregation Page Object and Assertion
- **Files**: `e2e/src/page-objects/overview-aggregation/overview-aggregation.po.ts`, `e2e/src/page-objects/overview-aggregation/overview-aggregation.assertion.ts`
- **Changes**: New PO with locators for filter, tabs, table; assertion class with `verifyPageLoaded` and `verifyComponentsTabHasData`.
- **Verification**: TypeScript compiles.

#### Step 3: Create test file for app header navigation (3 tests)
- **Files**: `e2e/tests/app-landing-page/app-header-navigation.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "App header navigation"`

#### Step 4: Create test file for overview page elements (4 tests)
- **Files**: `e2e/tests/overview-page/overview-page-elements.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "Overview page elements"`

#### Step 5: Create test file for overview → aggregation navigation (2 tests)
- **Files**: `e2e/tests/overview-page/overview-to-aggregation-navigation.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "Overview to aggregation navigation"`

#### Step 6: Create test file for components page elements (3 tests)
- **Files**: `e2e/tests/components-page/components-page-elements.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "Components page elements"`

#### Step 7: Create test file for app score page elements (3 tests)
- **Files**: `e2e/tests/app-score-page/app-score-page-elements.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "App score page elements"`

#### Step 8: Create test file for app score page signals (3 tests)
- **Files**: `e2e/tests/app-score-page/app-score-page-signals.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "App score page signals"`

#### Step 9: Create test file for overview aggregation page (2 tests)
- **Files**: `e2e/tests/overview-aggregation/overview-aggregation-page.spec.ts`
- **Verification**: `npm run test:e2e -- --grep "Overview aggregation page"`

#### Step 10: Run full validation
- `npm run typecheck`
- `npm run test:e2e`
- Verify ≥ 20 new tests pass with zero failures.

## Unit Test Plan

Not applicable — this ticket produces E2E/integration tests, not unit tests. No utils are being created.

## Edge Cases & Error Handling

- **No data from Grail**: Tests that intercept Grail responses validate `queryResult.records.length > 0` before proceeding. If the mocked backend returns empty data, the test fails with a descriptive message.
- **AppScorePage mock data**: This page uses hardcoded signals — no Grail interception needed. Tests verify the static content rendered from the mock data.
- **Navigation timing**: Multi-page navigation tests wait for target page elements (via `toBeVisible`) before asserting, relying on Playwright's auto-retry.
- **URL encoding**: The overview → aggregation navigation includes encoded query params. Tests use `toContain` for URL assertions to handle encoding differences.

## Out of Scope

- **Modifying existing 7 E2E tests** — they remain unchanged and continue testing the real deployed environment.
- **Creating a separate `ui-integration-tests/` directory** — tests live in existing `e2e/tests/`.
- **Testing error/loading states** — the mocked backend returns successful responses; error state testing is a separate concern.
- **Visual regression testing** — covered by a separate test suite.
- **Accessibility testing** — covered by a separate test suite.
