import { describe, expect, it } from 'vitest' import { HR_APP, PLATFORM_APPS, PLATFORM_HR_ENTITIES, getBuiltinApp, matchBuiltinApp, matchBuiltinModule, matchPlatformHrEntity, } from '../platform-catalog.js' describe('platform-catalog — matchBuiltinApp', () => { it('resolves the HR app from FR/EN domain names (the reported symptom)', () => { for (const name of ['RH', 'rh', 'Ressources Humaines', 'ressources humaines', 'HR', 'Human Resources', 'Personnel', 'GRH']) { expect(matchBuiltinApp(name)?.code, `"${name}" should resolve to hr`).toBe('hr') } }) it('resolves apps from their exact seed code', () => { expect(matchBuiltinApp('administration')?.code).toBe('administration') expect(matchBuiltinApp('support')?.code).toBe('support') expect(matchBuiltinApp('api')?.code).toBe('api') expect(matchBuiltinApp('myspace')?.code).toBe('myspace') }) it('is accent- and case-insensitive and singular-tolerant', () => { expect(matchBuiltinApp('SUPPORT')?.code).toBe('support') expect(matchBuiltinApp('helpdesk')?.code).toBe('support') }) it('never substring-matches (HRManager, RHexport are NOT the HR app)', () => { expect(matchBuiltinApp('HRManager')).toBeUndefined() expect(matchBuiltinApp('RHexport')).toBeUndefined() expect(matchBuiltinApp('Recrutement')).toBeUndefined() expect(matchBuiltinApp('CRM')).toBeUndefined() }) it('carries the HR app GUID a client extension FKs to', () => { expect(matchBuiltinApp('RH')?.guid).toBe('9cbeae29-772f-43b1-ac93-c56f2cb90921') expect(HR_APP.guid).toBe('9cbeae29-772f-43b1-ac93-c56f2cb90921') expect(HR_APP.extendable).toBe(true) }) }) describe('platform-catalog — matchBuiltinModule (distinctive only)', () => { it('flags distinctive HR modules a client should not recreate', () => { expect(matchBuiltinModule('Absences')?.module.code).toBe('absences') expect(matchBuiltinModule('Congés')?.module.code).toBe('absences') expect(matchBuiltinModule('Saisie du temps')?.module.code).toBe('time') expect(matchBuiltinModule('Employés')?.module.code).toBe('employees') expect(matchBuiltinModule('Tickets')?.app.code).toBe('support') }) it('does NOT flag generic modules a client legitimately owns', () => { expect(matchBuiltinModule('Reporting')).toBeUndefined() expect(matchBuiltinModule('Dashboard')).toBeUndefined() expect(matchBuiltinModule('Configuration')).toBeUndefined() expect(matchBuiltinModule('Organization')).toBeUndefined() expect(matchBuiltinModule('Profile')).toBeUndefined() }) }) describe('platform-catalog — matchPlatformHrEntity', () => { it('flags transactional HR entities (extend, do not rebuild)', () => { expect(matchPlatformHrEntity('Absence')?.name).toBe('Absence') expect(matchPlatformHrEntity('Congé')?.name).toBe('Absence') expect(matchPlatformHrEntity('LeaveRequest')?.name).toBe('Absence') expect(matchPlatformHrEntity('TimeEntry')?.name).toBe('TimeEntry') expect(matchPlatformHrEntity('Pointage')?.name).toBe('TimeEntry') expect(matchPlatformHrEntity('Timesheet')?.name).toBe('Timesheet') expect(matchPlatformHrEntity('ContractType')?.name).toBe('ContractType') }) it('does NOT flag Employee (a person-extension, owned by core-catalog PERSON_TRIGGERS)', () => { expect(matchPlatformHrEntity('Employee')).toBeUndefined() expect(matchPlatformHrEntity('Employé')).toBeUndefined() expect(matchPlatformHrEntity('Collaborateur')).toBeUndefined() }) it('does NOT substring-match', () => { expect(matchPlatformHrEntity('AbsenceReasonCatalog')).toBeUndefined() expect(matchPlatformHrEntity('TimeEntryProject')).toBeUndefined() }) }) describe('platform-catalog — invariants', () => { it('every app has a unique code and a GUID', () => { const codes = PLATFORM_APPS.map(a => a.code) expect(new Set(codes).size).toBe(codes.length) for (const app of PLATFORM_APPS) { expect(app.guid).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/) } }) it('only myspace is personal, and personal apps are not extendable', () => { expect(PLATFORM_APPS.filter(a => a.isPersonal).map(a => a.code)).toEqual(['myspace']) for (const app of PLATFORM_APPS) { if (app.isPersonal) expect(app.extendable).toBe(false) } }) it('getBuiltinApp resolves by exact code only', () => { expect(getBuiltinApp('hr')).toBe(HR_APP) expect(getBuiltinApp('HR')).toBeUndefined() expect(getBuiltinApp('nope')).toBeUndefined() }) it('does not double-flag: no HR transactional entity is also a distinctive module alias clash', () => { for (const e of PLATFORM_HR_ENTITIES) { // Employee excluded by design; transactional entities are not app names. expect(matchBuiltinApp(e.name)).toBeUndefined() } }) })