diff --git a/frontend/src/app/(editor)/@appBar/n/[noteId]/editor-app-bar.spec.tsx b/frontend/src/app/(editor)/@appBar/n/[noteId]/editor-app-bar.spec.tsx
index 6e9f05b98..e7a6e3df1 100644
--- a/frontend/src/app/(editor)/@appBar/n/[noteId]/editor-app-bar.spec.tsx
+++ b/frontend/src/app/(editor)/@appBar/n/[noteId]/editor-app-bar.spec.tsx
@@ -3,14 +3,14 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import * as UseApplicationStateModule from '../../../../../hooks/common/use-application-state'
-import type { ApplicationState } from '../../../../../redux/application-state'
import { mockI18n } from '../../../../../test-utils/mock-i18n'
import { EditorAppBar } from './editor-app-bar'
import type { NoteGroupPermissionEntry, NoteUserPermissionEntry } from '@hedgedoc/commons'
import { render } from '@testing-library/react'
import type { PropsWithChildren } from 'react'
import React from 'react'
+import { mockAppState } from '../../../../../test-utils/mock-app-state'
+import type { LoginUserInfo } from '../../../../../api/me/types'
jest.mock('../../../../../components/layout/app-bar/base-app-bar', () => ({
__esModule: true,
@@ -40,7 +40,7 @@ const mockedCommonAppState = {
},
user: {
username: 'test'
- }
+ } as LoginUserInfo
}
describe('app bar', () => {
@@ -48,40 +48,34 @@ describe('app bar', () => {
afterAll(() => jest.restoreAllMocks())
it('contains note title when editor is synced', () => {
- jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation((fn) => {
- return fn({
- ...mockedCommonAppState,
- realtimeStatus: {
- isSynced: true
- }
- } as ApplicationState)
+ mockAppState({
+ ...mockedCommonAppState,
+ realtimeStatus: {
+ isSynced: true
+ }
})
const view = render()
expect(view.container).toMatchSnapshot()
})
it('contains alert when editor is not synced', () => {
- jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation((fn) => {
- return fn({
- ...mockedCommonAppState,
- realtimeStatus: {
- isSynced: false
- }
- } as ApplicationState)
+ mockAppState({
+ ...mockedCommonAppState,
+ realtimeStatus: {
+ isSynced: false
+ }
})
const view = render()
expect(view.container).toMatchSnapshot()
})
it('contains note title and read-only marker when having only read permissions', () => {
- jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation((fn) => {
- return fn({
- ...mockedCommonAppState,
- realtimeStatus: {
- isSynced: true
- },
- user: null
- } as ApplicationState)
+ mockAppState({
+ ...mockedCommonAppState,
+ realtimeStatus: {
+ isSynced: true
+ },
+ user: null
})
const view = render()
expect(view.container).toMatchSnapshot()
diff --git a/frontend/src/components/common/modals/__snapshots__/deletion-moadal.spec.tsx.snap b/frontend/src/components/common/modals/__snapshots__/deletion-modal.spec.tsx.snap
similarity index 100%
rename from frontend/src/components/common/modals/__snapshots__/deletion-moadal.spec.tsx.snap
rename to frontend/src/components/common/modals/__snapshots__/deletion-modal.spec.tsx.snap
diff --git a/frontend/src/components/common/modals/deletion-moadal.spec.tsx b/frontend/src/components/common/modals/deletion-modal.spec.tsx
similarity index 87%
rename from frontend/src/components/common/modals/deletion-moadal.spec.tsx
rename to frontend/src/components/common/modals/deletion-modal.spec.tsx
index 38004077c..e6255f71c 100644
--- a/frontend/src/components/common/modals/deletion-moadal.spec.tsx
+++ b/frontend/src/components/common/modals/deletion-modal.spec.tsx
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { mockI18n } from '../../../test-utils/mock-i18n'
-import { mockNoteOwnership } from '../../../test-utils/note-ownership'
+import { mockNotePermissions } from '../../../test-utils/mock-note-permissions'
import { DeletionModal } from './deletion-modal'
import { render, screen } from '@testing-library/react'
@@ -19,7 +19,7 @@ describe('DeletionModal', () => {
})
it('renders correctly with deletionButtonI18nKey', async () => {
- mockNoteOwnership('test', 'test')
+ mockNotePermissions('test', 'test')
const onConfirm = jest.fn()
render(
@@ -31,7 +31,7 @@ describe('DeletionModal', () => {
})
it('disables deletion when user is not owner', async () => {
- mockNoteOwnership('test2', 'test')
+ mockNotePermissions('test2', 'test')
const onConfirm = jest.fn()
render(
diff --git a/frontend/src/components/editor-page/editor-pane/hooks/use-disconnect-on-user-login-status-change.spec.tsx b/frontend/src/components/editor-page/editor-pane/hooks/use-disconnect-on-user-login-status-change.spec.tsx
index 08b30d19e..9c5c50e52 100644
--- a/frontend/src/components/editor-page/editor-pane/hooks/use-disconnect-on-user-login-status-change.spec.tsx
+++ b/frontend/src/components/editor-page/editor-pane/hooks/use-disconnect-on-user-login-status-change.spec.tsx
@@ -4,13 +4,12 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { LoginUserInfo } from '../../../../api/me/types'
-import * as UseApplicationStateModule from '../../../../hooks/common/use-application-state'
-import type { ApplicationState } from '../../../../redux/application-state'
import { useDisconnectOnUserLoginStatusChange } from './use-disconnect-on-user-login-status-change'
import type { MessageTransporter } from '@hedgedoc/commons'
import { render } from '@testing-library/react'
import React, { Fragment } from 'react'
import { Mock } from 'ts-mockery'
+import { mockAppState } from '../../../../test-utils/mock-app-state'
jest.mock('../../../../hooks/common/use-application-state')
@@ -21,11 +20,9 @@ describe('use logout on user change', () => {
}
const mockUseApplicationState = (userLoggedIn: boolean) => {
- jest
- .spyOn(UseApplicationStateModule, 'useApplicationState')
- .mockImplementation((fn) =>
- fn(Mock.of({ user: userLoggedIn ? Mock.of({}) : null }))
- )
+ mockAppState({
+ user: userLoggedIn ? Mock.of({}) : null
+ })
}
let disconnectCallback: jest.Mock
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-add-form.spec.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-add-form.spec.tsx
index f2df404ef..37b755d54 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-add-form.spec.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-add-form.spec.tsx
@@ -7,12 +7,12 @@ import * as AliasModule from '../../../../../../api/alias'
import * as NoteDetailsReduxModule from '../../../../../../redux/note-details/methods'
import type { NoteDetails } from '../../../../../../redux/note-details/types/note-details'
import { mockI18n } from '../../../../../../test-utils/mock-i18n'
-import { mockNoteOwnership } from '../../../../../../test-utils/note-ownership'
-import * as useUiNotificationsModule from '../../../../../notifications/ui-notification-boundary'
+import { mockNotePermissions } from '../../../../../../test-utils/mock-note-permissions'
import { AliasesAddForm } from './aliases-add-form'
import { act, render, screen } from '@testing-library/react'
import testEvent from '@testing-library/user-event'
import React from 'react'
+import { mockUiNotifications } from '../../../../../../test-utils/mock-ui-notifications'
jest.mock('../../../../../../api/alias')
jest.mock('../../../../../../redux/note-details/methods')
@@ -24,14 +24,10 @@ const addPromise = Promise.resolve({ name: 'mock', primaryAlias: true, noteId: '
describe('AliasesAddForm', () => {
beforeEach(async () => {
await mockI18n()
+ mockUiNotifications()
jest.spyOn(AliasModule, 'addAlias').mockImplementation(() => addPromise)
jest.spyOn(NoteDetailsReduxModule, 'updateMetadata').mockImplementation(() => Promise.resolve())
- jest.spyOn(useUiNotificationsModule, 'useUiNotifications').mockReturnValue({
- showErrorNotification: jest.fn(),
- dismissNotification: jest.fn(),
- dispatchUiNotification: jest.fn()
- })
- mockNoteOwnership('test', 'test', { noteDetails: { id: 'mock-note' } as NoteDetails })
+ mockNotePermissions('test', 'test', undefined, { noteDetails: { id: 'mock-note' } as NoteDetails })
})
afterAll(() => {
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list-entry.spec.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list-entry.spec.tsx
index 7c3377057..2cbe12789 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list-entry.spec.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list-entry.spec.tsx
@@ -7,16 +7,15 @@ import * as AliasModule from '../../../../../../api/alias'
import type { Alias } from '../../../../../../api/alias/types'
import * as NoteDetailsReduxModule from '../../../../../../redux/note-details/methods'
import { mockI18n } from '../../../../../../test-utils/mock-i18n'
-import { mockNoteOwnership } from '../../../../../../test-utils/note-ownership'
-import * as useUiNotificationsModule from '../../../../../notifications/ui-notification-boundary'
+import { mockNotePermissions } from '../../../../../../test-utils/mock-note-permissions'
import { AliasesListEntry } from './aliases-list-entry'
import { act, render, screen } from '@testing-library/react'
import React from 'react'
+import { mockUiNotifications } from '../../../../../../test-utils/mock-ui-notifications'
jest.mock('../../../../../../api/alias')
jest.mock('../../../../../../redux/note-details/methods')
jest.mock('../../../../../notifications/ui-notification-boundary')
-// This needs to be mocked here in addition to note-ownership.ts, because jest doesn't work otherwise
jest.mock('../../../../../../hooks/common/use-application-state')
const deletePromise = Promise.resolve()
@@ -25,14 +24,10 @@ const markAsPrimaryPromise = Promise.resolve({ name: 'mock', primaryAlias: true,
describe('AliasesListEntry', () => {
beforeEach(async () => {
await mockI18n()
+ mockUiNotifications()
jest.spyOn(AliasModule, 'deleteAlias').mockImplementation(() => deletePromise)
jest.spyOn(AliasModule, 'markAliasAsPrimary').mockImplementation(() => markAsPrimaryPromise)
jest.spyOn(NoteDetailsReduxModule, 'updateMetadata').mockImplementation(() => Promise.resolve())
- jest.spyOn(useUiNotificationsModule, 'useUiNotifications').mockReturnValue({
- showErrorNotification: jest.fn(),
- dismissNotification: jest.fn(),
- dispatchUiNotification: jest.fn()
- })
})
afterEach(() => {
@@ -41,7 +36,7 @@ describe('AliasesListEntry', () => {
})
it('renders an AliasesListEntry that is primary', async () => {
- mockNoteOwnership('test', 'test')
+ mockNotePermissions('test', 'test')
const testAlias: Alias = {
name: 'test-primary',
primaryAlias: true,
@@ -59,7 +54,7 @@ describe('AliasesListEntry', () => {
})
it("disables button in AliasesListEntry if it's primary", () => {
- mockNoteOwnership('test2', 'test')
+ mockNotePermissions('test2', 'test')
const testAlias: Alias = {
name: 'test-primary',
primaryAlias: true,
@@ -70,7 +65,7 @@ describe('AliasesListEntry', () => {
})
it('renders an AliasesListEntry that is not primary', async () => {
- mockNoteOwnership('test', 'test')
+ mockNotePermissions('test', 'test')
const testAlias: Alias = {
name: 'test-non-primary',
primaryAlias: false,
@@ -95,7 +90,7 @@ describe('AliasesListEntry', () => {
})
it("disables button in AliasesListEntry if it's not primary", () => {
- mockNoteOwnership('test2', 'test')
+ mockNotePermissions('test2', 'test')
const testAlias: Alias = {
name: 'test-primary',
primaryAlias: false,
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list.spec.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list.spec.tsx
index e3e902372..d4e106ed4 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list.spec.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-list.spec.tsx
@@ -3,14 +3,13 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import type { Alias } from '../../../../../../api/alias/types'
-import * as useApplicationStateModule from '../../../../../../hooks/common/use-application-state'
import { mockI18n } from '../../../../../../test-utils/mock-i18n'
import { AliasesList } from './aliases-list'
import type { AliasesListEntryProps } from './aliases-list-entry'
import * as AliasesListEntryModule from './aliases-list-entry'
import { render } from '@testing-library/react'
import React from 'react'
+import { mockAppState } from '../../../../../../test-utils/mock-app-state'
jest.mock('../../../../../../hooks/common/use-application-state')
jest.mock('./aliases-list-entry')
@@ -18,23 +17,27 @@ jest.mock('./aliases-list-entry')
describe('AliasesList', () => {
beforeEach(async () => {
await mockI18n()
- jest.spyOn(useApplicationStateModule, 'useApplicationState').mockReturnValue([
- {
- name: 'a-test',
- noteId: 'note-id',
- primaryAlias: false
- },
- {
- name: 'z-test',
- noteId: 'note-id',
- primaryAlias: false
- },
- {
- name: 'b-test',
- noteId: 'note-id',
- primaryAlias: true
+ mockAppState({
+ noteDetails: {
+ aliases: [
+ {
+ name: 'a-test',
+ noteId: 'note-id',
+ primaryAlias: false
+ },
+ {
+ name: 'z-test',
+ noteId: 'note-id',
+ primaryAlias: false
+ },
+ {
+ name: 'b-test',
+ noteId: 'note-id',
+ primaryAlias: true
+ }
+ ]
}
- ] as Alias[])
+ })
jest.spyOn(AliasesListEntryModule, 'AliasesListEntry').mockImplementation((({ alias }) => {
return (
diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-modal.spec.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-modal.spec.tsx
index 0f256b33b..16c0b45bf 100644
--- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-modal.spec.tsx
+++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/aliases-sidebar-entry/aliases-modal/aliases-modal.spec.tsx
@@ -6,13 +6,13 @@
import { mockI18n } from '../../../../../../test-utils/mock-i18n'
import type { CommonModalProps } from '../../../../../common/modals/common-modal'
import * as CommonModalModule from '../../../../../common/modals/common-modal'
-import * as useUiNotificationsModule from '../../../../../notifications/ui-notification-boundary'
import * as AliasesAddFormModule from './aliases-add-form'
import * as AliasesListModule from './aliases-list'
import { AliasesModal } from './aliases-modal'
import { render } from '@testing-library/react'
import type { PropsWithChildren } from 'react'
import React from 'react'
+import { mockUiNotifications } from '../../../../../../test-utils/mock-ui-notifications'
jest.mock('./aliases-list')
jest.mock('./aliases-add-form')
@@ -22,6 +22,7 @@ jest.mock('../../../../../notifications/ui-notification-boundary')
describe('AliasesModal', () => {
beforeEach(async () => {
await mockI18n()
+ mockUiNotifications()
jest.spyOn(CommonModalModule, 'CommonModal').mockImplementation((({ children }) => {
return (
@@ -35,11 +36,6 @@ describe('AliasesModal', () => {
jest.spyOn(AliasesAddFormModule, 'AliasesAddForm').mockImplementation((() => {
return This is a mock for the AliasesAddForm that is tested separately.
}) as React.FC)
- jest.spyOn(useUiNotificationsModule, 'useUiNotifications').mockReturnValue({
- showErrorNotification: jest.fn(),
- dismissNotification: jest.fn(),
- dispatchUiNotification: jest.fn()
- })
})
afterAll(() => {
diff --git a/frontend/src/redux/dark-mode/reducers.ts b/frontend/src/redux/dark-mode/reducers.ts
index 196ea5ac0..47afd8aed 100644
--- a/frontend/src/redux/dark-mode/reducers.ts
+++ b/frontend/src/redux/dark-mode/reducers.ts
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -7,7 +7,7 @@ import type { DarkModeConfig, DarkModeConfigAction } from './types'
import { DarkModeConfigActionType, DarkModePreference } from './types'
import type { Reducer } from 'redux'
-const initialState: DarkModeConfig = {
+export const initialState: DarkModeConfig = {
darkModePreference: DarkModePreference.AUTO
}
diff --git a/frontend/src/redux/editor/reducers.ts b/frontend/src/redux/editor/reducers.ts
index dd5cb240a..e8bfa598f 100644
--- a/frontend/src/redux/editor/reducers.ts
+++ b/frontend/src/redux/editor/reducers.ts
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -10,7 +10,7 @@ import { Logger } from '../../utils/logger'
const logger = new Logger('EditorConfig Local Storage')
-const initialState: EditorConfig = {
+export const initialState: EditorConfig = {
ligatures: true,
syncScroll: true,
smartPaste: true,
diff --git a/frontend/src/redux/realtime/reducers.ts b/frontend/src/redux/realtime/reducers.ts
index c8becf160..90eedc7e1 100644
--- a/frontend/src/redux/realtime/reducers.ts
+++ b/frontend/src/redux/realtime/reducers.ts
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -7,7 +7,7 @@ import type { RealtimeStatus, RealtimeStatusActions } from './types'
import { RealtimeStatusActionType } from './types'
import type { Reducer } from 'redux'
-const initialState: RealtimeStatus = {
+export const initialState: RealtimeStatus = {
isSynced: false,
isConnected: false,
onlineUsers: [],
diff --git a/frontend/src/redux/renderer-status/reducers.ts b/frontend/src/redux/renderer-status/reducers.ts
index 0f73bbf20..8086d8746 100644
--- a/frontend/src/redux/renderer-status/reducers.ts
+++ b/frontend/src/redux/renderer-status/reducers.ts
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@@ -7,7 +7,7 @@ import type { RendererStatus, RendererStatusActions } from './types'
import { RendererStatusActionType } from './types'
import type { Reducer } from 'redux'
-const initialState: RendererStatus = {
+export const initialState: RendererStatus = {
rendererReady: false
}
diff --git a/frontend/src/test-utils/mock-app-state.ts b/frontend/src/test-utils/mock-app-state.ts
new file mode 100644
index 000000000..38df25b51
--- /dev/null
+++ b/frontend/src/test-utils/mock-app-state.ts
@@ -0,0 +1,56 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import * as useApplicationStateModule from '../hooks/common/use-application-state'
+import type { ApplicationState } from '../redux/application-state'
+import type { DeepPartial } from 'redux'
+import { initialState as initialStateDarkMode } from '../redux/dark-mode/reducers'
+import { initialState as initialStateEditorConfig } from '../redux/editor/reducers'
+import { initialState as initialStateNoteDetails } from '../redux/note-details/initial-state'
+import { initialState as initialStateRealtimeStatus } from '../redux/realtime/reducers'
+import { initialState as initialStateRendererStatus } from '../redux/renderer-status/reducers'
+import type { NoteDetails } from '../redux/note-details/types/note-details'
+import type { RealtimeStatus } from '../redux/realtime/types'
+import type { HistoryEntryWithOrigin } from '../api/history/types'
+
+jest.mock('../redux/editor/methods', () => ({
+ loadFromLocalStorage: jest.fn().mockReturnValue(undefined)
+}))
+jest.mock('../hooks/common/use-application-state')
+
+/**
+ * Mocks the {@link ApplicationState} for a test.
+ * When not overriden, it uses the initial state of the reducers.
+ *
+ * @param state Overrides for the mocked state
+ */
+export const mockAppState = (state?: DeepPartial) => {
+ jest.spyOn(useApplicationStateModule, 'useApplicationState').mockImplementation((fn) => {
+ return fn({
+ darkMode: {
+ ...initialStateDarkMode,
+ ...state?.darkMode
+ },
+ editorConfig: {
+ ...initialStateEditorConfig,
+ ...state?.editorConfig
+ },
+ history: (state?.history ?? []) as HistoryEntryWithOrigin[],
+ noteDetails: {
+ ...initialStateNoteDetails,
+ ...state?.noteDetails
+ } as NoteDetails,
+ realtimeStatus: {
+ ...initialStateRealtimeStatus,
+ ...state?.realtimeStatus
+ } as RealtimeStatus,
+ rendererStatus: {
+ ...initialStateRendererStatus,
+ ...state?.rendererStatus
+ },
+ user: state?.user ?? null
+ })
+ })
+}
diff --git a/frontend/src/test-utils/mock-note-permissions.ts b/frontend/src/test-utils/mock-note-permissions.ts
new file mode 100644
index 000000000..df9be71de
--- /dev/null
+++ b/frontend/src/test-utils/mock-note-permissions.ts
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import type { ApplicationState } from '../redux/application-state'
+import type { DeepPartial } from 'redux'
+import { mockAppState } from './mock-app-state'
+import type { LoginUserInfo } from '../api/me/types'
+import type { NotePermissions } from '@hedgedoc/commons'
+
+/**
+ * Mocks the {@link NotePermissions} field of a note in the {@link ApplicationState }for a test.
+ * This test-util should not be used alongside {@link mockAppState} to avoid overwriting the mocked state.
+ *
+ * @param ownUsername The name of the own user to set in the state (for comparing note ownership)
+ * @param noteOwner The owner's username of the mocked note
+ * @param permissions Overrides for the mocked permissions
+ * @param additionalState Overrides for the overall mocked application state
+ */
+export const mockNotePermissions = (
+ ownUsername: string,
+ noteOwner: string,
+ permissions?: DeepPartial,
+ additionalState?: DeepPartial
+) => {
+ mockAppState({
+ ...additionalState,
+ noteDetails: {
+ ...additionalState?.noteDetails,
+ permissions: {
+ sharedToGroups: [],
+ sharedToUsers: [],
+ ...permissions,
+ owner: noteOwner
+ }
+ },
+ user: {
+ ...additionalState?.user,
+ username: ownUsername
+ } as LoginUserInfo
+ })
+}
diff --git a/frontend/src/test-utils/mock-ui-notifications.ts b/frontend/src/test-utils/mock-ui-notifications.ts
new file mode 100644
index 000000000..0247fd312
--- /dev/null
+++ b/frontend/src/test-utils/mock-ui-notifications.ts
@@ -0,0 +1,19 @@
+/*
+ * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
+ *
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+import * as useUiNotificationsModule from '../components/notifications/ui-notification-boundary'
+
+jest.mock('../components/notifications/ui-notification-boundary')
+
+/**
+ * Mocks the {@link useUiNotifications} hook with stub functions for tests.
+ */
+export const mockUiNotifications = () => {
+ jest.spyOn(useUiNotificationsModule, 'useUiNotifications').mockReturnValue({
+ showErrorNotification: jest.fn(),
+ dismissNotification: jest.fn(),
+ dispatchUiNotification: jest.fn()
+ })
+}
diff --git a/frontend/src/test-utils/note-ownership.ts b/frontend/src/test-utils/note-ownership.ts
deleted file mode 100644
index 23276dad3..000000000
--- a/frontend/src/test-utils/note-ownership.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import * as useApplicationStateModule from '../hooks/common/use-application-state'
-import type { ApplicationState } from '../redux/application-state'
-
-jest.mock('../hooks/common/use-application-state')
-export const mockNoteOwnership = (
- ownUsername: string,
- noteOwner: string,
- additionalState?: Partial
-) => {
- jest.spyOn(useApplicationStateModule, 'useApplicationState').mockImplementation((fn) => {
- return fn({
- ...additionalState,
- noteDetails: {
- ...additionalState?.noteDetails,
- permissions: {
- owner: noteOwner
- }
- },
- user: {
- ...additionalState?.user,
- username: ownUsername
- }
- } as ApplicationState)
- })
-}