mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-29 00:01:29 +00:00
132 lines
3.8 KiB
TypeScript
132 lines
3.8 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { createRequire } from 'node:module'
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
type ConfiguratorField = {
|
|
label: string
|
|
path: string
|
|
structure?: ConfiguratorStructure
|
|
type: string
|
|
value: unknown
|
|
}
|
|
|
|
type ConfiguratorStructure = {
|
|
entries?: Array<{ structure: ConfiguratorStructure }>
|
|
fields?: Record<string, ConfiguratorStructure>
|
|
items?: ConfiguratorStructure[]
|
|
kind: string
|
|
mutableKeys?: boolean
|
|
template?: ConfiguratorStructure
|
|
}
|
|
|
|
type ConfiguratorSection = {
|
|
fields: ConfiguratorField[]
|
|
id: string
|
|
scope: 'config' | 'media'
|
|
}
|
|
|
|
const require = createRequire(import.meta.url)
|
|
const { loadConfiguratorSections } = require('./configurator-fixture.cjs') as {
|
|
loadConfiguratorSections: () => ConfiguratorSection[]
|
|
}
|
|
|
|
const configSource = readFileSync(
|
|
new URL('../../sky_phone/config/config.lua', import.meta.url),
|
|
'utf8',
|
|
)
|
|
|
|
function countStructure(structure: ConfiguratorStructure | undefined): number {
|
|
if (!structure) return 1
|
|
if (structure.fields) {
|
|
return Object.values(structure.fields).reduce(
|
|
(total, field) => total + countStructure(field),
|
|
0,
|
|
)
|
|
}
|
|
if (structure.items) {
|
|
return structure.items.reduce(
|
|
(total, item) => total + countStructure(item),
|
|
0,
|
|
)
|
|
}
|
|
if (structure.entries) {
|
|
return structure.entries.reduce(
|
|
(total, entry) => total + countStructure(entry.structure),
|
|
0,
|
|
)
|
|
}
|
|
return 1
|
|
}
|
|
|
|
describe('admin configurator fixture', () => {
|
|
it('exposes every config.lua root through the full live preview', () => {
|
|
const sections = loadConfiguratorSections()
|
|
const fields = sections.flatMap((section) => section.fields)
|
|
const roots = [
|
|
...configSource.matchAll(/^\s{0,4}Config\.([A-Za-z0-9_]+)\s*=/gm),
|
|
]
|
|
.map((match) => match[1])
|
|
.filter((root) => root !== 'Media' && root !== 'PhoneConfigurator')
|
|
|
|
expect(sections).toHaveLength(45)
|
|
expect(
|
|
fields.reduce(
|
|
(total, field) => total + countStructure(field.structure),
|
|
0,
|
|
),
|
|
).toBeGreaterThan(700)
|
|
for (const root of new Set(roots)) {
|
|
expect(
|
|
sections.some(
|
|
(section) =>
|
|
section.id === `config:${root}` ||
|
|
section.fields.some(
|
|
(field) =>
|
|
field.path === root || field.path.startsWith(`${root}.`),
|
|
),
|
|
),
|
|
`Missing Config.${root}`,
|
|
).toBe(true)
|
|
}
|
|
})
|
|
|
|
it('preserves numeric Lua map keys and the false keybind option', () => {
|
|
const fields = loadConfiguratorSections().flatMap(
|
|
(section) => section.fields,
|
|
)
|
|
const darkChat = fields.find((field) => field.path === 'DarkChat')
|
|
const phone = fields.find((field) => field.path === 'Phone')
|
|
const companyJobs = fields.find(
|
|
(field) => field.path === 'Companies.Definitions',
|
|
)
|
|
const garage = fields.find((field) => field.path === 'Garage')
|
|
const timers = (darkChat?.value as Record<string, unknown> | undefined)
|
|
?.AllowedDisappearTimers
|
|
|
|
expect(timers).toMatchObject({
|
|
__skyType: 'map',
|
|
entries: expect.arrayContaining([
|
|
{ key: -1, keyType: 'number', value: true },
|
|
{ key: 0, keyType: 'number', value: true },
|
|
{ key: 604800, keyType: 'number', value: true },
|
|
]),
|
|
})
|
|
expect(darkChat?.structure?.fields?.AllowedDisappearTimers.kind).toBe('map')
|
|
expect(phone?.structure?.fields?.Keybind.kind).toBe('optionalString')
|
|
expect(companyJobs?.label).toBe('Jobs')
|
|
expect(companyJobs?.structure).toMatchObject({
|
|
fields: {
|
|
ambulance: { kind: 'table' },
|
|
police: { kind: 'table' },
|
|
},
|
|
kind: 'table',
|
|
mutableKeys: true,
|
|
template: { kind: 'table' },
|
|
})
|
|
expect(
|
|
garage?.structure?.fields?.VehicleImages.fields?.ModelNames.kind,
|
|
).toBe('map')
|
|
})
|
|
})
|