Compare commits

..

1 Commits

Author SHA1 Message Date
privilegedescalation-engineer e565ecbd4c fix(e2e): use specific regex for pods, metrics, and device-plugins page headings
Fix overly-broad heading selectors that cause Playwright strict mode violations:
- /pods route: /pod/i -> /intel gpu.*pods/i
- /metrics route: /metric/i -> /intel gpu.*metrics/i
- /device-plugins route: /device plugin/i -> /intel gpu.*device plugins/i

Same specificity pattern as nodes page fix in PR #36.
Fixes GitHub #37.
2026-03-25 05:07:11 +00:00
3 changed files with 6 additions and 44 deletions
+3 -3
View File
@@ -43,7 +43,7 @@ test.describe('Intel GPU plugin smoke tests', () => {
test('device plugins page renders or shows empty state', async ({ page }) => {
await page.goto('/c/main/intel-gpu/device-plugins');
await expect(page.getByRole('heading', { name: /device plugin/i })).toBeVisible({
await expect(page.getByRole('heading', { name: /intel gpu.*device plugins/i })).toBeVisible({
timeout: 15_000,
});
@@ -69,10 +69,10 @@ test.describe('Intel GPU plugin smoke tests', () => {
await expect(page.getByRole('heading', { name: /intel gpu.*nodes/i })).toBeVisible({ timeout: 15_000 });
await page.goto('/c/main/intel-gpu/pods');
await expect(page.getByRole('heading', { name: /pod/i })).toBeVisible({ timeout: 15_000 });
await expect(page.getByRole('heading', { name: /intel gpu.*pods/i })).toBeVisible({ timeout: 15_000 });
await page.goto('/c/main/intel-gpu/metrics');
await expect(page.getByRole('heading', { name: /metric/i })).toBeVisible({ timeout: 15_000 });
await expect(page.getByRole('heading', { name: /intel gpu.*metrics/i })).toBeVisible({ timeout: 15_000 });
});
test('plugin settings page shows intel-gpu plugin entry', async ({ page }) => {
-23
View File
@@ -151,27 +151,4 @@ describe('IntelGpuDataProvider', () => {
expect(callCountAfter).toBeGreaterThan(callCountBefore);
});
});
it('treats a hanging CRD request as unavailable after 2s timeout', async () => {
vi.useFakeTimers();
const nodeWrapper = { jsonData: {} };
vi.mocked(K8s.ResourceClasses.Node.useList).mockReturnValue([[nodeWrapper], null] as any);
vi.mocked(K8s.ResourceClasses.Pod.useList).mockReturnValue([[nodeWrapper], null] as any);
vi.mocked(ApiProxy.request)
.mockReturnValueOnce(new Promise(() => {}))
.mockResolvedValueOnce({ items: [] })
.mockResolvedValueOnce({ items: [] })
.mockResolvedValueOnce({ items: [] });
const { result } = renderHook(() => useIntelGpuContext(), { wrapper: Wrapper });
expect(result.current.loading).toBe(true);
vi.advanceTimersByTime(2000);
await act(async () => {});
expect(result.current.crdAvailable).toBe(false);
expect(result.current.loading).toBe(false);
vi.useRealTimers();
});
});
+3 -18
View File
@@ -69,18 +69,6 @@ export function useIntelGpuContext(): IntelGpuContextValue {
// Helpers
// ---------------------------------------------------------------------------
const DEFAULT_REQUEST_TIMEOUT_MS = 2_000;
/** Wraps a promise with a timeout, rejecting if it doesn't settle within ms. */
function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
return Promise.race([
promise,
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error(`Request timed out after ${ms}ms`)), ms)
),
]);
}
/** Extract raw Kubernetes JSON from Headlamp KubeObject wrappers. */
const extractJsonData = (items: unknown[]): unknown[] =>
items.map(item =>
@@ -120,11 +108,8 @@ export function IntelGpuDataProvider({ children }: { children: React.ReactNode }
try {
// GpuDevicePlugin CRDs — graceful degradation if CRD not installed
try {
const pluginList = await withTimeout(
ApiProxy.request(
`/apis/${INTEL_DEVICE_PLUGIN_API_GROUP}/${INTEL_DEVICE_PLUGIN_API_VERSION}/gpudeviceplugins`
),
DEFAULT_REQUEST_TIMEOUT_MS
const pluginList = await ApiProxy.request(
`/apis/${INTEL_DEVICE_PLUGIN_API_GROUP}/${INTEL_DEVICE_PLUGIN_API_VERSION}/gpudeviceplugins`
);
if (!cancelled && isKubeList(pluginList)) {
setCrdAvailable(true);
@@ -154,7 +139,7 @@ export function IntelGpuDataProvider({ children }: { children: React.ReactNode }
for (const url of pluginPodSelectors) {
try {
const list = await withTimeout(ApiProxy.request(url), DEFAULT_REQUEST_TIMEOUT_MS);
const list = await ApiProxy.request(url);
if (!cancelled && isKubeList(list)) {
const gpuPluginPods = filterIntelGpuPluginPods(list.items);
foundPluginPods.push(...gpuPluginPods);