Skip to content

Commit 308b1dc

Browse files
test(vue3): add settings Validation coverage
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 7107d98 commit 308b1dc

1 file changed

Lines changed: 153 additions & 0 deletions

File tree

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 LibreSign contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
7+
import { flushPromises, mount } from '@vue/test-utils'
8+
9+
import Validation from '../../../views/Settings/Validation.vue'
10+
11+
const axiosGetMock = vi.fn()
12+
const loadStateMock = vi.fn()
13+
14+
vi.mock('@nextcloud/axios', () => ({
15+
default: {
16+
get: (...args: unknown[]) => axiosGetMock(...args),
17+
},
18+
}))
19+
20+
vi.mock('@nextcloud/initial-state', () => ({
21+
loadState: (...args: unknown[]) => loadStateMock(...args),
22+
}))
23+
24+
vi.mock('@nextcloud/router', () => ({
25+
generateOcsUrl: vi.fn((path: string) => path),
26+
}))
27+
28+
vi.mock('@nextcloud/l10n', () => ({
29+
t: vi.fn((_app: string, text: string) => text),
30+
translate: vi.fn((_app: string, text: string) => text),
31+
translatePlural: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
32+
n: vi.fn((_app: string, singular: string, plural: string, count: number) => (count === 1 ? singular : plural)),
33+
getLanguage: vi.fn(() => 'en'),
34+
getLocale: vi.fn(() => 'en'),
35+
isRTL: vi.fn(() => false),
36+
}))
37+
38+
const appConfigSetValueMock = vi.fn()
39+
40+
const FooterTemplateEditorStub = {
41+
name: 'FooterTemplateEditor',
42+
props: {
43+
initialIsDefault: {
44+
type: Boolean,
45+
default: true,
46+
},
47+
},
48+
template: '<div class="footer-template-editor-stub" />',
49+
methods: {
50+
resetFooterTemplate() {},
51+
},
52+
}
53+
54+
describe('Settings/Validation.vue', () => {
55+
beforeEach(() => {
56+
vi.clearAllMocks()
57+
loadStateMock.mockImplementation((_app: string, _key: string, fallback: unknown) => fallback)
58+
vi.stubGlobal('OCP', {
59+
AppConfig: {
60+
setValue: appConfigSetValueMock,
61+
},
62+
})
63+
})
64+
65+
function createWrapper() {
66+
return mount(Validation, {
67+
global: {
68+
stubs: {
69+
NcSettingsSection: { template: '<section><slot /></section>' },
70+
NcCheckboxRadioSwitch: { template: '<div><slot /></div>' },
71+
FooterTemplateEditor: FooterTemplateEditorStub,
72+
},
73+
},
74+
})
75+
}
76+
77+
it('loads validation settings on mount', async () => {
78+
axiosGetMock
79+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
80+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '0' } } } })
81+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
82+
.mockResolvedValueOnce({ data: { ocs: { data: { data: 'https://example.test/validation/' } } } })
83+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '0' } } } })
84+
85+
const wrapper = createWrapper()
86+
await flushPromises()
87+
88+
expect(axiosGetMock).toHaveBeenCalledTimes(5)
89+
expect(wrapper.vm.makeValidationUrlPrivate).toBe(true)
90+
expect(wrapper.vm.addFooter).toBe(false)
91+
expect(wrapper.vm.writeQrcodeOnFooter).toBe(true)
92+
expect(wrapper.vm.url).toBe('https://example.test/validation/')
93+
expect(wrapper.vm.isDefaultFooterTemplate).toBe(false)
94+
expect(wrapper.vm.customizeFooter).toBe(true)
95+
})
96+
97+
it('falls back to the default validation URL placeholder', async () => {
98+
axiosGetMock.mockResolvedValue({ data: { ocs: { data: { data: '' } } } })
99+
100+
const wrapper = createWrapper()
101+
await flushPromises()
102+
103+
expect(wrapper.vm.url).toBe(wrapper.vm.paternValidadeUrl)
104+
})
105+
106+
it('trims and saves the typed validation URL', async () => {
107+
axiosGetMock
108+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
109+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
110+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
111+
.mockResolvedValueOnce({ data: { ocs: { data: { data: 'https://example.test/' } } } })
112+
.mockResolvedValueOnce({ data: { ocs: { data: { data: '1' } } } })
113+
114+
const wrapper = createWrapper()
115+
await flushPromises()
116+
117+
const input = wrapper.get('#validation_site')
118+
;(input.element as HTMLInputElement).value = ' https://custom.test/validation '
119+
await input.trigger('input')
120+
121+
expect(appConfigSetValueMock).toHaveBeenCalledWith('libresign', 'validation_site', 'https://custom.test/validation')
122+
})
123+
124+
it('resets the footer template when customization is disabled', async () => {
125+
axiosGetMock.mockResolvedValue({ data: { ocs: { data: { data: '1' } } } })
126+
127+
const wrapper = createWrapper()
128+
await flushPromises()
129+
wrapper.vm.addFooter = true
130+
wrapper.vm.customizeFooter = true
131+
await wrapper.vm.$nextTick()
132+
133+
const footerEditor = wrapper.findComponent(FooterTemplateEditorStub)
134+
const resetFooterTemplateMock = vi.spyOn(footerEditor.vm, 'resetFooterTemplate')
135+
136+
await wrapper.vm.onCustomizeFooterChange(false)
137+
138+
expect(appConfigSetValueMock).toHaveBeenCalledWith('libresign', 'footer_template_is_default', '1')
139+
expect(wrapper.vm.isDefaultFooterTemplate).toBe(true)
140+
expect(resetFooterTemplateMock).toHaveBeenCalledTimes(1)
141+
})
142+
143+
it('persists the private validation URL toggle through the shared setter', async () => {
144+
axiosGetMock.mockResolvedValue({ data: { ocs: { data: { data: '1' } } } })
145+
146+
const wrapper = createWrapper()
147+
await flushPromises()
148+
149+
await wrapper.vm.onMakeValidationUrlPrivateChange(true)
150+
151+
expect(appConfigSetValueMock).toHaveBeenCalledWith('libresign', 'make_validation_url_private', '1')
152+
})
153+
})

0 commit comments

Comments
 (0)