Added custom json edit to config tab

This commit is contained in:
Richard Osborne
2026-01-08 13:27:38 +01:00
parent 4a1080d547
commit 67b8ddc9c3
53 changed files with 8756 additions and 210 deletions

View File

@@ -0,0 +1,197 @@
/**
* Tests for Config Validation
*/
import { describe, it, expect } from '@jest/globals';
import { DEFAULT_APP_CONFIG } from './types';
import { validateConfigKey, validateConfigValue, validateAppConfig } from './validation';
describe('validateConfigKey', () => {
it('should accept valid JavaScript identifiers', () => {
expect(validateConfigKey('apiKey').valid).toBe(true);
expect(validateConfigKey('API_KEY').valid).toBe(true);
expect(validateConfigKey('_privateKey').valid).toBe(true);
expect(validateConfigKey('$special').valid).toBe(true);
expect(validateConfigKey('key123').valid).toBe(true);
});
it('should reject empty keys', () => {
const result = validateConfigKey('');
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('cannot be empty');
});
it('should reject invalid identifiers', () => {
expect(validateConfigKey('123key').valid).toBe(false);
expect(validateConfigKey('my-key').valid).toBe(false);
expect(validateConfigKey('my key').valid).toBe(false);
expect(validateConfigKey('my.key').valid).toBe(false);
});
it('should reject reserved keys', () => {
const result = validateConfigKey('appName');
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('reserved');
});
});
describe('validateConfigValue', () => {
describe('number type', () => {
it('should accept valid numbers', () => {
expect(validateConfigValue(42, 'number').valid).toBe(true);
expect(validateConfigValue(0, 'number').valid).toBe(true);
expect(validateConfigValue(-10.5, 'number').valid).toBe(true);
});
it('should reject non-numbers', () => {
expect(validateConfigValue('42', 'number').valid).toBe(false);
expect(validateConfigValue(NaN, 'number').valid).toBe(false);
});
it('should enforce min/max validation', () => {
expect(validateConfigValue(5, 'number', { min: 0, max: 10 }).valid).toBe(true);
expect(validateConfigValue(-1, 'number', { min: 0 }).valid).toBe(false);
expect(validateConfigValue(11, 'number', { max: 10 }).valid).toBe(false);
});
});
describe('string type', () => {
it('should accept valid strings', () => {
expect(validateConfigValue('hello', 'string').valid).toBe(true);
expect(validateConfigValue('', 'string').valid).toBe(true);
});
it('should reject non-strings', () => {
expect(validateConfigValue(42, 'string').valid).toBe(false);
});
it('should enforce pattern validation', () => {
const result = validateConfigValue('abc', 'string', { pattern: '^[0-9]+$' });
expect(result.valid).toBe(false);
const validResult = validateConfigValue('123', 'string', { pattern: '^[0-9]+$' });
expect(validResult.valid).toBe(true);
});
});
describe('boolean type', () => {
it('should accept booleans', () => {
expect(validateConfigValue(true, 'boolean').valid).toBe(true);
expect(validateConfigValue(false, 'boolean').valid).toBe(true);
});
it('should reject non-booleans', () => {
expect(validateConfigValue('true', 'boolean').valid).toBe(false);
expect(validateConfigValue(1, 'boolean').valid).toBe(false);
});
});
describe('color type', () => {
it('should accept valid hex colors', () => {
expect(validateConfigValue('#ff0000', 'color').valid).toBe(true);
expect(validateConfigValue('#FF0000', 'color').valid).toBe(true);
expect(validateConfigValue('#ff0000ff', 'color').valid).toBe(true);
});
it('should reject invalid colors', () => {
expect(validateConfigValue('red', 'color').valid).toBe(false);
expect(validateConfigValue('#ff00', 'color').valid).toBe(false);
expect(validateConfigValue('ff0000', 'color').valid).toBe(false);
});
});
describe('array type', () => {
it('should accept arrays', () => {
expect(validateConfigValue([], 'array').valid).toBe(true);
expect(validateConfigValue([1, 2, 3], 'array').valid).toBe(true);
});
it('should reject non-arrays', () => {
expect(validateConfigValue('[]', 'array').valid).toBe(false);
expect(validateConfigValue({}, 'array').valid).toBe(false);
});
});
describe('object type', () => {
it('should accept objects', () => {
expect(validateConfigValue({}, 'object').valid).toBe(true);
expect(validateConfigValue({ key: 'value' }, 'object').valid).toBe(true);
});
it('should reject non-objects', () => {
expect(validateConfigValue([], 'object').valid).toBe(false);
expect(validateConfigValue(null, 'object').valid).toBe(false);
expect(validateConfigValue('{}', 'object').valid).toBe(false);
});
});
describe('required validation', () => {
it('should require non-empty values', () => {
expect(validateConfigValue('', 'string', { required: true }).valid).toBe(false);
expect(validateConfigValue(null, 'string', { required: true }).valid).toBe(false);
expect(validateConfigValue(undefined, 'string', { required: true }).valid).toBe(false);
});
it('should allow empty values when not required', () => {
expect(validateConfigValue('', 'string').valid).toBe(true);
expect(validateConfigValue(null, 'string').valid).toBe(true);
});
});
});
describe('validateAppConfig', () => {
it('should accept valid config', () => {
const config = {
...DEFAULT_APP_CONFIG,
identity: {
appName: 'Test App',
description: 'Test Description'
}
};
expect(validateAppConfig(config).valid).toBe(true);
});
it('should require app name', () => {
const config = {
...DEFAULT_APP_CONFIG,
identity: {
appName: '',
description: ''
}
};
const result = validateAppConfig(config);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('App name');
});
it('should detect duplicate variable keys', () => {
const config = {
...DEFAULT_APP_CONFIG,
identity: { appName: 'Test', description: '' },
variables: [
{ key: 'apiKey', type: 'string' as const, value: 'key1' },
{ key: 'apiKey', type: 'string' as const, value: 'key2' }
]
};
const result = validateAppConfig(config);
expect(result.valid).toBe(false);
expect(result.errors.some((e) => e.includes('Duplicate'))).toBe(true);
});
it('should validate individual variables', () => {
const config = {
...DEFAULT_APP_CONFIG,
identity: { appName: 'Test', description: '' },
variables: [{ key: 'my-invalid-key', type: 'string' as const, value: 'test' }]
};
const result = validateAppConfig(config);
expect(result.valid).toBe(false);
});
it('should reject non-object configs', () => {
const result = validateAppConfig(null);
expect(result.valid).toBe(false);
expect(result.errors[0]).toContain('must be an object');
});
});