From a13bf7da6d5d06b0b05c2fe23e58772549bb3dd9 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 19 May 2026 20:59:34 +0100 Subject: [PATCH] Keep guest drawer discovery reads non-suspending --- .../components/Workloads/GuestDrawer.test.tsx | 23 ++++++++++++- ...loadsSurface.performance.contract.test.tsx | 3 ++ .../Workloads/useGuestDrawerState.ts | 32 +++++++++++++------ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx b/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx index 72765fc067..6024527c1b 100644 --- a/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx +++ b/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx @@ -1,7 +1,9 @@ import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'; import { render, screen, fireEvent, cleanup, waitFor, within } from '@solidjs/testing-library'; +import { Suspense } from 'solid-js'; import type { WorkloadGuest } from '@/types/workloads'; import type { Memory, Disk, GuestNetworkInterface } from '@/types/api'; +import { resetCreateNonSuspendingQueryCacheForTest } from '@/hooks/createNonSuspendingQuery'; import { getCanonicalWorkloadId } from '@/utils/workloads'; // ── Mocks ────────────────────────────────────────────────────────────── @@ -118,6 +120,8 @@ const makeHistoryPoints = (base: number) => [ ]; beforeEach(() => { + resetCreateNonSuspendingQueryCacheForTest(); + discoveryApiMocks.getDiscovery.mockResolvedValue(null); chartsApiMocks.getMetricsHistory.mockResolvedValue({ resourceType: 'vm', resourceId: 'inst1:node1:100', @@ -216,13 +220,30 @@ describe('GuestDrawer', () => { it('hides the Identified Service card when the discovery record is null or empty', async () => { discoveryApiMocks.getDiscovery.mockResolvedValueOnce(null); render(() => ); - // Allow the resource to resolve and a render cycle to happen. await waitFor(() => { expect(discoveryApiMocks.getDiscovery).toHaveBeenCalled(); }); expect(screen.queryByText('Identified Service')).toBeNull(); }); + it('keeps the passive discovery lookup out of the parent Suspense fallback', () => { + discoveryApiMocks.getDiscovery.mockImplementationOnce( + () => + new Promise(() => undefined), + ); + + render(() => ( + Loading page}> + + + )); + + expect(screen.queryByTestId('parent-suspense-fallback')).toBeNull(); + expect(screen.getByText('Overview')).toBeInTheDocument(); + expect(screen.getByText('History')).toBeInTheDocument(); + expect(screen.getByText('Discovery')).toBeInTheDocument(); + }); + it('switches to Discovery tab on click', async () => { const { container } = render(() => ); await fireEvent.click(screen.getByText('Discovery')); diff --git a/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx b/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx index 78cab54b20..80f2f1a01a 100644 --- a/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx +++ b/frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx @@ -1266,6 +1266,9 @@ describe('Workloads performance contract', () => { expect(guestDrawerStateSource).toContain('historyRange'); expect(guestDrawerStateSource).not.toContain('buildInfrastructureHrefForWorkload'); expect(guestDrawerStateSource).not.toContain("from '@/routing/resourceLinks'"); + expect(guestDrawerStateSource).toContain("from '@/hooks/createNonSuspendingQuery'"); + expect(guestDrawerStateSource).toContain('createNonSuspendingQuery('overview'); @@ -97,18 +105,22 @@ export function useGuestDrawerState(props: GuestDrawerProps) { const agent = discoveryAgentId(); const resource = discoveryResourceId(); if (!type || !agent || !resource) return null; - return { type, agent, resource } as const; + return { type, agent, resource } as GuestDiscoverySourceKey; }); - const [discoveryRecord] = createResource(discoverySourceKey, async (key) => { - if (!key) return null; - try { - return await getDiscovery(key.type, key.agent, key.resource); - } catch { - return null; - } + const discoveryRecord = createNonSuspendingQuery({ + source: discoverySourceKey, + initialValue: null, + cacheKey: (key) => `guest-drawer-discovery:${key.type}:${key.agent}:${key.resource}`, + fetcher: async (key) => { + try { + return await getDiscovery(key.type, key.agent, key.resource); + } catch { + return null; + } + }, }); const discoveryIdentifiedSummary = createMemo(() => - getDiscoveryIdentifiedSummary(discoveryRecord()), + getDiscoveryIdentifiedSummary(discoveryRecord.value()), ); const switchTab = (tab: GuestDrawerTab) => {