@@ -120,36 +120,135 @@ describe('usage report adapters', () => {
120120 expect ( ( ) => validateUsageReportFirstRecord ( header , record ) ) . not . toThrow ( )
121121 } )
122122
123- it ( 'detects native AI Credits reports and routes them to an unsupported adapter' , ( ) => {
124- const header = parseTokenUsageHeader ( HEADER_WITHOUT_EXCEEDS_QUOTA )
125- const record = parseTokenUsageRecord (
123+ it ( 'normalizes transition-period rows through the adapter parser' , ( ) => {
124+ const header = parseTokenUsageHeader ( TRANSITION_PERIOD_HEADER )
125+ const adapter = validateUsageReportHeader ( header )
126+
127+ expect ( adapter . parseRecord (
126128 buildRow ( [
127- '2026-06-01 ' ,
129+ '2026-04-25 ' ,
128130 'mona' ,
129131 'copilot' ,
130- 'copilot_ai_credit' ,
131- 'Auto: Claude Haiku 4.5' ,
132- '96.9990345' ,
133- 'ai-credits' ,
134- '0.01' ,
135- '0.969990345' ,
132+ 'copilot_premium_request' ,
133+ 'GPT-5' ,
136134 '0' ,
137- '0.969990345' ,
138- '3900' ,
139- 'example-org' ,
135+ 'requests' ,
136+ '0.04' ,
137+ '0' ,
138+ '0' ,
139+ '0' ,
140+ 'False' ,
141+ '300' ,
142+ '' ,
143+ '' ,
144+ '0' ,
145+ '0' ,
146+ ] ) ,
147+ header ,
148+ ) ) . toBeNull ( )
149+
150+ expect ( adapter . parseRecord (
151+ buildRow ( [
152+ '2026-04-25' ,
153+ 'mona' ,
154+ 'copilot' ,
155+ 'copilot_premium_request' ,
156+ 'GPT-5' ,
157+ '10' ,
158+ 'requests' ,
159+ '0.04' ,
160+ '0.40' ,
161+ '0' ,
162+ '0.40' ,
163+ 'False' ,
164+ '0' ,
165+ '' ,
140166 '' ,
141- '96.9990345 ' ,
142- '0.969990345 ' ,
167+ '100 ' ,
168+ '1.00 ' ,
143169 ] ) ,
144170 header ,
171+ ) ) . toMatchObject ( {
172+ username : 'mona' ,
173+ quantity : 0 ,
174+ gross_amount : 0 ,
175+ net_amount : 0 ,
176+ aic_quantity : 50 ,
177+ aic_gross_amount : 0.5 ,
178+ aic_net_amount : 0.5 ,
179+ } )
180+ } )
181+
182+ it ( 'detects native AI Credits reports and routes them to an unsupported adapter' , ( ) => {
183+ const header = parseTokenUsageHeader ( HEADER_WITHOUT_EXCEEDS_QUOTA )
184+ const row = buildRow ( [
185+ '2026-06-01' ,
186+ 'mona' ,
187+ 'copilot' ,
188+ 'copilot_ai_credit' ,
189+ 'Auto: Claude Haiku 4.5' ,
190+ '96.9990345' ,
191+ 'ai-credits' ,
192+ '0.01' ,
193+ '0.969990345' ,
194+ '0' ,
195+ '0.969990345' ,
196+ '3900' ,
197+ 'example-org' ,
198+ '' ,
199+ '96.9990345' ,
200+ '0.969990345' ,
201+ ] )
202+ const record = parseTokenUsageRecord (
203+ row ,
204+ header ,
145205 )
146206
207+ const adapter = selectUsageReportAdapter ( header , record )
208+
147209 expect ( detectReportFormat ( header , record ) ) . toBe ( 'native-ai-credits' )
148- expect ( selectUsageReportAdapter ( header , record ) . metadata ) . toMatchObject ( {
210+ expect ( adapter . metadata ) . toMatchObject ( {
149211 format : 'native-ai-credits' ,
150212 supported : false ,
151213 } )
214+ expect ( ( ) => adapter . validateFirstRecord ( header , record ) ) . toThrow ( UnsupportedNativeAiCreditsReportError )
152215 expect ( ( ) => validateUsageReportFirstRecord ( header , record ) ) . toThrow ( UnsupportedNativeAiCreditsReportError )
216+ expect ( adapter . parseRecord ( row , header ) ) . toMatchObject ( {
217+ date : '2026-06-01' ,
218+ quantity : 96.9990345 ,
219+ unit_type : 'ai-credits' ,
220+ aic_quantity : 96.9990345 ,
221+ aic_gross_amount : 0.969990345 ,
222+ aic_net_amount : 0.969990345 ,
223+ has_aic_quantity : true ,
224+ has_aic_gross_amount : true ,
225+ } )
226+ } )
227+
228+ it ( 'normalizes native AI Credits dates through the unsupported adapter parser hook' , ( ) => {
229+ const header = parseTokenUsageHeader ( HEADER_WITHOUT_EXCEEDS_QUOTA )
230+ const row = buildRow ( [
231+ '2026-06-01' ,
232+ 'mona' ,
233+ 'copilot' ,
234+ 'copilot_ai_credit' ,
235+ 'Auto: Claude Haiku 4.5' ,
236+ '96.9990345' ,
237+ 'ai-credits' ,
238+ '0.01' ,
239+ '0.969990345' ,
240+ '0' ,
241+ '0.969990345' ,
242+ '3900' ,
243+ 'example-org' ,
244+ '' ,
245+ '96.9990345' ,
246+ '0.969990345' ,
247+ ] )
248+ const record = parseTokenUsageRecord ( row , header )
249+ const adapter = selectUsageReportAdapter ( header , record )
250+
251+ expect ( adapter . parseRecord ( row . replace ( '2026-06-01' , '6/1/26' ) , header ) ?. date ) . toBe ( '2026-06-01' )
153252 } )
154253
155254 it ( 'fails clearly for malformed billing headers before adapter selection' , ( ) => {
0 commit comments