Just make a copy when adding a new profile

This commit is contained in:
Matt Rubens
2025-01-07 23:57:56 -05:00
parent 16495560d7
commit 11612caac0
2 changed files with 158 additions and 4 deletions

View File

@@ -36,9 +36,9 @@ const ApiConfigManager = ({
setInputValue("");
}, [currentApiConfigName]);
const handleStartNew = () => {
setEditState('new');
setInputValue("");
const handleAdd = () => {
const newConfigName = currentApiConfigName + " (copy)";
onUpsertConfig(newConfigName);
};
const handleStartRename = () => {
@@ -162,7 +162,7 @@ const ApiConfigManager = ({
</select>
<VSCodeButton
appearance="icon"
onClick={handleStartNew}
onClick={handleAdd}
title="Add profile"
style={{
padding: 0,

View File

@@ -0,0 +1,154 @@
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import ApiConfigManager from '../ApiConfigManager';
// Mock VSCode components
jest.mock('@vscode/webview-ui-toolkit/react', () => ({
VSCodeButton: ({ children, onClick, title, disabled }: any) => (
<button onClick={onClick} title={title} disabled={disabled}>
{children}
</button>
),
VSCodeTextField: ({ value, onInput, placeholder }: any) => (
<input
value={value}
onChange={e => onInput(e)}
placeholder={placeholder}
ref={undefined} // Explicitly set ref to undefined to avoid warning
/>
),
}));
describe('ApiConfigManager', () => {
const mockOnSelectConfig = jest.fn();
const mockOnDeleteConfig = jest.fn();
const mockOnRenameConfig = jest.fn();
const mockOnUpsertConfig = jest.fn();
const defaultProps = {
currentApiConfigName: 'Default Config',
listApiConfigMeta: [
{ name: 'Default Config' },
{ name: 'Another Config' }
],
onSelectConfig: mockOnSelectConfig,
onDeleteConfig: mockOnDeleteConfig,
onRenameConfig: mockOnRenameConfig,
onUpsertConfig: mockOnUpsertConfig,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('immediately creates a copy when clicking add button', () => {
render(<ApiConfigManager {...defaultProps} />);
// Find and click the add button
const addButton = screen.getByTitle('Add profile');
fireEvent.click(addButton);
// Verify that onUpsertConfig was called with the correct name
expect(mockOnUpsertConfig).toHaveBeenCalledTimes(1);
expect(mockOnUpsertConfig).toHaveBeenCalledWith('Default Config (copy)');
});
it('creates copy with correct name when current config has spaces', () => {
render(
<ApiConfigManager
{...defaultProps}
currentApiConfigName="My Test Config"
/>
);
const addButton = screen.getByTitle('Add profile');
fireEvent.click(addButton);
expect(mockOnUpsertConfig).toHaveBeenCalledWith('My Test Config (copy)');
});
it('handles empty current config name gracefully', () => {
render(
<ApiConfigManager
{...defaultProps}
currentApiConfigName=""
/>
);
const addButton = screen.getByTitle('Add profile');
fireEvent.click(addButton);
expect(mockOnUpsertConfig).toHaveBeenCalledWith(' (copy)');
});
it('allows renaming the current config', () => {
render(<ApiConfigManager {...defaultProps} />);
// Start rename
const renameButton = screen.getByTitle('Rename profile');
fireEvent.click(renameButton);
// Find input and enter new name
const input = screen.getByDisplayValue('Default Config');
fireEvent.input(input, { target: { value: 'New Name' } });
// Save
const saveButton = screen.getByTitle('Save');
fireEvent.click(saveButton);
expect(mockOnRenameConfig).toHaveBeenCalledWith('Default Config', 'New Name');
});
it('allows selecting a different config', () => {
render(<ApiConfigManager {...defaultProps} />);
const select = screen.getByRole('combobox');
fireEvent.change(select, { target: { value: 'Another Config' } });
expect(mockOnSelectConfig).toHaveBeenCalledWith('Another Config');
});
it('allows deleting the current config when not the only one', () => {
render(<ApiConfigManager {...defaultProps} />);
const deleteButton = screen.getByTitle('Delete profile');
expect(deleteButton).not.toBeDisabled();
fireEvent.click(deleteButton);
expect(mockOnDeleteConfig).toHaveBeenCalledWith('Default Config');
});
it('disables delete button when only one config exists', () => {
render(
<ApiConfigManager
{...defaultProps}
listApiConfigMeta={[{ name: 'Default Config' }]}
/>
);
const deleteButton = screen.getByTitle('Cannot delete the only profile');
expect(deleteButton).toHaveAttribute('disabled');
});
it('cancels rename operation when clicking cancel', () => {
render(<ApiConfigManager {...defaultProps} />);
// Start rename
const renameButton = screen.getByTitle('Rename profile');
fireEvent.click(renameButton);
// Find input and enter new name
const input = screen.getByDisplayValue('Default Config');
fireEvent.input(input, { target: { value: 'New Name' } });
// Cancel
const cancelButton = screen.getByTitle('Cancel');
fireEvent.click(cancelButton);
// Verify rename was not called
expect(mockOnRenameConfig).not.toHaveBeenCalled();
// Verify we're back to normal view
expect(screen.queryByDisplayValue('New Name')).not.toBeInTheDocument();
});
});