- settingsSectionOf: null cases, category order, link entry placement - SettingsPanel: labels, links, current entry, empty category, collapse - AppShell: hidden cases, settings-link controllers, collapse, offset, narrow, focus hand-off
107 lines
4.2 KiB
TypeScript
107 lines
4.2 KiB
TypeScript
import { beforeEach, describe, expect, it } from 'vitest'
|
|
import {
|
|
hasSettings,
|
|
loadSettings,
|
|
setSettings,
|
|
settings,
|
|
settingsEntry,
|
|
settingsGroups,
|
|
settingsLinkFor,
|
|
settingsPath,
|
|
settingsSectionOf,
|
|
useSettings,
|
|
} from '../../src/state/useSettings'
|
|
import { settingsFixture } from '../fixtures/typed'
|
|
import { API, mockApi, resetState } from '../helpers'
|
|
|
|
beforeEach(() => {
|
|
resetState()
|
|
})
|
|
|
|
describe('useSettings (D-21)', () => {
|
|
it('is hidden until at least one settings page is permitted', async () => {
|
|
expect(hasSettings.value).toBe(false)
|
|
mockApi({ [`GET ${API}/settings`]: { body: settingsFixture.list } })
|
|
expect(await loadSettings()).toHaveLength(3)
|
|
expect(hasSettings.value).toBe(true)
|
|
expect(useSettings().settings).toBe(settings)
|
|
})
|
|
|
|
it('hides settings again when the request fails', async () => {
|
|
setSettings(settingsFixture.list.data)
|
|
mockApi({ [`GET ${API}/settings`]: { status: 403, body: { error: { code: 'forbidden', message: 'x', details: {} } } } })
|
|
expect(await loadSettings()).toEqual([])
|
|
expect(hasSettings.value).toBe(false)
|
|
})
|
|
|
|
it('finds an entry by code', () => {
|
|
setSettings(settingsFixture.list.data)
|
|
expect(settingsEntry('mail')?.label).toBe('Mail')
|
|
expect(settingsEntry('nope')).toBeNull()
|
|
})
|
|
|
|
it('groups by category in first-seen order after sorting by order', () => {
|
|
setSettings(settingsFixture.list.data)
|
|
expect(settingsGroups.value.map((group) => [group.category, group.entries.map((entry) => entry.code)])).toEqual([
|
|
['Appearance', ['branding']],
|
|
['System', ['mail', 'search']],
|
|
])
|
|
})
|
|
|
|
it('links a singleton to its form and a controller link to the controller route', () => {
|
|
const singleton = settingsFixture.list.data[0]!
|
|
expect(settingsPath({ ...singleton, code: 'a b' })).toBe('/settings/a%20b')
|
|
expect(settingsPath({ ...singleton, code: 'locales', model: '', controller: 'acme.demo.locales' })).toBe('/acme/demo/locales')
|
|
expect(settingsPath({ ...singleton, code: 'broken', model: '', controller: 'acme.demo' })).toBe('/settings')
|
|
expect(useSettings().settingsPath).toBe(settingsPath)
|
|
})
|
|
|
|
it('finds the link entry that opens a controller, never a singleton', () => {
|
|
const link = { ...settingsFixture.list.data[0]!, code: 'locales', model: '', controller: 'acme.demo.locales' }
|
|
setSettings([...settingsFixture.list.data, link])
|
|
expect(settingsLinkFor('acme.demo.locales')?.code).toBe('locales')
|
|
expect(settingsLinkFor('acme.demo.widgets')).toBeNull()
|
|
expect(settingsLinkFor('')).toBeNull()
|
|
expect(settingsLinkFor(null)).toBeNull()
|
|
expect(useSettings().settingsLinkFor).toBe(settingsLinkFor)
|
|
})
|
|
})
|
|
|
|
describe('settingsSectionOf (quick-261022-imo)', () => {
|
|
const link = (code: string, order: number, controller: string) => ({
|
|
...settingsFixture.list.data[0]!,
|
|
code,
|
|
label: code,
|
|
model: '',
|
|
controller,
|
|
order,
|
|
})
|
|
|
|
it('is null without a current entry or for a one-entry category', () => {
|
|
setSettings(settingsFixture.list.data)
|
|
expect(settingsSectionOf(null)).toBeNull()
|
|
expect(settingsSectionOf(settingsEntry('branding'))).toBeNull()
|
|
})
|
|
|
|
it('returns the current category in settingsGroups order', () => {
|
|
setSettings(settingsFixture.list.data)
|
|
const section = settingsSectionOf(settingsEntry('mail'))
|
|
expect(section?.category).toBe('System')
|
|
expect(section?.current.code).toBe('mail')
|
|
expect(section?.entries.map((entry) => entry.code)).toEqual(['mail', 'search'])
|
|
})
|
|
|
|
it('places a link entry by its order and never lists another category', () => {
|
|
setSettings([...settingsFixture.list.data, link('locales', 15, 'acme.lang.locales')])
|
|
const section = settingsSectionOf(settingsLinkFor('acme.lang.locales'))
|
|
expect(section?.current.code).toBe('locales')
|
|
expect(section?.entries.map((entry) => entry.code)).toEqual(['mail', 'locales', 'search'])
|
|
expect(section?.entries.some((entry) => entry.category === 'Appearance')).toBe(false)
|
|
expect(settingsSectionOf(settingsEntry('search'))?.entries.map((entry) => entry.code)).not.toContain('branding')
|
|
})
|
|
|
|
it('is exposed through useSettings', () => {
|
|
expect(useSettings().settingsSectionOf).toBe(settingsSectionOf)
|
|
})
|
|
})
|