From fb0d80d7f6c6083fbcc9906e53cf89de7c476b03 Mon Sep 17 00:00:00 2001 From: Jakob Scheid Date: Mon, 27 Jul 2026 18:18:32 +0200 Subject: [PATCH] test(settings): add tests for settings view Added tests for the settings view (SettingsView.vue): - heading translation - sidebar top-level sections - correct main element --- src/features/settings/views/SettingsView.vue | 6 +- .../views/__tests__/SettingsView.test.js | 306 ++++++++++++++++++ 2 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 src/features/settings/views/__tests__/SettingsView.test.js diff --git a/src/features/settings/views/SettingsView.vue b/src/features/settings/views/SettingsView.vue index 921114c..f1a9590 100644 --- a/src/features/settings/views/SettingsView.vue +++ b/src/features/settings/views/SettingsView.vue @@ -84,15 +84,15 @@ onMounted(async () => { -
+
{{ t('loading') }}
-
+
-
+
{{ t('settings.noSectionSelected') }}
diff --git a/src/features/settings/views/__tests__/SettingsView.test.js b/src/features/settings/views/__tests__/SettingsView.test.js new file mode 100644 index 0000000..e8584ce --- /dev/null +++ b/src/features/settings/views/__tests__/SettingsView.test.js @@ -0,0 +1,306 @@ +/* +Copyright 2026 Seekra + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import SettingsView from '../SettingsView.vue'; +import { mountComponent } from '@/test-utils/mountComponent.js'; +import { flushPromises } from '@vue/test-utils'; +import { beforeEach, describe, expect, test, vi } from 'vitest'; + +const settingsHoisted = vi.hoisted(() => [ + { + name: 's0', + i18n: 'settings.s0', + content: [] + }, + { + name: 's1', + i18n: 'settings.s1', + content: [ + { + type: 'bool', + name: 'b0', + i18n: 'settings.s1.b0' + }, + { + type: 'number', + name: 'n0', + i18n: 'settings.s1.n0' + }, + { + type: 'string', + name: 'st0', + i18n: 'settings.s1.st0' + }, + { + type: 'selection', + name: 'se0', + i18n: 'settings.s1.se0', + options: [ + { name: 'o0', i18n: 'settings.s1.se0.o0' }, + { name: 'o1', i18n: 'settings.s1.se0.o1' }, + { name: 'o2', i18n: 'settings.s1.se0.o2' }, + { name: 'o3', i18n: 'settings.s1.se0.o3' } + ] + }, + { + type: 'section', + name: 's0', + i18n: 'settings.s1.s0', + content: [] + }, + { + type: 'section', + name: 's1', + i18n: 'settings.s1.s1', + content: [ + { + type: 'bool', + name: 'b0', + i18n: 'settings.s1.s1.b0', + default: true + } + ] + } + ] + }, + { + name: 's2', + i18n: 'settings.s2', + content: [ + { + type: 'section', + name: 's0', + i18n: 'settings.s2.s0', + content: [ + { + type: 'bool', + name: 'b0', + i18n: 'settings.s2.s0.b0', + default: true + } + ] + } + ] + }, + { + name: 's3', + i18n: 'settings.s3', + content: [ + { + type: 'section', + name: 's0', + i18n: 'settings.s3.s0', + content: [] + } + ] + }, + { + name: 's4', + i18n: 'settings.s4', + content: [ + { + type: 'selection', + name: 'se0', + i18n: 'settings.s4.se0', + options: [ + { name: 'o0', i18n: 'settings.s4.se0.o0' }, + { name: 'o1', i18n: 'settings.s4.se0.o1' }, + { name: 'o2', i18n: 'settings.s4.se0.o2' }, + { name: 'o3', i18n: 'settings.s4.se0.o3' } + ] + } + ] + }, + { + name: 's5', + i18n: 'settings.s5', + content: [ + { + type: 'string', + name: 'st0', + i18n: 'settings.s5.st0' + } + ] + }, + { + name: 's6', + i18n: 'settings.s6', + content: [ + { + type: 'number', + name: 'n0', + i18n: 'settings.s6.n0' + } + ] + }, + { + name: 's7', + i18n: 'settings.s7', + content: [ + { + type: 'bool', + name: 'b0', + i18n: 'settings.s7.b0' + } + ] + }, + { + name: 's8', + i18n: 'settings.s8', + content: [ + { + type: 'section', + name: 's0', + i18n: 'settings.s8.s0', + content: [ + { + type: 'section', + name: 's0', + i18n: 'settings.s8.s0.s0', + content: [ + { + type: 'section', + name: 's0', + i18n: 'settings.s8.s0.s0.s0', + content: [ + { + type: 'selection', + name: 'se0', + i18n: 'settings.s8.s0.s0.s0.se0', + allowMultiple: true, + options: [] + } + ] + } + ] + } + ] + } + ] + } +]); +const settings = settingsHoisted.values(); + +const originalCurrentSection = 's0'; +let currentSection = originalCurrentSection; + +vi.mock('../../utils/settingsParser', () => ({ + loadSettingsConfig: vi.fn().mockResolvedValue({ + contents: settingsHoisted + }) +})); + +vi.mock('vue-router', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + useRoute: () => ({ + path: `/settings/${currentSection}` + }) + }; +}); + +const getWrapper = function getWrapper ({ translations = {} } = {}) { + return mountComponent(SettingsView, {}, translations, [], {}); +}; + +describe('SettingsView', () => { + describe('heading', () => { + test('shows correct translation', () => { + const translation = 'Settings'; + const wrapper = getWrapper({ + translations: { + 'preferences.settings': translation + } + }); + + const header = wrapper.find('header'); + expect(header.text()).toBe(translation); + }); + }); + + describe('sidebar', () => { + test('shows all top-level sections', async () => { + const wrapper = getWrapper(); + + await flushPromises(); + await wrapper.vm.$nextTick(); + + const sidebarItems = wrapper.findAll('.sidebar-sections-list > li'); + settings.forEach((setting, index) => { + const sidebarItem = sidebarItems[index]; + + expect(sidebarItem.text()).toBe(setting.i18n); + + const link = sidebarItem.find('*'); + expect(link.attributes('href')).toBe(`/settings/${setting.name}`); + expect(link.classes('active')).toBe(setting.name === currentSection); + }); + }); + }); + + describe('main', () => { + describe('correct element', () => { + test('shows that it is loading', () => { + const wrapper = getWrapper(); + + const mainContentLoading = wrapper.find('.main-content--loading'); + const mainContentLoaded = wrapper.find('.main-content--loaded'); + const mainContentNoSection = wrapper.find('.main-content--no-section'); + + expect(mainContentLoading.exists()).toBe(true); + expect(mainContentLoaded.exists()).toBe(false); + expect(mainContentNoSection.exists()).toBe(false); + }); + + test('shows that no section is selected', async () => { + currentSection = ''; + + const wrapper = getWrapper(); + + await flushPromises(); + await wrapper.vm.$nextTick(); + + const mainContentLoading = wrapper.find('.main-content--loading'); + const mainContentLoaded = wrapper.find('.main-content--loaded'); + const mainContentNoSection = wrapper.find('.main-content--no-section'); + + expect(mainContentLoading.exists()).toBe(false); + expect(mainContentLoaded.exists()).toBe(false); + expect(mainContentNoSection.exists()).toBe(true); + }); + + test('shows main content', async () => { + const wrapper = getWrapper(); + + await flushPromises(); + await wrapper.vm.$nextTick(); + + const mainContentLoading = wrapper.find('.main-content--loading'); + const mainContentLoaded = wrapper.find('.main-content--loaded'); + const mainContentNoSection = wrapper.find('.main-content--no-section'); + + expect(mainContentLoading.exists()).toBe(false); + expect(mainContentLoaded.exists()).toBe(true); + expect(mainContentNoSection.exists()).toBe(false); + }); + }); + }); +}); + +beforeEach(() => { + currentSection = originalCurrentSection; +}); \ No newline at end of file