feat(types): 添加类型检查脚本和迁移指南
添加 check-types.ps1 脚本用于检查项目各模块的类型定义 添加 migrate-types.ps1 脚本用于自动迁移类型导入路径 添加类型迁移指南文档说明迁移步骤和最佳实践 添加共享类型测试用例验证 schema 定义
This commit is contained in:
247
server/src/shared/schemas/__tests__/schemas.test.ts
Normal file
247
server/src/shared/schemas/__tests__/schemas.test.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
UserSchema,
|
||||
UserRoleSchema,
|
||||
UserStatusSchema,
|
||||
CreateUserSchema,
|
||||
UpdateUserSchema
|
||||
} from '@shared/schemas/user.schema';
|
||||
import {
|
||||
ProductSchema,
|
||||
ProductStatusSchema
|
||||
} from '@shared/schemas/product.schema';
|
||||
import {
|
||||
OrderSchema,
|
||||
OrderStatusSchema
|
||||
} from '@shared/schemas/order.schema';
|
||||
import {
|
||||
BaseMessageSchema,
|
||||
MessageTypeSchema,
|
||||
MessageResponseSchema
|
||||
} from '@shared/schemas/message.schema';
|
||||
|
||||
describe('User Schema', () => {
|
||||
it('should validate valid user data', () => {
|
||||
const validUser = {
|
||||
id: '123',
|
||||
name: 'John Doe',
|
||||
email: 'john@example.com',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = UserSchema.safeParse(validUser);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject invalid email', () => {
|
||||
const invalidUser = {
|
||||
id: '123',
|
||||
name: 'John Doe',
|
||||
email: 'invalid-email',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = UserSchema.safeParse(invalidUser);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should reject invalid role', () => {
|
||||
const invalidUser = {
|
||||
id: '123',
|
||||
name: 'John Doe',
|
||||
email: 'john@example.com',
|
||||
role: 'invalid_role',
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = UserSchema.safeParse(invalidUser);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Product Schema', () => {
|
||||
it('should validate valid product data', () => {
|
||||
const validProduct = {
|
||||
id: '123',
|
||||
name: 'Test Product',
|
||||
sku: 'SKU-001',
|
||||
price: 99.99,
|
||||
stock: 100,
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = ProductSchema.safeParse(validProduct);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject negative price', () => {
|
||||
const invalidProduct = {
|
||||
id: '123',
|
||||
name: 'Test Product',
|
||||
sku: 'SKU-001',
|
||||
price: -10,
|
||||
stock: 100,
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = ProductSchema.safeParse(invalidProduct);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Order Schema', () => {
|
||||
it('should validate valid order data', () => {
|
||||
const validOrder = {
|
||||
id: '123',
|
||||
orderNumber: 'ORD-001',
|
||||
status: 'pending',
|
||||
items: [
|
||||
{
|
||||
productId: 'p1',
|
||||
productName: 'Product 1',
|
||||
quantity: 2,
|
||||
unitPrice: 50,
|
||||
totalPrice: 100
|
||||
}
|
||||
],
|
||||
totalAmount: 100,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = OrderSchema.safeParse(validOrder);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Message Schema', () => {
|
||||
it('should validate valid message', () => {
|
||||
const validMessage = {
|
||||
type: 'COLLECT_ORDERS',
|
||||
payload: { shopId: 'shop1' },
|
||||
traceId: 'trace-123'
|
||||
};
|
||||
|
||||
const result = BaseMessageSchema.safeParse(validMessage);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject invalid message type', () => {
|
||||
const invalidMessage = {
|
||||
type: 'INVALID_TYPE',
|
||||
payload: {}
|
||||
};
|
||||
|
||||
const result = BaseMessageSchema.safeParse(invalidMessage);
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate message response', () => {
|
||||
const validResponse = {
|
||||
success: true,
|
||||
data: { orders: [] },
|
||||
traceId: 'trace-123'
|
||||
};
|
||||
|
||||
const result = MessageResponseSchema.safeParse(validResponse);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should validate error response', () => {
|
||||
const errorResponse = {
|
||||
success: false,
|
||||
error: {
|
||||
code: 'ERROR_001',
|
||||
message: 'Something went wrong'
|
||||
},
|
||||
traceId: 'trace-123'
|
||||
};
|
||||
|
||||
const result = MessageResponseSchema.safeParse(errorResponse);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Type Inference', () => {
|
||||
it('should infer correct types from schema', () => {
|
||||
type User = z.infer<typeof UserSchema>;
|
||||
type UserRole = z.infer<typeof UserRoleSchema>;
|
||||
type UserStatus = z.infer<typeof UserStatusSchema>;
|
||||
|
||||
const user: User = {
|
||||
id: '123',
|
||||
name: 'Test',
|
||||
email: 'test@example.com',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
expect(user.role).toBe('admin');
|
||||
expect(user.status).toBe('active');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Schema Extensions', () => {
|
||||
it('should extend schema correctly', () => {
|
||||
const ExtendedUserSchema = UserSchema.extend({
|
||||
department: z.string()
|
||||
});
|
||||
|
||||
const validExtendedUser = {
|
||||
id: '123',
|
||||
name: 'John',
|
||||
email: 'john@example.com',
|
||||
role: 'admin',
|
||||
status: 'active',
|
||||
department: 'Engineering',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
const result = ExtendedUserSchema.safeParse(validExtendedUser);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should pick fields from schema', () => {
|
||||
const UserPreviewSchema = UserSchema.pick({
|
||||
id: true,
|
||||
name: true,
|
||||
email: true
|
||||
});
|
||||
|
||||
const validPreview = {
|
||||
id: '123',
|
||||
name: 'John',
|
||||
email: 'john@example.com'
|
||||
};
|
||||
|
||||
const result = UserPreviewSchema.safeParse(validPreview);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('should make schema partial', () => {
|
||||
const PartialUserSchema = UserSchema.partial();
|
||||
|
||||
const validPartial = {
|
||||
name: 'John'
|
||||
};
|
||||
|
||||
const result = PartialUserSchema.safeParse(validPartial);
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user