226 lines
7.2 KiB
TypeScript
226 lines
7.2 KiB
TypeScript
import {
|
|
TIER_LEVELS,
|
|
FEATURE_TIERS,
|
|
VEHICLE_LIMITS,
|
|
getTierLevel,
|
|
canAccessFeature,
|
|
getRequiredTier,
|
|
getFeatureConfig,
|
|
getAllFeatureConfigs,
|
|
getVehicleLimit,
|
|
canAddVehicle,
|
|
getVehicleLimitConfig,
|
|
} from '../feature-tiers';
|
|
|
|
describe('feature-tiers', () => {
|
|
describe('TIER_LEVELS', () => {
|
|
it('defines correct tier hierarchy', () => {
|
|
expect(TIER_LEVELS.free).toBe(0);
|
|
expect(TIER_LEVELS.pro).toBe(1);
|
|
expect(TIER_LEVELS.enterprise).toBe(2);
|
|
});
|
|
|
|
it('enterprise > pro > free', () => {
|
|
expect(TIER_LEVELS.enterprise).toBeGreaterThan(TIER_LEVELS.pro);
|
|
expect(TIER_LEVELS.pro).toBeGreaterThan(TIER_LEVELS.free);
|
|
});
|
|
});
|
|
|
|
describe('FEATURE_TIERS', () => {
|
|
it('includes scanMaintenanceSchedule feature', () => {
|
|
const feature = FEATURE_TIERS['document.scanMaintenanceSchedule'];
|
|
expect(feature).toBeDefined();
|
|
expect(feature.minTier).toBe('pro');
|
|
expect(feature.name).toBe('Scan for Maintenance Schedule');
|
|
expect(feature.upgradePrompt).toBeTruthy();
|
|
});
|
|
|
|
it('includes fuelLog.receiptScan feature', () => {
|
|
const feature = FEATURE_TIERS['fuelLog.receiptScan'];
|
|
expect(feature).toBeDefined();
|
|
expect(feature.minTier).toBe('pro');
|
|
expect(feature.name).toBe('Receipt Scan');
|
|
expect(feature.upgradePrompt).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('canAccessFeature - fuelLog.receiptScan', () => {
|
|
const featureKey = 'fuelLog.receiptScan';
|
|
|
|
it('denies access for free tier user', () => {
|
|
expect(canAccessFeature('free', featureKey)).toBe(false);
|
|
});
|
|
|
|
it('allows access for pro tier user', () => {
|
|
expect(canAccessFeature('pro', featureKey)).toBe(true);
|
|
});
|
|
|
|
it('allows access for enterprise tier user (inherits pro)', () => {
|
|
expect(canAccessFeature('enterprise', featureKey)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getTierLevel', () => {
|
|
it('returns correct level for each tier', () => {
|
|
expect(getTierLevel('free')).toBe(0);
|
|
expect(getTierLevel('pro')).toBe(1);
|
|
expect(getTierLevel('enterprise')).toBe(2);
|
|
});
|
|
|
|
it('returns 0 for unknown tier', () => {
|
|
expect(getTierLevel('unknown' as any)).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('canAccessFeature', () => {
|
|
const featureKey = 'document.scanMaintenanceSchedule';
|
|
|
|
it('denies access for free tier to pro feature', () => {
|
|
expect(canAccessFeature('free', featureKey)).toBe(false);
|
|
});
|
|
|
|
it('allows access for pro tier to pro feature', () => {
|
|
expect(canAccessFeature('pro', featureKey)).toBe(true);
|
|
});
|
|
|
|
it('allows access for enterprise tier to pro feature (inheritance)', () => {
|
|
expect(canAccessFeature('enterprise', featureKey)).toBe(true);
|
|
});
|
|
|
|
it('allows access for unknown feature (fail open)', () => {
|
|
expect(canAccessFeature('free', 'unknown.feature')).toBe(true);
|
|
expect(canAccessFeature('pro', 'unknown.feature')).toBe(true);
|
|
expect(canAccessFeature('enterprise', 'unknown.feature')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getRequiredTier', () => {
|
|
it('returns required tier for known feature', () => {
|
|
expect(getRequiredTier('document.scanMaintenanceSchedule')).toBe('pro');
|
|
});
|
|
|
|
it('returns null for unknown feature', () => {
|
|
expect(getRequiredTier('unknown.feature')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('getFeatureConfig', () => {
|
|
it('returns full config for known feature', () => {
|
|
const config = getFeatureConfig('document.scanMaintenanceSchedule');
|
|
expect(config).toEqual({
|
|
minTier: 'pro',
|
|
name: 'Scan for Maintenance Schedule',
|
|
upgradePrompt: expect.any(String),
|
|
});
|
|
});
|
|
|
|
it('returns undefined for unknown feature', () => {
|
|
expect(getFeatureConfig('unknown.feature')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('getAllFeatureConfigs', () => {
|
|
it('returns copy of all feature configs', () => {
|
|
const configs = getAllFeatureConfigs();
|
|
expect(configs['document.scanMaintenanceSchedule']).toBeDefined();
|
|
|
|
// Verify it's a copy, not the original
|
|
configs['test'] = { minTier: 'free', name: 'test', upgradePrompt: '' };
|
|
expect(FEATURE_TIERS['test' as keyof typeof FEATURE_TIERS]).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('VEHICLE_LIMITS', () => {
|
|
it('defines correct limits for each tier', () => {
|
|
expect(VEHICLE_LIMITS.free).toBe(2);
|
|
expect(VEHICLE_LIMITS.pro).toBe(5);
|
|
expect(VEHICLE_LIMITS.enterprise).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('getVehicleLimit', () => {
|
|
it('returns 2 for free tier', () => {
|
|
expect(getVehicleLimit('free')).toBe(2);
|
|
});
|
|
|
|
it('returns 5 for pro tier', () => {
|
|
expect(getVehicleLimit('pro')).toBe(5);
|
|
});
|
|
|
|
it('returns null for enterprise tier (unlimited)', () => {
|
|
expect(getVehicleLimit('enterprise')).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('canAddVehicle', () => {
|
|
describe('free tier (limit 2)', () => {
|
|
it('returns true when below limit', () => {
|
|
expect(canAddVehicle('free', 0)).toBe(true);
|
|
expect(canAddVehicle('free', 1)).toBe(true);
|
|
});
|
|
|
|
it('returns false when at limit', () => {
|
|
expect(canAddVehicle('free', 2)).toBe(false);
|
|
});
|
|
|
|
it('returns false when over limit', () => {
|
|
expect(canAddVehicle('free', 3)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('pro tier (limit 5)', () => {
|
|
it('returns true when below limit', () => {
|
|
expect(canAddVehicle('pro', 0)).toBe(true);
|
|
expect(canAddVehicle('pro', 4)).toBe(true);
|
|
});
|
|
|
|
it('returns false when at limit', () => {
|
|
expect(canAddVehicle('pro', 5)).toBe(false);
|
|
});
|
|
|
|
it('returns false when over limit', () => {
|
|
expect(canAddVehicle('pro', 6)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('enterprise tier (unlimited)', () => {
|
|
it('always returns true regardless of count', () => {
|
|
expect(canAddVehicle('enterprise', 0)).toBe(true);
|
|
expect(canAddVehicle('enterprise', 100)).toBe(true);
|
|
expect(canAddVehicle('enterprise', 999999)).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getVehicleLimitConfig', () => {
|
|
it('returns correct config for free tier', () => {
|
|
const config = getVehicleLimitConfig('free');
|
|
expect(config.limit).toBe(2);
|
|
expect(config.tier).toBe('free');
|
|
expect(config.upgradePrompt).toContain('Free tier is limited to 2 vehicles');
|
|
expect(config.upgradePrompt).toContain('Pro');
|
|
expect(config.upgradePrompt).toContain('Enterprise');
|
|
});
|
|
|
|
it('returns correct config for pro tier', () => {
|
|
const config = getVehicleLimitConfig('pro');
|
|
expect(config.limit).toBe(5);
|
|
expect(config.tier).toBe('pro');
|
|
expect(config.upgradePrompt).toContain('Pro tier is limited to 5 vehicles');
|
|
expect(config.upgradePrompt).toContain('Enterprise');
|
|
});
|
|
|
|
it('returns correct config for enterprise tier', () => {
|
|
const config = getVehicleLimitConfig('enterprise');
|
|
expect(config.limit).toBeNull();
|
|
expect(config.tier).toBe('enterprise');
|
|
expect(config.upgradePrompt).toBeTruthy();
|
|
});
|
|
|
|
it('provides default upgradePrompt fallback', () => {
|
|
const config = getVehicleLimitConfig('enterprise');
|
|
expect(config.upgradePrompt).toBe('Upgrade to access additional vehicles.');
|
|
});
|
|
});
|
|
});
|