Files
DECNET/decnet_web/src/components/DeckyFleet/DeployWizard.test.tsx
anti 1e2bc41ab1 refactor(decnet_web/DeckyFleet): move DeployWizard out
Lift the multi-step deploy wizard (~520 LOC) plus its private
INI-builder helpers (PLACEHOLDER_LINES, b64encodeUtf8, buildIni,
PickMode type) into their own file. Verbatim move; the
underscore-prefixed helpers drop the leading underscore now that
they're file-local rather than competing with hoisted parent
constants.

- New DeckyFleet/DeployWizard.tsx
- DeployWizard.test.tsx covers the closed render guard, the
  open-at-step-0 archetype list, NEXT-disabled-until-archetype,
  and CANCEL -> onClose. ServiceConfigFields is vi.mock'd to a
  stub since it pulls schemas via api.get() that are out of
  scope for these tests.
- DeckyFleet.tsx loses the wizard plus the now-unused imports
  (DEFAULT_SERVICES, Modal, PickIcon, ServiceConfigFields and
  its type aliases).
2026-05-09 05:01:33 -04:00

85 lines
2.4 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { DeployWizard } from './DeployWizard';
import type { Archetype } from './types';
// ServiceConfigFields fetches the per-service schema; replace with a stub
// so the wizard tests don't need MSW handlers for that side-channel.
vi.mock('../ServiceConfigFields', async () => {
const actual = await vi.importActual<object>('../ServiceConfigFields');
return {
...actual,
default: () => null,
};
});
const archetypes: Archetype[] = [
{ slug: 'web-server', name: 'Web Server', services: ['http', 'https'], icon: 'globe' },
{ slug: 'database', name: 'Database', services: ['postgres'], icon: 'database' },
];
describe('DeployWizard', () => {
it('renders nothing meaningful when closed', () => {
render(
<DeployWizard
open={false}
onClose={() => {}}
onComplete={() => {}}
archetypes={archetypes}
fleetSize={0}
/>,
);
expect(screen.queryByText('DEPLOY NEW DECKIES')).not.toBeInTheDocument();
});
it('opens at step 0 with archetype list rendered', () => {
render(
<DeployWizard
open
onClose={() => {}}
onComplete={() => {}}
archetypes={archetypes}
fleetSize={0}
/>,
);
expect(screen.getByText('DEPLOY NEW DECKIES')).toBeInTheDocument();
expect(screen.getByText('Web Server')).toBeInTheDocument();
expect(screen.getByText('Database')).toBeInTheDocument();
});
it('disables NEXT until an archetype is selected', async () => {
const user = userEvent.setup();
render(
<DeployWizard
open
onClose={() => {}}
onComplete={() => {}}
archetypes={archetypes}
fleetSize={0}
/>,
);
const nextBtn = screen.getByText('NEXT →') as HTMLButtonElement;
expect(nextBtn.disabled).toBe(true);
await user.click(screen.getByText('Web Server'));
expect(nextBtn.disabled).toBe(false);
});
it('CANCEL button invokes onClose', async () => {
const onClose = vi.fn();
const user = userEvent.setup();
render(
<DeployWizard
open
onClose={onClose}
onComplete={() => {}}
archetypes={archetypes}
fleetSize={0}
/>,
);
await user.click(screen.getByText('CANCEL'));
expect(onClose).toHaveBeenCalled();
});
});