From f7a2886c91444ad43b6b3a7ec6c8e7f120707039 Mon Sep 17 00:00:00 2001 From: Maximilian Mayer Date: Sat, 12 Sep 2026 21:02:01 +0200 Subject: [PATCH 1/3] feat: explain when signer has no visible signature field Signed-off-by: Maximilian Mayer --- src/tests/views/SignPDF/Sign.spec.ts | 39 +++++++++++++++++++++++++++- src/views/SignPDF/_partials/Sign.vue | 10 +++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/tests/views/SignPDF/Sign.spec.ts b/src/tests/views/SignPDF/Sign.spec.ts index 752de7d9cf..b1a3e9e352 100644 --- a/src/tests/views/SignPDF/Sign.spec.ts +++ b/src/tests/views/SignPDF/Sign.spec.ts @@ -884,7 +884,8 @@ describe('Sign.vue - signWithTokenCode', () => { expect(wrapper.text()).toContain('Try signing again') expect(wrapper.text()).not.toContain('Sign document') - expect(wrapper.findAll('.nc-note-card-stub')).toHaveLength(1) + // One card for the blocking error, one for the missing visible signature field. + expect(wrapper.findAll('.nc-note-card-stub')).toHaveLength(2) }) }) @@ -2267,3 +2268,39 @@ describe('Sign.vue - required device geolocation', () => { expect(submitSignatureMock.mock.calls[0]?.[0]).not.toHaveProperty('geolocation') }) }) + +describe('Sign.vue - no visible signature notice', () => { + it('detects a visible signature field when the signer has one', async () => { + setActivePinia(createPinia()) + const SignComponent = await import('../../../views/SignPDF/_partials/Sign.vue') + const { useSignStore } = await import('../../../store/sign.js') + const signStore = useSignStore() + signStore.document = createSignDocument({ + nodeType: 'file', + signers: [ + { signRequestId: 501, me: true }, + ], + visibleElements: [ + { elementId: 201, fileId: 1, signRequestId: 501, type: 'signature', coordinates: { page: 1, left: 10, top: 20, width: 30, height: 40 } }, + ], + }) + const wrapper = mount(SignComponent.default, createSignMountOptions()) + expect(wrapper.vm.hasVisibleSignatureField).toBe(true) + }) + + it('detects no visible signature field when the signer has none', async () => { + setActivePinia(createPinia()) + const SignComponent = await import('../../../views/SignPDF/_partials/Sign.vue') + const { useSignStore } = await import('../../../store/sign.js') + const signStore = useSignStore() + signStore.document = createSignDocument({ + nodeType: 'file', + signers: [ + { signRequestId: 501, me: true }, + ], + visibleElements: [], + }) + const wrapper = mount(SignComponent.default, createSignMountOptions()) + expect(wrapper.vm.hasVisibleSignatureField).toBe(false) + }) +}) diff --git a/src/views/SignPDF/_partials/Sign.vue b/src/views/SignPDF/_partials/Sign.vue index f79302a091..3deaf2581c 100644 --- a/src/views/SignPDF/_partials/Sign.vue +++ b/src/views/SignPDF/_partials/Sign.vue @@ -37,6 +37,14 @@ + +

+ + {{ t('libresign', 'Your digital signature will still be added to the PDF and can be validated after signing.') }} +

+

@@ -587,6 +595,7 @@ const needCreateSignature = computed(() => { } return hasVisibleElementsForCurrentUser(visibleElementsDocument.value) }) +const hasVisibleSignatureField = computed(() => hasVisibleElementsForCurrentUser(visibleElementsDocument.value)) const needIdentificationDocuments = computed(() => identificationDocumentStore.showDocumentsComponent()) const canCreateSignature = computed(() => { const capabilities = getCapabilities() as LibresignCapabilities @@ -953,6 +962,7 @@ defineExpose({ hasSignatures, needCreateSignature, canCreateSignature, + hasVisibleSignatureField, submitSignature, signWithTokenCode, requiresDeviceGeolocation, From ea5c6ae1a832669432cc57d46ad5eb56e3e83fcd Mon Sep 17 00:00:00 2001 From: Maximilian Mayer Date: Sat, 12 Sep 2026 21:43:34 +0200 Subject: [PATCH 2/3] test: assert no-visible-signature notice in click-to-sign flow Signed-off-by: Maximilian Mayer --- playwright/e2e/sign-herself-with-click-to-sign.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/playwright/e2e/sign-herself-with-click-to-sign.spec.ts b/playwright/e2e/sign-herself-with-click-to-sign.spec.ts index 1f432d883a..912b444287 100644 --- a/playwright/e2e/sign-herself-with-click-to-sign.spec.ts +++ b/playwright/e2e/sign-herself-with-click-to-sign.spec.ts @@ -53,6 +53,7 @@ test('sign herself with click to sign', async ({ page }) => { await expect(page.getByLabel('PDF document to sign')).toBeVisible({ timeout: 15_000 }) const signButton = page.locator('.sign-pdf-sidebar .button-wrapper').getByRole('button', { name: 'Sign document' }) await expect(signButton).toBeVisible({ timeout: 15_000 }) + await expect(page.getByText('No visible signature is required')).toBeVisible() await signButton.click({ force: true }) const signResponsePromise = page.waitForResponse((response) => response.request().method() === 'POST' From 0c4b594769ea7c1b884087b2d2da67223db31a8a Mon Sep 17 00:00:00 2001 From: Maximilian Mayer Date: Sun, 13 Sep 2026 08:24:07 +0200 Subject: [PATCH 3/3] fix: hide no-visible-signature notice while signing is blocked Signed-off-by: Maximilian Mayer --- src/tests/views/SignPDF/Sign.spec.ts | 65 ++++++++++++++++++---------- src/views/SignPDF/_partials/Sign.vue | 3 +- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/tests/views/SignPDF/Sign.spec.ts b/src/tests/views/SignPDF/Sign.spec.ts index b1a3e9e352..46112998ea 100644 --- a/src/tests/views/SignPDF/Sign.spec.ts +++ b/src/tests/views/SignPDF/Sign.spec.ts @@ -884,8 +884,7 @@ describe('Sign.vue - signWithTokenCode', () => { expect(wrapper.text()).toContain('Try signing again') expect(wrapper.text()).not.toContain('Sign document') - // One card for the blocking error, one for the missing visible signature field. - expect(wrapper.findAll('.nc-note-card-stub')).toHaveLength(2) + expect(wrapper.findAll('.nc-note-card-stub')).toHaveLength(1) }) }) @@ -2270,37 +2269,59 @@ describe('Sign.vue - required device geolocation', () => { }) describe('Sign.vue - no visible signature notice', () => { - it('detects a visible signature field when the signer has one', async () => { + const mountWithVisibleElementFor = async (signRequestId: number) => { setActivePinia(createPinia()) + const SignComponent = await import('../../../views/SignPDF/_partials/Sign.vue') const { useSignStore } = await import('../../../store/sign.js') const signStore = useSignStore() + signStore.document = createSignDocument({ - nodeType: 'file', + status: FILE_STATUS.ABLE_TO_SIGN, signers: [ - { signRequestId: 501, me: true }, + { signRequestId: 501, me: true, status: SIGN_REQUEST_STATUS.ABLE_TO_SIGN }, + { signRequestId: 502 }, ], visibleElements: [ - { elementId: 201, fileId: 1, signRequestId: 501, type: 'signature', coordinates: { page: 1, left: 10, top: 20, width: 30, height: 40 } }, + { elementId: 201, fileId: 1, signRequestId, type: 'signature', coordinates: { page: 1, left: 10, top: 20, width: 30, height: 40 } }, ], }) - const wrapper = mount(SignComponent.default, createSignMountOptions()) - expect(wrapper.vm.hasVisibleSignatureField).toBe(true) + + const base = createSignMountOptions() + const options = { + ...base, + global: { + ...base.global, + stubs: { + ...base.global.stubs, + NcNoteCard: { template: '

' }, + NcButton: { template: '' }, + }, + }, + } + + const wrapper = mount(SignComponent.default, options) + await flushPromises() + + return wrapper + } + + it('shows the notice when only another signer has a visible element', async () => { + const wrapper = await mountWithVisibleElementFor(502) + + expect(wrapper.text()).toContain('Your digital signature will still be added') }) - it('detects no visible signature field when the signer has none', async () => { - setActivePinia(createPinia()) - const SignComponent = await import('../../../views/SignPDF/_partials/Sign.vue') - const { useSignStore } = await import('../../../store/sign.js') - const signStore = useSignStore() - signStore.document = createSignDocument({ - nodeType: 'file', - signers: [ - { signRequestId: 501, me: true }, - ], - visibleElements: [], - }) - const wrapper = mount(SignComponent.default, createSignMountOptions()) - expect(wrapper.vm.hasVisibleSignatureField).toBe(false) + it('does not show the notice when the current signer has a visible element', async () => { + const wrapper = await mountWithVisibleElementFor(501) + + expect(wrapper.text()).not.toContain('Your digital signature will still be added') + }) + + it('keeps Sign document available while the notice is shown', async () => { + const wrapper = await mountWithVisibleElementFor(502) + + expect(wrapper.text()).toContain('Your digital signature will still be added') + expect(wrapper.text()).toContain('Sign document') }) }) diff --git a/src/views/SignPDF/_partials/Sign.vue b/src/views/SignPDF/_partials/Sign.vue index 3deaf2581c..ad8fe0a3b7 100644 --- a/src/views/SignPDF/_partials/Sign.vue +++ b/src/views/SignPDF/_partials/Sign.vue @@ -37,7 +37,7 @@ -

@@ -962,7 +962,6 @@ defineExpose({ hasSignatures, needCreateSignature, canCreateSignature, - hasVisibleSignatureField, submitSignature, signWithTokenCode, requiresDeviceGeolocation,