@@ -9,23 +9,51 @@ import { describe, it, expect } from 'vitest';
99// Or sometimes as: { name: "header-name", value: "actual-value" }
1010
1111/**
12- * Replica of the parseHeaders logic for testing
12+ * Replica of the parseHeaders logic for testing (matches src/firefox/events/network.ts)
1313 */
1414function parseHeaders ( headers : any [ ] ) : Record < string , string > {
1515 const result : Record < string , string > = { } ;
1616
17+ const normalizeValue = ( value : unknown ) : string | null => {
18+ if ( value === null || value === undefined ) {
19+ return null ;
20+ }
21+ if ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ) {
22+ return String ( value ) ;
23+ }
24+ if ( Array . isArray ( value ) ) {
25+ const parts = value
26+ . map ( ( item ) => normalizeValue ( item ) )
27+ . filter ( ( item ) : item is string => ! ! item ) ;
28+ return parts . length > 0 ? parts . join ( ', ' ) : null ;
29+ }
30+ if ( typeof value === 'object' ) {
31+ const obj = value as Record < string , unknown > ;
32+ if ( 'value' in obj ) {
33+ return normalizeValue ( obj . value ) ;
34+ }
35+ if ( 'bytes' in obj ) {
36+ return normalizeValue ( obj . bytes ) ;
37+ }
38+ try {
39+ return JSON . stringify ( obj ) ;
40+ } catch {
41+ return null ;
42+ }
43+ }
44+ return String ( value ) ;
45+ } ;
46+
1747 if ( Array . isArray ( headers ) ) {
1848 for ( const h of headers ) {
19- if ( h . name && h . value !== undefined ) {
20- // BiDi returns header values as { type: "string", value: "actual value" }
21- const value = h . value ;
22- if ( typeof value === 'string' ) {
23- result [ h . name . toLowerCase ( ) ] = value ;
24- } else if ( value && typeof value === 'object' && 'value' in value ) {
25- result [ h . name . toLowerCase ( ) ] = String ( value . value ) ;
26- } else {
27- result [ h . name . toLowerCase ( ) ] = String ( value ) ;
28- }
49+ const name = h ?. name ? String ( h . name ) . toLowerCase ( ) : '' ;
50+ if ( ! name ) {
51+ continue ;
52+ }
53+
54+ const normalizedValue = normalizeValue ( h ?. value ) ;
55+ if ( normalizedValue !== null ) {
56+ result [ name ] = normalizedValue ;
2957 }
3058 }
3159 }
@@ -103,22 +131,82 @@ describe('NetworkEvents Header Parsing', () => {
103131 expect ( parseHeaders ( 'not-an-array' as any ) ) . toEqual ( { } ) ;
104132 } ) ;
105133
106- it ( 'should skip headers without name or value' , ( ) => {
134+ it ( 'should skip headers without name or with null/undefined value' , ( ) => {
107135 const headers = [
108136 { name : 'Valid' , value : 'value' } ,
109137 { name : 'NoValue' } ,
110138 { value : 'no-name' } ,
139+ { name : 'NullValue' , value : null } ,
140+ { name : 'UndefinedValue' , value : undefined } ,
111141 { name : 'Empty' , value : '' } ,
112142 ] ;
113143
114144 const result = parseHeaders ( headers ) ;
115145
116146 expect ( result [ 'valid' ] ) . toBe ( 'value' ) ;
117147 expect ( result [ 'novalue' ] ) . toBeUndefined ( ) ;
148+ expect ( result [ 'nullvalue' ] ) . toBeUndefined ( ) ;
149+ expect ( result [ 'undefinedvalue' ] ) . toBeUndefined ( ) ;
118150 expect ( result [ 'empty' ] ) . toBe ( '' ) ;
119151 expect ( Object . keys ( result ) ) . toHaveLength ( 2 ) ;
120152 } ) ;
121153
154+ it ( 'should handle BiDi bytes format (binary data)' , ( ) => {
155+ const headers = [
156+ { name : 'X-Binary' , value : { type : 'base64' , bytes : 'SGVsbG8gV29ybGQ=' } } ,
157+ ] ;
158+
159+ const result = parseHeaders ( headers ) ;
160+
161+ expect ( result [ 'x-binary' ] ) . toBe ( 'SGVsbG8gV29ybGQ=' ) ;
162+ } ) ;
163+
164+ it ( 'should handle array values (multi-value headers)' , ( ) => {
165+ const headers = [
166+ { name : 'Set-Cookie' , value : [ 'cookie1=value1' , 'cookie2=value2' ] } ,
167+ {
168+ name : 'X-Multi' ,
169+ value : [
170+ { type : 'string' , value : 'first' } ,
171+ { type : 'string' , value : 'second' } ,
172+ ] ,
173+ } ,
174+ ] ;
175+
176+ const result = parseHeaders ( headers ) ;
177+
178+ expect ( result [ 'set-cookie' ] ) . toBe ( 'cookie1=value1, cookie2=value2' ) ;
179+ expect ( result [ 'x-multi' ] ) . toBe ( 'first, second' ) ;
180+ } ) ;
181+
182+ it ( 'should handle empty array values' , ( ) => {
183+ const headers = [ { name : 'X-Empty-Array' , value : [ ] } ] ;
184+
185+ const result = parseHeaders ( headers ) ;
186+
187+ expect ( result [ 'x-empty-array' ] ) . toBeUndefined ( ) ;
188+ } ) ;
189+
190+ it ( 'should handle unknown object format with JSON.stringify fallback' , ( ) => {
191+ const headers = [ { name : 'X-Unknown' , value : { foo : 'bar' , baz : 123 } } ] ;
192+
193+ const result = parseHeaders ( headers ) ;
194+
195+ expect ( result [ 'x-unknown' ] ) . toBe ( '{"foo":"bar","baz":123}' ) ;
196+ } ) ;
197+
198+ it ( 'should handle boolean values' , ( ) => {
199+ const headers = [
200+ { name : 'X-True' , value : true } ,
201+ { name : 'X-False' , value : false } ,
202+ ] ;
203+
204+ const result = parseHeaders ( headers ) ;
205+
206+ expect ( result [ 'x-true' ] ) . toBe ( 'true' ) ;
207+ expect ( result [ 'x-false' ] ) . toBe ( 'false' ) ;
208+ } ) ;
209+
122210 it ( 'should handle numeric values in BiDi format' , ( ) => {
123211 const headers = [
124212 { name : 'Content-Length' , value : { type : 'string' , value : 12345 } } ,
0 commit comments