chore: update gitignore and restore backend files
- Add backend/node_modules to .gitignore - Untrack backend/node_modules from git - Restore backend source files (go.mod, main.go, etc.) that were missing in HEAD - Include frontend test updates
This commit is contained in:
@@ -88,10 +88,11 @@ export default function ProxyHostForm({ host, onSubmit, onCancel }: ProxyHostFor
|
||||
{/* Remote Server Quick Select */}
|
||||
{remoteServers.length > 0 && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
<label htmlFor="quick-select" className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Quick Select from Remote Servers
|
||||
</label>
|
||||
<select
|
||||
id="quick-select"
|
||||
onChange={e => handleServerSelect(e.target.value)}
|
||||
className="w-full bg-gray-900 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
@@ -212,10 +213,11 @@ export default function ProxyHostForm({ host, onSubmit, onCancel }: ProxyHostFor
|
||||
|
||||
{/* Advanced Config */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-300 mb-2">
|
||||
<label htmlFor="advanced-config" className="block text-sm font-medium text-gray-300 mb-2">
|
||||
Advanced Caddy Config (Optional)
|
||||
</label>
|
||||
<textarea
|
||||
id="advanced-config"
|
||||
value={formData.advanced_config}
|
||||
onChange={e => setFormData({ ...formData, advanced_config: e.target.value })}
|
||||
placeholder="Additional Caddy directives..."
|
||||
|
||||
@@ -149,4 +149,54 @@ describe('ProxyHostForm', () => {
|
||||
expect(sslCheckbox).toBeChecked()
|
||||
expect(wsCheckbox).toBeChecked()
|
||||
})
|
||||
|
||||
it('populates fields when remote server is selected', async () => {
|
||||
renderWithClient(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Local Docker Registry/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
const select = screen.getByRole('combobox', { name: /quick select/i })
|
||||
fireEvent.change(select, { target: { value: mockRemoteServers[0].uuid } })
|
||||
|
||||
expect(screen.getByDisplayValue(mockRemoteServers[0].host)).toBeInTheDocument()
|
||||
expect(screen.getByDisplayValue(mockRemoteServers[0].port)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('displays error message on submission failure', async () => {
|
||||
const mockErrorSubmit = vi.fn(() => Promise.reject(new Error('Submission failed')))
|
||||
renderWithClient(
|
||||
<ProxyHostForm onSubmit={mockErrorSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
fireEvent.change(screen.getByPlaceholderText('example.com, www.example.com'), {
|
||||
target: { value: 'test.com' },
|
||||
})
|
||||
fireEvent.change(screen.getByPlaceholderText('192.168.1.100'), {
|
||||
target: { value: 'localhost' },
|
||||
})
|
||||
fireEvent.change(screen.getByDisplayValue('80'), {
|
||||
target: { value: '8080' },
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByText('Create'))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Submission failed')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
it('handles advanced config input', async () => {
|
||||
renderWithClient(
|
||||
<ProxyHostForm onSubmit={mockOnSubmit} onCancel={mockOnCancel} />
|
||||
)
|
||||
|
||||
const advancedInput = screen.getByLabelText(/Advanced Caddy Config/i)
|
||||
fireEvent.change(advancedInput, { target: { value: 'header_up X-Test "True"' } })
|
||||
|
||||
expect(advancedInput).toHaveValue('header_up X-Test "True"')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||
import Setup from '../Setup';
|
||||
import * as setupApi from '../../api/setup';
|
||||
|
||||
// Mock react-router-dom
|
||||
const mockNavigate = vi.fn();
|
||||
vi.mock('react-router-dom', async () => {
|
||||
const actual = await vi.importActual('react-router-dom');
|
||||
return {
|
||||
...actual,
|
||||
useNavigate: () => mockNavigate,
|
||||
};
|
||||
});
|
||||
|
||||
// Mock the API module
|
||||
vi.mock('../../api/setup', () => ({
|
||||
getSetupStatus: vi.fn(),
|
||||
@@ -57,5 +67,61 @@ describe('Setup Page', () => {
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('Welcome to CPM+')).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockNavigate).toHaveBeenCalledWith('/login');
|
||||
});
|
||||
});
|
||||
|
||||
it('submits form successfully', async () => {
|
||||
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
|
||||
vi.mocked(setupApi.performSetup).mockResolvedValue();
|
||||
|
||||
renderWithProviders(<Setup />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Welcome to CPM+')).toBeTruthy();
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText('Name'), { target: { value: 'Admin' } });
|
||||
fireEvent.change(screen.getByLabelText('Email Address'), { target: { value: 'admin@example.com' } });
|
||||
fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'password123' } });
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Create Admin Account' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(setupApi.performSetup).toHaveBeenCalledWith({
|
||||
name: 'Admin',
|
||||
email: 'admin@example.com',
|
||||
password: 'password123',
|
||||
}, expect.anything());
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockNavigate).toHaveBeenCalledWith('/login');
|
||||
});
|
||||
});
|
||||
|
||||
it('displays error on submission failure', async () => {
|
||||
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
|
||||
vi.mocked(setupApi.performSetup).mockRejectedValue({
|
||||
response: { data: { error: 'Setup failed' } }
|
||||
});
|
||||
|
||||
renderWithProviders(<Setup />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Welcome to CPM+')).toBeTruthy();
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText('Name'), { target: { value: 'Admin' } });
|
||||
fireEvent.change(screen.getByLabelText('Email Address'), { target: { value: 'admin@example.com' } });
|
||||
fireEvent.change(screen.getByLabelText('Password'), { target: { value: 'password123' } });
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Create Admin Account' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Setup failed')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user