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).
This commit is contained in:
84
decnet_web/src/components/DeckyFleet/DeployWizard.test.tsx
Normal file
84
decnet_web/src/components/DeckyFleet/DeployWizard.test.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user