From 87176b124b4b6474620ad7f36a66058e8ed6fb2e Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Thu, 18 Apr 2024 20:09:20 +0200 Subject: [PATCH] Test PendingEditContext --- src/contexts/PendingEditContext.test.ts | 45 +++++++++++++++++ src/contexts/PendingEditContext.tsx | 48 +++++++------------ .../component/{ => Layout}/LangSelector.tsx | 4 +- .../Layout/PendingEditSyncButton.tsx | 30 ++++++++++++ .../component/{ => Layout}/ThemeSelector.tsx | 6 +-- .../RawSqlResult/RowDataPacketResult.tsx | 2 +- src/renderer/routes/root.tsx | 12 ++--- 7 files changed, 102 insertions(+), 45 deletions(-) create mode 100644 src/contexts/PendingEditContext.test.ts rename src/renderer/component/{ => Layout}/LangSelector.tsx (78%) create mode 100644 src/renderer/component/Layout/PendingEditSyncButton.tsx rename src/renderer/component/{ => Layout}/ThemeSelector.tsx (83%) diff --git a/src/contexts/PendingEditContext.test.ts b/src/contexts/PendingEditContext.test.ts new file mode 100644 index 0000000..ada1e18 --- /dev/null +++ b/src/contexts/PendingEditContext.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, test } from 'vitest'; +import { PendingEdit, PendingEditState } from '../sql/types'; +import { testables } from './PendingEditContext'; + +const { reducer, ActionType } = testables; + +const edit: PendingEdit = { + state: PendingEditState.Pending, + connectionSlug: 'conn', + tableName: 'tablename', + primaryKeys: { id: 123 }, + values: { title: 'new title' }, +}; + +const edit2: PendingEdit = { + state: PendingEditState.Pending, + connectionSlug: 'conn', + tableName: 'tablename', + primaryKeys: { id: 123 }, + values: { status: 'new status' }, +}; + +describe('reducer', () => { + test('addPendingEdit', () => { + let newState = reducer([], { + type: ActionType.Add, + edit, + }); + + expect(newState).toEqual([edit]); + + newState = reducer(newState, { type: ActionType.Add, edit: edit2 }); + + expect(newState).toEqual([edit, edit2]); + }); + + test('markAllAsApplied', () => { + expect( + reducer([edit, edit2], { type: ActionType.MarkAllAsApplied }) + ).toEqual([ + { ...edit, state: PendingEditState.Applied }, + { ...edit2, state: PendingEditState.Applied }, + ]); + }); +}); diff --git a/src/contexts/PendingEditContext.tsx b/src/contexts/PendingEditContext.tsx index 62608fc..640d0f2 100644 --- a/src/contexts/PendingEditContext.tsx +++ b/src/contexts/PendingEditContext.tsx @@ -6,7 +6,6 @@ import { useMemo, useReducer, } from 'react'; -import { Button } from 'antd'; import { FieldPacket, RowDataPacket } from 'mysql2'; import invariant from 'tiny-invariant'; import { PendingEdit, PendingEditState } from '../sql/types'; @@ -29,13 +28,20 @@ const PendingEditContext = createContext(null); type State = Array; -type Action = { type: 'add'; edit: PendingEdit } | { type: 'markAllAsApplied' }; +enum ActionType { + Add = 'add', + MarkAllAsApplied = 'MarkAllAsApplied', +} + +type Action = + | { type: ActionType.Add; edit: PendingEdit } + | { type: ActionType.MarkAllAsApplied }; function reducer(state: State, action: Action): State { switch (action.type) { - case 'add': + case ActionType.Add: return [...state, action.edit]; - case 'markAllAsApplied': + case ActionType.MarkAllAsApplied: return state.map((edit) => ({ ...edit, state: PendingEditState.Applied, @@ -58,7 +64,7 @@ export function PendingEditContextProvider({ invariant(currentConnectionSlug, 'Current connection slug should be set'); dispatch({ - type: 'add', + type: ActionType.Add, edit: { state: PendingEditState.Pending, connectionSlug: currentConnectionSlug, @@ -70,7 +76,7 @@ export function PendingEditContextProvider({ ); const markAllAsApplied = useCallback( - () => dispatch({ type: 'markAllAsApplied' }), + () => dispatch({ type: ActionType.MarkAllAsApplied }), [] ); @@ -134,29 +140,7 @@ export function usePendingEditContext() { return context; } -export function PendingEditDebug() { - const { pendingEdits, markAllAsApplied } = usePendingEditContext(); - - const unappliedPendingEdits = pendingEdits.filter( - (edit) => edit.state === PendingEditState.Pending - ); - - return ( - - ); -} +export const testables = { + reducer, + ActionType, +}; diff --git a/src/renderer/component/LangSelector.tsx b/src/renderer/component/Layout/LangSelector.tsx similarity index 78% rename from src/renderer/component/LangSelector.tsx rename to src/renderer/component/Layout/LangSelector.tsx index 10fcdf1..e46ef8e 100644 --- a/src/renderer/component/LangSelector.tsx +++ b/src/renderer/component/Layout/LangSelector.tsx @@ -1,6 +1,6 @@ import { Select } from 'antd'; -import { LOCALE_LIST } from '../../configuration/locale'; -import { useConfiguration } from '../../contexts/ConfigurationContext'; +import { LOCALE_LIST } from '../../../configuration/locale'; +import { useConfiguration } from '../../../contexts/ConfigurationContext'; export default function LangSelector() { const { configuration, changeLanguage } = useConfiguration(); diff --git a/src/renderer/component/Layout/PendingEditSyncButton.tsx b/src/renderer/component/Layout/PendingEditSyncButton.tsx new file mode 100644 index 0000000..de9ab5b --- /dev/null +++ b/src/renderer/component/Layout/PendingEditSyncButton.tsx @@ -0,0 +1,30 @@ +import { Button } from 'antd'; +import { usePendingEditContext } from '../../../contexts/PendingEditContext'; +import { PendingEditState } from '../../../sql/types'; + +export function PendingEditSyncButton() { + const { pendingEdits, markAllAsApplied } = usePendingEditContext(); + + const unappliedPendingEdits = pendingEdits.filter( + (edit) => edit.state === PendingEditState.Pending + ); + + return ( + + ); +} diff --git a/src/renderer/component/ThemeSelector.tsx b/src/renderer/component/Layout/ThemeSelector.tsx similarity index 83% rename from src/renderer/component/ThemeSelector.tsx rename to src/renderer/component/Layout/ThemeSelector.tsx index c6d29fe..ffb65dc 100644 --- a/src/renderer/component/ThemeSelector.tsx +++ b/src/renderer/component/Layout/ThemeSelector.tsx @@ -1,7 +1,7 @@ import { Select } from 'antd'; -import { THEME_LIST } from '../../configuration/themes'; -import { useTheme } from '../../contexts/ThemeContext'; -import { background, selection } from '../theme'; +import { THEME_LIST } from '../../../configuration/themes'; +import { useTheme } from '../../../contexts/ThemeContext'; +import { background, selection } from '../../theme'; export default function ThemeSelector() { const { themeName, changeTheme } = useTheme(); diff --git a/src/renderer/component/Query/RawSqlResult/RowDataPacketResult.tsx b/src/renderer/component/Query/RawSqlResult/RowDataPacketResult.tsx index aab903c..f3fbeb0 100644 --- a/src/renderer/component/Query/RawSqlResult/RowDataPacketResult.tsx +++ b/src/renderer/component/Query/RawSqlResult/RowDataPacketResult.tsx @@ -49,7 +49,7 @@ export default function RawSqlResult({ fetcher }: Props) { {result && isRowDataPacketArray(result[0]) && ( // TOOD maybe fetch foreign keys of queried table to activate navlinks t('rawSql.result.title')} diff --git a/src/renderer/routes/root.tsx b/src/renderer/routes/root.tsx index 87961a3..60659da 100644 --- a/src/renderer/routes/root.tsx +++ b/src/renderer/routes/root.tsx @@ -6,10 +6,7 @@ import packageJson from '../../../package.json'; import { ConfigurationContextProvider } from '../../contexts/ConfigurationContext'; import { useConnectionContext } from '../../contexts/ConnectionContext'; import { useDatabaseContext } from '../../contexts/DatabaseContext'; -import { - PendingEditContextProvider, - PendingEditDebug, -} from '../../contexts/PendingEditContext'; +import { PendingEditContextProvider } from '../../contexts/PendingEditContext'; import { ThemeContextProvider } from '../../contexts/ThemeContext'; import { useTranslation } from '../../i18n'; import ButtonLink from '../component/ButtonLink'; @@ -17,8 +14,9 @@ import ConnectionStack from '../component/Connection/ConnectionStack'; import ConnectionNav from '../component/Connection/Nav'; import Debug from '../component/Debug'; import { KeyboardShortcutTooltip } from '../component/KeyboardShortcut'; -import LangSelector from '../component/LangSelector'; -import ThemeSelector from '../component/ThemeSelector'; +import LangSelector from '../component/Layout/LangSelector'; +import { PendingEditSyncButton } from '../component/Layout/PendingEditSyncButton'; +import ThemeSelector from '../component/Layout/ThemeSelector'; import useEffectOnce from '../hooks/useEffectOnce'; import { background, foreground, selection } from '../theme'; @@ -95,7 +93,7 @@ export default function Root() { - + {t('language.switch.label')} {t('theme.switch.label')}