diff --git a/client/test/preview/integration/components/asset/AssetBoard.test.tsx b/client/test/preview/integration/components/asset/AssetBoard.test.tsx index 17b3e204a..5bb51fac5 100644 --- a/client/test/preview/integration/components/asset/AssetBoard.test.tsx +++ b/client/test/preview/integration/components/asset/AssetBoard.test.tsx @@ -119,4 +119,19 @@ describe('AssetBoard Integration Tests', () => { expect(screen.queryByText('Asset 1')).not.toBeInTheDocument(); }); }); + + it('shows an error message', async () => { + const error = 'An error occurred'; + jest.spyOn(React, 'useState').mockReturnValue([error, jest.fn()]); + + act(() => { + render( + + + , + ); + }); + + expect(screen.getByText(error)).toBeInTheDocument(); + }); }); diff --git a/client/test/preview/integration/route/digitaltwins/create/ChangeFileNameDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/create/ChangeFileNameDialog.test.tsx new file mode 100644 index 000000000..a860a4904 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/ChangeFileNameDialog.test.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import ChangeFileNameDialog from 'preview/route/digitaltwins/create/ChangeFileNameDialog'; +import { Provider } from 'react-redux'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import fileSlice from 'preview/store/file.slice'; +import { act } from 'react'; + +const store = configureStore({ + reducer: combineReducers({ + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('ChangeFileNameDialog', () => { + const setShowDialog = jest.fn(); + const setFileName = jest.fn(); + const setFileType = jest.fn(); + const fileName = 'testName'; + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('handles click on change button', () => { + const changeButton = screen.getByRole('button', { name: /Change/i }); + act(() => { + changeButton.click(); + }); + + expect(setFileName).toHaveBeenCalled(); + expect(setFileType).toHaveBeenCalled(); + }); + + it('handles click on cancel button', () => { + const cancelButton = screen.getByRole('button', { name: /Cancel/i }); + act(() => { + cancelButton.click(); + }); + + expect(setShowDialog).toHaveBeenCalled(); + }); + + it('handles change in text field', () => { + const textField = screen.getByRole('textbox'); + + act(() => { + fireEvent.change(textField, { + target: { value: 'modifiedDTName' }, + }); + }); + + waitFor(() => { + expect(textField).toHaveValue('modifiedDTName'); + }); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/create/ConfirmDeleteDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/create/ConfirmDeleteDialog.test.tsx new file mode 100644 index 000000000..b92aefe97 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/ConfirmDeleteDialog.test.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import ConfirmDeleteDialog from 'preview/route/digitaltwins/create/ConfirmDeleteDialog'; +import { act } from 'react'; +import { render, screen } from '@testing-library/react'; +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import { Provider } from 'react-redux'; +import fileSlice, { addOrUpdateFile } from 'preview/store/file.slice'; + +const store = configureStore({ + reducer: combineReducers({ + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('ConfirmDeleteDialog', () => { + const setOpenConfirmDeleteDialog = jest.fn(); + const setFileName = jest.fn(); + const setFileContent = jest.fn(); + const setFileType = jest.fn(); + const setNewDigitalTwinName = jest.fn(); + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('handles fileExists functionality', () => { + const file = { + name: 'description.md', + content: 'test', + isNew: true, + isModified: false, + }; + + act(() => { + store.dispatch(addOrUpdateFile(file)); + }); + + const yesButton = screen.getByRole('button', { name: /Yes/i }); + act(() => { + yesButton.click(); + }); + + expect(setOpenConfirmDeleteDialog).toHaveBeenCalled(); + }); + + it('handles cancel', () => { + const cancelButton = screen.getByRole('button', { name: /Cancel/i }); + + act(() => { + cancelButton.click(); + }); + + expect(setOpenConfirmDeleteDialog).toHaveBeenCalled(); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/create/CreateDTDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/create/CreateDTDialog.test.tsx new file mode 100644 index 000000000..b692143a0 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/CreateDTDialog.test.tsx @@ -0,0 +1,118 @@ +import * as React from 'react'; +import CreateDTDialog from 'preview/route/digitaltwins/create/CreateDTDialog'; +import { act, render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import fileSlice from 'preview/store/file.slice'; +import { validateFiles } from 'preview/util/fileUtils'; +import { initDigitalTwin } from 'preview/util/init'; + +jest.mock('preview/util/fileUtils', () => ({ + validateFiles: jest.fn(), + addDefaultFiles: jest.fn(), +})); +jest.mock('preview/util/init', () => ({ + initDigitalTwin: jest.fn(), +})); + +const store = configureStore({ + reducer: combineReducers({ + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('CreateDTDialog - handleConfirm function', () => { + const newDigitalTwinName = 'newDTName'; + const errorMessage = ''; + const setOpenCreateDTDialog = jest.fn(); + const setNewDigitalTwinName = jest.fn(); + const setErrorMessage = jest.fn(); + const setFileName = jest.fn(); + const setFileContent = jest.fn(); + const setFileType = jest.fn(); + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('does not proceed if file validation fails', async () => { + (validateFiles as jest.Mock).mockReturnValue(true); + + const confirmButton = screen.getByRole('button', { name: /Confirm/i }); + await act(async () => { + confirmButton.click(); + }); + + expect(validateFiles).toHaveBeenCalled(); + expect(initDigitalTwin).not.toHaveBeenCalled(); + }); + + it('handles error if digitalTwin.create returns an error', async () => { + (validateFiles as jest.Mock).mockReturnValue(false); + const mockDigitalTwin = { + create: jest.fn().mockResolvedValue('Error: creation failed'), + }; + (initDigitalTwin as jest.Mock).mockResolvedValue(mockDigitalTwin); + + const confirmButton = screen.getByRole('button', { name: /Confirm/i }); + await act(async () => { + confirmButton.click(); + }); + + expect(initDigitalTwin).toHaveBeenCalledWith(newDigitalTwinName); + expect(mockDigitalTwin.create).toHaveBeenCalled(); + }); + + it('handles success if digitalTwin.create is successful', async () => { + (validateFiles as jest.Mock).mockReturnValue(false); + const mockDigitalTwin = { create: jest.fn().mockResolvedValue('Success') }; + (initDigitalTwin as jest.Mock).mockResolvedValue(mockDigitalTwin); + + const confirmButton = screen.getByRole('button', { name: /Confirm/i }); + await act(async () => { + confirmButton.click(); + }); + + expect(initDigitalTwin).toHaveBeenCalledWith(newDigitalTwinName); + expect(mockDigitalTwin.create).toHaveBeenCalled(); + }); + + it('resets dialog after clicking cancel', async () => { + const cancelButton = screen.getByRole('button', { name: /Cancel/i }); + await act(async () => { + cancelButton.click(); + }); + + expect(setOpenCreateDTDialog).toHaveBeenCalled(); + expect(setFileName).toHaveBeenCalledWith(''); + expect(setFileContent).toHaveBeenCalledWith(''); + expect(setFileType).toHaveBeenCalledWith(''); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/create/CreatePage.test.tsx b/client/test/preview/integration/route/digitaltwins/create/CreatePage.test.tsx new file mode 100644 index 000000000..3ad183e3f --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/CreatePage.test.tsx @@ -0,0 +1,99 @@ +import * as React from 'react'; +import CreatePage from 'preview/route/digitaltwins/create/CreatePage'; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import digitalTwinReducer from 'preview/store/digitalTwin.slice'; +import snackbarSlice from 'preview/store/snackbar.slice'; +import fileSlice from 'preview/store/file.slice'; + +const store = configureStore({ + reducer: combineReducers({ + digitalTwin: digitalTwinReducer, + snackbar: snackbarSlice, + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('CreatePage', () => { + const setNewDigitalTwinName = jest.fn(); + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + /* + it('renders CreatePage', () => { + expect(screen.getByText('Please select a file to edit')).toBeInTheDocument(); + }); + */ + + it('handles cancel when clicking on cancel button and confirm', () => { + act(() => { + screen.getByText('Cancel').click(); + }); + + expect( + screen.getByText( + 'Are you sure you want to delete the inserted files and their content?', + ), + ).toBeInTheDocument(); + + act(() => { + screen.getByText('Yes').click(); + }); + + expect(setNewDigitalTwinName).toHaveBeenCalled(); + }); + + it('opens confirm dialog when clicking on save button', () => { + act(() => { + screen.getByText('Save').click(); + }); + + expect( + screen.getByText(/Are you sure you want to create/i), + ).toBeInTheDocument(); + }); + + it('changes the digital twin name', () => { + const textField = screen.getByRole('textbox'); + + act(() => { + fireEvent.change(textField, { + target: { value: 'modifiedDTName' }, + }); + }); + + waitFor(() => { + expect(textField).toHaveValue('modifiedDTName'); + }); + expect(setNewDigitalTwinName).toHaveBeenCalled(); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/create/DeleteFileDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/create/DeleteFileDialog.test.tsx new file mode 100644 index 000000000..8a3b9c812 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/DeleteFileDialog.test.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import DeleteFileDialog from 'preview/route/digitaltwins/create/DeleteFileDialog'; +import { render, screen } from '@testing-library/react'; +import { Provider } from 'react-redux'; +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import fileSlice from 'preview/store/file.slice'; +import { act } from 'react'; + +const store = configureStore({ + reducer: combineReducers({ + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('DeleteFileDialog', () => { + const setOpenDeleteFileDialog = jest.fn(); + const setFileName = jest.fn(); + const setFileContent = jest.fn(); + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('handles click on yes button', () => { + const yesButton = screen.getByRole('button', { name: /Yes/i }); + act(() => { + yesButton.click(); + }); + + expect(setFileName).toHaveBeenCalled(); + expect(setFileContent).toHaveBeenCalled(); + }); + + it('handles click on no button', () => { + const noButton = screen.getByRole('button', { name: /No/i }); + act(() => { + noButton.click(); + }); + + expect(setOpenDeleteFileDialog).toHaveBeenCalled(); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/create/FileActionButtons.test.tsx b/client/test/preview/integration/route/digitaltwins/create/FileActionButtons.test.tsx new file mode 100644 index 000000000..27bc2e8d9 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/create/FileActionButtons.test.tsx @@ -0,0 +1,45 @@ +import { render, screen } from '@testing-library/react'; +import FileActionButtons from 'preview/route/digitaltwins/create/FileActionButtons'; +import * as React from 'react'; +import { act } from 'react'; + +describe('FileActionButtons', () => { + const setOpenDeleteFileDialog = jest.fn(); + const setOpenChangeFileNameDialog = jest.fn(); + + beforeEach(() => { + act(() => { + render( + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('handles click on delete button', () => { + const deleteButton = screen.getByRole('button', { name: /Delete/i }); + act(() => { + deleteButton.click(); + }); + + expect(setOpenDeleteFileDialog).toHaveBeenCalled(); + }); + + it('handles click on change file name button', () => { + const changeFileNameButton = screen.getByRole('button', { + name: /Change file name/i, + }); + act(() => { + changeFileNameButton.click(); + }); + + expect(setOpenChangeFileNameDialog).toHaveBeenCalled(); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/editor/Sidebar.test.tsx b/client/test/preview/integration/route/digitaltwins/editor/Sidebar.test.tsx index ee93add0a..8b983926d 100644 --- a/client/test/preview/integration/route/digitaltwins/editor/Sidebar.test.tsx +++ b/client/test/preview/integration/route/digitaltwins/editor/Sidebar.test.tsx @@ -20,6 +20,7 @@ import { Provider } from 'react-redux'; import * as React from 'react'; import { mockGitlabInstance } from 'test/preview/__mocks__/global_mocks'; import DigitalTwin from 'preview/util/digitalTwin'; +import * as SidebarFunctions from 'preview/route/digitaltwins/editor/sidebarFunctions'; describe('Sidebar', () => { const setFileNameMock = jest.fn(); @@ -119,7 +120,13 @@ describe('Sidebar', () => { setupDigitalTwin('Asset 1'); store.dispatch(setDigitalTwin({ assetName: 'Asset 1', digitalTwin })); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + it('calls handleFileClick when a file type is clicked', async () => { await act(async () => { render( @@ -133,13 +140,87 @@ describe('Sidebar', () => { , ); }); + + await performFileTests(); }); - afterEach(() => { - jest.clearAllMocks(); + it('calls handle addFileCkick when add file is clicked', async () => { + const handleAddFileClick = jest.spyOn( + SidebarFunctions, + 'handleAddFileClick', + ); + + await act(async () => { + render( + + + , + ); + }); + + const addFile = screen.getByText('Add new file'); + await act(async () => { + fireEvent.click(addFile); + }); + + await waitFor(() => { + expect(handleAddFileClick).toHaveBeenCalled(); + }); }); - it('calls handleFileClick when a file type is clicked', async () => { - await performFileTests(); + it('should open the sidebar dialog when a new file is added', async () => { + await act(async () => { + render( + + + , + ); + }); + + const addFile = screen.getByText('Add new file'); + act(() => { + fireEvent.click(addFile); + }); + + waitFor(() => { + expect(screen.getByText('Enter the file name')).toBeInTheDocument(); + }); + }); + + it('renders file section when no digital twin is selected', async () => { + await act(async () => { + render( + + + , + ); + }); + + const lifecycle = screen.getByText('Lifecycle'); + act(() => { + fireEvent.click(lifecycle); + }); + + waitFor(() => { + expect(screen.getByText('Asset 1')).toBeInTheDocument(); + }); }); }); diff --git a/client/test/preview/integration/route/digitaltwins/editor/SidebarDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/editor/SidebarDialog.test.tsx new file mode 100644 index 000000000..0788106fc --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/editor/SidebarDialog.test.tsx @@ -0,0 +1,87 @@ +import { + combineReducers, + configureStore, + getDefaultMiddleware, +} from '@reduxjs/toolkit'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import SidebarDialog from 'preview/route/digitaltwins/editor/SidebarDialog'; +import fileSlice from 'preview/store/file.slice'; +import * as React from 'react'; +import { act } from 'react'; +import { Provider } from 'react-redux'; + +const store = configureStore({ + reducer: combineReducers({ + files: fileSlice, + }), + middleware: getDefaultMiddleware({ + serializableCheck: false, + }), +}); + +describe('SidebarDialog', () => { + const setNewFileName = jest.fn(); + const setIsFileNameDialogOpen = jest.fn(); + const setErrorMessage = jest.fn(); + + beforeEach(() => { + act(() => { + render( + + + , + ); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should handle click on cancel button', () => { + const cancelButton = screen.getByText('Cancel'); + + act(() => { + cancelButton.click(); + }); + + expect(setIsFileNameDialogOpen).toHaveBeenCalledTimes(1); + expect(setNewFileName).toHaveBeenCalledTimes(1); + expect(setErrorMessage).toHaveBeenCalledTimes(1); + }); + + it('should handle click on add button', () => { + const addButton = screen.getByText('Add'); + + act(() => { + addButton.click(); + }); + + expect(setErrorMessage).toHaveBeenCalledTimes(1); + }); + + it('should handle change in file name', () => { + const textField = screen.getByRole('textbox'); + + act(() => { + fireEvent.change(textField, { + target: { value: 'modifiedFileName' }, + }); + }); + + waitFor(() => { + expect(textField).toHaveValue('modifiedFileName'); + }); + + expect(setNewFileName).toHaveBeenCalledTimes(1); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/editor/SidebarFunctions.test.tsx b/client/test/preview/integration/route/digitaltwins/editor/SidebarFunctions.test.tsx new file mode 100644 index 000000000..5bd70e607 --- /dev/null +++ b/client/test/preview/integration/route/digitaltwins/editor/SidebarFunctions.test.tsx @@ -0,0 +1,142 @@ +import { + handleFileClick, + handleFileSubmit, +} from 'preview/route/digitaltwins/editor/sidebarFunctions'; +import DigitalTwin from 'preview/util/digitalTwin'; +import { FileState, addOrUpdateFile } from 'preview/store/file.slice'; +import { mockGitlabInstance } from 'test/preview/__mocks__/global_mocks'; +import { useDispatch } from 'react-redux'; + +describe('File Click Handlers', () => { + const mockSetFileName = jest.fn(); + const mockSetFileContent = jest.fn(); + const mockSetFileType = jest.fn(); + + const mockDigitalTwin = new DigitalTwin('Asset 1', mockGitlabInstance); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('calls handleCreateFileClick if tab is "create"', () => { + const fileName = 'example.md'; + const files: FileState[] = [ + { name: fileName, content: 'content', isNew: true, isModified: false }, + ]; + + handleFileClick( + fileName, + null, + mockSetFileName, + mockSetFileContent, + mockSetFileType, + files, + 'create', + ); + expect(mockSetFileName).toHaveBeenCalledWith(fileName); + expect(mockSetFileContent).toHaveBeenCalledWith('content'); + }); + + it('calls handleReconfigureFileClick if tab is "reconfigure"', () => { + const fileName = 'example.json'; + const files: FileState[] = [ + { name: fileName, content: 'content', isNew: false, isModified: true }, + ]; + + handleFileClick( + fileName, + mockDigitalTwin, + mockSetFileName, + mockSetFileContent, + mockSetFileType, + files, + 'reconfigure', + ); + expect(mockSetFileName).toHaveBeenCalledWith(fileName); + expect(mockSetFileContent).toHaveBeenCalledWith('content'); + }); +}); + +jest.mock('react-redux', () => ({ + useDispatch: jest.fn(), +})); + +describe('handleFileSubmit', () => { + const mockSetErrorMessage = jest.fn(); + const mockSetIsFileNameDialogOpen = jest.fn(); + const mockSetNewFileName = jest.fn(); + const dispatch = jest.fn(); + + (useDispatch as jest.Mock).mockReturnValue(dispatch); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('dispatches addOrUpdateFile if new file name does not exist', () => { + const files: FileState[] = [ + { name: 'existingFile.md', content: '', isNew: true, isModified: false }, + ]; + const newFileName = 'newFile.md'; + + handleFileSubmit( + files, + newFileName, + mockSetErrorMessage, + dispatch, + mockSetIsFileNameDialogOpen, + mockSetNewFileName, + ); + expect(dispatch).toHaveBeenCalledWith( + addOrUpdateFile({ + name: newFileName, + content: '', + isNew: true, + isModified: false, + type: 'description', + }), + ); + expect(mockSetIsFileNameDialogOpen).toHaveBeenCalledWith(false); + expect(mockSetNewFileName).toHaveBeenCalledWith(''); + }); + + it('sets error message if file name already exists', () => { + const files: FileState[] = [ + { name: 'existingFile.md', content: '', isNew: true, isModified: false }, + ]; + const newFileName = 'existingFile.md'; + + handleFileSubmit( + files, + newFileName, + mockSetErrorMessage, + dispatch, + mockSetIsFileNameDialogOpen, + mockSetNewFileName, + ); + expect(mockSetErrorMessage).toHaveBeenCalledWith( + 'A file with this name already exists.', + ); + expect(dispatch).not.toHaveBeenCalled(); + }); + + it('sets error message if file name is empty', () => { + const files: FileState[] = [ + { name: 'existingFile.md', content: '', isNew: true, isModified: false }, + ]; + const newFileName = ''; + + handleFileSubmit( + files, + newFileName, + mockSetErrorMessage, + dispatch, + mockSetIsFileNameDialogOpen, + mockSetNewFileName, + ); + expect(mockSetErrorMessage).toHaveBeenCalledWith( + "File name can't be empty.", + ); + expect(dispatch).not.toHaveBeenCalled(); + }); +}); diff --git a/client/test/preview/integration/route/digitaltwins/manage/ConfigDialog.test.tsx b/client/test/preview/integration/route/digitaltwins/manage/ConfigDialog.test.tsx index 1c31c8f7f..9db5258ed 100644 --- a/client/test/preview/integration/route/digitaltwins/manage/ConfigDialog.test.tsx +++ b/client/test/preview/integration/route/digitaltwins/manage/ConfigDialog.test.tsx @@ -7,7 +7,10 @@ import { mockGitlabInstance } from 'test/preview/__mocks__/global_mocks'; import { showSnackbar } from 'preview/store/snackbar.slice'; import * as ReconfigureDialog from 'preview/route/digitaltwins/manage/ReconfigureDialog'; import FileHandler from 'preview/util/fileHandler'; -import { addOrUpdateFile } from 'preview/store/file.slice'; +import { + addOrUpdateFile, + removeAllModifiedFiles, +} from 'preview/store/file.slice'; import setupStore from './utils'; jest.useFakeTimers(); @@ -18,10 +21,13 @@ jest.mock('preview/util/init', () => ({ describe('ReconfigureDialog', () => { let storeConfig: ReturnType; + let dispatchSpy: jest.SpyInstance; beforeEach(() => { storeConfig = setupStore(); + dispatchSpy = jest.spyOn(storeConfig, 'dispatch'); + React.act(() => { render( @@ -81,6 +87,8 @@ describe('ReconfigureDialog', () => { await waitFor(() => { expect(screen.queryByText('Editor')).toBeNull(); }); + + expect(dispatchSpy).toHaveBeenCalledWith(removeAllModifiedFiles()); }); it('updates the description when description.md is modified', async () => {