fortify-schema
Version:
TypeScript interface-like schema validation system that's easier to use than Zod
207 lines (167 loc) • 6.72 kB
text/typescript
/**
* Test script for the modular Schema validation system
* Demonstrates the clean separation between schema logic and validators
*/
import { Schema } from '../core/schema/mode/general/Schema';
console.log('=== FORTIFYJS MODULAR SCHEMA TESTS ===\n');
// ===== BASIC TYPES =====
console.log('1. Basic Type Validation:');
// String validation
const nameSchema = Schema.string().min(2).max(50);
console.log('✅ Valid name:', nameSchema.safeParse('John Doe'));
console.log('❌ Invalid name:', nameSchema.safeParse('J'));
// Number validation
const ageSchema = Schema.number().int().min(0).max(120);
console.log('✅ Valid age:', ageSchema.safeParse(25));
console.log('❌ Invalid age:', ageSchema.safeParse(-5));
// Boolean validation
const activeSchema = Schema.boolean();
console.log('✅ Valid boolean:', activeSchema.safeParse(true));
console.log('✅ String to boolean:', activeSchema.safeParse('true'));
// ===== ADVANCED STRING VALIDATION =====
console.log('\n2. Advanced String Validation:');
// Email validation (using built-in format validation)
const emailSchema = Schema.string().email();
console.log('✅ Valid email:', emailSchema.safeParse('user@example.com'));
console.log('❌ Invalid email:', emailSchema.safeParse('invalid-email'));
// Phone validation
const phoneSchema = Schema.string().phone();
console.log('✅ Valid phone:', phoneSchema.safeParse('+1234567890'));
console.log('❌ Invalid phone:', phoneSchema.safeParse('123'));
// UUID validation
const uuidSchema = Schema.string().uuid();
console.log('✅ Valid UUID:', uuidSchema.safeParse('123e4567-e89b-12d3-a456-426614174000'));
console.log('❌ Invalid UUID:', uuidSchema.safeParse('not-a-uuid'));
// ===== ARRAY VALIDATION =====
console.log('\n3. Array Validation:');
// Array of strings
const tagsSchema = Schema.array(Schema.string()).min(1).max(5);
console.log('✅ Valid tags:', tagsSchema.safeParse(['javascript', 'typescript']));
console.log('❌ Empty tags:', tagsSchema.safeParse([]));
// Array with unique elements
const uniqueNumbersSchema = Schema.array(Schema.number()).unique();
console.log('✅ Unique numbers:', uniqueNumbersSchema.safeParse([1, 2, 3]));
console.log('❌ Duplicate numbers:', uniqueNumbersSchema.safeParse([1, 2, 2]));
// ===== OBJECT VALIDATION =====
console.log('\n4. Object Validation:');
// User schema
const UserSchema = Schema.object({
id: Schema.number().int().positive(),
email: Schema.string().email(),
name: Schema.string().min(2).max(50),
age: Schema.number().int().min(0).max(120).optional(),
isActive: Schema.boolean().default(true),
tags: Schema.array(Schema.string()).max(10).optional()
});
// Valid user
const validUser = {
id: 1,
email: 'john@example.com',
name: 'John Doe',
age: 30,
isActive: true,
tags: ['developer', 'javascript']
};
console.log('✅ Valid user:', UserSchema.safeParse(validUser));
// Invalid user (missing required fields)
const invalidUser = {
email: 'invalid-email',
name: 'J'
};
console.log('❌ Invalid user:', UserSchema.safeParse(invalidUser));
// ===== NESTED OBJECT VALIDATION =====
console.log('\n5. Nested Object Validation:');
// Address schema
const AddressSchema = Schema.object({
street: Schema.string().min(5),
city: Schema.string().min(2),
zipCode: Schema.string().regex(/^\d{5}(-\d{4})?$/),
country: Schema.string().length(2) // ISO country code
});
// User with address
const UserWithAddressSchema = Schema.object({
id: Schema.number().int().positive(),
name: Schema.string().min(2),
email: Schema.string().email(),
address: AddressSchema,
alternateAddresses: Schema.array(AddressSchema).max(3).optional()
});
const userWithAddress = {
id: 1,
name: 'Jane Doe',
email: 'jane@example.com',
address: {
street: '123 Main Street',
city: 'New York',
zipCode: '10001',
country: 'US'
}
};
console.log('✅ Valid user with address:', UserWithAddressSchema.safeParse(userWithAddress));
// ===== OPTIONAL AND DEFAULT VALUES =====
console.log('\n6. Optional and Default Values:');
const ConfigSchema = Schema.object({
apiUrl: Schema.string().url(),
timeout: Schema.number().int().min(1000).default(5000),
retries: Schema.number().int().min(0).max(10).default(3),
debug: Schema.boolean().default(false),
features: Schema.array(Schema.string()).optional()
});
// Minimal config (uses defaults)
const minimalConfig = {
apiUrl: 'https://api.example.com'
};
console.log('✅ Config with defaults:', ConfigSchema.safeParse(minimalConfig));
// ===== STRICT MODE =====
console.log('\n7. Strict Mode (No Extra Properties):');
const StrictUserSchema = Schema.object({
id: Schema.number().int(),
name: Schema.string()
}).strict();
const userWithExtra = {
id: 1,
name: 'John',
extraField: 'not allowed'
};
console.log('❌ Strict validation fails:', StrictUserSchema.safeParse(userWithExtra));
// ===== CUSTOM VALIDATION =====
console.log('\n8. Custom Validation:');
const customSchema = Schema.custom<string>((value) => {
if (typeof value !== 'string') {
throw new Error('Expected string');
}
if (!value.startsWith('custom_')) {
throw new Error('Must start with custom_');
}
return value;
});
console.log('✅ Valid custom:', customSchema.safeParse('custom_value'));
console.log('❌ Invalid custom:', customSchema.safeParse('invalid'));
// ===== ERROR HANDLING =====
console.log('\n9. Error Handling:');
try {
// Using parse() throws on validation error
UserSchema.parse({ invalid: 'data' });
} catch (error) {
console.log('❌ Parse error:', (error as Error).message);
}
// Using safeParse() returns result object
const result = UserSchema.safeParse({ invalid: 'data' });
if (!result.success) {
console.log('❌ SafeParse errors:', result.errors);
}
console.log('\n=== MODULAR SCHEMA VALIDATION TESTS COMPLETED ===');
console.log('🎉 Modular schema validation working perfectly!');
console.log('📚 Features demonstrated:');
console.log(' - Complete separation from validators');
console.log(' - Modular architecture with individual schema types');
console.log(' - Type-safe schema definition');
console.log(' - Chainable validation methods');
console.log(' - Built-in format validators (email, phone, UUID, URL)');
console.log(' - Array validation with uniqueness');
console.log(' - Nested object validation');
console.log(' - Optional fields and default values');
console.log(' - Strict mode for extra property detection');
console.log(' - Custom validation functions');
console.log(' - Comprehensive error reporting');
console.log(' - Clean, maintainable code structure!');