feat(delete): shorten undo window to 20s and make undo toast dismissible

This commit is contained in:
Will Miao
2026-08-12 19:15:03 +08:00
parent 680f0a57f5
commit 1ca99294c9
15 changed files with 150 additions and 90 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ describe('translate() with real en.json locale', () => {
installWindowI18n();
expect(translate('modals.deleteModel.recoverableWarning')).toBe(
'This will permanently delete the file after 30 seconds unless you undo.',
'This will permanently delete the file after 20 seconds unless you undo.',
);
expect(translate('modals.deleteModel.freesSpace', { size: '1.2 MB' })).toBe(
'Frees 1.2 MB',
+31 -3
View File
@@ -133,14 +133,14 @@ describe('UI helper DOM utilities', () => {
const countdown = toast.querySelector('.toast-countdown');
expect(countdown).not.toBeNull();
expect(countdown.textContent).toBe('(30s)');
expect(countdown.textContent).toBe('(20s)');
// Ticking one second updates the countdown text
vi.advanceTimersByTime(1000);
expect(countdown.textContent).toBe('(29s)');
expect(countdown.textContent).toBe('(19s)');
// Drain remaining timers so no state leaks into other tests
vi.advanceTimersByTime(30000);
vi.advanceTimersByTime(20000);
});
it('invokes onAction once and dismisses immediately when the button is clicked', async () => {
@@ -186,6 +186,34 @@ describe('UI helper DOM utilities', () => {
expect(onAction).toHaveBeenCalledTimes(1);
});
it('dismisses the toast via the close button without firing onAction', async () => {
vi.useFakeTimers();
translateMock.mockReturnValue('Deleted Demo Model');
const { showActionToast } = await import(UI_HELPERS_MODULE);
const onAction = vi.fn();
showActionToast('toast.undo.deleted', {}, 'success', {
actionText: 'Undo',
onAction,
});
const toast = document.querySelector('.toast-container .toast');
const countdown = toast.querySelector('.toast-countdown');
toast.querySelector('.toast-close-btn').click();
expect(onAction).not.toHaveBeenCalled();
expect(toast.classList.contains('show')).toBe(false);
// Advancing past the full duration must not tick the countdown further,
// throw, or re-dismiss the already-dismissed toast
vi.advanceTimersByTime(60000);
expect(countdown.textContent).toBe('(20s)');
toast.dispatchEvent(new Event('transitionend', { bubbles: true }));
expect(document.querySelector('.toast-container .toast')).toBeNull();
});
it('dismisses the toast when the countdown reaches zero', async () => {
vi.useFakeTimers();
translateMock.mockReturnValue('Deleted Demo Model');