Files
mdm-ordinis/ordinis-admin-ui/src/routes/dictionaries.index.test.ts
T
2026-05-10 18:26:30 +00:00

175 lines
5.3 KiB
TypeScript

/**
* Unit tests для catalog list-view pure helpers (parseScopeFilter +
* matchesQuery + groupByBundle).
*
* См. design_handoff_dictionary_catalog/ для полной spec'и (List view D).
*/
import { describe, it, expect } from 'vitest'
import type { DictionaryDefinition } from '@/api/client'
import {
parseScopeFilter,
matchesQuery,
groupByBundle,
uniqueRefBy,
} from './dictionaries.index'
import type { SchemaDependent } from '@/api/client'
const mkDict = (overrides: Partial<DictionaryDefinition>): DictionaryDefinition => ({
id: 'id-' + (overrides.name ?? 'x'),
name: overrides.name ?? 'test',
displayName: overrides.displayName,
description: overrides.description,
scope: overrides.scope ?? 'PUBLIC',
schemaVersion: overrides.schemaVersion ?? '1.0.0',
bundle: overrides.bundle ?? 'cuod',
supportedLocales: overrides.supportedLocales ?? ['ru-RU'],
defaultLocale: overrides.defaultLocale ?? 'ru-RU',
redisProjectionEnabled: overrides.redisProjectionEnabled ?? false,
approvalRequired: overrides.approvalRequired ?? false,
approvalMinRole: overrides.approvalMinRole ?? null,
recordCount: overrides.recordCount,
createdAt: overrides.createdAt ?? '2026-01-01T00:00:00Z',
updatedAt: overrides.updatedAt ?? '2026-01-01T00:00:00Z',
})
describe('parseScopeFilter', () => {
it('returns empty Set for undefined / empty input', () => {
expect(parseScopeFilter(undefined).size).toBe(0)
expect(parseScopeFilter('').size).toBe(0)
})
it('parses single valid scope', () => {
const out = parseScopeFilter('PUBLIC')
expect(out.size).toBe(1)
expect(out.has('PUBLIC')).toBe(true)
})
it('parses CSV with multiple scopes', () => {
const out = parseScopeFilter('PUBLIC,INTERNAL,RESTRICTED')
expect(out.size).toBe(3)
})
it('case-insensitive — lowercase + mixed case normalized to UPPER', () => {
const out = parseScopeFilter('public,Internal')
expect(out.has('PUBLIC')).toBe(true)
expect(out.has('INTERNAL')).toBe(true)
})
it('skips invalid scopes (bookmark protection)', () => {
const out = parseScopeFilter('FOO,PUBLIC,BAR')
expect(out.size).toBe(1)
expect(out.has('PUBLIC')).toBe(true)
})
it('deduplicates repeated scopes via Set', () => {
const out = parseScopeFilter('PUBLIC,PUBLIC,public')
expect(out.size).toBe(1)
})
it('handles whitespace', () => {
const out = parseScopeFilter(' PUBLIC , INTERNAL ')
expect(out.size).toBe(2)
})
})
describe('matchesQuery', () => {
const dict = mkDict({
name: 'spacecraft',
displayName: 'Космические аппараты',
description: 'Реестр спутников',
})
it('empty query matches anything', () => {
expect(matchesQuery(dict, '')).toBe(true)
})
it('matches name substring', () => {
expect(matchesQuery(dict, 'space')).toBe(true)
})
it('matches displayName (RU)', () => {
expect(matchesQuery(dict, 'космич')).toBe(true)
})
it('matches description', () => {
expect(matchesQuery(dict, 'спутник')).toBe(true)
})
it('returns false on miss', () => {
expect(matchesQuery(dict, 'абракадабра')).toBe(false)
})
})
describe('groupByBundle', () => {
it('groups dicts by bundle', () => {
const list = [
mkDict({ name: 'a', bundle: 'cuod' }),
mkDict({ name: 'b', bundle: 'geo' }),
mkDict({ name: 'c', bundle: 'cuod' }),
]
const out = groupByBundle(list)
expect(out.size).toBe(2)
expect(out.get('cuod')).toHaveLength(2)
expect(out.get('geo')).toHaveLength(1)
})
it('sorts dicts within group by displayName/name', () => {
const list = [
mkDict({ name: 'zebra', displayName: 'Зебра', bundle: 'cuod' }),
mkDict({ name: 'alpha', displayName: 'Альфа', bundle: 'cuod' }),
mkDict({ name: 'beta', displayName: 'Бета', bundle: 'cuod' }),
]
const out = groupByBundle(list)
expect(out.get('cuod')!.map((d) => d.name)).toEqual(['alpha', 'beta', 'zebra'])
})
it('empty input returns empty Map', () => {
expect(groupByBundle([]).size).toBe(0)
})
it('falls back to "default" bundle если bundle пуст', () => {
const list = [mkDict({ name: 'x', bundle: '' })]
const out = groupByBundle(list)
expect(out.has('default')).toBe(true)
})
})
describe('uniqueRefBy', () => {
const mkDep = (sourceDict: string, sourceField = 'fk'): SchemaDependent => ({
sourceDict,
sourceDisplayName: `${sourceDict}-display`,
sourceField,
targetField: 'id',
onClose: 'BLOCK',
activeRecordsInSourceDict: 0,
})
it('empty input returns empty array', () => {
expect(uniqueRefBy([])).toEqual([])
})
it('preserves single entry as-is', () => {
const out = uniqueRefBy([mkDep('missions')])
expect(out).toHaveLength(1)
expect(out[0].sourceDict).toBe('missions')
})
it('dedups by sourceDict — multiple fields → один chip', () => {
const out = uniqueRefBy([
mkDep('satellites', 'type_id'),
mkDep('satellites', 'mission_id'),
mkDep('missions', 'fk'),
])
expect(out.map((d) => d.sourceDict)).toEqual(['satellites', 'missions'])
})
it('preserves first-occurrence displayName', () => {
const out = uniqueRefBy([
{ ...mkDep('x'), sourceDisplayName: 'First' },
{ ...mkDep('x'), sourceDisplayName: 'Second' },
])
expect(out).toHaveLength(1)
expect(out[0].sourceDisplayName).toBe('First')
})
})