@@ -29,55 +29,82 @@ const validChecks = [
2929 { name : 'duplicate-tags' , passed : true , errors : 0 , warnings : 0 } ,
3030] ;
3131
32+ function validAuditReport ( overrides : Record < string , unknown > = { } ) {
33+ return {
34+ generatedAt : '2026-08-18T00:00:00.000Z' ,
35+ passed : true ,
36+ ruleCount : 1 ,
37+ checks : validChecks ,
38+ statistics : validStatistics ,
39+ ...overrides ,
40+ } ;
41+ }
42+
3243describe ( 'schema parsing' , ( ) => {
3344 it ( 'accepts a complete audit report' , ( ) => {
34- const report = parseAuditReport ( {
35- generatedAt : '2026-08-18T00:00:00.000Z' ,
36- passed : true ,
37- ruleCount : 1 ,
38- checks : validChecks ,
39- statistics : validStatistics ,
40- } ) ;
45+ const report = parseAuditReport ( validAuditReport ( ) ) ;
4146
4247 expect ( report . statistics . totalRules ) . toBe ( 1 ) ;
4348 expect ( report . checks ) . toHaveLength ( 5 ) ;
4449 } ) ;
4550
51+ it . each ( [ validChecks . slice ( 0 , 4 ) , [ ...validChecks , ...validChecks . slice ( 0 , 1 ) ] ] ) (
52+ 'rejects an audit report with %s checks' ,
53+ ( checks ) => {
54+ expect ( ( ) => parseAuditReport ( validAuditReport ( { checks } ) ) ) . toThrow ( ) ;
55+ }
56+ ) ;
57+
4658 it ( 'rejects an unknown audit check name' , ( ) => {
4759 expect ( ( ) =>
48- parseAuditReport ( {
49- generatedAt : '2026-08-18T00:00:00.000Z' ,
50- passed : false ,
51- ruleCount : 1 ,
52- checks : [
53- ...validChecks . slice ( 0 , 4 ) ,
54- { name : 'unknown-check' , passed : false , errors : 1 , warnings : 0 } ,
55- ] ,
56- statistics : validStatistics ,
57- } )
60+ parseAuditReport (
61+ validAuditReport ( {
62+ passed : false ,
63+ checks : [
64+ ...validChecks . slice ( 0 , 4 ) ,
65+ { name : 'unknown-check' , passed : false , errors : 1 , warnings : 0 } ,
66+ ] ,
67+ } )
68+ )
5869 ) . toThrow ( ) ;
5970 } ) ;
6071
6172 it ( 'rejects missing nested statistics' , ( ) => {
73+ const { statistics, ...reportWithoutStatistics } = validAuditReport ( ) ;
74+
75+ expect ( statistics ) . toBeDefined ( ) ;
76+ expect ( ( ) => parseAuditReport ( reportWithoutStatistics ) ) . toThrow ( ) ;
77+ } ) ;
78+
79+ it ( 'rejects wrong primitive types' , ( ) => {
80+ expect ( ( ) => parseAuditReport ( validAuditReport ( { passed : 'true' } ) ) ) . toThrow ( ) ;
81+ expect ( ( ) => parseAuditReport ( validAuditReport ( { ruleCount : '1' } ) ) ) . toThrow ( ) ;
82+ } ) ;
83+
84+ it ( 'rejects non-integer or negative counters' , ( ) => {
85+ expect ( ( ) => parseStatsReport ( { ...validStatistics , totalRules : 1.5 } ) ) . toThrow ( ) ;
6286 expect ( ( ) =>
63- parseAuditReport ( {
64- generatedAt : '2026-08-18T00:00:00.000Z' ,
65- passed : true ,
66- ruleCount : 1 ,
67- checks : validChecks ,
87+ parseStatsReport ( {
88+ ...validStatistics ,
89+ impactDistribution : { HIGH : - 1 , MEDIUM : 0 , LOW : 0 } ,
6890 } )
6991 ) . toThrow ( ) ;
7092 } ) ;
7193
72- it ( 'rejects negative counters ' , ( ) => {
94+ it ( 'rejects incomplete nested skill statistics ' , ( ) => {
7395 expect ( ( ) =>
7496 parseStatsReport ( {
7597 ...validStatistics ,
76- totalRules : - 1 ,
98+ skills : [ { name : 'nextdns-api' , total : 1 } ] ,
7799 } )
78100 ) . toThrow ( ) ;
79101 } ) ;
80102
103+ it ( 'rejects unknown input' , ( ) => {
104+ expect ( ( ) => parseAuditReport ( null ) ) . toThrow ( ) ;
105+ expect ( ( ) => parseStatsReport ( 'not-a-report' ) ) . toThrow ( ) ;
106+ } ) ;
107+
81108 it ( 'returns type-safe stats data for a valid report' , ( ) => {
82109 const report = parseStatsReport ( validStatistics ) ;
83110
0 commit comments