Files
portainer/app/react/docker/containers/components/UpdateStatusBadge/UpdateStatusBadge.test.tsx
T
claude code agent f69eb3f9eb feat(automation): CE container image update detection endpoint + badge (#9, epic #3 M2)
Add native CE detection of "a newer image is available" for running
containers, surfaced as a read-only HTTP endpoint and a containers-list
badge/column. No applying of updates (M3/M4), no auto-heal (M1).

Backend:
- New CE handler GET /docker/{id}/containers/{containerId}/image_status
  backed by the existing zlib/CE digest engine
  (images.NewClientWithRegistry + ContainerImageStatus). Honors nodeName,
  authz, and routes registry calls through the credential store / SSRF
  AllowList. Engine failures degrade to a 200 {Status:"error"} so the UI
  stays graceful. Response shape: {Status, Message?}.

Frontend (CE-only, no isBE gating; the EE ImageStatus component is left
untouched):
- useContainerImageStatus TanStack Query hook (5min staleTime, no
  refetch-on-focus; backend caches 24h) calling the non-proxied endpoint.
- UpdateStatusBadge component (own assets, neutral on skipped/error).
- "Update available" column in the containers datatable; one cached,
  non-blocking query per visible row.

Tests: Go response-shape unit test; vitest for the badge (all statuses)
and the hook (url + nodeName query param via msw).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 08:59:54 +03:00

45 lines
1.3 KiB
TypeScript

import { render, screen } from '@testing-library/react';
import { ContainerImageStatusValue } from '../../queries/useContainerImageStatus';
import { UpdateStatusBadge } from './UpdateStatusBadge';
describe('UpdateStatusBadge', () => {
it('renders "Update available" when the image is outdated', () => {
render(<UpdateStatusBadge status="outdated" />);
expect(screen.getByText('Update available')).toBeInTheDocument();
});
it('renders an up-to-date indicator when the image is updated', () => {
render(<UpdateStatusBadge status="updated" />);
expect(screen.getByText('Up to date')).toBeInTheDocument();
});
it('shows a spinner while loading', () => {
render(<UpdateStatusBadge isLoading />);
expect(
screen.getByLabelText('Checking for image updates')
).toBeInTheDocument();
});
it.each<ContainerImageStatusValue>([
'skipped',
'error',
'processing',
'preparing',
])('renders nothing for the neutral status "%s"', (status) => {
const { container } = render(<UpdateStatusBadge status={status} />);
expect(container).toBeEmptyDOMElement();
});
it('renders nothing when status is undefined and not loading', () => {
const { container } = render(<UpdateStatusBadge />);
expect(container).toBeEmptyDOMElement();
});
});