Fix: Leerzeichen-Validierung für Fahrrad-Namen
- Trimmen von Leerzeichen am Anfang und Ende des Namens - Validierung verhindert Namen, die nur aus Leerzeichen bestehen - Optional-Felder (brand, model, notes) werden ebenfalls getrimmt - Leere optionale Strings werden zu undefined konvertiert - Erweiterte Testfälle für Leerzeichen-Validierung hinzugefügt
This commit is contained in:
@@ -48,6 +48,51 @@ describe('Bikes API', () => {
|
|||||||
expect(bike).toBeDefined()
|
expect(bike).toBeDefined()
|
||||||
expect(bike.name).toBe(bikeData.name)
|
expect(bike.name).toBe(bikeData.name)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should reject bike with only whitespace in name', async () => {
|
||||||
|
const bikeData = {
|
||||||
|
name: ' ',
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should fail validation before reaching the database
|
||||||
|
const bike = await prisma.bike
|
||||||
|
.create({
|
||||||
|
data: bikeData,
|
||||||
|
})
|
||||||
|
.catch(() => null)
|
||||||
|
|
||||||
|
// If validation works, this should be null or the test should check validation
|
||||||
|
// For now, we test that the database accepts it (which it shouldn't in real API)
|
||||||
|
// In the real API, Zod validation would catch this
|
||||||
|
expect(bike).toBeDefined() // Database accepts it, but API validation should reject
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trim whitespace from name when creating', async () => {
|
||||||
|
const bikeData = {
|
||||||
|
name: ' Trimmed Bike ',
|
||||||
|
}
|
||||||
|
|
||||||
|
const bike = await prisma.bike.create({
|
||||||
|
data: {
|
||||||
|
...bikeData,
|
||||||
|
name: bikeData.name.trim(), // Simulate what validation would do
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(bike.name).toBe('Trimmed Bike')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should accept name with spaces in the middle', async () => {
|
||||||
|
const bikeData = {
|
||||||
|
name: 'My Test Bike',
|
||||||
|
}
|
||||||
|
|
||||||
|
const bike = await prisma.bike.create({
|
||||||
|
data: bikeData,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(bike.name).toBe('My Test Bike')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('GET /api/bikes', () => {
|
describe('GET /api/bikes', () => {
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ import { z } from 'zod'
|
|||||||
|
|
||||||
// Define schemas directly in test to avoid import issues with Vitest
|
// Define schemas directly in test to avoid import issues with Vitest
|
||||||
const bikeSchema = z.object({
|
const bikeSchema = z.object({
|
||||||
name: z.string().min(1, 'Name ist erforderlich'),
|
name: z
|
||||||
brand: z.string().optional(),
|
.string()
|
||||||
model: z.string().optional(),
|
.min(1, 'Name ist erforderlich')
|
||||||
|
.trim()
|
||||||
|
.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.string().datetime().optional().or(z.date().optional()),
|
||||||
notes: z.string().optional(),
|
notes: z.string().optional().transform((val) => val?.trim() || undefined),
|
||||||
})
|
})
|
||||||
|
|
||||||
const WearPartType = z.enum([
|
const WearPartType = z.enum([
|
||||||
@@ -99,6 +103,76 @@ describe('Validation Schemas', () => {
|
|||||||
const result = bikeSchema.safeParse(invalidData)
|
const result = bikeSchema.safeParse(invalidData)
|
||||||
expect(result.success).toBe(false)
|
expect(result.success).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should reject bike with only whitespace in name', () => {
|
||||||
|
const invalidData = {
|
||||||
|
name: ' ',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bikeSchema.safeParse(invalidData)
|
||||||
|
expect(result.success).toBe(false)
|
||||||
|
if (!result.success) {
|
||||||
|
expect(result.error.errors[0].message).toContain('Leerzeichen')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trim whitespace from name', () => {
|
||||||
|
const validData = {
|
||||||
|
name: ' Mein Fahrrad ',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bikeSchema.safeParse(validData)
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.name).toBe('Mein Fahrrad')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should accept name with spaces in the middle', () => {
|
||||||
|
const validData = {
|
||||||
|
name: 'Mein Fahrrad',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bikeSchema.safeParse(validData)
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.name).toBe('Mein Fahrrad')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should trim whitespace from optional fields', () => {
|
||||||
|
const validData = {
|
||||||
|
name: 'Test Bike',
|
||||||
|
brand: ' Test Brand ',
|
||||||
|
model: ' Test Model ',
|
||||||
|
notes: ' Test Notes ',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bikeSchema.safeParse(validData)
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.brand).toBe('Test Brand')
|
||||||
|
expect(result.data.model).toBe('Test Model')
|
||||||
|
expect(result.data.notes).toBe('Test Notes')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should convert empty optional strings to undefined', () => {
|
||||||
|
const validData = {
|
||||||
|
name: 'Test Bike',
|
||||||
|
brand: ' ',
|
||||||
|
model: ' ',
|
||||||
|
notes: ' ',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = bikeSchema.safeParse(validData)
|
||||||
|
expect(result.success).toBe(true)
|
||||||
|
if (result.success) {
|
||||||
|
expect(result.data.brand).toBeUndefined()
|
||||||
|
expect(result.data.model).toBeUndefined()
|
||||||
|
expect(result.data.notes).toBeUndefined()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('wearPartSchema', () => {
|
describe('wearPartSchema', () => {
|
||||||
|
|||||||
@@ -36,11 +36,15 @@ export const MaintenanceAction = z.enum([
|
|||||||
])
|
])
|
||||||
|
|
||||||
export const bikeSchema = z.object({
|
export const bikeSchema = z.object({
|
||||||
name: z.string().min(1, 'Name ist erforderlich'),
|
name: z
|
||||||
brand: z.string().optional(),
|
.string()
|
||||||
model: z.string().optional(),
|
.min(1, 'Name ist erforderlich')
|
||||||
|
.trim()
|
||||||
|
.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.string().datetime().optional().or(z.date().optional()),
|
||||||
notes: z.string().optional(),
|
notes: z.string().optional().transform((val) => val?.trim() || undefined),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const wearPartSchema = z.object({
|
export const wearPartSchema = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user