Files
summercms/admin/tests/state/useSettings.test.ts
Jakub Zych 0b09acdb0c feat(admin): open controller-link settings entries from the settings index
A settings entry with a controller opens that controller's route from
its card (settingsPath); singleton cards still open /settings/<code>.
On a linked controller with no navigation entry of its own the rail
marks Settings current, the breadcrumbs read Settings > entry label
(plus the record title on record and create routes) and the page title
uses the entry label. The settings docs describe the admin behaviour;
the embedded admin shell is rebuilt.
2026-10-07 18:24:54 +02:00

68 lines
2.6 KiB
TypeScript

import { beforeEach, describe, expect, it } from 'vitest'
import {
hasSettings,
loadSettings,
setSettings,
settings,
settingsEntry,
settingsGroups,
settingsLinkFor,
settingsPath,
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)
})
})