Fixed deleting files that are not open in the editor.

This commit is contained in:
David Lechner
2022-07-06 17:56:08 -05:00
parent 2ed784f4cd
commit 1e0d44bbe4
4 changed files with 51 additions and 31 deletions
+3
View File
@@ -4,6 +4,9 @@
## [Unreleased]
### Fixed
- Fixed deleting files that are not open in the editor.
## [2.0.0-beta.3] - 2022-07-06
### Changed
+38 -21
View File
@@ -14,6 +14,7 @@ import {
editorDidFailToActivateFile,
} from '../editor/actions';
import { EditorError } from '../editor/error';
import { UUID } from '../fileStorage';
import {
fileStorageCopyFile,
fileStorageDeleteFile,
@@ -471,31 +472,47 @@ describe('handleExplorerDeleteFile', () => {
);
});
describe('accepted', () => {
beforeEach(async () => {
saga.put(deleteFileAlertDidAccept());
describe.each([false, true])(
'accepted, file is open: %o',
(fileIsOpenInEditor: boolean) => {
beforeEach(async () => {
if (fileIsOpenInEditor) {
const openFileUuids: readonly UUID[] = [uuid(0)];
saga.updateState({ editor: { openFileUuids } });
}
// should close the editor first
await expect(saga.take()).resolves.toEqual(editorCloseFile(uuid(0)));
saga.put(editorDidCloseFile(uuid(0)));
saga.put(deleteFileAlertDidAccept());
// then delete the file
await expect(saga.take()).resolves.toEqual(fileStorageDeleteFile(testFile));
});
if (fileIsOpenInEditor) {
// should close the editor first
await expect(saga.take()).resolves.toEqual(
editorCloseFile(uuid(0)),
);
saga.put(editorDidCloseFile(uuid(0)));
}
it('should propagate error', async () => {
const testError = new Error('test error');
saga.put(fileStorageDidFailToDeleteFile(testFile, testError));
await expect(saga.take()).resolves.toEqual(
explorerDidFailToDeleteFile(testFile, testError),
);
});
// then delete the file
await expect(saga.take()).resolves.toEqual(
fileStorageDeleteFile(testFile),
);
});
it('should succeed', async () => {
saga.put(fileStorageDidDeleteFile(testFile));
await expect(saga.take()).resolves.toEqual(explorerDidDeleteFile(testFile));
});
});
it('should propagate error', async () => {
const testError = new Error('test error');
saga.put(fileStorageDidFailToDeleteFile(testFile, testError));
await expect(saga.take()).resolves.toEqual(
explorerDidFailToDeleteFile(testFile, testError),
);
});
it('should succeed', async () => {
saga.put(fileStorageDidDeleteFile(testFile));
await expect(saga.take()).resolves.toEqual(
explorerDidDeleteFile(testFile),
);
});
},
);
afterEach(async () => {
await saga.end();
+8 -3
View File
@@ -3,7 +3,7 @@
import { fileOpen, fileSave } from 'browser-fs-access';
import JSZip from 'jszip';
import { call, put, race, take, takeEvery } from 'typed-redux-saga/macro';
import { call, put, race, select, take, takeEvery } from 'typed-redux-saga/macro';
import { alertsShowAlert } from '../alerts/actions';
import {
editorActivateFile,
@@ -41,6 +41,7 @@ import {
pythonFileMimeType,
validateFileName,
} from '../pybricksMicropython/lib';
import { RootState } from '../reducers';
import { defined, ensureError, timestamp } from '../utils';
import {
explorerArchiveAllFiles,
@@ -405,9 +406,13 @@ function* handleExplorerDeleteFile(action: ReturnType<typeof explorerDeleteFile>
// at this point we know the user accepted
const openUuids = yield* select((s: RootState) => s.editor.openFileUuids);
// have to close editor before deleting, otherwise we get "in use" error
yield* put(editorCloseFile(action.uuid));
yield* take(editorDidCloseFile.when((a) => a.uuid === action.uuid));
if (openUuids.includes(action.uuid)) {
yield* put(editorCloseFile(action.uuid));
yield* take(editorDidCloseFile.when((a) => a.uuid === action.uuid));
}
yield* put(fileStorageDeleteFile(action.fileName));
+2 -7
View File
@@ -9,12 +9,7 @@ import userEvent from '@testing-library/user-event';
import type { UserEvent } from '@testing-library/user-event/dist/types/setup';
import React, { ReactElement } from 'react';
import { Provider } from 'react-redux';
import {
AnyAction,
DeepPartial,
PreloadedState,
legacy_createStore as createStore,
} from 'redux';
import { AnyAction, PreloadedState, legacy_createStore as createStore } from 'redux';
import { END, MulticastChannel, Saga, Task, runSaga, stdChannel } from 'redux-saga';
import { UUID } from '../src/fileStorage';
import { RootState, rootReducer } from '../src/reducers';
@@ -81,7 +76,7 @@ export class AsyncSaga {
return Promise.resolve(next);
}
public updateState(state: DeepPartial<RootState>): void {
public updateState(state: PreloadedState<RootState>): void {
for (const key of Object.keys(state) as Array<keyof RootState>) {
// @ts-expect-error: writing to readonly for testing
this.state[key] = { ...this.state[key], ...state[key] };