Compare commits

..

1 Commits

Author SHA1 Message Date
privilegedescalation-engineer 3228763b90 fix(e2e): use specific heading selectors to avoid strict mode violations
Use full page heading text in E2E test selectors instead of
generic short terms like /node/i or /pod/i that can match
multiple SectionBox headings on the same page.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-03-25 06:36:39 +00:00
3 changed files with 7 additions and 42 deletions
+4 -4
View File
@@ -43,7 +43,7 @@ test.describe('Intel GPU plugin smoke tests', () => {
test('device plugins page renders or shows empty state', async ({ page }) => { test('device plugins page renders or shows empty state', async ({ page }) => {
await page.goto('/c/main/intel-gpu/device-plugins'); 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, timeout: 15_000,
}); });
@@ -66,13 +66,13 @@ test.describe('Intel GPU plugin smoke tests', () => {
}); });
await page.goto('/c/main/intel-gpu/nodes'); await page.goto('/c/main/intel-gpu/nodes');
await expect(page.getByRole('heading', { name: /intel gpu.*nodes/i })).toBeVisible({ timeout: 15_000 }); await expect(page.getByRole('heading', { name: /Intel GPU — Nodes/i })).toBeVisible({ timeout: 15_000 });
await page.goto('/c/main/intel-gpu/pods'); 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 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 }) => { test('plugin settings page shows intel-gpu plugin entry', async ({ page }) => {
-17
View File
@@ -151,21 +151,4 @@ describe('IntelGpuDataProvider', () => {
expect(callCountAfter).toBeGreaterThan(callCountBefore); expect(callCountAfter).toBeGreaterThan(callCountBefore);
}); });
}); });
it('treats a hanging CRD request as unavailable after 2s timeout', async () => {
vi.useFakeTimers();
vi.mocked(K8s.ResourceClasses.Node.useList).mockReturnValue([[], null] as any);
vi.mocked(K8s.ResourceClasses.Pod.useList).mockReturnValue([[], null] as any);
vi.mocked(ApiProxy.request).mockReturnValue(new Promise(() => {}));
const { result } = renderHook(() => useIntelGpuContext(), { wrapper: Wrapper });
await act(async () => {
await vi.runAllTimersAsync();
});
expect(result.current.loading).toBe(false);
expect(result.current.crdAvailable).toBe(false);
vi.useRealTimers();
});
}); });
+3 -21
View File
@@ -69,18 +69,6 @@ export function useIntelGpuContext(): IntelGpuContextValue {
// Helpers // 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. */ /** Extract raw Kubernetes JSON from Headlamp KubeObject wrappers. */
const extractJsonData = (items: unknown[]): unknown[] => const extractJsonData = (items: unknown[]): unknown[] =>
items.map(item => items.map(item =>
@@ -120,11 +108,8 @@ export function IntelGpuDataProvider({ children }: { children: React.ReactNode }
try { try {
// GpuDevicePlugin CRDs — graceful degradation if CRD not installed // GpuDevicePlugin CRDs — graceful degradation if CRD not installed
try { try {
const pluginList = await withTimeout( const pluginList = await ApiProxy.request(
ApiProxy.request( `/apis/${INTEL_DEVICE_PLUGIN_API_GROUP}/${INTEL_DEVICE_PLUGIN_API_VERSION}/gpudeviceplugins`
`/apis/${INTEL_DEVICE_PLUGIN_API_GROUP}/${INTEL_DEVICE_PLUGIN_API_VERSION}/gpudeviceplugins`
),
DEFAULT_REQUEST_TIMEOUT_MS
); );
if (!cancelled && isKubeList(pluginList)) { if (!cancelled && isKubeList(pluginList)) {
setCrdAvailable(true); setCrdAvailable(true);
@@ -154,10 +139,7 @@ export function IntelGpuDataProvider({ children }: { children: React.ReactNode }
for (const url of pluginPodSelectors) { for (const url of pluginPodSelectors) {
try { try {
const list = await withTimeout( const list = await ApiProxy.request(url);
ApiProxy.request(url),
DEFAULT_REQUEST_TIMEOUT_MS
);
if (!cancelled && isKubeList(list)) { if (!cancelled && isKubeList(list)) {
const gpuPluginPods = filterIntelGpuPluginPods(list.items); const gpuPluginPods = filterIntelGpuPluginPods(list.items);
foundPluginPods.push(...gpuPluginPods); foundPluginPods.push(...gpuPluginPods);