diff --git a/src/App.vue b/src/App.vue
index 5ba4789edc..3fda7423c5 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -23,7 +23,7 @@
diff --git a/src/tests/views/Documents/IdDocsValidation.spec.ts b/src/tests/views/Documents/IdDocsValidation.spec.ts
new file mode 100644
index 0000000000..baf597fd52
--- /dev/null
+++ b/src/tests/views/Documents/IdDocsValidation.spec.ts
@@ -0,0 +1,292 @@
+/*
+ * SPDX-FileCopyrightText: 2026 LibreSign contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { flushPromises, mount } from '@vue/test-utils'
+
+import IdDocsValidation from '../../../views/Documents/IdDocsValidation.vue'
+import { FILE_STATUS } from '../../../constants.js'
+
+const axiosGetMock = vi.fn()
+const axiosDeleteMock = vi.fn()
+const showErrorMock = vi.fn()
+const openDocumentMock = vi.fn()
+const routerPushMock = vi.fn()
+const userConfigUpdateMock = vi.fn()
+
+const userConfigStore = {
+ id_docs_filters: {
+ owner: '',
+ status: null,
+ },
+ id_docs_sort: {
+ sortBy: 'owner',
+ sortOrder: 'DESC',
+ },
+ update: vi.fn((...args: unknown[]) => userConfigUpdateMock(...args)),
+}
+
+vi.mock('@nextcloud/l10n', () => ({
+ t: vi.fn((_app: string, text: string) => text),
+}))
+
+vi.mock('@nextcloud/axios', () => ({
+ default: {
+ get: vi.fn((...args: unknown[]) => axiosGetMock(...args)),
+ delete: vi.fn((...args: unknown[]) => axiosDeleteMock(...args)),
+ },
+}))
+
+vi.mock('@nextcloud/dialogs', () => ({
+ showError: vi.fn((...args: unknown[]) => showErrorMock(...args)),
+}))
+
+vi.mock('@nextcloud/router', () => ({
+ generateOcsUrl: vi.fn((path: string, params?: Record) => {
+ let resolvedPath = path
+ for (const [key, value] of Object.entries(params || {})) {
+ resolvedPath = resolvedPath.replace(`{${key}}`, String(value))
+ }
+ return `/ocs/v2.php${resolvedPath}`
+ }),
+}))
+
+vi.mock('vue-router', () => ({
+ useRouter: vi.fn(() => ({
+ push: routerPushMock,
+ })),
+}))
+
+vi.mock('../../../store/userconfig.js', () => ({
+ useUserConfigStore: vi.fn(() => userConfigStore),
+}))
+
+vi.mock('../../../utils/viewer.js', () => ({
+ openDocument: vi.fn((...args: unknown[]) => openDocumentMock(...args)),
+}))
+
+vi.mock('@nextcloud/vue/components/NcActions', () => ({
+ default: { name: 'NcActions', template: '
' },
+}))
+
+vi.mock('@nextcloud/vue/components/NcActionButton', () => ({
+ default: {
+ name: 'NcActionButton',
+ emits: ['click', 'update:modelValue'],
+ template: '',
+ },
+}))
+
+vi.mock('@nextcloud/vue/components/NcActionInput', () => ({
+ default: {
+ name: 'NcActionInput',
+ props: ['modelValue', 'label'],
+ emits: ['update:modelValue'],
+ template: '',
+ },
+}))
+
+vi.mock('@nextcloud/vue/components/NcActionSeparator', () => ({
+ default: { name: 'NcActionSeparator', template: '
' },
+}))
+
+vi.mock('@nextcloud/vue/components/NcAvatar', () => ({
+ default: { name: 'NcAvatar', template: '' },
+}))
+
+vi.mock('@nextcloud/vue/components/NcEmptyContent', () => ({
+ default: { name: 'NcEmptyContent', template: '
' },
+}))
+
+vi.mock('@nextcloud/vue/components/NcLoadingIcon', () => ({
+ default: { name: 'NcLoadingIcon', template: '' },
+}))
+
+vi.mock('@nextcloud/vue/components/NcIconSvgWrapper', () => ({
+ default: { name: 'NcIconSvgWrapper', template: '' },
+}))
+
+describe('IdDocsValidation.vue', () => {
+ const signedDoc = {
+ uuid: 'doc-1',
+ account: {
+ userId: 'alice',
+ displayName: 'Alice',
+ },
+ file_type: {
+ type: 'passport',
+ name: 'Passport',
+ },
+ file: {
+ uuid: 'file-1',
+ status: FILE_STATUS.SIGNED,
+ statusText: 'Signed',
+ name: 'alice-passport.pdf',
+ file: {
+ nodeId: 10,
+ url: '/files/alice-passport.pdf',
+ },
+ signers: [{ uid: 'approver', displayName: 'Approver', sign_date: '2026-03-06T12:00:00Z' }],
+ },
+ }
+
+ const pendingDoc = {
+ uuid: 'doc-2',
+ account: {
+ userId: 'bob',
+ displayName: 'Bob',
+ },
+ file_type: {
+ type: 'driver-license',
+ name: 'Driver License',
+ },
+ file: {
+ uuid: 'file-2',
+ status: FILE_STATUS.ABLE_TO_SIGN,
+ statusText: 'Pending',
+ name: 'bob-license.pdf',
+ file: {
+ nodeId: 11,
+ url: '/files/bob-license.pdf',
+ },
+ signers: [],
+ },
+ }
+
+ const createWrapper = () => mount(IdDocsValidation)
+
+ beforeEach(() => {
+ axiosGetMock.mockReset()
+ axiosDeleteMock.mockReset()
+ showErrorMock.mockReset()
+ openDocumentMock.mockReset()
+ routerPushMock.mockReset()
+ userConfigUpdateMock.mockReset()
+ userConfigStore.update.mockClear()
+ userConfigStore.id_docs_filters = { owner: '', status: null }
+ userConfigStore.id_docs_sort = { sortBy: 'owner', sortOrder: 'DESC' }
+
+ axiosGetMock.mockResolvedValue({
+ data: {
+ ocs: {
+ data: {
+ data: [signedDoc, pendingDoc],
+ total: 2,
+ },
+ },
+ },
+ })
+
+ axiosDeleteMock.mockResolvedValue({
+ data: {
+ ocs: {
+ data: {
+ success: true,
+ },
+ },
+ },
+ })
+ })
+
+ it('loads documents on mount using saved sort', async () => {
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ expect(axiosGetMock).toHaveBeenCalledWith('/ocs/v2.php/apps/libresign/api/v1/id-docs/approval/list', {
+ params: {
+ page: 1,
+ length: 50,
+ sortBy: 'owner',
+ sortOrder: 'DESC',
+ },
+ })
+ expect(wrapper.vm.documentList).toHaveLength(2)
+ expect(wrapper.vm.hasMore).toBe(false)
+ })
+
+ it('filters by owner and status and persists filter changes', async () => {
+ vi.useFakeTimers()
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ wrapper.vm.filters.owner = 'bob'
+ wrapper.vm.setStatusFilter('pending', true)
+ vi.runAllTimers()
+ await flushPromises()
+
+ expect(wrapper.vm.hasActiveFilters).toBe(true)
+ expect(wrapper.vm.activeFilterCount).toBe(2)
+ expect(wrapper.vm.filteredDocuments).toEqual([pendingDoc])
+ expect(userConfigUpdateMock).toHaveBeenCalledWith('id_docs_filters', {
+ owner: 'bob',
+ status: {
+ value: 'pending',
+ label: 'Pending',
+ },
+ })
+
+ vi.useRealTimers()
+ })
+
+ it('toggles sort direction and then clears the sort for the same column', async () => {
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ await wrapper.vm.sortColumn('owner')
+ expect(wrapper.vm.sortOrder).toBe('ASC')
+
+ await wrapper.vm.sortColumn('owner')
+ expect(wrapper.vm.sortBy).toBeNull()
+ expect(wrapper.vm.sortOrder).toBeNull()
+ expect(userConfigUpdateMock).toHaveBeenCalledWith('id_docs_sort', {
+ sortBy: null,
+ sortOrder: null,
+ })
+ })
+
+ it('routes to approve and validation pages using document uuid', async () => {
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ wrapper.vm.openApprove(pendingDoc)
+ wrapper.vm.openValidationURL(signedDoc)
+
+ expect(routerPushMock).toHaveBeenNthCalledWith(1, {
+ name: 'IdDocsApprove',
+ params: { uuid: 'file-2' },
+ query: { idDocApproval: 'true' },
+ })
+ expect(routerPushMock).toHaveBeenNthCalledWith(2, {
+ name: 'ValidationFile',
+ params: { uuid: 'file-1' },
+ })
+ })
+
+ it('opens the file in the viewer and reports missing urls', async () => {
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ wrapper.vm.openFile(signedDoc)
+ wrapper.vm.openFile({ file: { file: { nodeId: 12 }, name: 'missing.pdf' } })
+
+ expect(openDocumentMock).toHaveBeenCalledWith({
+ fileUrl: '/files/alice-passport.pdf',
+ filename: 'alice-passport.pdf',
+ nodeId: 10,
+ })
+ expect(showErrorMock).toHaveBeenCalledWith('File not found')
+ })
+
+ it('deletes a document and reloads the list', async () => {
+ const wrapper = createWrapper()
+ await flushPromises()
+
+ await wrapper.vm.deleteDocument(signedDoc)
+ await flushPromises()
+
+ expect(axiosDeleteMock).toHaveBeenCalledWith('/ocs/v2.php/apps/libresign/api/v1/id-docs/10')
+ expect(axiosGetMock).toHaveBeenCalledTimes(2)
+ })
+})
\ No newline at end of file
diff --git a/src/tests/views/FilesList/FileEntry.spec.ts b/src/tests/views/FilesList/FileEntry.spec.ts
index dc3fd9def9..66178a8708 100644
--- a/src/tests/views/FilesList/FileEntry.spec.ts
+++ b/src/tests/views/FilesList/FileEntry.spec.ts
@@ -9,6 +9,7 @@ import { setActivePinia, createPinia } from 'pinia'
import FileEntry from '../../../views/FilesList/FileEntry/FileEntry.vue'
import { useFilesStore } from '../../../store/files.js'
import { useActionsMenuStore } from '../../../store/actionsmenu.js'
+import { useSidebarStore } from '../../../store/sidebar.js'
import type { TranslationFunction } from '../../test-types'
type FileEntrySource = {
@@ -18,6 +19,9 @@ type FileEntrySource = {
statusText: string
signers: unknown[]
created_at: number
+ metadata?: {
+ extension?: string
+ }
}
const t: TranslationFunction = (_app, text) => text
@@ -91,39 +95,33 @@ vi.mock('../../../views/FilesList/FileEntry/FileEntrySigners.vue', () => ({
},
}))
-vi.mock('../../../views/FilesList/FileEntry/FileEntryMixin.js', () => ({
- default: {
- computed: {
- fileExtension() {
- return 'pdf'
- },
- mtime(this: { source?: FileEntrySource }): number {
- return this.source?.created_at ?? Date.now()
- },
- mtimeOpacity() {
- return {}
- },
+describe('FileEntry.vue - Individual File Entry', () => {
+ const source: FileEntrySource = {
+ id: 1,
+ name: 'test.pdf',
+ status: 1,
+ statusText: 'Ready',
+ signers: [],
+ created_at: Date.now(),
+ metadata: {
+ extension: 'pdf',
},
- data() {
- const source: FileEntrySource = {
- id: 1,
- name: 'test.pdf',
- status: 1,
- statusText: 'Ready',
- signers: [],
- created_at: Date.now(),
- }
-
- return {
+ }
+
+ function createWrapper() {
+ return mount(FileEntry, {
+ props: {
source,
loading: false,
- openedMenu: false,
- }
- },
- },
-}))
+ },
+ global: {
+ mocks: {
+ t,
+ },
+ },
+ })
+ }
-describe('FileEntry.vue - Individual File Entry', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
@@ -133,53 +131,25 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('renders file entry row', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.find('tr.files-list__row').exists()).toBe(true)
})
it('initializes renaming state as false', () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.vm.isRenaming).toBe(false)
})
it('initializes renaming saving state as false', () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.vm.renamingSaving).toBe(false)
})
it('renames file on rename event', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
await wrapper.vm.onRename('newname.pdf')
@@ -187,14 +157,7 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('clears renaming saving flag after rename', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
wrapper.vm.renamingSaving = true
@@ -203,29 +166,15 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('starts rename on file', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
wrapper.vm.onStartRename()
- expect(wrapper.vm.$refs.name).toBeDefined()
+ expect(wrapper.vm.name).toBeDefined()
})
it('tracks file renaming state', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
expect(wrapper.vm.isRenaming).toBe(false)
@@ -237,14 +186,7 @@ describe('FileEntry.vue - Individual File Entry', () => {
it('uses files store for file operations', async () => {
const store = useFilesStore()
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
expect(wrapper.vm.filesStore).toBe(store)
@@ -252,93 +194,44 @@ describe('FileEntry.vue - Individual File Entry', () => {
it('uses actions menu store for menu state', async () => {
const store = useActionsMenuStore()
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
expect(wrapper.vm.actionsMenuStore).toBe(store)
})
it('renders file entry checkbox', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'FileEntryCheckbox' }).exists()).toBe(true)
})
it('renders file entry name', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'FileEntryName' }).exists()).toBe(true)
})
it('renders file entry actions', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'FileEntryActions' }).exists()).toBe(true)
})
it('renders file entry status', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'FileEntryStatus' }).exists()).toBe(true)
})
it('renders file entry signers', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'FileEntrySigners' }).exists()).toBe(true)
})
it('passes signersCount to FileEntrySigners', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
const signersComponent = wrapper.findComponent({ name: 'FileEntrySigners' })
@@ -347,14 +240,7 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('passes signers array to FileEntrySigners', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
const signersComponent = wrapper.findComponent({ name: 'FileEntrySigners' })
@@ -363,41 +249,20 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('renders row signers cell with click handler', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
const signersCell = wrapper.find('.files-list__row-signers')
expect(signersCell.exists()).toBe(true)
})
it('renders file modification time', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
expect(wrapper.findComponent({ name: 'NcDateTime' }).exists()).toBe(true)
})
it('passes source to child components', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
expect(wrapper.vm.filesStore).toBeDefined()
@@ -405,32 +270,34 @@ describe('FileEntry.vue - Individual File Entry', () => {
it('shows success message after rename', async () => {
const { showSuccess } = await import('@nextcloud/dialogs')
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
await wrapper.vm.onRename('newname.pdf')
expect(showSuccess).toHaveBeenCalled()
})
+ it('opens details through the sidebar store', async () => {
+ const sidebarStore = useSidebarStore()
+ const selectFileSpy = vi.spyOn(useFilesStore(), 'selectFile')
+ const activeRequestSignatureTabSpy = vi.spyOn(sidebarStore, 'activeRequestSignatureTab')
+ const wrapper = createWrapper()
+ const event = {
+ preventDefault: vi.fn(),
+ stopPropagation: vi.fn(),
+ } as unknown as Event
+
+ wrapper.vm.openDetailsIfAvailable(event)
+
+ expect(selectFileSpy).toHaveBeenCalledWith(1)
+ expect(activeRequestSignatureTabSpy).toHaveBeenCalled()
+ })
+
it('restores file name on rename failure', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
- vi.spyOn(wrapper.vm.$refs.actions, 'doRename').mockRejectedValueOnce(new Error('Rename failed'))
+ vi.spyOn(wrapper.vm.actions, 'doRename').mockRejectedValueOnce(new Error('Rename failed'))
try {
await wrapper.vm.onRename('newname.pdf')
} catch (e) {}
@@ -438,15 +305,7 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('handles right click on row', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- onRightClick: vi.fn(),
- },
- },
- })
+ const wrapper = createWrapper()
await wrapper.vm.$nextTick()
const row = wrapper.find('.files-list__row')
@@ -454,42 +313,21 @@ describe('FileEntry.vue - Individual File Entry', () => {
})
it('renders row name cell with click handler', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
const nameCell = wrapper.find('.files-list__row-name')
expect(nameCell.exists()).toBe(true)
})
it('renders row status cell with click handler', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
const statusCell = wrapper.find('.files-list__row-status')
expect(statusCell.exists()).toBe(true)
})
it('renders row mtime cell', async () => {
- const wrapper = mount(FileEntry, {
- props: {},
- global: {
- mocks: {
- t,
- },
- },
- })
+ const wrapper = createWrapper()
const mtimeCell = wrapper.find('.files-list__row-mtime')
expect(mtimeCell.exists()).toBe(true)
diff --git a/src/tests/views/FilesList/FileEntryGrid.spec.ts b/src/tests/views/FilesList/FileEntryGrid.spec.ts
index 6e76d51f30..eb2c6dbb3e 100644
--- a/src/tests/views/FilesList/FileEntryGrid.spec.ts
+++ b/src/tests/views/FilesList/FileEntryGrid.spec.ts
@@ -5,6 +5,7 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { mount } from '@vue/test-utils'
+import { setActivePinia, createPinia } from 'pinia'
import FileEntryGrid from '../../../views/FilesList/FileEntry/FileEntryGrid.vue'
@@ -14,6 +15,11 @@ const actionsMenuStoreMock = {
const filesStoreMock = {
loading: true,
+ selectFile: vi.fn(),
+}
+
+const sidebarStoreMock = {
+ activeRequestSignatureTab: vi.fn(),
}
vi.mock('@nextcloud/vue/components/NcDateTime', () => ({
@@ -72,42 +78,6 @@ vi.mock('../../../views/FilesList/FileEntry/FileEntryStatus.vue', () => ({
},
}))
-vi.mock('../../../views/FilesList/FileEntry/FileEntryMixin.js', () => ({
- default: {
- props: {
- source: {
- type: Object,
- required: true,
- },
- loading: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- fileExtension() {
- return '.pdf'
- },
- mtime() {
- return new Date('2026-03-06T10:00:00Z')
- },
- mtimeOpacity() {
- return { color: 'red' }
- },
- openedMenu: {
- get() {
- return false
- },
- set() {},
- },
- },
- methods: {
- onRightClick: vi.fn(),
- openDetailsIfAvailable: vi.fn(),
- },
- },
-}))
-
vi.mock('../../../store/actionsmenu.js', () => ({
useActionsMenuStore: vi.fn(() => actionsMenuStoreMock),
}))
@@ -116,10 +86,17 @@ vi.mock('../../../store/files.js', () => ({
useFilesStore: vi.fn(() => filesStoreMock),
}))
+vi.mock('../../../store/sidebar.js', () => ({
+ useSidebarStore: vi.fn(() => sidebarStoreMock),
+}))
+
describe('FileEntryGrid.vue', () => {
beforeEach(() => {
+ setActivePinia(createPinia())
actionsMenuStoreMock.opened = null
filesStoreMock.loading = true
+ filesStoreMock.selectFile.mockReset()
+ sidebarStoreMock.activeRequestSignatureTab.mockReset()
})
function createWrapper() {
@@ -160,4 +137,17 @@ describe('FileEntryGrid.vue', () => {
expect(checkbox.props('isLoading')).toBe(true)
expect(checkbox.props('source')).toMatchObject({ id: 7 })
})
+
+ it('opens the details sidebar for the selected file', () => {
+ const wrapper = createWrapper()
+ const event = {
+ preventDefault: vi.fn(),
+ stopPropagation: vi.fn(),
+ } as unknown as Event
+
+ wrapper.vm.openDetailsIfAvailable(event)
+
+ expect(filesStoreMock.selectFile).toHaveBeenCalledWith(7)
+ expect(sidebarStoreMock.activeRequestSignatureTab).toHaveBeenCalled()
+ })
})
diff --git a/src/views/Documents/IdDocsValidation.vue b/src/views/Documents/IdDocsValidation.vue
index dce6d2d207..8b574970f0 100644
--- a/src/views/Documents/IdDocsValidation.vue
+++ b/src/views/Documents/IdDocsValidation.vue
@@ -169,8 +169,22 @@
-