Files
cameleer-server/ui/src/components/EnvironmentSwitcherModal.test.tsx
hsiegeln 2835d08418
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 2m6s
CI / docker (push) Successful in 1m18s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 38s
ui(env): explicit switcher button+modal, forced selection, 3px color bar
- Replace EnvironmentSelector "All Envs" dropdown with Button+Modal (DS Modal, forced on first-use).
- Add 8-swatch preset color picker in the Environment settings "Appearance" section; commits via useUpdateEnvironment.
- Render a 3px fixed top bar in the current env's color across every page (z-index 900, below DS modals).
- New env-colors tokens (--env-color-*, light + dark) and envColorVar() helper with slate fallback.
- Vitest coverage for button, modal, and color helpers (13 new specs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:24:48 +02:00

112 lines
2.9 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { ThemeProvider } from '@cameleer/design-system';
import type { ReactNode } from 'react';
import { EnvironmentSwitcherModal } from './EnvironmentSwitcherModal';
import type { Environment } from '../api/queries/admin/environments';
function wrap(ui: ReactNode) {
return render(<ThemeProvider>{ui}</ThemeProvider>);
}
const envs: Environment[] = [
{
id: '11111111-1111-1111-1111-111111111111',
slug: 'dev',
displayName: 'Development',
production: false,
enabled: true,
defaultContainerConfig: {},
jarRetentionCount: 5,
color: 'amber',
createdAt: '2026-04-22T00:00:00Z',
},
{
id: '22222222-2222-2222-2222-222222222222',
slug: 'prod',
displayName: 'Production',
production: true,
enabled: true,
defaultContainerConfig: {},
jarRetentionCount: 10,
color: 'red',
createdAt: '2026-04-22T00:00:00Z',
},
];
describe('EnvironmentSwitcherModal', () => {
it('renders one row per env when open', () => {
wrap(
<EnvironmentSwitcherModal
open
onClose={() => {}}
envs={envs}
value="dev"
onPick={() => {}}
/>,
);
expect(screen.getByText('Development')).toBeInTheDocument();
expect(screen.getByText('Production')).toBeInTheDocument();
});
it('calls onPick with slug when a row is clicked', () => {
const onPick = vi.fn();
wrap(
<EnvironmentSwitcherModal
open
onClose={() => {}}
envs={envs}
value="dev"
onPick={onPick}
/>,
);
fireEvent.click(screen.getByRole('option', { name: /production/i }));
expect(onPick).toHaveBeenCalledWith('prod');
});
it('marks the current env with aria-selected', () => {
wrap(
<EnvironmentSwitcherModal
open
onClose={() => {}}
envs={envs}
value="dev"
onPick={() => {}}
/>,
);
const selected = screen.getByRole('option', { name: /development/i });
expect(selected).toHaveAttribute('aria-selected', 'true');
});
it('renders empty state when no envs exist', () => {
wrap(
<EnvironmentSwitcherModal
open
onClose={() => {}}
envs={[]}
value={undefined}
onPick={() => {}}
/>,
);
expect(screen.getByText(/no environments/i)).toBeInTheDocument();
});
it('forced mode swaps the title and ignores onClose', () => {
const onClose = vi.fn();
wrap(
<EnvironmentSwitcherModal
open
onClose={onClose}
envs={envs}
value={undefined}
onPick={() => {}}
forced
/>,
);
expect(screen.getByText(/select an environment/i)).toBeInTheDocument();
// Simulate ESC — DS Modal forwards this to onClose, which we wrapped in a no-op.
fireEvent.keyDown(document, { key: 'Escape' });
expect(onClose).not.toHaveBeenCalled();
});
});