@@ -85,18 +85,6 @@ describe('profilePlugins', () => {
8585 jest . spyOn ( timer , 'end' ) ;
8686 jest . spyOn ( logger , 'time' ) . mockReturnValue ( timer ) ;
8787
88- const mockPlugin : PluginOptions = {
89- name : 'datadog-test-1-plugin' ,
90- transform : jest . fn ( async ( ) => {
91- await wait ( 500 ) ;
92- return 'transform' ;
93- } ) ,
94- resolveId : jest . fn ( async ( ) => {
95- await wait ( 500 ) ;
96- throw new Error ( 'resolveId' ) ;
97- } ) ,
98- } ;
99-
10088 beforeAll ( ( ) => {
10189 jest . useFakeTimers ( ) ;
10290 } ) ;
@@ -105,37 +93,193 @@ describe('profilePlugins', () => {
10593 jest . useRealTimers ( ) ;
10694 } ) ;
10795
108- test ( 'Should wrap the hook and measure time.' , async ( ) => {
109- const wrappedHook = wrapHook (
110- mockPlugin . name ,
111- 'buildStart' ,
112- mockPlugin . transform ! ,
113- logger ,
114- ) ;
96+ describe ( 'Function hooks' , ( ) => {
97+ test ( 'Should wrap a function hook and measure time' , async ( ) => {
98+ const mockTransform = jest . fn ( async ( code : string ) => {
99+ await wait ( 500 ) ;
100+ return { code : `${ code } -transformed` , map : null } ;
101+ } ) ;
115102
116- const prom = wrappedHook ( ) ;
117- jest . advanceTimersByTime ( 500 ) ;
118- const result = await prom ;
103+ const wrappedHook = wrapHook ( 'test-plugin' , 'transform' , mockTransform , logger ) ;
119104
120- expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
121- expect ( timer . timer . total ) . toBeGreaterThan ( 500 ) ;
122- expect ( result ) . toBe ( 'transform' ) ;
105+ const prom = wrappedHook ( 'const a = 1' ) ;
106+ jest . advanceTimersByTime ( 500 ) ;
107+ const result = await prom ;
108+
109+ expect ( mockTransform ) . toHaveBeenCalledWith ( 'const a = 1' ) ;
110+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
111+ expect ( timer . timer . total ) . toBeGreaterThan ( 500 ) ;
112+ expect ( result ) . toEqual ( { code : 'const a = 1-transformed' , map : null } ) ;
113+ } ) ;
114+
115+ test ( 'Should handle synchronous function hooks' , ( ) => {
116+ const mockResolveId = jest . fn ( ( id : string ) => {
117+ return id . startsWith ( './' ) ? `/resolved${ id } ` : null ;
118+ } ) ;
119+
120+ const wrappedHook = wrapHook ( 'test-plugin' , 'resolveId' , mockResolveId , logger ) ;
121+
122+ const result = wrappedHook ( './test.ts' ) ;
123+
124+ expect ( mockResolveId ) . toHaveBeenCalledWith ( './test.ts' ) ;
125+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
126+ expect ( result ) . toBe ( '/resolved./test.ts' ) ;
127+ } ) ;
128+
129+ test ( 'Should measure time for throwing hooks' , async ( ) => {
130+ const mockBuildStart = jest . fn ( async ( ) => {
131+ await wait ( 500 ) ;
132+ throw new Error ( 'Build failed' ) ;
133+ } ) ;
134+
135+ const wrappedHook = wrapHook ( 'test-plugin' , 'buildStart' , mockBuildStart , logger ) ;
136+
137+ const prom = wrappedHook ( ) ;
138+ jest . advanceTimersByTime ( 500 ) ;
139+
140+ await expect ( prom ) . rejects . toThrow ( 'Build failed' ) ;
141+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
142+ expect ( timer . timer . total ) . toBeGreaterThan ( 500 ) ;
143+ } ) ;
123144 } ) ;
124145
125- test ( 'Should still measure a throwing hook.' , async ( ) => {
126- const wrappedHook = wrapHook (
127- mockPlugin . name ,
128- 'buildStart' ,
129- mockPlugin . resolveId ! ,
130- logger ,
131- ) ;
146+ describe ( 'Object hooks' , ( ) => {
147+ test ( 'Should wrap transform hook with filter object' , async ( ) => {
148+ const mockHandler = jest . fn ( async ( code : string ) => {
149+ await wait ( 300 ) ;
150+ return { code : `${ code } -filtered` , map : null } ;
151+ } ) ;
132152
133- const prom = wrappedHook ( ) ;
134- jest . advanceTimersByTime ( 500 ) ;
153+ const transformHook = {
154+ filter : {
155+ id : {
156+ include : [ '**/*.ts' , '**/*.tsx' ] ,
157+ exclude : [ 'node_modules/**' ] ,
158+ } ,
159+ } ,
160+ handler : mockHandler ,
161+ } ;
135162
136- await expect ( prom ) . rejects . toThrow ( 'resolveId' ) ;
137- expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
138- expect ( timer . timer . total ) . toBeGreaterThan ( 500 ) ;
163+ const wrappedHook = wrapHook ( 'test-plugin' , 'transform' , transformHook , logger ) ;
164+
165+ // Verify the filter is preserved
166+ expect ( wrappedHook . filter ) . toEqual ( transformHook . filter ) ;
167+
168+ // Test the wrapped handler
169+ const prom = wrappedHook . handler ( 'const a = 1' ) ;
170+ jest . advanceTimersByTime ( 300 ) ;
171+ const result = await prom ;
172+
173+ expect ( mockHandler ) . toHaveBeenCalledWith ( 'const a = 1' ) ;
174+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
175+ expect ( timer . timer . total ) . toBeGreaterThan ( 300 ) ;
176+ expect ( result ) . toEqual ( { code : 'const a = 1-filtered' , map : null } ) ;
177+ } ) ;
178+
179+ test ( 'Should wrap load hook with RegExp filter' , async ( ) => {
180+ const mockHandler = jest . fn ( async ( id : string ) => {
181+ await wait ( 200 ) ;
182+ return { code : `export default "${ id } "` } ;
183+ } ) ;
184+
185+ const loadHook = {
186+ filter : {
187+ id : / \. v i r t u a l $ / ,
188+ } ,
189+ handler : mockHandler ,
190+ } ;
191+
192+ const wrappedHook = wrapHook ( 'test-plugin' , 'load' , loadHook , logger ) ;
193+
194+ // Verify the filter is preserved
195+ expect ( wrappedHook . filter ) . toEqual ( loadHook . filter ) ;
196+
197+ // Test the wrapped handler
198+ const prom = wrappedHook . handler ( '/src/test.virtual' ) ;
199+ jest . advanceTimersByTime ( 200 ) ;
200+ const result = await prom ;
201+
202+ expect ( mockHandler ) . toHaveBeenCalledWith ( '/src/test.virtual' ) ;
203+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
204+ expect ( timer . timer . total ) . toBeGreaterThan ( 200 ) ;
205+ expect ( result ) . toEqual ( { code : 'export default "/src/test.virtual"' } ) ;
206+ } ) ;
207+
208+ test ( 'Should handle synchronous object hook handlers' , ( ) => {
209+ const mockHandler = jest . fn ( ( code : string ) => {
210+ return code . toUpperCase ( ) ;
211+ } ) ;
212+
213+ const transformHook = {
214+ filter : {
215+ id : '*.css' ,
216+ } ,
217+ handler : mockHandler ,
218+ } ;
219+
220+ const wrappedHook = wrapHook ( 'test-plugin' , 'transform' , transformHook , logger ) ;
221+
222+ const result = wrappedHook . handler ( 'body { color: red; }' ) ;
223+
224+ expect ( mockHandler ) . toHaveBeenCalledWith ( 'body { color: red; }' ) ;
225+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
226+ expect ( result ) . toBe ( 'BODY { COLOR: RED; }' ) ;
227+ } ) ;
228+
229+ test ( 'Should preserve all properties of object hooks' , ( ) => {
230+ const transformHook = {
231+ filter : {
232+ id : {
233+ include : [ '**/*.vue' ] ,
234+ exclude : [ '**/*.test.vue' ] ,
235+ } ,
236+ } ,
237+ handler : jest . fn ( ( code : string ) => code ) ,
238+ enforce : 'pre' ,
239+ // Custom property that might be used by the bundler
240+ customOption : true ,
241+ } ;
242+
243+ const wrappedHook = wrapHook ( 'test-plugin' , 'transform' , transformHook , logger ) ;
244+
245+ // All properties should be preserved
246+ expect ( wrappedHook . filter ) . toEqual ( transformHook . filter ) ;
247+ expect ( wrappedHook . enforce ) . toBe ( 'pre' ) ;
248+ expect ( ( wrappedHook as any ) . customOption ) . toBe ( true ) ;
249+ expect ( wrappedHook . handler ) . not . toBe ( transformHook . handler ) ; // Handler should be wrapped
250+ } ) ;
251+ } ) ;
252+
253+ describe ( 'Edge cases' , ( ) => {
254+ test ( 'Should handle hooks that return void' , ( ) => {
255+ const mockBuildEnd = jest . fn ( ( ) => {
256+ // Side effect only, no return value
257+ } ) ;
258+
259+ const wrappedHook = wrapHook ( 'test-plugin' , 'buildEnd' , mockBuildEnd , logger ) ;
260+
261+ const result = wrappedHook ( ) ;
262+
263+ expect ( mockBuildEnd ) . toHaveBeenCalled ( ) ;
264+ expect ( timer . end ) . toHaveBeenCalledTimes ( 1 ) ;
265+ expect ( result ) . toBeUndefined ( ) ;
266+ } ) ;
267+
268+ test ( 'Should preserve "this" context for hooks' , async ( ) => {
269+ let capturedThis : any ;
270+ const mockTransform = jest . fn ( function ( this : any , code : string ) {
271+ capturedThis = this ;
272+ return { code : `${ code } -modified` } ;
273+ } ) ;
274+
275+ const wrappedHook = wrapHook ( 'test-plugin' , 'transform' , mockTransform , logger ) ;
276+
277+ const mockContext = { addWatchFile : jest . fn ( ) } ;
278+ const result = wrappedHook . call ( mockContext , 'const a = 1' ) ;
279+
280+ expect ( capturedThis ) . toBe ( mockContext ) ;
281+ expect ( result ) . toEqual ( { code : 'const a = 1-modified' } ) ;
282+ } ) ;
139283 } ) ;
140284 } ) ;
141285} ) ;
0 commit comments