@@ -102,4 +102,151 @@ describe('wrappingLoader', () => {
102102
103103 expect ( callback ) . toHaveBeenCalledWith ( null , expect . stringContaining ( "'/my/route'" ) , expect . anything ( ) ) ;
104104 } ) ;
105+
106+ describe ( 'middleware wrapping' , ( ) => {
107+ it ( 'should export proxy when user exports named "proxy" export' , async ( ) => {
108+ const callback = vi . fn ( ) ;
109+
110+ const userCode = `
111+ export function proxy(request) {
112+ return new Response('ok');
113+ }
114+ ` ;
115+ const userCodeSourceMap = undefined ;
116+
117+ const loaderPromise = new Promise < void > ( resolve => {
118+ const loaderThis = {
119+ ...defaultLoaderThis ,
120+ resourcePath : '/my/src/proxy.ts' ,
121+ callback : callback . mockImplementation ( ( ) => {
122+ resolve ( ) ;
123+ } ) ,
124+ getOptions ( ) {
125+ return {
126+ pagesDir : '/my/pages' ,
127+ appDir : '/my/app' ,
128+ pageExtensionRegex : DEFAULT_PAGE_EXTENSION_REGEX ,
129+ excludeServerRoutes : [ ] ,
130+ wrappingTargetKind : 'middleware' ,
131+ vercelCronsConfig : undefined ,
132+ nextjsRequestAsyncStorageModulePath : '/my/request-async-storage.js' ,
133+ } ;
134+ } ,
135+ } satisfies LoaderThis < WrappingLoaderOptions > ;
136+
137+ wrappingLoader . call ( loaderThis , userCode , userCodeSourceMap ) ;
138+ } ) ;
139+
140+ await loaderPromise ;
141+
142+ const wrappedCode = callback . mock . calls [ 0 ] [ 1 ] ;
143+
144+ // Verify both exports are present in export statement (Rollup bundles this way)
145+ expect ( wrappedCode ) . toMatch ( / e x p o r t \{ [ ^ } ] * \b m i d d l e w a r e \b [ ^ } ] * \b p r o x y \b [ ^ } ] * \} / ) ;
146+
147+ // Should detect proxy export
148+ expect ( wrappedCode ) . toContain ( 'userProvidedProxy = true' ) ;
149+
150+ // Proxy should be wrapped, middleware should be undefined
151+ expect ( wrappedCode ) . toMatch ( / c o n s t p r o x y = u s e r P r o v i d e d P r o x y \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
152+ expect ( wrappedCode ) . toMatch ( / c o n s t m i d d l e w a r e = u s e r P r o v i d e d M i d d l e w a r e \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
153+ } ) ;
154+
155+ it ( 'should export middleware when user exports named "middleware" export' , async ( ) => {
156+ const callback = vi . fn ( ) ;
157+
158+ const userCode = `
159+ export function middleware(request) {
160+ return new Response('ok');
161+ }
162+ ` ;
163+ const userCodeSourceMap = undefined ;
164+
165+ const loaderPromise = new Promise < void > ( resolve => {
166+ const loaderThis = {
167+ ...defaultLoaderThis ,
168+ resourcePath : '/my/src/middleware.ts' ,
169+ callback : callback . mockImplementation ( ( ) => {
170+ resolve ( ) ;
171+ } ) ,
172+ getOptions ( ) {
173+ return {
174+ pagesDir : '/my/pages' ,
175+ appDir : '/my/app' ,
176+ pageExtensionRegex : DEFAULT_PAGE_EXTENSION_REGEX ,
177+ excludeServerRoutes : [ ] ,
178+ wrappingTargetKind : 'middleware' ,
179+ vercelCronsConfig : undefined ,
180+ nextjsRequestAsyncStorageModulePath : '/my/request-async-storage.js' ,
181+ } ;
182+ } ,
183+ } satisfies LoaderThis < WrappingLoaderOptions > ;
184+
185+ wrappingLoader . call ( loaderThis , userCode , userCodeSourceMap ) ;
186+ } ) ;
187+
188+ await loaderPromise ;
189+
190+ const wrappedCode = callback . mock . calls [ 0 ] [ 1 ] ;
191+
192+ // Should detect middleware export
193+ expect ( wrappedCode ) . toContain ( 'userProvidedMiddleware = true' ) ;
194+
195+ // Should NOT detect proxy export
196+ expect ( wrappedCode ) . toContain ( 'userProvidedProxy = false' ) ;
197+
198+ // Middleware should be wrapped, proxy should be undefined
199+ expect ( wrappedCode ) . toMatch ( / c o n s t m i d d l e w a r e = u s e r P r o v i d e d M i d d l e w a r e \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
200+ expect ( wrappedCode ) . toMatch ( / c o n s t p r o x y = u s e r P r o v i d e d P r o x y \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
201+ } ) ;
202+
203+ it ( 'should export undefined middleware/proxy when user only exports default' , async ( ) => {
204+ const callback = vi . fn ( ) ;
205+
206+ const userCode = `
207+ export default function(request) {
208+ return new Response('ok');
209+ }
210+ ` ;
211+ const userCodeSourceMap = undefined ;
212+
213+ const loaderPromise = new Promise < void > ( resolve => {
214+ const loaderThis = {
215+ ...defaultLoaderThis ,
216+ resourcePath : '/my/src/middleware.ts' ,
217+ callback : callback . mockImplementation ( ( ) => {
218+ resolve ( ) ;
219+ } ) ,
220+ getOptions ( ) {
221+ return {
222+ pagesDir : '/my/pages' ,
223+ appDir : '/my/app' ,
224+ pageExtensionRegex : DEFAULT_PAGE_EXTENSION_REGEX ,
225+ excludeServerRoutes : [ ] ,
226+ wrappingTargetKind : 'middleware' ,
227+ vercelCronsConfig : undefined ,
228+ nextjsRequestAsyncStorageModulePath : '/my/request-async-storage.js' ,
229+ } ;
230+ } ,
231+ } satisfies LoaderThis < WrappingLoaderOptions > ;
232+
233+ wrappingLoader . call ( loaderThis , userCode , userCodeSourceMap ) ;
234+ } ) ;
235+
236+ await loaderPromise ;
237+
238+ const wrappedCode = callback . mock . calls [ 0 ] [ 1 ] ;
239+
240+ // Should export default
241+ expect ( wrappedCode ) . toMatch ( / e x p o r t \{ [ ^ } ] * a s d e f a u l t [ ^ } ] * \} / ) ;
242+
243+ // Both flags should be false (no named exports provided by user)
244+ expect ( wrappedCode ) . toContain ( 'userProvidedMiddleware = false' ) ;
245+ expect ( wrappedCode ) . toContain ( 'userProvidedProxy = false' ) ;
246+
247+ // Both middleware and proxy should be undefined (conditionals evaluate to false)
248+ expect ( wrappedCode ) . toMatch ( / c o n s t m i d d l e w a r e = u s e r P r o v i d e d M i d d l e w a r e \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
249+ expect ( wrappedCode ) . toMatch ( / c o n s t p r o x y = u s e r P r o v i d e d P r o x y \? w r a p p e d H a n d l e r : u n d e f i n e d / ) ;
250+ } ) ;
251+ } ) ;
105252} ) ;
0 commit comments