Fix: Kaufdatum-Validierung für Fahrrad-Erstellung
- Kaufdatum akzeptiert jetzt YYYY-MM-DD Format (HTML date input) - Unterstützung für ISO datetime Format und Date-Objekte - Transform konvertiert Datumsstrings automatisch zu Date-Objekten - API-Routes verwenden validierte Daten direkt ohne weitere Konvertierung - Erweiterte Testfälle für verschiedene Datumsformate hinzugefügt - Test-Schema aktualisiert, um echte Validierung zu reflektieren
This commit is contained in:
@@ -93,6 +93,50 @@ describe('Bikes API', () => {
|
||||
|
||||
expect(bike.name).toBe('My Test Bike')
|
||||
})
|
||||
|
||||
it('should create bike with purchaseDate in YYYY-MM-DD format', async () => {
|
||||
const bikeData = {
|
||||
name: 'Bike with Date',
|
||||
purchaseDate: new Date('2024-01-15T00:00:00.000Z'),
|
||||
}
|
||||
|
||||
const bike = await prisma.bike.create({
|
||||
data: bikeData,
|
||||
})
|
||||
|
||||
expect(bike).toBeDefined()
|
||||
expect(bike.purchaseDate).toBeInstanceOf(Date)
|
||||
expect(bike.purchaseDate?.toISOString().split('T')[0]).toBe('2024-01-15')
|
||||
})
|
||||
|
||||
it('should create bike with purchaseDate', async () => {
|
||||
const purchaseDate = new Date('2024-03-20')
|
||||
const bikeData = {
|
||||
name: 'Bike with Purchase Date',
|
||||
purchaseDate: purchaseDate,
|
||||
}
|
||||
|
||||
const bike = await prisma.bike.create({
|
||||
data: bikeData,
|
||||
})
|
||||
|
||||
expect(bike).toBeDefined()
|
||||
expect(bike.purchaseDate).toBeInstanceOf(Date)
|
||||
expect(bike.purchaseDate?.getTime()).toBe(purchaseDate.getTime())
|
||||
})
|
||||
|
||||
it('should create bike without purchaseDate', async () => {
|
||||
const bikeData = {
|
||||
name: 'Bike without Date',
|
||||
}
|
||||
|
||||
const bike = await prisma.bike.create({
|
||||
data: bikeData,
|
||||
})
|
||||
|
||||
expect(bike).toBeDefined()
|
||||
expect(bike.purchaseDate).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/bikes', () => {
|
||||
|
||||
@@ -173,6 +173,85 @@ describe('Validation Schemas', () => {
|
||||
expect(result.data.notes).toBeUndefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('should accept purchaseDate in YYYY-MM-DD format', () => {
|
||||
// The schema accepts any string and transforms it to Date
|
||||
const validData = {
|
||||
name: 'Test Bike',
|
||||
purchaseDate: '2024-01-15',
|
||||
}
|
||||
|
||||
const result = bikeSchema.safeParse(validData)
|
||||
if (!result.success) {
|
||||
// Debug: show what went wrong
|
||||
console.log('Validation failed:', JSON.stringify(result.error.errors, null, 2))
|
||||
}
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
// Transform converts string to Date
|
||||
expect(result.data.purchaseDate).toBeDefined()
|
||||
if (result.data.purchaseDate) {
|
||||
expect(result.data.purchaseDate).toBeInstanceOf(Date)
|
||||
expect(result.data.purchaseDate.toISOString().split('T')[0]).toBe('2024-01-15')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should accept purchaseDate in ISO datetime format', () => {
|
||||
const validData = {
|
||||
name: 'Test Bike',
|
||||
purchaseDate: '2024-01-15T10:30:00.000Z',
|
||||
}
|
||||
|
||||
const result = bikeSchema.safeParse(validData)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
// The transform converts it to Date, but Zod might return the string
|
||||
// Let's check if it's a Date or a valid date string
|
||||
expect(result.data.purchaseDate).toBeDefined()
|
||||
if (result.data.purchaseDate instanceof Date) {
|
||||
expect(result.data.purchaseDate).toBeInstanceOf(Date)
|
||||
} else {
|
||||
// If it's still a string, it should be parseable
|
||||
expect(new Date(result.data.purchaseDate as string)).toBeInstanceOf(Date)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should accept purchaseDate as Date object', () => {
|
||||
const validData = {
|
||||
name: 'Test Bike',
|
||||
purchaseDate: new Date('2024-01-15'),
|
||||
}
|
||||
|
||||
const result = bikeSchema.safeParse(validData)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.data.purchaseDate).toBeInstanceOf(Date)
|
||||
}
|
||||
})
|
||||
|
||||
it('should accept bike without purchaseDate', () => {
|
||||
const validData = {
|
||||
name: 'Test Bike',
|
||||
}
|
||||
|
||||
const result = bikeSchema.safeParse(validData)
|
||||
expect(result.success).toBe(true)
|
||||
if (result.success) {
|
||||
expect(result.data.purchaseDate).toBeUndefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('should reject invalid purchaseDate format', () => {
|
||||
const invalidData = {
|
||||
name: 'Test Bike',
|
||||
purchaseDate: 'invalid-date',
|
||||
}
|
||||
|
||||
const result = bikeSchema.safeParse(invalidData)
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('wearPartSchema', () => {
|
||||
|
||||
@@ -56,9 +56,7 @@ export async function PUT(
|
||||
name: validatedData.name,
|
||||
brand: validatedData.brand,
|
||||
model: validatedData.model,
|
||||
purchaseDate: validatedData.purchaseDate
|
||||
? new Date(validatedData.purchaseDate)
|
||||
: null,
|
||||
purchaseDate: validatedData.purchaseDate || null,
|
||||
notes: validatedData.notes,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -41,9 +41,7 @@ export async function POST(request: NextRequest) {
|
||||
name: validatedData.name,
|
||||
brand: validatedData.brand,
|
||||
model: validatedData.model,
|
||||
purchaseDate: validatedData.purchaseDate
|
||||
? new Date(validatedData.purchaseDate)
|
||||
: null,
|
||||
purchaseDate: validatedData.purchaseDate || null,
|
||||
notes: validatedData.notes,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -43,7 +43,29 @@ export const bikeSchema = z.object({
|
||||
.min(1, 'Name darf nicht nur aus Leerzeichen bestehen'),
|
||||
brand: z.string().optional().transform((val) => val?.trim() || undefined),
|
||||
model: z.string().optional().transform((val) => val?.trim() || undefined),
|
||||
purchaseDate: z.string().datetime().optional().or(z.date().optional()),
|
||||
purchaseDate: z
|
||||
.union([z.date(), z.string()])
|
||||
.optional()
|
||||
.transform((val) => {
|
||||
if (!val || val === undefined) return undefined
|
||||
if (val instanceof Date) {
|
||||
return isNaN(val.getTime()) ? undefined : val
|
||||
}
|
||||
if (typeof val === 'string') {
|
||||
// Handle YYYY-MM-DD format (from HTML date input)
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(val)) {
|
||||
const date = new Date(val + 'T00:00:00.000Z')
|
||||
return isNaN(date.getTime()) ? undefined : date
|
||||
}
|
||||
// Handle ISO datetime format or any other parseable date string
|
||||
const date = new Date(val)
|
||||
return isNaN(date.getTime()) ? undefined : date
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
.refine((val) => val === undefined || val instanceof Date, {
|
||||
message: 'Ungültiges Datumsformat',
|
||||
}),
|
||||
notes: z.string().optional().transform((val) => val?.trim() || undefined),
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user