generated from Seekra/repository-template
Feat(settings): add renderer for settings configuration #142
@@ -84,15 +84,15 @@ onMounted(async () => {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="!settingsLoaded">
|
<div v-if="!settingsLoaded" class="main-content--loading">
|
||||||
{{ t('loading') }}
|
{{ t('loading') }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="activeSection">
|
<div v-else-if="activeSection" class="main-content--loaded">
|
||||||
<div class="settings-main-content">
|
<div class="settings-main-content">
|
||||||
<SettingsPage :setting="activeSectionContent" :path="activeSection" />
|
<SettingsPage :setting="activeSectionContent" :path="activeSection" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else class="main-content--no-section">
|
||||||
{{ t('settings.noSectionSelected') }}
|
{{ t('settings.noSectionSelected') }}
|
||||||
</div>
|
</div>
|
||||||
</LeftSidebarLayout>
|
</LeftSidebarLayout>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user