-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add input and schema validation tckt-365
- Loading branch information
kalasgarov
committed
Nov 29, 2024
1 parent
4fafc9d
commit 8be510e
Showing
8 changed files
with
233 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
packages/forms/src/patterns/gender-id/gender-id.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { | ||
createGenderIdSchema, | ||
genderIdConfig, | ||
type GenderIdPattern, | ||
} from './gender-id'; | ||
|
||
describe('GenderIdPattern tests', () => { | ||
describe('createGenderIdSchema', () => { | ||
it('should create schema for required gender identity input', () => { | ||
const data: GenderIdPattern['data'] = { | ||
label: 'Test Gender Identity Label', | ||
required: true, | ||
}; | ||
|
||
const schema = createGenderIdSchema(data); | ||
const validInput = 'Test Gender'; | ||
const invalidInput = ''; | ||
|
||
expect(schema.safeParse(validInput).success).toBe(true); | ||
expect(schema.safeParse(invalidInput).success).toBe(false); | ||
}); | ||
|
||
it('should create schema for optional gender identity input', () => { | ||
const data: GenderIdPattern['data'] = { | ||
label: 'Test Gender Identity Label', | ||
required: false, | ||
}; | ||
|
||
const schema = createGenderIdSchema(data); | ||
const validInput = 'Test Gender'; | ||
const emptyInput = ''; | ||
|
||
expect(schema.safeParse(validInput).success).toBe(true); | ||
expect(schema.safeParse(emptyInput).success).toBe(true); | ||
}); | ||
}); | ||
|
||
describe('genderIdConfig', () => { | ||
it('should parse user input correctly', () => { | ||
const pattern: GenderIdPattern = { | ||
id: 'gender-identity-1', | ||
type: 'gender-id', | ||
data: { | ||
label: 'Test Gender Identity Label', | ||
required: true, | ||
}, | ||
}; | ||
|
||
const inputValue = 'Test Gender'; | ||
if (!genderIdConfig.parseUserInput) { | ||
expect.fail('genderIdConfig.parseUserInput is undefined'); | ||
} | ||
const result = genderIdConfig.parseUserInput(pattern, inputValue); | ||
if (result.success) { | ||
expect(result.data).toEqual(inputValue); | ||
} else { | ||
expect.fail('Unexpected validation failure'); | ||
} | ||
}); | ||
|
||
it('should handle validation error for user input', () => { | ||
const pattern: GenderIdPattern = { | ||
id: 'gender-identity-1', | ||
type: 'gender-id', | ||
data: { | ||
label: 'Test Gender Identity Label', | ||
required: true, | ||
}, | ||
}; | ||
|
||
const inputValue = ''; | ||
if (!genderIdConfig.parseUserInput) { | ||
expect.fail('genderIdConfig.parseUserInput is undefined'); | ||
} | ||
const result = genderIdConfig.parseUserInput(pattern, inputValue); | ||
if (!result.success) { | ||
expect(result.error).toBeDefined(); | ||
} else { | ||
expect.fail('Unexpected validation success'); | ||
} | ||
}); | ||
|
||
it('should parse config data correctly', () => { | ||
const obj = { | ||
label: 'Test Gender Identity Label', | ||
required: true, | ||
hint: 'For example, man, woman, non-binary', | ||
preferNotToAnswerText: 'Prefer not to share my gender identity', | ||
}; | ||
|
||
if (!genderIdConfig.parseConfigData) { | ||
expect.fail('genderIdConfig.parseConfigData is undefined'); | ||
} | ||
const result = genderIdConfig.parseConfigData(obj); | ||
if (result.success) { | ||
expect(result.data.label).toBe('Test Gender Identity Label'); | ||
expect(result.data.required).toBe(true); | ||
expect(result.data.hint).toBe('For example, man, woman, non-binary'); | ||
expect(result.data.preferNotToAnswerText).toBe( | ||
'Prefer not to share my gender identity' | ||
); | ||
} else { | ||
expect.fail('Unexpected validation failure'); | ||
} | ||
}); | ||
|
||
it('should handle invalid config data', () => { | ||
const obj = { | ||
label: '', | ||
required: true, | ||
}; | ||
|
||
if (!genderIdConfig.parseConfigData) { | ||
expect.fail('genderIdConfig.parseConfigData is undefined'); | ||
} | ||
const result = genderIdConfig.parseConfigData(obj); | ||
if (!result.success) { | ||
expect(result.error).toBeDefined(); | ||
} else { | ||
expect.fail('Unexpected validation success'); | ||
} | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import * as z from 'zod'; | ||
import { type GenderIdProps } from '../../components.js'; | ||
import { type Pattern, type PatternConfig } from '../../pattern.js'; | ||
import { getFormSessionValue } from '../../session.js'; | ||
import { | ||
safeZodParseFormErrors, | ||
safeZodParseToFormError, | ||
} from '../../util/zod.js'; | ||
|
||
const configSchema = z.object({ | ||
label: z.string().min(1), | ||
required: z.boolean(), | ||
hint: z.string().optional(), | ||
preferNotToAnswerText: z.string().optional(), | ||
}); | ||
|
||
export type GenderIdPattern = Pattern<z.infer<typeof configSchema>>; | ||
|
||
export type GenderIdPatternOutput = z.infer< | ||
ReturnType<typeof createGenderIdSchema> | ||
>; | ||
|
||
export const createGenderIdSchema = (data: GenderIdPattern['data']) => { | ||
return z.string().superRefine((value, ctx) => { | ||
if (value === data.preferNotToAnswerText) { | ||
return; | ||
} | ||
if (data.required && value.trim() === '') { | ||
ctx.addIssue({ | ||
code: z.ZodIssueCode.custom, | ||
message: 'This field is required', | ||
}); | ||
} | ||
}); | ||
}; | ||
|
||
export const genderIdConfig: PatternConfig< | ||
GenderIdPattern, | ||
GenderIdPatternOutput | ||
> = { | ||
displayName: 'Gender ID', | ||
iconPath: 'gender-id-icon.svg', | ||
initial: { | ||
label: 'Gender identity', | ||
required: true, | ||
hint: 'For example, man, woman, non-binary', | ||
preferNotToAnswerText: 'Prefer not to share my gender identity', | ||
}, | ||
|
||
parseUserInput: (pattern, inputValue) => { | ||
const result = safeZodParseToFormError( | ||
createGenderIdSchema(pattern.data), | ||
inputValue | ||
); | ||
return result; | ||
}, | ||
|
||
parseConfigData: obj => { | ||
return safeZodParseFormErrors(configSchema, obj); | ||
}, | ||
getChildren() { | ||
return []; | ||
}, | ||
|
||
createPrompt(_, session, pattern, options) { | ||
const extraAttributes: Record<string, any> = {}; | ||
const sessionValue = getFormSessionValue(session, pattern.id); | ||
const error = session.data.errors[pattern.id]; | ||
|
||
return { | ||
props: { | ||
_patternId: pattern.id, | ||
type: 'gender-id', | ||
label: pattern.data.label, | ||
genderId: pattern.id, | ||
required: pattern.data.required, | ||
hint: pattern.data.hint, | ||
preferNotToAnswerText: pattern.data.preferNotToAnswerText, | ||
value: sessionValue, | ||
error, | ||
...extraAttributes, | ||
} as GenderIdProps, | ||
children: [], | ||
}; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters