Skip to content

Commit f74bf75

Browse files
committed
refactor(zod): reorganize optionality tests to focus on type inference
Consolidate optionality: 'all' tests by removing redundant runtime validation tests and keeping only type-level inference assertions. The runtime behavior is already covered by other test suites, so this change reduces duplication and improves test organization by grouping type inference tests together.
1 parent 5de0984 commit f74bf75

1 file changed

Lines changed: 15 additions & 105 deletions

File tree

packages/zod/test/factory.test.ts

Lines changed: 15 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,60 +1339,20 @@ describe('SchemaFactory - makeModelSchema with options', () => {
13391339
expect(schema.shape.email.meta()?.description).toBe("The user's email address");
13401340
});
13411341
});
1342-
});
1343-
1344-
// ── optionality ─────────────────────────────────────────────────────────
1345-
describe('optionality option', () => {
1346-
describe('optionality: "all" — every field becomes optional', () => {
1347-
it('accepts an empty object when optionality is "all"', () => {
1348-
const schema = factory.makeModelSchema('User', { optionality: 'all' });
1349-
expect(schema.safeParse({}).success).toBe(true);
1350-
});
1351-
1352-
it('still accepts the full object when optionality is "all"', () => {
1353-
const schema = factory.makeModelSchema('User', { optionality: 'all' });
1354-
expect(schema.safeParse(validUser).success).toBe(true);
1355-
});
13561342

1357-
it('infers all scalar fields as optional when optionality is "all"', () => {
1343+
// Additional type-level assertions for optionality: 'all'
1344+
describe("optionality: 'all' — type inference", () => {
1345+
it('infers all scalar fields as optional (including already-optional)', () => {
13581346
const _schema = factory.makeModelSchema('User', { optionality: 'all' });
13591347
type Result = z.infer<typeof _schema>;
1360-
// required fields become optional
13611348
expectTypeOf<Result['email']>().toEqualTypeOf<string | undefined>();
13621349
expectTypeOf<Result['username']>().toEqualTypeOf<string | undefined>();
13631350
expectTypeOf<Result['age']>().toEqualTypeOf<number | undefined>();
1364-
// already-optional field stays valid as optional
1351+
// already-optional nullable field
13651352
expectTypeOf<Result['website']>().toEqualTypeOf<string | null | undefined>();
13661353
});
13671354

1368-
it('still rejects extra fields (strict) with optionality "all"', () => {
1369-
const schema = factory.makeModelSchema('User', { optionality: 'all' });
1370-
expect(schema.safeParse({ unknownField: 'x' }).success).toBe(false);
1371-
});
1372-
1373-
it('still validates field constraints with optionality "all"', () => {
1374-
const schema = factory.makeModelSchema('User', { optionality: 'all' });
1375-
// email is optional, but if provided must be a valid email
1376-
expect(schema.safeParse({ email: 'not-an-email' }).success).toBe(false);
1377-
expect(schema.safeParse({ email: 'valid@example.com' }).success).toBe(true);
1378-
// empty object passes (all optional, null comparisons in @@validate pass through)
1379-
expect(schema.safeParse({}).success).toBe(true);
1380-
});
1381-
1382-
it('combines optionality: "all" with omit', () => {
1383-
const schema = factory.makeModelSchema('User', {
1384-
omit: { username: true },
1385-
optionality: 'all',
1386-
});
1387-
// empty object (all fields optional, username omitted)
1388-
expect(schema.safeParse({}).success).toBe(true);
1389-
// username still rejected (omitted)
1390-
expect(schema.safeParse({ username: 'alice' }).success).toBe(false);
1391-
// other fields accepted when provided
1392-
expect(schema.safeParse({ email: 'a@b.com' }).success).toBe(true);
1393-
});
1394-
1395-
it('infers omitted field absent even with optionality "all"', () => {
1355+
it('infers omitted field absent even with optionality all', () => {
13961356
const _schema = factory.makeModelSchema('User', {
13971357
omit: { username: true },
13981358
optionality: 'all',
@@ -1402,20 +1362,7 @@ describe('SchemaFactory - makeModelSchema with options', () => {
14021362
expectTypeOf<Result['email']>().toEqualTypeOf<string | undefined>();
14031363
});
14041364

1405-
it('combines optionality: "all" with select', () => {
1406-
const schema = factory.makeModelSchema('User', {
1407-
select: { id: true, email: true },
1408-
optionality: 'all',
1409-
});
1410-
// all selected fields optional (no @@validate fields in shape)
1411-
expect(schema.safeParse({}).success).toBe(true);
1412-
expect(schema.safeParse({ id: 'u1' }).success).toBe(true);
1413-
expect(schema.safeParse({ id: 'u1', email: 'a@b.com' }).success).toBe(true);
1414-
// non-selected field still rejected
1415-
expect(schema.safeParse({ id: 'u1', username: 'alice' }).success).toBe(false);
1416-
});
1417-
1418-
it('infers selected fields as optional when optionality is "all"', () => {
1365+
it('infers selected fields as optional when optionality is all', () => {
14191366
const _schema = factory.makeModelSchema('User', {
14201367
select: { id: true, email: true },
14211368
optionality: 'all',
@@ -1425,79 +1372,42 @@ describe('SchemaFactory - makeModelSchema with options', () => {
14251372
expectTypeOf<Result['email']>().toEqualTypeOf<string | undefined>();
14261373
expectTypeOf<Result>().not.toHaveProperty('username');
14271374
});
1428-
1429-
it('preserves @meta description on fields when optionality is "all"', () => {
1430-
const schema = factory.makeModelSchema('User', { optionality: 'all' });
1431-
expect(schema.shape.email.meta()?.description).toBe("The user's email address");
1432-
});
14331375
});
14341376

1435-
describe('optionality: "defaults" — only fields with @default or @updatedAt become optional', () => {
1436-
it('makes @default fields optional', () => {
1437-
// User.id has @default(cuid())
1377+
// Additional cases for optionality: 'defaults' with User model
1378+
describe("optionality: 'defaults' — User model", () => {
1379+
it('makes @default(cuid) id field optional on User', () => {
14381380
const schema = factory.makeModelSchema('User', { optionality: 'defaults' });
1439-
// omitting id should be fine (it has a default)
14401381
const { id: _, ...withoutId } = validUser;
14411382
expect(schema.safeParse(withoutId).success).toBe(true);
14421383
});
14431384

1444-
it('keeps required fields required', () => {
1445-
// User.email has no @default
1385+
it('keeps non-default fields required on User', () => {
14461386
const schema = factory.makeModelSchema('User', { optionality: 'defaults' });
14471387
const { email: _, ...withoutEmail } = validUser;
14481388
expect(schema.safeParse(withoutEmail).success).toBe(false);
14491389
});
14501390

1451-
it('still accepts the full valid object', () => {
1391+
it('still accepts the full valid User object', () => {
14521392
const schema = factory.makeModelSchema('User', { optionality: 'defaults' });
14531393
expect(schema.safeParse(validUser).success).toBe(true);
14541394
});
14551395

1456-
it('makes @default(0) fields on Product optional', () => {
1457-
// Product.discount has @default(0); finalPrice is computed (no @default, required)
1458-
const schema = factory.makeModelSchema('Product', { optionality: 'defaults' });
1459-
// without discount — should pass (discount has a default)
1460-
expect(schema.safeParse({ name: 'Widget', price: 10.0, finalPrice: 8.0 }).success).toBe(true);
1461-
// without name — should fail (no default)
1462-
expect(schema.safeParse({ price: 10.0, finalPrice: 8.0 }).success).toBe(false);
1463-
});
1464-
14651396
it('makes @default(autoincrement) and @default(now) fields optional on Asset', () => {
1466-
// Asset.id has @default(autoincrement), Asset.createdAt has @default(now)
14671397
const schema = factory.makeModelSchema('Asset', { optionality: 'defaults' });
1468-
// discriminator assetType has no default — must be provided
1398+
// assetType has no default — must be provided
14691399
expect(schema.safeParse({ assetType: 'Video' }).success).toBe(true);
14701400
// omitting assetType fails
14711401
expect(schema.safeParse({}).success).toBe(false);
14721402
});
1473-
1474-
it('preserves @meta description on fields when optionality is "defaults"', () => {
1475-
const schema = factory.makeModelSchema('User', { optionality: 'defaults' });
1476-
// email has no default so it stays required and its schema is unchanged
1477-
expect(schema.shape.email.meta()?.description).toBe("The user's email address");
1478-
});
1479-
1480-
it('combines optionality: "defaults" with omit', () => {
1481-
// omit username; id has default so it becomes optional
1482-
const schema = factory.makeModelSchema('User', {
1483-
omit: { username: true },
1484-
optionality: 'defaults',
1485-
});
1486-
const { id: _i, username: _u, ...withoutIdAndUsername } = validUser;
1487-
expect(schema.safeParse(withoutIdAndUsername).success).toBe(true);
1488-
// username still rejected
1489-
expect(schema.safeParse({ ...withoutIdAndUsername, username: 'alice' }).success).toBe(false);
1490-
});
14911403
});
14921404

1493-
describe('makeModelCreateSchema / makeModelUpdateSchema use optionality internally', () => {
1405+
// makeModelCreateSchema / makeModelUpdateSchema
1406+
describe('makeModelCreateSchema and makeModelUpdateSchema', () => {
14941407
it('makeModelCreateSchema makes @default fields optional', () => {
1495-
// User.id has @default, so it must be optional in create
14961408
const createSchema = factory.makeModelCreateSchema('User');
14971409
const { id: _, ...withoutId } = validUser;
1498-
// strip relations — create schema has no relation fields
1499-
const { ...withoutRelations } = withoutId;
1500-
expect(createSchema.safeParse(withoutRelations).success).toBe(true);
1410+
expect(createSchema.safeParse(withoutId).success).toBe(true);
15011411
});
15021412

15031413
it('makeModelUpdateSchema makes all fields optional', () => {

0 commit comments

Comments
 (0)