@@ -193,6 +193,235 @@ createStart(() => ({
193193 } ) ;
194194} ) ;
195195
196+ describe ( 'route-level middleware auto-instrumentation' , ( ) => {
197+ const routeFileWithMiddleware = `
198+ import { createFileRoute } from '@tanstack/react-router';
199+ import { loggingMiddleware } from '../middleware';
200+
201+ export const Route = createFileRoute('/api/test')({
202+ server: {
203+ middleware: [loggingMiddleware],
204+ handlers: {
205+ GET: async () => ({ message: 'test' }),
206+ },
207+ },
208+ });
209+ ` ;
210+
211+ it ( 'instruments route-level middleware arrays' , ( ) => {
212+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
213+ const result = plugin . transform ( routeFileWithMiddleware , '/app/routes/api.test.ts' ) ;
214+
215+ expect ( result ) . not . toBeNull ( ) ;
216+ expect ( result ! . code ) . toContain ( "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react'" ) ;
217+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ loggingMiddleware })' ) ;
218+ } ) ;
219+
220+ it ( 'instruments multiple middlewares in route file' , ( ) => {
221+ const code = `
222+ import { createFileRoute } from '@tanstack/react-router';
223+ export const Route = createFileRoute('/foo')({
224+ server: {
225+ middleware: [authMiddleware, loggingMiddleware],
226+ handlers: { GET: () => ({}) },
227+ },
228+ });
229+ ` ;
230+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
231+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
232+
233+ expect ( result ) . not . toBeNull ( ) ;
234+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ authMiddleware, loggingMiddleware })' ) ;
235+ } ) ;
236+
237+ it ( 'does not instrument files without createFileRoute' , ( ) => {
238+ const code = `
239+ const middleware = [someMiddleware];
240+ export const foo = { middleware };
241+ ` ;
242+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
243+ const result = plugin . transform ( code , '/app/utils.ts' ) ;
244+
245+ expect ( result ) . toBeNull ( ) ;
246+ } ) ;
247+
248+ it ( 'does not instrument route files without middleware arrays' , ( ) => {
249+ const code = `
250+ import { createFileRoute } from '@tanstack/react-router';
251+ export const Route = createFileRoute('/client')({
252+ component: () => '<div>Client only</div>',
253+ });
254+ ` ;
255+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
256+ const result = plugin . transform ( code , '/app/routes/client.tsx' ) ;
257+
258+ expect ( result ) . toBeNull ( ) ;
259+ } ) ;
260+
261+ it ( 'does not instrument empty middleware arrays in route files' , ( ) => {
262+ const code = `
263+ import { createFileRoute } from '@tanstack/react-router';
264+ export const Route = createFileRoute('/foo')({
265+ server: {
266+ middleware: [],
267+ handlers: { GET: () => ({}) },
268+ },
269+ });
270+ ` ;
271+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
272+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
273+
274+ expect ( result ) . toBeNull ( ) ;
275+ } ) ;
276+ } ) ;
277+
278+ describe ( 'handler-specific middleware auto-instrumentation' , ( ) => {
279+ it ( 'instruments handler-level middleware arrays' , ( ) => {
280+ const code = `
281+ import { createFileRoute } from '@tanstack/react-router';
282+ export const Route = createFileRoute('/foo')({
283+ server: {
284+ handlers: ({ createHandlers }) =>
285+ createHandlers({
286+ GET: {
287+ middleware: [loggingMiddleware],
288+ handler: () => ({ data: 'test' }),
289+ },
290+ }),
291+ },
292+ });
293+ ` ;
294+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
295+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
296+
297+ expect ( result ) . not . toBeNull ( ) ;
298+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ loggingMiddleware })' ) ;
299+ } ) ;
300+
301+ it ( 'instruments multiple handler-level middleware arrays in same file' , ( ) => {
302+ const code = `
303+ import { createFileRoute } from '@tanstack/react-router';
304+ export const Route = createFileRoute('/foo')({
305+ server: {
306+ handlers: ({ createHandlers }) =>
307+ createHandlers({
308+ GET: {
309+ middleware: [readMiddleware],
310+ handler: () => ({}),
311+ },
312+ POST: {
313+ middleware: [writeMiddleware, authMiddleware],
314+ handler: () => ({}),
315+ },
316+ }),
317+ },
318+ });
319+ ` ;
320+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
321+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
322+
323+ expect ( result ) . not . toBeNull ( ) ;
324+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ readMiddleware })' ) ;
325+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ writeMiddleware, authMiddleware })' ) ;
326+ } ) ;
327+ } ) ;
328+
329+ describe ( 'route middleware edge cases' , ( ) => {
330+ it ( 'does not wrap middleware containing function calls in route files' , ( ) => {
331+ const code = `
332+ import { createFileRoute } from '@tanstack/react-router';
333+ export const Route = createFileRoute('/foo')({
334+ server: {
335+ middleware: [createMiddleware()],
336+ handlers: { GET: () => ({}) },
337+ },
338+ });
339+ ` ;
340+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
341+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
342+
343+ expect ( result ) . toBeNull ( ) ;
344+ } ) ;
345+
346+ it ( 'warns about route middleware that cannot be auto-wrapped' , ( ) => {
347+ const consoleWarnSpy = vi . spyOn ( console , 'warn' ) . mockImplementation ( ( ) => { } ) ;
348+
349+ const code = `
350+ import { createFileRoute } from '@tanstack/react-router';
351+ export const Route = createFileRoute('/foo')({
352+ server: {
353+ middleware: [getMiddleware()],
354+ handlers: { GET: () => ({}) },
355+ },
356+ });
357+ ` ;
358+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
359+ plugin . transform ( code , '/app/routes/foo.ts' ) ;
360+
361+ expect ( consoleWarnSpy ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Could not auto-instrument route middleware' ) ) ;
362+
363+ consoleWarnSpy . mockRestore ( ) ;
364+ } ) ;
365+
366+ it ( 'handles route files with use server directive' , ( ) => {
367+ const code = `'use server';
368+ import { createFileRoute } from '@tanstack/react-router';
369+ export const Route = createFileRoute('/foo')({
370+ server: {
371+ middleware: [authMiddleware],
372+ handlers: { GET: () => ({}) },
373+ },
374+ });
375+ ` ;
376+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
377+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
378+
379+ expect ( result ) . not . toBeNull ( ) ;
380+ expect ( result ! . code ) . toMatch ( / ^ ' u s e s e r v e r ' ; \s * \n i m p o r t \{ w r a p M i d d l e w a r e s W i t h S e n t r y \} / ) ;
381+ } ) ;
382+
383+ it ( 'does not instrument route files that already use wrapMiddlewaresWithSentry' , ( ) => {
384+ const code = `
385+ import { createFileRoute } from '@tanstack/react-router';
386+ import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';
387+ export const Route = createFileRoute('/foo')({
388+ server: {
389+ middleware: wrapMiddlewaresWithSentry({ authMiddleware }),
390+ handlers: { GET: () => ({}) },
391+ },
392+ });
393+ ` ;
394+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
395+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
396+
397+ expect ( result ) . toBeNull ( ) ;
398+ } ) ;
399+
400+ it ( 'handles both route-level and handler-level middleware in same file' , ( ) => {
401+ const code = `
402+ import { createFileRoute } from '@tanstack/react-router';
403+ export const Route = createFileRoute('/foo')({
404+ server: {
405+ middleware: [routeMiddleware],
406+ handlers: ({ createHandlers }) =>
407+ createHandlers({
408+ GET: {
409+ middleware: [getMiddleware],
410+ handler: () => ({}),
411+ },
412+ }),
413+ },
414+ });
415+ ` ;
416+ const plugin = makeAutoInstrumentMiddlewarePlugin ( ) as PluginWithTransform ;
417+ const result = plugin . transform ( code , '/app/routes/foo.ts' ) ;
418+
419+ expect ( result ) . not . toBeNull ( ) ;
420+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ routeMiddleware })' ) ;
421+ expect ( result ! . code ) . toContain ( 'middleware: wrapMiddlewaresWithSentry({ getMiddleware })' ) ;
422+ } ) ;
423+ } ) ;
424+
196425describe ( 'arrayToObjectShorthand' , ( ) => {
197426 it ( 'converts single identifier' , ( ) => {
198427 expect ( arrayToObjectShorthand ( 'foo' ) ) . toBe ( '{ foo }' ) ;
0 commit comments