Skip to content

Commit 2f81e87

Browse files
committed
test(dashboard): verify type compiler validation and schema constraints for historical trend view
1 parent c8fb1e5 commit 2f81e87

1 file changed

Lines changed: 150 additions & 0 deletions

File tree

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { describe, it, expect, expectTypeOf } from 'vitest';
2+
import { z } from 'zod';
3+
import type { ActivityData } from '@/types/dashboard';
4+
import type { DashboardPeriod } from '@/utils/dashboardPeriod';
5+
6+
export interface HistoricalTrendViewProps {
7+
username: string;
8+
activity: ActivityData[];
9+
period: DashboardPeriod;
10+
}
11+
12+
describe('HistoricalTrendView type & schema compiler checks (Variation 10)', () => {
13+
// Case 1: Verifies baseline types for primitive and union properties match accurately
14+
it('Case 1: Validate baseline property fields (date, count, intensity) to verify type matching parameters align perfectly', () => {
15+
expectTypeOf<ActivityData['date']>().toEqualTypeOf<string>();
16+
expectTypeOf<ActivityData['count']>().toEqualTypeOf<number>();
17+
expectTypeOf<ActivityData['intensity']>().toEqualTypeOf<0 | 1 | 2 | 3 | 4>();
18+
});
19+
20+
// Case 2: Asserts static type checking blocks misaligned interface layouts from compiling
21+
it('Case 2: Ensure invalid structural definitions are caught and blocked during static assignment checks', () => {
22+
type InvalidActivity = {
23+
date: number;
24+
count: string;
25+
intensity: 5;
26+
};
27+
28+
type InvalidPeriod = {
29+
kind: 'unknown';
30+
label: number;
31+
};
32+
33+
expectTypeOf<InvalidActivity>().not.toMatchTypeOf<ActivityData>();
34+
expectTypeOf<InvalidPeriod>().not.toMatchTypeOf<DashboardPeriod>();
35+
});
36+
37+
// Case 3: Confirms the component wrapper handles minimal and complete optional envelopes cleanly
38+
it('Case 3: Verify the complex trend props envelope seamlessly tolerates optional parameters without dropping compilation support', () => {
39+
type MinimalActivity = {
40+
date: string;
41+
count: number;
42+
intensity: 0 | 1 | 2 | 3 | 4;
43+
};
44+
45+
type MinimalPeriod = {
46+
kind: 'rolling';
47+
label: string;
48+
from: string;
49+
to: string;
50+
};
51+
52+
type MinimalProps = {
53+
username: string;
54+
activity: MinimalActivity[];
55+
period: MinimalPeriod;
56+
};
57+
58+
expectTypeOf<MinimalProps>().toMatchTypeOf<HistoricalTrendViewProps>();
59+
60+
type FullActivity = {
61+
date: string;
62+
count: number;
63+
intensity: 0 | 1 | 2 | 3 | 4;
64+
locAdditions: number;
65+
locDeletions: number;
66+
};
67+
68+
type FullPeriod = {
69+
kind: 'month';
70+
label: string;
71+
from: string;
72+
to: string;
73+
month: string;
74+
year: string;
75+
};
76+
77+
type FullProps = {
78+
username: string;
79+
activity: FullActivity[];
80+
period: FullPeriod;
81+
};
82+
83+
expectTypeOf<FullProps>().toMatchTypeOf<HistoricalTrendViewProps>();
84+
});
85+
86+
// Case 4: Checks that out-of-bounds parameters generate flat field errors and catch unexpected fields
87+
it('Case 4: Assert that an associated strict validation schema rejects out-of-bounds metrics fields with explicit flat error reports', () => {
88+
const activityDataSchema = z
89+
.object({
90+
date: z.string().min(1),
91+
count: z.number().int().nonnegative(),
92+
intensity: z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
93+
locAdditions: z.number().int().nonnegative().optional(),
94+
locDeletions: z.number().int().nonnegative().optional(),
95+
})
96+
.strict();
97+
98+
const outOfBoundsRecord = {
99+
date: '',
100+
count: -15,
101+
intensity: 10,
102+
locAdditions: -5,
103+
extraField: 'unexpected',
104+
};
105+
106+
const result = activityDataSchema.safeParse(outOfBoundsRecord);
107+
expect(result.success).toBe(false);
108+
109+
if (!result.success) {
110+
const flatErrors = result.error.flatten();
111+
112+
expect(flatErrors.fieldErrors).toHaveProperty('date');
113+
expect(flatErrors.fieldErrors).toHaveProperty('count');
114+
expect(flatErrors.fieldErrors).toHaveProperty('intensity');
115+
expect(flatErrors.fieldErrors).toHaveProperty('locAdditions');
116+
117+
const hasUnrecognizedExtra = result.error.issues.some(
118+
(issue) => issue.code === 'unrecognized_keys' && issue.keys.includes('extraField')
119+
);
120+
expect(hasUnrecognizedExtra).toBe(true);
121+
}
122+
});
123+
124+
// Case 5: Validates clean payloads clear parsing pipelines and maintain type assignability properties
125+
it('Case 5: Prove that standard compliant data records cleanly clear validation gates and preserve underlying type integrity definitions', () => {
126+
const activityDataSchema = z
127+
.object({
128+
date: z.string().min(1),
129+
count: z.number().int().nonnegative(),
130+
intensity: z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3), z.literal(4)]),
131+
locAdditions: z.number().int().nonnegative().optional(),
132+
locDeletions: z.number().int().nonnegative().optional(),
133+
})
134+
.strict();
135+
136+
const validRecord = {
137+
date: '2026-06-03',
138+
count: 12,
139+
intensity: 3 as const,
140+
locAdditions: 150,
141+
locDeletions: 20,
142+
};
143+
144+
const parsed = activityDataSchema.parse(validRecord);
145+
expect(parsed).toEqual(validRecord);
146+
147+
type ParsedType = z.infer<typeof activityDataSchema>;
148+
expectTypeOf<ParsedType>().toMatchTypeOf<ActivityData>();
149+
});
150+
});

0 commit comments

Comments
 (0)