diff --git a/docs/frontend/audit-capability-card.md b/docs/frontend/audit-capability-card.md index 67b919b458..d8e2e6abaa 100644 --- a/docs/frontend/audit-capability-card.md +++ b/docs/frontend/audit-capability-card.md @@ -2,120 +2,50 @@ This document describes the audit capability card component, its various states, and how to test them both manually and automatically. +For shared frontend mock and Vitest workflow, see `docs/frontend/testing-basics.md`. + ## Overview The Audit Capability Card displays on the ServicePulse dashboard and shows the status of the auditing feature. The card's status depends on: 1. Whether audit instances are configured -2. Whether audit instances are available (online) -3. Whether successful messages exist (endpoints configured for auditing) +2. Whether all or only some audit instances are available +3. Capability-specific message readiness shown by the `Messages` indicator 4. Whether the ServiceControl version supports the "All Messages" feature (>= 6.6.0) ## Card States -| Status | Condition | Badge | Action Button | -|--------------------------|--------------------------------------------------|-------------|---------------| -| Instance Not Configured | No audit instances configured | - | Get Started | -| Unavailable | All audit instances offline | Unavailable | Learn More | -| Degraded | Some audit instances offline | Degraded | - | -| Endpoints Not Configured | Instance available but no messages OR SC < 6.6.0 | - | Learn More | -| Available | Instance available with messages AND SC >= 6.6.0 | Available | View Messages | - -## Manual Testing with Mock Scenarios - -### Prerequisites - -```bash -cd src/Frontend -npm install -``` - -### Running the Dev Server with Mocks +| Status | Condition | Badge | Action Button | +|-------------------------|-------------------------------|----------------|---------------| +| Instance Not Configured | No audit instances configured | Not configured | Get Started | +| Unavailable | All audit instances offline | Unavailable | Learn More | +| Degraded | Some audit instances offline | Degraded | Learn More | +| Available | All audit instances available | Available | View Messages | -```bash -npm run dev:mocks -``` +The `Messages` indicator carries the capability-specific readiness state. If no successful messages exist yet, or if `All Messages` is not supported, the card remains `Available` while the indicator is yellow. -This starts the dev server at `http://localhost:5173` with MSW (Mock Service Worker) intercepting API calls. +An audit instance that is degraded but still responding remains available for this card. Only unavailable audit instances affect the badge state. -### Switching Between Scenarios - -Set the `VITE_MOCK_SCENARIO` environment variable before running the dev server: - -```bash -# Linux/macOS -VITE_MOCK_SCENARIO=audit-available npm run dev:mocks +## Manual Testing with Mock Scenarios -# Windows CMD -set VITE_MOCK_SCENARIO=audit-available && npm run dev:mocks +Start from the shared frontend mocking workflow in `docs/frontend/testing-basics.md`, then select one of the audit scenarios below. -# Windows PowerShell -$env:VITE_MOCK_SCENARIO="audit-available"; npm run dev:mocks -``` +For the shared meaning of audit and remote error platform instances, use `docs/frontend/platform-health-page.md` as the canonical reference. This page documents only the auditing-specific layer on top. -Open the browser console to see available scenarios. +### Available Audit Scenarios -#### Available Audit Scenarios - -| Scenario | Status | Badge | Button | Description | Indicators | -|----------------------------|--------------------------|-------------|---------------|------------------------------------------------------------------------------------------------------|-------------------------------------------| -| `audit-no-instance` | Instance Not Configured | - | Get Started | "A ServiceControl Audit instance has not been configured..." | None | -| `audit-unavailable` | Unavailable | Unavailable | Learn More | "All ServiceControl Audit instances are configured but not responding..." | Instance: ❌ | -| `audit-degraded` | Partially Unavailable | Degraded | - | "Some ServiceControl Audit instances are not responding." | Instance 1: ✅, Instance 2: ❌, Messages: ✅ | -| `audit-available` | Available | Available | View Messages | "All ServiceControl Audit instances are available and endpoints have been configured..." | Instance: ✅, Messages: ✅ | -| `audit-old-sc-version` | Endpoints Not Configured | - | Learn More | "A ServiceControl Audit instance is connected but no successful messages..." | Instance: ✅, Messages: ⚠️ (SC < 6.6.0) | -| `audit-no-messages` | Endpoints Not Configured | - | Learn More | "A ServiceControl Audit instance is connected but no successful messages have been processed yet..." | Instance: ✅, Messages: ⚠️ | -| `audit-multiple-instances` | Available | Available | View Messages | "All ServiceControl Audit instances are available..." | Instance 1: ✅, Instance 2: ✅, Messages: ✅ | +| Scenario | Status | Badge | Button | Description | Indicators | +|----------------------------|-------------------------|----------------|---------------|-------------------------------------------------------------------|-----------------| +| `audit-no-instance` | Instance Not Configured | Not configured | Get Started | "A ServiceControl Audit instance has not been configured..." | None | +| `audit-unavailable` | Unavailable | Unavailable | Learn More | "All ServiceControl Audit instances are configured but not responding..." | None | +| `audit-degraded` | Degraded | Degraded | Learn More | "Some ServiceControl Audit instances are not responding." | Messages: ✅ | +| `audit-available` | Available | Available | View Messages | "All ServiceControl Audit instances are available." | Messages: ✅ | +| `audit-old-sc-version` | Available | Available | View Messages | "All ServiceControl Audit instances are available." | Messages: ⚠️ | +| `audit-no-messages` | Available | Available | View Messages | "All ServiceControl Audit instances are available." | Messages: ⚠️ | +| `audit-multiple-instances` | Available | Available | View Messages | "All ServiceControl Audit instances are available." | Messages: ✅ | **Indicator Legend:** ✅ = Available/Success, ❌ = Unavailable/Error, ⚠️ = Warning/Not Configured -### Adding New Scenarios - -1. Add a scenario precondition to `src/Frontend/test/preconditions/platformCapabilities.ts`: - -```typescript -export const scenarioMyScenario = async ({ driver }: SetupFactoryOptions) => { - await driver.setUp(precondition.serviceControlWithMonitoring); - // Add scenario-specific preconditions here -}; -``` - -2. Create a new file in `src/Frontend/test/mocks/scenarios/` (e.g., `my-scenario.ts`): - -```typescript -import { setupWorker } from "msw/browser"; -import { Driver } from "../../driver"; -import { makeMockEndpoint, makeMockEndpointDynamic } from "../../mock-endpoint"; -import * as precondition from "../../preconditions"; - -export const worker = setupWorker(); -const mockEndpoint = makeMockEndpoint({ mockServer: worker }); -const mockEndpointDynamic = makeMockEndpointDynamic({ mockServer: worker }); - -const makeDriver = (): Driver => ({ - goTo() { throw new Error("Not implemented"); }, - mockEndpoint, - mockEndpointDynamic, - setUp(factory) { return factory({ driver: this }); }, - disposeApp() { throw new Error("Not implemented"); }, -}); - -const driver = makeDriver(); - -export const setupComplete = (async () => { - await driver.setUp(precondition.scenarioMyScenario); -})(); -``` - -1. Register it in `src/Frontend/test/mocks/scenarios/index.ts`: - -```typescript -const scenarios: Record Promise> = { - // ... existing scenarios - "my-scenario": () => import("./my-scenario"), -}; -``` - ## Automated Tests ### Test Files @@ -127,34 +57,26 @@ const scenarios: Record Promise> = { ### Running Automated Tests -From the `src/Frontend` directory: +Use the shared commands in `docs/frontend/testing-basics.md`, then run these audit-specific specs: ```bash -# Run all audit capability tests npx vitest run test/specs/platformcapabilities/audit-capability-card.spec.ts - -# Run helper function unit tests npx vitest run test/specs/platformcapabilities/auditing-capability-helpers.spec.ts - -# Run all platform capability tests -npx vitest run test/specs/platformcapabilities/ ``` ### Test Coverage #### Application Tests (`audit-capability-card.spec.ts`) -| Rule | Test Case | -|---------------------------------|---------------------------------------------------------------| -| No audit instance configured | Shows "Get Started" button | -| Audit instance unavailable | Shows "Unavailable" status | -| Partially unavailable instances | Shows "Degraded" status | -| Available but no messages | Shows "Endpoints Not Configured" status | -| Available with messages | Shows "Available" status + "View Messages" button | -| ServiceControl < 6.6.0 | Shows "Endpoints Not Configured" (All Messages not supported) | -| Single instance indicator | Shows "Instance" label | -| Messages indicator | Shows "Messages" label when messages exist | -| Multiple instances | Shows numbered "Instance 1", "Instance 2" labels | +| Rule | Test Case | +|---------------------------------|-------------------------------------------------------------------| +| No audit instance configured | Shows "Get Started" button | +| Audit instance unavailable | Shows "Unavailable" status | +| Partially unavailable instances | Shows "Degraded" status | +| Available but no messages | Keeps card available and shows a warning `Messages` indicator | +| Available with messages | Shows "Available" status + "View Messages" button | +| ServiceControl < 6.6.0 | Keeps card available and shows warning `Messages` indicator | +| Shared card signals | Shows only the shared `Messages` indicator, not per-instance ones | #### Unit Tests (`auditing-capability-helpers.spec.ts`) @@ -173,23 +95,27 @@ npx vitest run test/specs/platformcapabilities/ |---------------------------------------------------------------------------------------|----------------------------------------| | `src/Frontend/src/components/platformcapabilities/capabilities/AuditingCapability.ts` | Main composable and helper functions | | `src/Frontend/src/components/audit/isAllMessagesSupported.ts` | Version check for All Messages feature | +| `src/Frontend/src/stores/PlatformModelStore.ts` | Shared platform model for audit instances | | `src/Frontend/test/preconditions/platformCapabilities.ts` | Test preconditions and fixtures | | `src/Frontend/test/mocks/scenarios/` | Manual testing scenarios | -## Troubleshooting +## Status Indicators -### Scenario not loading +The auditing card no longer renders per-instance widgets. -1. Check the browser console for errors -2. Verify the scenario name matches exactly (case-sensitive) -3. Ensure MSW is enabled (look for "[MSW] Mocking enabled" in console) +It shows a single `Messages` indicator when at least one audit instance is available: + +- green when `All Messages` is supported and successful messages exist +- yellow when no successful messages exist yet +- yellow when the current ServiceControl version does not support `All Messages` + +Instance-level audit visibility lives on the `Platform health` page. + +## Troubleshooting -### Tests failing +Use `docs/frontend/testing-basics.md` for shared troubleshooting. -1. Run `npm run type-check` to verify TypeScript compilation -2. Check if preconditions are properly set up -3. Use `--reporter=verbose` for detailed test output: +Audit-specific checks: - ```bash - npx vitest run test/specs/platformcapabilities/ --reporter=verbose - ``` +1. If the card badge is wrong, inspect whether the scenario is changing instance availability or only message readiness. +2. If the `Messages` indicator is wrong, check both successful-message mocks and the ServiceControl version used by the scenario. diff --git a/docs/frontend/custom-checks-page.md b/docs/frontend/custom-checks-page.md new file mode 100644 index 0000000000..22f51d4fec --- /dev/null +++ b/docs/frontend/custom-checks-page.md @@ -0,0 +1,109 @@ +# Custom Checks Page Testing Guide + +This document describes the frontend Custom Checks page behavior, with a focus on internal platform custom checks and how they relate to other frontend views. + +For shared frontend mock and Vitest workflow, see `docs/frontend/testing-basics.md`. + +## Overview + +The Custom Checks page shows failing custom checks reported to ServiceControl. + +Internal platform custom checks are handled differently from user-defined custom checks: + +- they are hidden by default from the Custom Checks page +- they are hidden by default from the Custom Checks dashboard tile and menu badge +- operators can reveal them with `Show platform custom checks` when internal checks are present +- Platform health consumes those internal checks as secondary platform signals + +## Internal Platform Custom Checks + +ServiceControl now marks internal custom checks with `internal: true`. + +The frontend uses that flag for two different purposes: + +1. filtering internal platform checks out of the Custom Checks UI by default +2. recognizing internal platform checks that Platform health can use as secondary instance signals + +Older ServiceControl versions may omit the flag. In that case, the check is treated as non-internal. + +## Page Behavior + +The Custom Checks page: + +- fetches failed custom checks from `customchecks?status=fail&page=` +- shows only non-internal custom checks by default +- exposes `Show platform custom checks` to reveal internal platform checks when any are present +- keeps pagination tied to the visible filtered list + +Relevant frontend pieces: + +- `src/Frontend/src/views/CustomChecksView.vue` +- `src/Frontend/src/stores/CustomChecksStore.ts` +- `src/Frontend/src/components/customchecks/CustomCheckView.vue` + +## Platform Health Relationship + +Platform health uses internal platform checks even when the Custom Checks page hides them. + +Platform health also refreshes those custom checks directly, so this behavior does not depend on visiting the Custom Checks page first. + +That logic is documented in: + +- `docs/frontend/platform-health-page.md` + +When Platform health assigns an internal custom check to a specific platform instance, it uses: + +- instance assignment by `originating_endpoint.name` + +The Custom Checks page itself does not perform that instance correlation. It only exposes the raw custom check data and the show/hide toggle. + +## Manual Testing with Mock Scenarios + +Start from the shared frontend mocking workflow in `docs/frontend/testing-basics.md`. + +For internal platform custom check behavior, the most useful mock setup is: + +- `VITE_MOCK_SCENARIO=platform-health npm run dev:mocks` + +Then use: + +- `window.__platformHealth.setCustomCheckPreset("none")` +- `window.__platformHealth.setCustomCheckPreset("user-only")` +- `window.__platformHealth.setCustomCheckPreset("platform-only-primary-degraded")` +- `window.__platformHealth.setCustomCheckPreset("platform-only-audit")` +- `window.__platformHealth.setCustomCheckPreset("mixed-primary-and-user")` + +### Manual Checks + +| Behavior | How to exercise it | +|----------|--------------------| +| Internal platform checks hidden by default | Apply `platform-only-primary-degraded` or `platform-only-audit`, then open Custom Checks page | +| Internal platform checks shown when toggled on | Apply a platform-only preset, enable `Show platform custom checks` | +| User-defined checks visible by default | Apply `user-only` or `mixed-primary-and-user` | +| Platform health reacts to hidden internal checks | Apply `platform-only-primary-degraded` or `platform-only-audit`, then compare Platform health with Custom Checks page | + +## Automated Tests + +### Test Files + +| File | Type | Description | +|------|------|-------------| +| `src/Frontend/src/stores/CustomChecksStore.spec.ts` | Unit | internal check filtering and toggle behavior | + +### Running Automated Tests + +Use the shared commands in `docs/frontend/testing-basics.md`, then run: + +```bash +npx vitest run src/stores/CustomChecksStore.spec.ts +``` + +## Troubleshooting + +Use `docs/frontend/testing-basics.md` for shared troubleshooting. + +Custom Checks-specific checks: + +1. If an internal platform check is visible unexpectedly, confirm `showPlatformCustomChecks` is off. +2. If Platform health reacts to a check that the page is hiding, that is expected behavior. +3. If an internal check is classified incorrectly, inspect the `internal` flag in the ServiceControl response. diff --git a/docs/frontend/error-capability-card.md b/docs/frontend/error-capability-card.md index 574102b58c..adc599387c 100644 --- a/docs/frontend/error-capability-card.md +++ b/docs/frontend/error-capability-card.md @@ -2,9 +2,11 @@ This document describes the error/recoverability capability card component, its various states, and how to test them both manually and automatically. +For shared frontend mock and Vitest workflow, see `docs/frontend/testing-basics.md`. + ## Overview -The Recoverability Capability Card displays on the ServicePulse dashboard and shows the status of the error handling (recoverability) feature. The card's status depends on whether the ServiceControl instance is available and responding. +The Recoverability Capability Card displays on the ServicePulse dashboard and shows the status of the error handling (recoverability) feature. The card's status depends on whether the primary ServiceControl instance is available and responding. Unlike the Monitoring and Auditing cards, the Recoverability card has a simpler state model because: @@ -21,43 +23,15 @@ Unlike the Monitoring and Auditing cards, the Recoverability card has a simpler ## Manual Testing with Mock Scenarios -### Prerequisites +Start from the shared frontend mocking workflow in `docs/frontend/testing-basics.md`, then select the recoverability scenario below. -```bash -cd src/Frontend -npm install -``` +For the shared meaning of primary and remote error instance states, use `docs/frontend/platform-health-page.md` as the canonical reference. This page documents only the recoverability-specific layer on top. -### Running the Dev Server with Mocks +### Available Recoverability Scenarios -```bash -npm run dev:mocks -``` - -This starts the dev server at `http://localhost:5173` with MSW (Mock Service Worker) intercepting API calls. - -### Switching Between Scenarios - -Set the `VITE_MOCK_SCENARIO` environment variable before running the dev server: - -```bash -# Linux/macOS -VITE_MOCK_SCENARIO=recoverability-available npm run dev:mocks - -# Windows CMD -set VITE_MOCK_SCENARIO=recoverability-available && npm run dev:mocks - -# Windows PowerShell -$env:VITE_MOCK_SCENARIO="recoverability-available"; npm run dev:mocks -``` - -Open the browser console to see available scenarios. - -#### Available Recoverability Scenarios - -| Scenario | Status | Badge | Button | Description | Indicators | -|----------------------------|-----------|-----------|----------------------|---------------------------------------------|---------------------| -| `recoverability-available` | Available | Available | View Failed Messages | "The ServiceControl instance is available." | Instance: Available | +| Scenario | Status | Badge | Button | Description | +|----------------------------|-----------|-----------|----------------------|---------------------------------------------| +| `recoverability-available` | Available | Available | View Failed Messages | "The ServiceControl instance is available." | ### Testing "Unavailable" State @@ -69,53 +43,6 @@ To observe the connection error behavior: 2. Set `service_control_url` to an invalid/unreachable URL 3. Run `npm run dev` (without mocks) -### Adding New Scenarios - -1. Add a scenario precondition to `src/Frontend/test/preconditions/platformCapabilities.ts`: - -```typescript -export const scenarioMyScenario = async ({ driver }: SetupFactoryOptions) => { - await driver.setUp(precondition.serviceControlWithMonitoring); - // Add scenario-specific preconditions here -}; -``` - -1. Create a new file in `src/Frontend/test/mocks/scenarios/` (e.g., `my-scenario.ts`): - -```typescript -import { setupWorker } from "msw/browser"; -import { Driver } from "../../driver"; -import { makeMockEndpoint, makeMockEndpointDynamic } from "../../mock-endpoint"; -import * as precondition from "../../preconditions"; - -export const worker = setupWorker(); -const mockEndpoint = makeMockEndpoint({ mockServer: worker }); -const mockEndpointDynamic = makeMockEndpointDynamic({ mockServer: worker }); - -const makeDriver = (): Driver => ({ - goTo() { throw new Error("Not implemented"); }, - mockEndpoint, - mockEndpointDynamic, - setUp(factory) { return factory({ driver: this }); }, - disposeApp() { throw new Error("Not implemented"); }, -}); - -const driver = makeDriver(); - -export const setupComplete = (async () => { - await driver.setUp(precondition.scenarioMyScenario); -})(); -``` - -1. Register it in `src/Frontend/test/mocks/scenarios/index.ts`: - -```typescript -const scenarios: Record Promise> = { - // ... existing scenarios - "my-scenario": () => import("./my-scenario"), -}; -``` - ## Automated Tests ### Test Files @@ -126,14 +53,10 @@ const scenarios: Record Promise> = { ### Running Automated Tests -From the `src/Frontend` directory: +Use the shared commands in `docs/frontend/testing-basics.md`, then run this recoverability-specific spec: ```bash -# Run all recoverability capability tests npx vitest run test/specs/platformcapabilities/recoverability-capability-card.spec.ts - -# Run all platform capability tests -npx vitest run test/specs/platformcapabilities/ ``` ### Test Coverage @@ -143,7 +66,7 @@ npx vitest run test/specs/platformcapabilities/ | Rule | Test Case | |-----------------------------------|----------------------------------------------------------| | ServiceControl instance available | Shows "Available" status + "View Failed Messages" button | -| Instance indicator | Shows "Instance" indicator with version info | +| Degraded primary instance | Still shows "Available" status while connected | **Note:** The "Unavailable" state is not tested because when ServiceControl is unavailable, the entire dashboard is replaced with a connection error view, making the recoverability card inaccessible. @@ -152,17 +75,17 @@ npx vitest run test/specs/platformcapabilities/ | File | Purpose | |------------------------------------------------------------------------------------------|-----------------------------------------| | `src/Frontend/src/components/platformcapabilities/capabilities/ErrorCapability.ts` | Main composable for recoverability card | -| `src/Frontend/src/stores/ConnectionsAndStatsStore.ts` | Connection state management | +| `src/Frontend/src/stores/PlatformModelStore.ts` | Shared platform state for primary health | | `src/Frontend/test/specs/platformcapabilities/questions/recoverabilityCapabilityCard.ts` | Test helper functions | | `src/Frontend/test/mocks/scenarios/` | Manual testing scenarios | ## How Recoverability Status is Determined -The recoverability status is determined by checking the ServiceControl connection state: +The recoverability status is determined by checking the primary instance in the shared platform model: ```typescript // Simplified status determination logic -const isConnected = connectionState.connected && !connectionState.unableToConnect; +const isConnected = platformModelStore.primary?.health !== "unavailable"; if (!isConnected) { return CapabilityStatus.Unavailable; @@ -172,11 +95,9 @@ return CapabilityStatus.Available; ## Status Indicators -The recoverability card shows a single "Instance" indicator that displays: +The recoverability card does not display status indicators. Instance-level visibility for ServiceControl lives on the `Platform health` page instead of on the capability card. -- The ServiceControl instance URL -- The ServiceControl version number -- Connection status (Available or Unavailable icon) +A degraded primary instance remains connected for this card. Platform health owns the degraded vs unavailable distinction at the instance level. ## Relationship with Dashboard @@ -187,20 +108,13 @@ The Recoverability capability card is tightly coupled to the main ServiceControl This is different from the Monitoring and Auditing cards, which can show "Unavailable" states independently while the dashboard remains functional. -## Troubleshooting - -### Scenario not loading +When the card is in an available or unavailable state, the status badge links to `Platform health`. There is no separate instance widget on the card. -1. Check the browser console for errors -2. Verify the scenario name matches exactly (case-sensitive) -3. Ensure MSW is enabled (look for "[MSW] Mocking enabled" in console) +## Troubleshooting -### Tests failing +Use `docs/frontend/testing-basics.md` for shared troubleshooting. -1. Run `npm run type-check` to verify TypeScript compilation -2. Check if preconditions are properly set up -3. Use `--reporter=verbose` for detailed test output: +Recoverability-specific checks: - ```bash - npx vitest run test/specs/platformcapabilities/ --reporter=verbose - ``` +1. If the card disappears instead of showing `Unavailable`, confirm the scenario has crossed into full ServiceControl connection failure, which replaces the dashboard. +2. If the `FailedMessages` indicator is wrong, inspect whether the primary instance is connected. diff --git a/docs/frontend/monitoring-capability-card.md b/docs/frontend/monitoring-capability-card.md index 3fe1c7762a..758096ce0d 100644 --- a/docs/frontend/monitoring-capability-card.md +++ b/docs/frontend/monitoring-capability-card.md @@ -2,64 +2,41 @@ This document describes the monitoring capability card component, its various states, and how to test them both manually and automatically. +For shared frontend mock and Vitest workflow, see `docs/frontend/testing-basics.md`. + ## Overview The Monitoring Capability Card displays on the ServicePulse dashboard and shows the status of the monitoring feature. The card's status depends on: 1. Whether the monitoring instance is configured in ServicePulse 2. Whether the monitoring instance is available (responding) -3. Whether endpoints are sending throughput data (monitoring plugin enabled) +3. Capability-specific metrics readiness shown by the `Metrics` indicator ## Card States -| Status | Condition | Badge | Action Button | -|--------------------------|---------------------------------------------------|-------------|---------------| -| Instance Not Configured | Monitoring URL not configured in ServicePulse | - | Get Started | -| Unavailable | Monitoring instance configured but not responding | Unavailable | Learn More | -| Endpoints Not Configured | Instance available but no endpoints sending data | - | Learn More | -| Available | Instance available with endpoints sending data | Available | View Metrics | - -## Manual Testing with Mock Scenarios - -### Prerequisites - -```bash -cd src/Frontend -npm install -``` - -### Running the Dev Server with Mocks +| Status | Condition | Badge | Action Button | +|-------------------------|---------------------------------------------------|----------------|---------------| +| Instance Not Configured | Monitoring URL not configured in ServicePulse | Not configured | Get Started | +| Unavailable | Monitoring instance configured but not responding | Unavailable | Learn More | +| Available | Monitoring instance configured and responding | Available | View Metrics | -```bash -npm run dev:mocks -``` +The `Metrics` indicator carries the capability-specific readiness state. If no endpoints are sending throughput data, the card stays `Available` while the indicator is yellow. -This starts the dev server at `http://localhost:5173` with MSW (Mock Service Worker) intercepting API calls. +A degraded monitoring instance still counts as connected for this card. Only `unavailable` drives the card into the unavailable state. -### Switching Between Scenarios - -Set the `VITE_MOCK_SCENARIO` environment variable before running the dev server: - -```bash -# Linux/macOS -VITE_MOCK_SCENARIO=monitoring-available npm run dev:mocks +## Manual Testing with Mock Scenarios -# Windows CMD -set VITE_MOCK_SCENARIO=monitoring-available && npm run dev:mocks +Start from the shared frontend mocking workflow in `docs/frontend/testing-basics.md`, then select one of the monitoring scenarios below. -# Windows PowerShell -$env:VITE_MOCK_SCENARIO="monitoring-available"; npm run dev:mocks -``` +For the shared meaning of instance topology and availability states, use `docs/frontend/platform-health-page.md` as the canonical reference. This page documents only the monitoring-specific layer on top. -Open the browser console to see available scenarios. +### Available Monitoring Scenarios -#### Available Monitoring Scenarios - -| Scenario | Status | Badge | Button | Description | Indicators | -|---------------------------|--------------------------|-------------|--------------|-------------------------------------------------------------------------------------------------------------------|--------------------------| -| `monitoring-available` | Available | Available | View Metrics | "The ServiceControl Monitoring instance is available and endpoints have been configured to send throughput data." | Instance: ✅, Metrics: ✅ | -| `monitoring-unavailable` | Unavailable | Unavailable | Learn More | "The ServiceControl Monitoring instance is configured but not responding..." | Instance: ❌ | -| `monitoring-no-endpoints` | Endpoints Not Configured | - | Learn More | "The ServiceControl Monitoring instance is connected but no endpoints are sending throughput data..." | Instance: ✅, Metrics: ⚠️ | +| Scenario | Status | Badge | Button | Description | Indicators | +|---------------------------|-------------|-------------|--------------|-------------------------------------------------------------------------------------------------------------------|-------------| +| `monitoring-available` | Available | Available | View Metrics | "The ServiceControl Monitoring instance is available. Use the Metrics indicator to see whether endpoints are sending throughput data." | Metrics: ✅ | +| `monitoring-unavailable` | Unavailable | Unavailable | Learn More | "The ServiceControl Monitoring instance is configured but not responding..." | None | +| `monitoring-no-endpoints` | Available | Available | View Metrics | "The ServiceControl Monitoring instance is available. Use the Metrics indicator to see whether endpoints are sending throughput data." | Metrics: ⚠️ | **Indicator Legend:** ✅ = Available/Success, ❌ = Unavailable/Error, ⚠️ = Warning/Not Configured @@ -78,53 +55,6 @@ window.defaultConfig = { }; ``` -### Adding New Scenarios - -1. Add a scenario precondition to `src/Frontend/test/preconditions/platformCapabilities.ts`: - -```typescript -export const scenarioMyScenario = async ({ driver }: SetupFactoryOptions) => { - await driver.setUp(precondition.serviceControlWithMonitoring); - // Add scenario-specific preconditions here -}; -``` - -1. Create a new file in `src/Frontend/test/mocks/scenarios/` (e.g., `my-scenario.ts`): - -```typescript -import { setupWorker } from "msw/browser"; -import { Driver } from "../../driver"; -import { makeMockEndpoint, makeMockEndpointDynamic } from "../../mock-endpoint"; -import * as precondition from "../../preconditions"; - -export const worker = setupWorker(); -const mockEndpoint = makeMockEndpoint({ mockServer: worker }); -const mockEndpointDynamic = makeMockEndpointDynamic({ mockServer: worker }); - -const makeDriver = (): Driver => ({ - goTo() { throw new Error("Not implemented"); }, - mockEndpoint, - mockEndpointDynamic, - setUp(factory) { return factory({ driver: this }); }, - disposeApp() { throw new Error("Not implemented"); }, -}); - -const driver = makeDriver(); - -export const setupComplete = (async () => { - await driver.setUp(precondition.scenarioMyScenario); -})(); -``` - -1. Register it in `src/Frontend/test/mocks/scenarios/index.ts`: - -```typescript -const scenarios: Record Promise> = { - // ... existing scenarios - "my-scenario": () => import("./my-scenario"), -}; -``` - ## Automated Tests ### Test Files @@ -135,28 +65,24 @@ const scenarios: Record Promise> = { ### Running Automated Tests -From the `src/Frontend` directory: +Use the shared commands in `docs/frontend/testing-basics.md`, then run this monitoring-specific spec: ```bash -# Run all monitoring capability tests npx vitest run test/specs/platformcapabilities/monitoring-capability-card.spec.ts - -# Run all platform capability tests -npx vitest run test/specs/platformcapabilities/ ``` ### Test Coverage #### Application Tests (`monitoring-capability-card.spec.ts`) -| Rule | Test Case | -|-------------------------------------------|------------------------------------------------------| -| Available with endpoints sending data | Shows "Available" status + "View Metrics" button | -| Available but no endpoints sending data | Shows "Endpoints Not Configured" status | -| Instance configured but not responding | Shows "Unavailable" status | -| Monitoring not configured in ServicePulse | Shows "Get Started" button | -| Instance indicator | Shows "Instance" label when monitoring is configured | -| Metrics indicator | Shows "Metrics" label when instance is connected | +| Rule | Test Case | +|-------------------------------------------|----------------------------------------------------------------| +| Available with endpoints sending data | Shows "Available" status + "View Metrics" button | +| Available but no endpoints sending data | Keeps card available and shows a warning `Metrics` indicator | +| Degraded but responding instance | Keeps card available and still shows `Metrics` behavior | +| Instance configured but not responding | Shows "Unavailable" status | +| Monitoring not configured in ServicePulse | Shows "Get Started" button | +| Shared card signals | Shows only the `Metrics` indicator when connected | ## Key Source Files @@ -164,16 +90,16 @@ npx vitest run test/specs/platformcapabilities/ |-----------------------------------------------------------------------------------------|-------------------------------------| | `src/Frontend/src/components/platformcapabilities/capabilities/MonitoringCapability.ts` | Main composable for monitoring card | | `src/Frontend/src/components/monitoring/monitoringClient.ts` | Monitoring API client | +| `src/Frontend/src/stores/PlatformModelStore.ts` | Shared platform model for monitoring state | | `src/Frontend/test/preconditions/platformCapabilities.ts` | Test preconditions and fixtures | | `src/Frontend/test/mocks/scenarios/` | Manual testing scenarios | ## How Monitoring Status is Determined -The monitoring status is determined by checking three conditions in order: +The monitoring status is determined by checking two conditions in order: 1. **Is monitoring configured?** - Checks if `monitoring_urls` contains a valid URL (not "!" or empty) 2. **Is the instance responding?** - Checks if the connection to the monitoring instance succeeds -3. **Are endpoints sending data?** - Checks if any monitored endpoints exist ```typescript // Simplified status determination logic @@ -183,26 +109,26 @@ if (!isMonitoringEnabled) { if (!connectionSuccessful) { return CapabilityStatus.Unavailable; } -if (!hasMonitoredEndpoints) { - return CapabilityStatus.EndpointsNotConfigured; -} return CapabilityStatus.Available; ``` -## Troubleshooting +## Status Indicators -### Scenario not loading +The monitoring card no longer renders a separate instance widget. -1. Check the browser console for errors -2. Verify the scenario name matches exactly (case-sensitive) -3. Ensure MSW is enabled (look for "[MSW] Mocking enabled" in console) +It shows a single `Metrics` indicator only when the monitoring instance is configured and connected: + +- green when monitored endpoints exist +- yellow when no endpoints are sending throughput data yet + +Instance-level monitoring visibility lives on the `Platform health` page. + +## Troubleshooting -### Tests failing +Use `docs/frontend/testing-basics.md` for shared troubleshooting. -1. Run `npm run type-check` to verify TypeScript compilation -2. Check if preconditions are properly set up -3. Use `--reporter=verbose` for detailed test output: +Monitoring-specific checks: - ```bash - npx vitest run test/specs/platformcapabilities/ --reporter=verbose - ``` +1. If the badge is wrong, verify whether the scenario is changing instance connectivity or only endpoint throughput presence. +2. If the `Metrics` indicator is wrong, inspect the `monitored-endpoints` response for the active scenario. +3. The `Instance Not Configured` case is a config-driven manual case, not a standard mock scenario. diff --git a/docs/frontend/platform-health-page.md b/docs/frontend/platform-health-page.md new file mode 100644 index 0000000000..3a3cfba6cc --- /dev/null +++ b/docs/frontend/platform-health-page.md @@ -0,0 +1,235 @@ +# Platform Health Page Testing Guide + +This document describes the Platform health page, how it derives its rows and severity, and how to test it manually and automatically. + +For shared frontend mock and Vitest workflow, see `docs/frontend/testing-basics.md`. + +This page is also the canonical reference for shared platform topology scenarios used across Platform health and the capability-card docs. + +For Custom Checks page behavior around internal platform checks, see `docs/frontend/custom-checks-page.md`. + +## Overview + +The Platform health page provides instance-level visibility across the ServiceControl platform. + +The page is frontend-first and mock-driven. It: + +- uses the shared platform model from `PlatformModelStore` as its source of truth for platform instances +- derives page-specific row and details behavior in `PlatformHealthStore` +- follows the shared topology rule in `docs/platform-topology.md`: primary and monitoring are direct API targets, while audit/remote rows come from ServiceControl remote configuration and are informational only +- keeps topology and instance visibility on the page instead of duplicating per-instance widgets on capability cards +- uses internal platform custom checks as secondary health signals for page-specific health inference, including instance-mapped degraded states +- refreshes custom checks together with platform instance data so hidden internal signals are available even when the Custom Checks page has not been opened + +## Page Behavior + +The page renders one row per platform instance: + +- primary error instance +- zero or more remote instances +- monitoring instance when configured +- ServicePulse + +Each row shows: + +- instance type +- name +- current version +- health state +- upgrade cue when a newer version is known +- no upgrade cue when the page only knows that versions differ but does not know a newer target version + +Rows are always expandable via the health badge. Expanded content separates informational details such as `API: ` from `healthDetails` such as unavailability or degradation messages. + +See `docs/platform-topology.md` for the direct-access rule. + +Rows expand from the health badge to show details. + +Those details come from: + +- informational row context: API URL, transport type, error/audit queue names, forward error messages setting, and error/audit retention periods (when available from instance configuration) +- matching internal platform custom checks when available +- fallback page-specific messages when no custom-check detail is available + +Built-in custom-check `healthDetails` can include both the failure summary and a `Reported at: ` line. + +## Severity Model + +The page-level severity shown in navigation follows this precedence: + +1. `danger` +2. `warning` +3. `info` for outdated-only states + +Current severity rules: + +- `danger` + - primary error instance unavailable + - any remote error instance not healthy + - any audit instance unavailable + - monitoring unavailable +- `warning` + - primary error instance degraded + - any audit instance degraded +- `none` + - no availability or degradation issues + +When severity is `none` but at least one row has an upgrade cue, the nav shows the info/outdated-only state. + +## Shared Model Split + +The architecture intentionally separates shared platform state from page-specific health semantics: + +- `src/Frontend/src/stores/PlatformModelStore.ts` + - shared aggregation and normalization layer +- `src/Frontend/src/resources/PlatformModel.ts` + - shared platform types including backend platform instances and the frontend `ServicePulse` model +- `src/Frontend/src/stores/PlatformHealthStore.ts` + - page-specific severity, rows, upgrade cues, and details + +### Primary and Monitoring version sourcing + +- the primary root document exposes its version through the `X-Particular-Version` response header, so Platform health reads the primary version from that header; a successful primary root fetch maps to an `healthy` baseline (degraded/unavailable are then derived from internal custom checks or a fetch failure) +- the Monitoring root document exposes its version in a `version` field, so Platform health reads the monitoring version from that field + +## Internal Custom Checks + +Platform health consumes internal platform custom checks as secondary signals even when those checks are hidden by default on the Custom Checks page. + +On Platform health they are used to: + +- degrade platform-health rows +- populate expanded row details, including `failure_reason` + +For the shared internal-check behavior and Custom Checks page behavior, see `docs/frontend/custom-checks-page.md`. + +Platform health-specific rule: + +- when assigning an internal degraded check to a specific instance, use `originating_endpoint.name` to match the emitting platform instance +- internal platform custom checks are loaded by `PlatformHealthStore` itself, not only as a side effect of visiting the Custom Checks page + +## Manual Testing with Mock Scenarios + +Start from the shared frontend mocking workflow in `docs/frontend/testing-basics.md`, then use the Platform health scenario and runtime helpers below. + +### Startup Scenario + +The Platform health page has a single startup scenario: + +- `platform-health` + +After startup, use the browser console runtime helpers to switch topology, status, and custom-check conditions live. + +### Runtime Helpers + +```javascript +window.__platformHealth.getState() +window.__platformHealth.reset() +window.__platformHealth.setScenario("audit-remotes-healthy") +window.__platformHealth.setStatus("remote-0", "unavailable") +``` + +For custom-check-specific helpers and presets, see `docs/frontend/custom-checks-page.md`. + +### Topology Scenarios + +Switch topology at runtime with `window.__platformHealth.setScenario(...)`: + +| Scenario | Purpose | +|----------|---------| +| `audit-remotes-healthy` | Primary and monitoring healthy, audit remotes healthy | +| `audit-remotes-danger` | Primary healthy, both audit remotes unavailable, monitoring healthy | +| `remote-errors-healthy` | Primary healthy with remote error instances and no monitoring | +| `remote-errors-danger` | One remote error instance unavailable | +| `primary-unavailable` | Primary root unavailable, no remotes discovered, monitoring healthy | + +### Custom Check Presets + +Switch custom-check state independently with `window.__platformHealth.setCustomCheckPreset(...)`: + +| Preset | Purpose | +|--------|---------| +| `none` | No custom checks | +| `user-only` | Non-platform custom checks only | +| `platform-only-primary-degraded` | Internal primary degraded signal | +| `platform-only-audit` | Internal audit degraded signal targeted at a specific audit instance | +| `mixed-primary-and-user` | Combined platform and user checks | +| `Show platform custom checks` | Only appears when internal checks are present | + +### Manual Checks + +Verify these behaviors from the single startup scenario plus runtime switches: + +| Behavior | How to exercise it | +|----------|--------------------| +| Healthy audit-remote table | `setScenario("audit-remotes-healthy")` | +| Warning state from degraded audit instance | `setScenario("audit-remotes-healthy")` plus `setCustomCheckPreset("platform-only-audit")` | +| Danger state from unavailable instances | `setScenario("audit-remotes-danger")` or `setScenario("remote-errors-danger")` | +| Remote error instances | `setScenario("remote-errors-healthy")` | +| Primary unavailable with no remotes | `setScenario("primary-unavailable")` | +| Internal platform checks hidden from Custom Checks UI but applied to Platform health | `setCustomCheckPreset("platform-only-primary-degraded")` or `setCustomCheckPreset("platform-only-audit")` | +| Expanded row details with separate info and issue sections | trigger any row, then click the health badge | +| Upgrade cue rendering | use instances whose versions differ from the known latest version in the scenario data | +| Support-case modal preview and download flow | click `Open support case`, preview `platform-health.json`, then download it and verify the support link becomes enabled | + +The support export includes both the current Platform health payload and the current failed custom checks. + +## Automated Tests + +### Test Files + +| File | Type | Description | +|------|------|-------------| +| `src/Frontend/src/stores/PlatformHealthStore.spec.ts` | Component/unit | Platform health severity, row derivation, and internal check inference | +| `src/Frontend/src/views/PlatformHealthView.spec.ts` | Component | Page rendering, upgrade cues, row expansion, and support modal behavior | +| `src/Frontend/test/mocks/platform-health-state.spec.ts` | Unit | Runtime mock helper behavior and custom-check preset switching | + +### Running Automated Tests + +Use the shared commands in `docs/frontend/testing-basics.md`, then run these Platform health-specific specs: + +```bash +npx vitest run src/stores/PlatformHealthStore.spec.ts +npx vitest run src/views/PlatformHealthView.spec.ts +npx vitest run test/mocks/platform-health-state.spec.ts +``` + +### Test Coverage + +| Area | Covered behavior | +|------|------------------| +| Platform health store | warning/danger severity, unavailable audit remotes, remote error instance danger, monitoring presence, version fallback, internal custom-check health inference, transport and retention details in infoDetails | +| Platform health view | support download gating, known-version-only upgrade cue rendering, plain-text names, API-in-details rendering, monitoring row rendering, always-expandable health badges | +| Mock helpers | independent topology and custom-check switching | + +## Key Source Files + +| File | Purpose | +|------|---------| +| `src/Frontend/src/views/PlatformHealthView.vue` | Platform health page UI | +| `src/Frontend/src/stores/PlatformHealthStore.ts` | Page-specific rows, severity, and details | +| `src/Frontend/src/stores/PlatformModelStore.ts` | Shared platform instance aggregation | +| `src/Frontend/src/resources/PlatformModel.ts` | Shared platform types | +| `src/Frontend/src/resources/PlatformHealth.ts` | Page-specific response/row types | +| `src/Frontend/test/mocks/platform-health-state.ts` | Runtime mock topology and custom-check controls | +| `src/Frontend/src/components/platformhealth/PlatformHealthMenuItem.vue` | Navigation severity and tooltip behavior | +| `src/Frontend/src/components/PageFooter.vue` | Aggregate platform update status in the footer | + +## Troubleshooting + +Use `docs/frontend/testing-basics.md` for shared troubleshooting. + +Platform health-specific checks: + +### Unexpected topology or custom-check state + +1. Run `window.__platformHealth.reset()`. +2. Reapply `setScenario(...)` and `setCustomCheckPreset(...)` separately. +3. Use `window.__platformHealth.getState()` and `getCustomChecks()` to confirm the active mock state. + +### Tests failing + +1. Run the focused Platform health specs listed above. +2. If a degraded row is missing or assigned to the wrong instance, inspect the check's `originating_endpoint.name` and the instance name carried in the platform model. +3. If hidden platform checks are not affecting the page, inspect the `customchecks?status=fail` response instead of assuming the Custom Checks page must be visited first. +4. If remotes are unexpectedly present after a primary outage, verify the `primary-unavailable` mock scenario is active and that remote discovery is skipped for that refresh. diff --git a/docs/frontend/testing-basics.md b/docs/frontend/testing-basics.md new file mode 100644 index 0000000000..332ac00d52 --- /dev/null +++ b/docs/frontend/testing-basics.md @@ -0,0 +1,114 @@ +# Frontend Testing And Mocking Basics + +This document covers the shared workflow for frontend mock scenarios and focused Vitest runs. + +Use the page-specific docs for feature behavior and scenario meaning: + +- `docs/frontend/custom-checks-page.md` +- `docs/frontend/audit-capability-card.md` +- `docs/frontend/monitoring-capability-card.md` +- `docs/frontend/error-capability-card.md` +- `docs/frontend/platform-health-page.md` + +## Prerequisites + +```bash +cd src/Frontend +npm install +``` + +## Running The Dev Server With Mocks + +```bash +npm run dev:mocks +``` + +This starts the frontend with MSW intercepting API calls. + +## Selecting A Mock Scenario + +Set `VITE_MOCK_SCENARIO` before starting `dev:mocks`. + +```bash +# Linux/macOS +VITE_MOCK_SCENARIO=platform-health npm run dev:mocks + +# Windows CMD +set VITE_MOCK_SCENARIO=platform-health && npm run dev:mocks + +# Windows PowerShell +$env:VITE_MOCK_SCENARIO="platform-health"; npm run dev:mocks +``` + +## Where Mock Scenarios Live + +- `src/Frontend/test/mocks/scenarios/` + - scenario entry points +- `src/Frontend/test/preconditions/` + - reusable API mocks and scenario setup helpers +- `src/Frontend/test/mocks/scenarios/index.ts` + - scenario registry keyed by `VITE_MOCK_SCENARIO` + +## Adding A New Scenario + +1. Add or reuse preconditions in `src/Frontend/test/preconditions/`. +2. Create a scenario entry under `src/Frontend/test/mocks/scenarios/`. +3. Register it in `src/Frontend/test/mocks/scenarios/index.ts`. + +Example shape: + +```ts +import { createScenario } from "../scenario-helper"; +import * as precondition from "../../../preconditions"; + +const { worker, runScenario } = createScenario(); + +export { worker }; + +export const setupComplete = (async () => { + await runScenario(precondition.scenarioMyScenario); +})(); +``` + +## Common Test Commands + +Run focused Vitest specs from `src/Frontend`: + +```bash +npx vitest run src/components/PageFooter.spec.ts +npx vitest run test/specs/platformcapabilities/monitoring-capability-card.spec.ts +npx vitest run test/specs/platformcapabilities/recoverability-capability-card.spec.ts +npx vitest run src/views/PlatformHealthView.spec.ts +``` + +Run broader checks: + +```bash +npm run lint +npm run type-check +``` + +Use verbose output when needed: + +```bash +npx vitest run test/specs/platformcapabilities/ --reporter=verbose +``` + +## Troubleshooting + +### Scenario not loading + +1. Check the browser console. +2. Verify the `VITE_MOCK_SCENARIO` name matches a registered scenario. +3. Confirm MSW is enabled. + +### Reload issues in `dev:mocks` + +1. Reload once more after scenario changes if the service worker was updated. +2. If needed, clear the browser's site data for the local Vite origin and restart `npm run dev:mocks`. + +### Test failures + +1. Run `npm run type-check`. +2. Run only the focused spec for the affected page first. +3. Verify the required preconditions are registered for that scenario. diff --git a/docs/platform-topology.md b/docs/platform-topology.md new file mode 100644 index 0000000000..5cebd95b1b --- /dev/null +++ b/docs/platform-topology.md @@ -0,0 +1,53 @@ +# Platform Topology + +This document defines the shared topology language used by Platform health and the related frontend docs. + +## Topology + +ServicePulse models the platform as: + +- primary ServiceControl +- zero or more remote instances +- monitoring when configured +- ServicePulse itself + +Remote instances are rendered with `remote-audit` or `remote-error` roles, but they are still model-derived rows. Their `apiUrl` is shown for context. + +## Direct Access Rule + +Only the primary ServiceControl instance and Monitoring are treated as direct API targets. + +Audit remote rows are not assumed to be directly reachable even if they have an API URL. + +## Backend Remote Relay + +Primary ServiceControl does fan out to remotes when building `GET /api/configuration/remotes`. + +It calls each remote's `/api/configuration`, gathers the responses in parallel, and returns a transformed `RemoteConfiguration[]` payload with: + +- `api_uri` +- `version` +- `status` +- `configuration` + +This is an enriched relay, not a raw pass-through. + +If the primary ServiceControl root is unavailable, ServicePulse does not attempt remote discovery for that refresh cycle. + +## Shared Uses + +- `docs/frontend/platform-health-page.md` +- `docs/frontend/platform-health-expanded-settings-mock.html` +- capability-card docs under `docs/frontend/` + +## Row Data + +Rows can show: + +- instance type +- name +- version +- health state +- API URL as informational context + +Expanded row details should come from model data and capability signals, not from calling audit endpoints directly. diff --git a/src/Frontend/public/js/app.constants.js b/src/Frontend/public/js/app.constants.js index 1c1a6c9e2f..0e13e04020 100644 --- a/src/Frontend/public/js/app.constants.js +++ b/src/Frontend/public/js/app.constants.js @@ -1,6 +1,6 @@ window.defaultConfig = { default_route: '/dashboard', - version: '1.2.0', + version: '2.10.2', service_control_url: 'http://localhost:33333/api/', monitoring_urls: ['http://localhost:33633/'], showPendingRetry: false, diff --git a/src/Frontend/public/mockServiceWorker.js b/src/Frontend/public/mockServiceWorker.js index 33dde9e770..036285ff06 100644 --- a/src/Frontend/public/mockServiceWorker.js +++ b/src/Frontend/public/mockServiceWorker.js @@ -12,6 +12,26 @@ const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() +function sleep(duration) { + return new Promise((resolve) => { + setTimeout(resolve, duration) + }) +} + +async function waitForClientActivation(clientId, timeout = 500) { + const startedAt = Date.now() + + while (Date.now() - startedAt < timeout) { + if (activeClientIds.has(clientId)) { + return true + } + + await sleep(10) + } + + return activeClientIds.has(clientId) +} + addEventListener('install', function () { self.skipWaiting() }) @@ -122,6 +142,10 @@ addEventListener('fetch', function (event) { * @param {number} requestInterceptedAt */ async function handleRequest(event, requestId, requestInterceptedAt) { + if (event.request.mode === 'navigate' || event.request.destination === 'document') { + return fetch(event.request) + } + const client = await resolveMainClient(event) const requestCloneForEvents = event.request.clone() const response = await getResponse( @@ -244,11 +268,17 @@ async function getResponse(event, client, requestId, requestInterceptedAt) { } // Bypass initial page load requests (i.e. static assets). - // The absence of the immediate/parent client in the map of the active clients - // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet - // and is not ready to handle requests. + // For XHR/fetch requests, wait briefly for the reloaded page to re-activate mocking + // so startup API calls do not leak to the real network during reload races. if (!activeClientIds.has(client.id)) { - return passthrough() + if (event.request.destination) { + return passthrough() + } + + const activated = await waitForClientActivation(client.id) + if (!activated) { + return passthrough() + } } // Notify the client that a request has been intercepted. diff --git a/src/Frontend/src/components/ExclamationMark.spec.ts b/src/Frontend/src/components/ExclamationMark.spec.ts new file mode 100644 index 0000000000..27ec6c7af8 --- /dev/null +++ b/src/Frontend/src/components/ExclamationMark.spec.ts @@ -0,0 +1,23 @@ +import { render } from "@component-test-utils"; +import { describe, expect, test } from "vitest"; +import ExclamationMark from "@/components/ExclamationMark.vue"; +import { WarningLevel } from "@/components/WarningLevel"; + +describe("ExclamationMark", () => { + test("updates icon class when the warning level changes", async () => { + const { container, rerender } = render(ExclamationMark, { + props: { + type: WarningLevel.Info, + }, + }); + + expect(container.querySelector(".info")).not.toBeNull(); + + await rerender({ + type: WarningLevel.Warning, + }); + + expect(container.querySelector(".warning")).not.toBeNull(); + expect(container.querySelector(".info")).toBeNull(); + }); +}); diff --git a/src/Frontend/src/components/ExclamationMark.vue b/src/Frontend/src/components/ExclamationMark.vue index 397cf31cfb..c33b233cfb 100644 --- a/src/Frontend/src/components/ExclamationMark.vue +++ b/src/Frontend/src/components/ExclamationMark.vue @@ -1,4 +1,5 @@  diff --git a/src/Frontend/src/components/FAIcon.vue b/src/Frontend/src/components/FAIcon.vue index 9660ecbe41..3ea1427b12 100644 --- a/src/Frontend/src/components/FAIcon.vue +++ b/src/Frontend/src/components/FAIcon.vue @@ -13,5 +13,6 @@ withDefaults( diff --git a/src/Frontend/src/components/PageFooter.spec.ts b/src/Frontend/src/components/PageFooter.spec.ts new file mode 100644 index 0000000000..16db358a20 --- /dev/null +++ b/src/Frontend/src/components/PageFooter.spec.ts @@ -0,0 +1,59 @@ +import { render, screen } from "@component-test-utils"; +import { createTestingPinia } from "@pinia/testing"; +import { describe, expect, test, vi } from "vitest"; +import PageFooter from "@/components/PageFooter.vue"; +import { useLicenseStore } from "@/stores/LicenseStore"; + +const RouterLinkStub = { + props: ["to"], + template: '', +}; + +const platformHealthStore = vi.hoisted(() => ({ + outdatedOnly: false, + rows: [] as Array<{ upgradeAvailable: boolean }>, +})); + +vi.mock("@/composables/usePlatformHealthStoreAutoRefresh", () => ({ + default: () => ({ + store: platformHealthStore, + }), +})); + +describe("PageFooter", () => { + test("shows updates available and links to platform health when any row is outdated", () => { + platformHealthStore.outdatedOnly = false; + platformHealthStore.rows = [{ upgradeAvailable: false }, { upgradeAvailable: true }]; + + renderFooter(); + + const updatesLink = screen.getByRole("link", { name: /Updates available/i }); + expect(updatesLink).toBeInTheDocument(); + expect(updatesLink).toHaveAttribute("href", "/platform-health"); + }); + + test("shows platform up to date when no rows are outdated", () => { + platformHealthStore.outdatedOnly = false; + platformHealthStore.rows = [{ upgradeAvailable: false }]; + + renderFooter(); + + expect(screen.getByText("Platform up to date")).toBeInTheDocument(); + }); +}); + +function renderFooter() { + const pinia = createTestingPinia({ stubActions: false }); + const licenseStore = useLicenseStore(pinia); + licenseStore.license.license_status = "valid" as never; + licenseStore.licenseStatus.isTrialLicense = false; + + return render(PageFooter, { + global: { + plugins: [pinia], + stubs: { + RouterLink: RouterLinkStub, + }, + }, + }); +} diff --git a/src/Frontend/src/components/PageFooter.vue b/src/Frontend/src/components/PageFooter.vue index 976bd36c2d..649b1b9cfa 100644 --- a/src/Frontend/src/components/PageFooter.vue +++ b/src/Frontend/src/components/PageFooter.vue @@ -1,36 +1,18 @@ @@ -46,40 +28,12 @@ const { configuration } = storeToRefs(configurationStore); Integrated ServicePulse - - - Service Control: - -
- Connected - v{{ environment.sc_version }} - ( v{{ newVersions.newSCVersion.newscversionnumber }} available) -
- Not connected - Connecting -
- -