Files
DECNET/decnet_web/src/components/CanaryTokens/CreateTokenModal.test.tsx
anti e30455551d refactor(decnet_web/CanaryTokens): move CreateTokenModal out
Verbatim move of the canary-token creation modal (~280 LOC) into
its own file. Renamed from CreateModal to CreateTokenModal so the
component name carries scope across the package boundary.

- New CanaryTokens/CreateTokenModal.tsx
- CreateTokenModal.test.tsx covers title rendering, CANCEL ->
  onClose, empty-deckies hint, and the Operator-upload mode
  switch revealing the no-blobs message. useFocusTrap is
  vi.mock'd to avoid jsdom focus shenanigans.
- CanaryTokens.tsx loses the inline modal + its now-unused
  imports (KNOWN_GENERATORS, KIND_OPTIONS, GeneratorName).
2026-05-09 05:10:27 -04:00

77 lines
2.2 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CreateTokenModal } from './CreateTokenModal';
import type { DeckyOption, TopologyOption } from './types';
// useFocusTrap depends on focus-trap-react that yells at jsdom.
vi.mock('../../hooks/useFocusTrap', () => ({ useFocusTrap: () => {} }));
const deckies: DeckyOption[] = [{ name: 'decoy-01', ip: '10.0.0.1' }];
const topologies: TopologyOption[] = [{ id: 't-1', name: 'corp-net', status: 'active' }];
describe('CreateTokenModal', () => {
it('renders the title and the Fleet/MazeNET scope toggle', () => {
render(
<CreateTokenModal
blobs={[]}
deckies={deckies}
topologies={topologies}
onClose={() => {}}
onCreated={() => {}}
/>,
);
expect(screen.getByText('NEW CANARY TOKEN')).toBeInTheDocument();
expect(screen.getByText('Fleet')).toBeInTheDocument();
expect(screen.getByText('MazeNET topology')).toBeInTheDocument();
});
it('CANCEL invokes onClose', async () => {
const onClose = vi.fn();
const user = userEvent.setup();
render(
<CreateTokenModal
blobs={[]}
deckies={deckies}
topologies={topologies}
onClose={onClose}
onCreated={() => {}}
/>,
);
await user.click(screen.getByText('CANCEL'));
expect(onClose).toHaveBeenCalled();
});
it('shows the empty-deckies message when fleet has no deckies', () => {
render(
<CreateTokenModal
blobs={[]}
deckies={[]}
topologies={topologies}
onClose={() => {}}
onCreated={() => {}}
/>,
);
expect(
screen.getByText('No fleet deckies running. Deploy a fleet first.'),
).toBeInTheDocument();
});
it('switching to Operator upload reveals the no-blobs hint', async () => {
const user = userEvent.setup();
render(
<CreateTokenModal
blobs={[]}
deckies={deckies}
topologies={topologies}
onClose={() => {}}
onCreated={() => {}}
/>,
);
await user.click(screen.getByText('Operator upload'));
expect(
screen.getByText(/No blobs uploaded yet/),
).toBeInTheDocument();
});
});