Skip to content
This repository was archived by the owner on Mar 7, 2026. It is now read-only.

bugfix(KLEFF): Add#121

Merged
isaacwallace123 merged 5 commits intomainfrom
tes
Mar 4, 2026
Merged

bugfix(KLEFF): Add#121
isaacwallace123 merged 5 commits intomainfrom
tes

Conversation

@JeremyNRoos
Copy link
Contributor

🚀 Pull Request Overview

📌 Summary

🔗 Related Issues

Closes #


🧪 Changes

✅ What’s Included

❌ What’s Not Included


🧪 Testing

🔍 How Was This Tested?

🧪 Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • End-to-end scenarios tested manually

🧩 Breaking Changes

Does this PR introduce breaking changes?

  • Yes
  • No

If yes, describe the impact and migration steps:


🔐 Security Considerations

  • This PR affects authentication or authorization
  • This PR touches secrets, tokens, or environment variables
  • This PR affects infrastructure or deployment pipeline

If checked, explain:


📝 Documentation

Does this PR require updates to documentation?

  • Yes
  • No

If yes, update the relevant locations:

  • /docs
  • README.md
  • API reference
  • Architecture diagrams / C4 / DDD docs

🎨 UI/UX Considerations (If Applicable)

  • Includes new components
  • Changes styles or theme tokens
  • Requires design approval
  • Responsive behavior tested

Screenshots / recordings (if applicable):


📦 Checklist Before Merge

  • Follows project coding style
  • PR title follows semantic format (feat:, fix:, chore:, docs:, refactor:, test:)
  • All CI checks passing
  • No debug logs or commented-out code
  • Dependencies reviewed
  • No sensitive information added

👤 Contributor Notes (Optional)

Copilot AI review requested due to automatic review settings March 4, 2026 19:08
@JeremyNRoos JeremyNRoos changed the title added bigfix(KLEFF): add Mar 4, 2026
@JeremyNRoos JeremyNRoos changed the title bigfix(KLEFF): add bugfix(KLEFF): add Mar 4, 2026
@github-actions github-actions bot added the chore Maintenance/devex label Mar 4, 2026
@JeremyNRoos JeremyNRoos changed the title bugfix(KLEFF): add bugfix(KLEFF): Add Mar 4, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new Playwright E2E test suite for the Systems/Metrics dashboard (“cluster health”), along with a dedicated page object that encapsulates navigation, UI assertions, and API route mocking for /api/v1/systems/metrics.

Changes:

  • Added cluster-health.spec.ts covering navigation, initial fetch, time-range refetch, rendering, partial-data scenarios, and error scenarios.
  • Introduced MetricsDashboardPage page object with helpers for assertions and mocked API responses.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.

File Description
frontend/e2e/specs/cluster-health.spec.ts New UC-50 cluster health E2E suite exercising happy path, partial-data, and error states.
frontend/e2e/pages/dashboard/metrics-dashboard.page.ts New page object for /dashboard/systems, including UI helpers and /systems/metrics route mocks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +162 to +166
nodes: [
{
name: "node-1",
cpuUsagePercent: 35.0,
memoryUsagePercent: 60.0,
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The happy-path mock response reports overview.totalNodes: 3 / runningNodes: 3 and nodesMetric.value: "3/3", but the nodes array only contains 2 entries. This inconsistency can make UI behavior or future assertions confusing if counts are cross-checked. Adjust the mock so the overview/node-card counts match the nodes list.

Copilot uses AI. Check for mistakes.
* • Use MetricsDashboardPage page-object
*/

import { expect } from "@playwright/test";
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description/template is still largely blank (no summary, related issue, or testing notes). Please fill it in so reviewers understand the intent of the added E2E suite/page object and how it was validated.

Copilot uses AI. Check for mistakes.
* Extension 6a – Prometheus timeout → null fields → 200 OK → zero-value cards, no crash
* Extension 10a – Some metric fields null → available cards render normally
* Exception – API 500 / network error → inline red error alert with exact text
* Postcondition – MetricCard elements present; NodesList has ≥1 row
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment says the four summary cards are "CPU%, RAM%, RunningNodes/TotalNodes, Tenants", but the current MetricsDashboard renders Requests/s, Running Pods, Nodes, and CPU Usage. Please update the comment to match the UI under test so the documented coverage/requirements aren’t misleading.

Suggested change
* Postcondition MetricCard elements present; NodesList has ≥1 row
* Postcondition MetricCard elements present (Requests/s, Running Pods, Nodes, CPU Usage); NodesList has ≥1 row

Copilot uses AI. Check for mistakes.
Comment on lines +215 to +220
const refreshPromise = page.waitForRequest(
(req) => req.url().includes("/api/v1/systems/metrics"),
{ timeout: 10_000 }
);
await metricsPage.clickRefresh();
await refreshPromise;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForRequest here can resolve due to the initial fetch on mount (or the 30s interval) rather than the Refresh click, so the test may pass even if the button doesn’t trigger a new request. Make it deterministic by awaiting the click and request together (e.g., Promise.all([page.waitForRequest(...), metricsPage.clickRefresh()])) and/or waiting for the initial metrics request to complete first.

Suggested change
const refreshPromise = page.waitForRequest(
(req) => req.url().includes("/api/v1/systems/metrics"),
{ timeout: 10_000 }
);
await metricsPage.clickRefresh();
await refreshPromise;
// Wait for the initial metrics request that fires on mount, so that the
// subsequent waitForRequest is guaranteed to correspond to the manual refresh.
await page.waitForRequest(
(req) => req.url().includes("/api/v1/systems/metrics"),
{ timeout: 10_000 }
);
// Tie the Refresh click and the expected API call together to avoid
// accidentally matching an earlier or timer-based request.
await Promise.all([
page.waitForRequest(
(req) => req.url().includes("/api/v1/systems/metrics"),
{ timeout: 10_000 }
),
metricsPage.clickRefresh()
]);

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +26
/** Confirms the happy-path "ready" state: no error banner visible. */
async expectReady() {
await expect(this.page.getByTestId("systems-error")).not.toBeVisible({ timeout: 15_000 });
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expectReady() only asserts that the error banner is not visible, but systems-error is also absent during the initial loading state (before the first metrics fetch resolves). That means callers can treat the page as "ready" even though it’s still rendering skeletons. Consider renaming this to reflect what it checks (e.g., expectNoErrorBanner) and adding a separate readiness assertion that waits for the metrics request to complete and/or for at least one known piece of loaded content to appear.

Suggested change
/** Confirms the happy-path "ready" state: no error banner visible. */
async expectReady() {
await expect(this.page.getByTestId("systems-error")).not.toBeVisible({ timeout: 15_000 });
/** Confirms no error banner is visible. */
async expectNoErrorBanner() {
await expect(this.errorBanner()).not.toBeVisible({ timeout: 15_000 });
}
/**
* Confirms the happy-path "ready" state:
* - no error banner visible
* - expected metric cards rendered (metrics fetch completed)
*/
async expectReady() {
await this.expectNoErrorBanner();
await this.expectMetricCardsPresent();

Copilot uses AI. Check for mistakes.
Comment on lines +48 to +54
* MetricCard has no individual data-testid so we locate them by their
* shared CSS classes rendered inside data-testid="systems-page".
*/
metricCards() {
return this.page
.getByTestId("systems-page")
.locator(".rounded-xl.border.border-white\\/6.bg-white\\/3");
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metricCards() locates cards via Tailwind class strings. This is brittle (style refactors break tests) and it matches both skeleton and loaded MetricCard markup, so expectMetricCardsPresent() can pass before data has rendered. Prefer a more stable selector (e.g., add a data-testid on MetricCard/summary grid or assert on stable card titles from the mock response).

Suggested change
* MetricCard has no individual data-testid so we locate them by their
* shared CSS classes rendered inside data-testid="systems-page".
*/
metricCards() {
return this.page
.getByTestId("systems-page")
.locator(".rounded-xl.border.border-white\\/6.bg-white\\/3");
* MetricCard elements are located via a dedicated data-testid to avoid
* brittle Tailwind class selectors and to distinguish loaded cards from
* any skeleton placeholders.
*
* NOTE: Each rendered MetricCard in the app should expose
* `data-testid="systems-metric-card"`.
*/
metricCards() {
return this.page.getByTestId("systems-metric-card");

Copilot uses AI. Check for mistakes.
// ── Time-range selector ───────────────────────────────────────────────────

timeRangeSelect() {
return this.page.locator("select");
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeRangeSelect() targets the first matching select on the page. This page already contains other selects when dropdown menus are opened (e.g., Export Metrics), so this locator is prone to strict-mode failures if UI structure changes. Scope the locator under data-testid="systems-page" and/or select by accessible name/label to keep it stable.

Suggested change
return this.page.locator("select");
return this.page.getByTestId("systems-page").locator("select");

Copilot uses AI. Check for mistakes.
@isaacwallace123 isaacwallace123 merged commit 18b7fb6 into main Mar 4, 2026
13 of 14 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

chore Maintenance/devex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants