diff --git a/src/containers/Edit.test.tsx b/src/containers/Edit.test.tsx new file mode 100644 index 00000000..2d98f32d --- /dev/null +++ b/src/containers/Edit.test.tsx @@ -0,0 +1,221 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { StoreProvider, createStore } from 'easy-peasy'; +import Edit from './Edit'; +import { StoreModel } from '../store/model'; + +// Mock Monaco Editor +vi.mock('@monaco-editor/react', () => ({ + default: vi.fn(({ options, value }) => ( +
+ {value} +
+ )), + loader: { + init: vi.fn(() => Promise.resolve({ + languages: { + register: vi.fn(), + setMonarchTokensProvider: vi.fn(), + }, + })), + }, +})); + +describe('Edit', () => { + let store: any; + + beforeEach(() => { + // Create a minimal store with the necessary state + store = createStore>({ + app: { + selectedFile: { + fileName: 'test.in', + content: 'units lj\natom_style atomic', + url: '', + }, + setSelectedFile: vi.fn(), + setStatus: vi.fn(), + }, + simulation: { + running: false, + paused: false, + showConsole: false, + files: [], + lammpsOutput: [], + simulation: { + id: 'test-sim', + files: [ + { + fileName: 'test.in', + content: 'units lj\natom_style atomic', + url: '', + }, + ], + inputScript: 'test.in', + start: false, + }, + resetLammpsOutput: vi.fn(), + addLammpsOutput: vi.fn(), + setShowConsole: vi.fn(), + setPaused: vi.fn(), + setCameraPosition: vi.fn(), + setCameraTarget: vi.fn(), + setSimulation: vi.fn(), + setRunning: vi.fn(), + setFiles: vi.fn(), + setLammps: vi.fn(), + extractAndApplyAtomifyCommands: vi.fn(), + syncFilesWasm: vi.fn(), + syncFilesJupyterLite: vi.fn(), + run: vi.fn(), + newSimulation: vi.fn(), + reset: vi.fn(), + }, + } as any); + }); + + it('should render editor when file is selected', () => { + // Arrange & Act + render( + + + + ); + + // Assert + expect(screen.getByTestId('monaco-editor')).toBeInTheDocument(); + expect(screen.getByTestId('monaco-editor')).toHaveTextContent('units lj'); + }); + + it('should render "No file selected" when no file is selected', () => { + // Arrange + store = createStore({ + app: { + selectedFile: undefined, + setSelectedFile: vi.fn(), + setStatus: vi.fn(), + }, + simulation: { + running: false, + paused: false, + showConsole: false, + files: [], + lammpsOutput: [], + resetLammpsOutput: vi.fn(), + addLammpsOutput: vi.fn(), + setShowConsole: vi.fn(), + setPaused: vi.fn(), + setCameraPosition: vi.fn(), + setCameraTarget: vi.fn(), + setSimulation: vi.fn(), + setRunning: vi.fn(), + setFiles: vi.fn(), + setLammps: vi.fn(), + extractAndApplyAtomifyCommands: vi.fn(), + syncFilesWasm: vi.fn(), + syncFilesJupyterLite: vi.fn(), + run: vi.fn(), + newSimulation: vi.fn(), + reset: vi.fn(), + }, + } as any); + + // Act + render( + + + + ); + + // Assert + expect(screen.getByText('No file selected')).toBeInTheDocument(); + expect(screen.queryByTestId('monaco-editor')).not.toBeInTheDocument(); + }); + + it('should be editable when simulation is not running', () => { + // Arrange + store.getState().simulation.running = false; + + // Act + render( + + + + ); + + // Assert + const editor = screen.getByTestId('monaco-editor'); + expect(editor).toHaveAttribute('data-readonly', 'false'); + }); + + it('should be read-only when simulation is running', () => { + // Arrange + store.getState().simulation.running = true; + + // Act + render( + + + + ); + + // Assert + const editor = screen.getByTestId('monaco-editor'); + expect(editor).toHaveAttribute('data-readonly', 'true'); + }); + + it('should show notification banner when simulation is running', () => { + // Arrange + store.getState().simulation.running = true; + + // Act + render( + + + + ); + + // Assert + expect(screen.getByText(/File editing is disabled while simulation is running/i)).toBeInTheDocument(); + }); + + it('should not show notification banner when simulation is not running', () => { + // Arrange + store.getState().simulation.running = false; + + // Act + render( + + + + ); + + // Assert + expect(screen.queryByText(/File editing is disabled while simulation is running/i)).not.toBeInTheDocument(); + }); + + it('should update content when file content changes', () => { + // Arrange + const { rerender } = render( + + + + ); + + // Act - Update the selected file content + store.getState().app.selectedFile = { + fileName: 'test.in', + content: 'units metal\natom_style full', + url: '', + }; + + rerender( + + + + ); + + // Assert + expect(screen.getByTestId('monaco-editor')).toHaveTextContent('units metal'); + }); +}); diff --git a/src/containers/Edit.tsx b/src/containers/Edit.tsx index 927d95c6..169d2d97 100644 --- a/src/containers/Edit.tsx +++ b/src/containers/Edit.tsx @@ -1415,8 +1415,10 @@ loader.init().then((monaco) => { const Edit = () => { const selectedFile = useStoreState((state) => state.app.selectedFile); const simulation = useStoreState((state) => state.simulation.simulation); + const isRunning = useStoreState((state) => state.simulation.running); const options = { selectOnLineNumbers: true, + readOnly: isRunning, }; const handleEditorDidMount = useCallback( @@ -1444,15 +1446,31 @@ const Edit = () => { } return ( - + <> + {isRunning && ( +
+ ⓘ File editing is disabled while simulation is running +
+ )} + + ); }; export default Edit;