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;