@@ -24,13 +24,102 @@ import { FirebaseApp, initializeApp } from '@firebase/app';
2424
2525import { Firestore , initializeFirestore , setLogLevel } from '../../../src' ;
2626import { PrivateSettings } from '../../../src/lite-api/settings' ;
27+ import { logDebug } from '../../../src/util/log' ;
2728
2829// TODO(dimond): Right now we create a new app and Firestore instance for
2930// every test and never clean them up. We may need to revisit.
3031let appCount = 0 ;
3132
33+ const originalFetch = globalThis . fetch ;
34+
35+ /**
36+ * A class that acts as a spy for a ReadableStream.
37+ * It logs the content of the input stream as it's read and then pipes it through.
38+ */
39+ class ReadableStreamSpy < Uint8Array > {
40+ private inputReadableStream : ReadableStream < Uint8Array > ;
41+ private spyTransformStream : TransformStream < Uint8Array , Uint8Array > ;
42+ private spiedReadableStream : ReadableStream < Uint8Array > ;
43+
44+ private readonly decoder = new TextDecoder ( ) ;
45+
46+ /**
47+ * Creates an instance of ReadableStreamSpy.
48+ * @param inputReadableStream The ReadableStream to spy on.
49+ */
50+ constructor ( inputReadableStream : ReadableStream < Uint8Array > ) {
51+ if ( ! ( inputReadableStream instanceof ReadableStream ) ) {
52+ throw new Error ( 'Input must be a ReadableStream.' ) ;
53+ }
54+
55+ this . inputReadableStream = inputReadableStream ;
56+
57+ // Create a TransformStream that logs data
58+ this . spyTransformStream = new TransformStream < Uint8Array , Uint8Array > ( {
59+ transform : (
60+ chunk : Uint8Array ,
61+ controller : TransformStreamDefaultController < Uint8Array >
62+ ) => {
63+ // @ts -ignore
64+ logDebug ( this . decoder . decode ( chunk ) ) ;
65+
66+ controller . enqueue ( chunk ) ; // Pass the chunk along
67+ } ,
68+ flush : ( controller : TransformStreamDefaultController < Uint8Array > ) => {
69+ // Any cleanup or final actions if needed
70+ }
71+ } ) ;
72+
73+ // Pipe the input stream through the spy transform stream
74+ this . spiedReadableStream = this . inputReadableStream . pipeThrough (
75+ this . spyTransformStream
76+ ) ;
77+ }
78+
79+ /**
80+ * Gets the spied-on ReadableStream.
81+ * You should read from this stream to observe the logged chunks.
82+ * @returns The ReadableStream with spy functionality.
83+ */
84+ get readableStream ( ) : ReadableStream < Uint8Array > {
85+ return this . spiedReadableStream ;
86+ }
87+ }
88+
89+ globalThis . fetch = async function ( requestOrUrl , options ) {
90+ // @ts -ignore
91+ const url =
92+ typeof requestOrUrl === 'string' ? requestOrUrl : requestOrUrl . url ;
93+
94+ logDebug ( `FETCH FOR ${ url } ` ) ;
95+
96+ if (
97+ url . startsWith (
98+ 'https://firestore.googleapis.com/google.firestore.v1.Firestore/Listen/channel'
99+ )
100+ ) {
101+ const response = await originalFetch ( requestOrUrl , options ) ;
102+
103+ if ( response . body ) {
104+ const spy = new ReadableStreamSpy ( response . body ) ;
105+
106+ return Promise . resolve (
107+ new Response ( spy . readableStream , {
108+ headers : response . headers ,
109+ status : response . status ,
110+ statusText : response . statusText
111+ } )
112+ ) ;
113+ }
114+
115+ return Promise . resolve ( response ) ;
116+ }
117+
118+ return originalFetch ( requestOrUrl , options ) ;
119+ } ;
120+
32121// enable contextual debug logging
33- setLogLevel ( 'error' , 100 ) ;
122+ setLogLevel ( 'error' , 200 ) ;
34123
35124export function newTestApp ( projectId : string , appName ?: string ) : FirebaseApp {
36125 if ( appName === undefined ) {
0 commit comments