diff --git a/src/servers/DeleteServerModal.tsx b/src/servers/DeleteServerModal.tsx index e4561f22..1f1b65b0 100644 --- a/src/servers/DeleteServerModal.tsx +++ b/src/servers/DeleteServerModal.tsx @@ -1,3 +1,4 @@ +import type { ExitAction } from '@shlinkio/shlink-frontend-kit/tailwind'; import { CardModal } from '@shlinkio/shlink-frontend-kit/tailwind'; import type { FC } from 'react'; import { useCallback } from 'react'; @@ -14,10 +15,11 @@ type DeleteServerModalConnectProps = DeleteServerModalProps & { }; export const DeleteServerModal: FC = ({ server, onClose, open, deleteServer }) => { - const onConfirm = useCallback(() => { - deleteServer(server); - onClose(true); - }, [deleteServer, onClose, server]); + const onClosed = useCallback((exitAction: ExitAction) => { + if (exitAction === 'confirm') { + deleteServer(server); + } + }, [deleteServer, server]); return ( = ({ server, o title="Remove server" variant="danger" onClose={() => onClose(false)} - onConfirm={onConfirm} + onConfirm={() => onClose(true)} + onClosed={onClosed} confirmText="Delete" > -

Are you sure you want to remove {server ? server.name : ''}?

-

- - No data will be deleted, only the access to this server will be removed from this device. - You can create it again at any moment. - -

+
+

Are you sure you want to remove {server ? server.name : ''}?

+

+ + No data will be deleted, only the access to this server will be removed from this device. + You can create it again at any moment. + +

+
); }; diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx index 30fd5717..503c7736 100644 --- a/src/servers/helpers/ImportServersBtn.tsx +++ b/src/servers/helpers/ImportServersBtn.tsx @@ -47,8 +47,9 @@ const ImportServersBtn: FCWithDeps { createServers(serversData); + hideModal(); onImport(); - }, [createServers, onImport]); + }, [createServers, hideModal, onImport]); const onFile = useCallback( async ({ target }: ChangeEvent) => serversImporter.importServersFromFile(target.files?.[0]) @@ -73,14 +74,8 @@ const ImportServersBtn: FCWithDeps { - create(importedServersRef.current); - hideModal(); - }, [create, hideModal]); - const createNonDuplicatedServers = useCallback(() => { - create(newServersRef.current); - hideModal(); - }, [create, hideModal]); + const createAllServers = useCallback(() => create(importedServersRef.current), [create]); + const createNonDuplicatedServers = useCallback(() => create(newServersRef.current), [create]); return ( <> diff --git a/test/__helpers__/TestModalWrapper.tsx b/test/__helpers__/TestModalWrapper.tsx index 28ade53a..6f33b5aa 100644 --- a/test/__helpers__/TestModalWrapper.tsx +++ b/test/__helpers__/TestModalWrapper.tsx @@ -1,5 +1,5 @@ import type { FC, ReactElement } from 'react'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect , useState } from 'react'; export type RenderModalArgs = { open: boolean; @@ -12,5 +12,13 @@ export const TestModalWrapper: FC<{ renderModal: (args: RenderModalArgs) => Reac const [open, setOpen] = useState(true); const onClose = useCallback(() => setOpen(false), []); + // Workaround to ensure CardModals from shlink-frontend-shared can be closed, as they depend on CSS transitions + // Since JSDOM does not support them, this dispatches the event right after the listener has been set-up + useEffect(() => { + if (!open) { + document.querySelector('[data-testid="transition-container"]')?.dispatchEvent(new Event('transitionend')); + } + }, [open]); + return renderModal({ open, onClose }); }; diff --git a/test/servers/DeleteServerModal.test.tsx b/test/servers/DeleteServerModal.test.tsx index dfc24a1b..c2d6b7bb 100644 --- a/test/servers/DeleteServerModal.test.tsx +++ b/test/servers/DeleteServerModal.test.tsx @@ -1,4 +1,4 @@ -import { screen, waitFor } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; import { DeleteServerModal } from '../../src/servers/DeleteServerModal'; import { checkAccessibility } from '../__helpers__/accessibility'; @@ -36,13 +36,15 @@ describe('', () => { expect(screen.getByText(serverName)).toBeInTheDocument(); }); - it.each([ + it.only.each([ [() => screen.getByRole('button', { name: 'Cancel' })], [() => screen.getByLabelText('Close dialog')], - ])('toggles when clicking cancel button', async (getButton) => { + ])('closes dialog when clicking cancel button', async (getButton) => { const { user } = setUp(); + expect(screen.getByRole('dialog')).toBeInTheDocument(); await user.click(getButton()); + expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); expect(deleteServerMock).not.toHaveBeenCalled(); }); @@ -51,7 +53,6 @@ describe('', () => { expect(deleteServerMock).not.toHaveBeenCalled(); await user.click(screen.getByRole('button', { name: 'Delete' })); - - await waitFor(() => expect(deleteServerMock).toHaveBeenCalledTimes(1)); + expect(deleteServerMock).toHaveBeenCalledOnce(); }); }); diff --git a/vite.config.ts b/vite.config.ts index 3c5e44b3..6ebdefc6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -60,6 +60,9 @@ export default defineConfig({ }, }, + // Silent warnings triggered by reactstrap components, as it's getting removed + onConsoleLog: (log) => !log.includes('`transition.timeout` is marked as required'), + // Workaround for bug in react-router (or vitest module resolution) which causes different react-router versions to // be resolved for the main package and dependencies who have a peer dependency in react-router. // This ensures always the same version is resolved.