@@ -2,7 +2,7 @@ import path from 'path'
2
2
import { nextTestSetup } from 'e2e-utils'
3
3
import { retry } from 'next-test-utils'
4
4
5
- describe ( 'log-file MCP integration ' , ( ) => {
5
+ describe ( 'get-logs MCP tool ' , ( ) => {
6
6
const { next, skipped } = nextTestSetup ( {
7
7
files : path . join ( __dirname , 'fixtures' , 'log-file-app' ) ,
8
8
skipDeployment : true ,
@@ -12,48 +12,7 @@ describe('log-file MCP integration', () => {
12
12
return
13
13
}
14
14
15
- function filterOutPaginationHeaders ( content : string ) : string {
16
- return content
17
- . split ( '\n' )
18
- . filter ( ( line ) => {
19
- if ( / S h o w i n g l a s t / . test ( line ) ) {
20
- return false
21
- }
22
- return true
23
- } )
24
- . join ( '\n' )
25
- . trim ( )
26
- }
27
-
28
- function normalizeLogContent ( content : string ) : string {
29
- return (
30
- content
31
- // Strip lines containing "Download the React DevTools"
32
- . split ( '\n' )
33
- . filter ( ( line ) => {
34
- // filter out the noise logs and pagination headers
35
- if (
36
- / D o w n l o a d t h e R e a c t D e v T o o l s | c o n n e c t e d t o w s a t | r e c e i v e d w s m e s s a g e | N e x t .j s p a g e a l r e a d y h y d r a t e d | N e x t .j s h y d r a t e c a l l b a c k f i r e d | C o m p i l i n g | C o m p i l e d | R e a d y i n / . test (
37
- line
38
- )
39
- ) {
40
- return false
41
- }
42
- return true
43
- } )
44
- . join ( '\n' )
45
- // Normalize timestamps to consistent format
46
- . replace ( / \[ \d { 2 } : \d { 2 } : \d { 2 } \. \d { 3 } \] / g, '[xx:xx:xx.xxx]' )
47
- // Normalize dynamic content that might vary between test runs
48
- . replace ( / l o c a l h o s t : \d + / g, 'localhost:PORT' )
49
- . trim ( )
50
- )
51
- }
52
-
53
- async function callGetLogs (
54
- id : string ,
55
- args ?: { lines ?: number ; offset ?: number }
56
- ) : Promise < string > {
15
+ async function callGetLogs ( id : string ) : Promise < string > {
57
16
const response = await fetch ( `${ next . url } /_next/mcp` , {
58
17
method : 'POST' ,
59
18
headers : {
@@ -64,7 +23,7 @@ describe('log-file MCP integration', () => {
64
23
jsonrpc : '2.0' ,
65
24
id,
66
25
method : 'tools/call' ,
67
- params : { name : 'get_logs' , arguments : args || { } } ,
26
+ params : { name : 'get_logs' , arguments : { } } ,
68
27
} ) ,
69
28
} )
70
29
@@ -74,174 +33,29 @@ describe('log-file MCP integration', () => {
74
33
return result . result ?. content ?. [ 0 ] ?. text
75
34
}
76
35
77
- it ( 'should retrieve logs via MCP get_logs tool' , async ( ) => {
78
- // Generate some logs by visiting pages that create log entries
79
- await next . browser ( '/server' )
80
- await next . browser ( '/client' )
81
- await next . browser ( '/pages-router-page' )
82
-
83
- let logs : string = ''
84
-
85
- await retry ( async ( ) => {
86
- const sessionId = 'test-mcp-logs-' + Date . now ( )
87
- logs = await callGetLogs ( sessionId )
88
-
89
- // Should have some log content
90
- expect ( logs ) . not . toBe (
91
- 'Log file is empty. No logs have been recorded yet.'
92
- )
93
- expect ( logs ) . not . toContain ( 'Log file not found at' )
94
- } )
95
-
96
- await retry ( async ( ) => {
97
- const normalizedLogs = filterOutPaginationHeaders (
98
- normalizeLogContent ( logs )
99
- )
100
-
101
- // Use inline snapshot to capture the actual log content
102
- expect ( normalizedLogs ) . toMatchInlineSnapshot ( `
103
- "[xx:xx:xx.xxx] Server LOG RSC: This is a log message from server component
104
- [xx:xx:xx.xxx] Server ERROR RSC: This is an error message from server component
105
- [xx:xx:xx.xxx] Server WARN RSC: This is a warning message from server component
106
- [xx:xx:xx.xxx] Server LOG Pages Router SSR: This is a log message from getServerSideProps
107
- [xx:xx:xx.xxx] Server ERROR Pages Router SSR: This is an error message from getServerSideProps
108
- [xx:xx:xx.xxx] Server WARN Pages Router SSR: This is a warning message from getServerSideProps
109
- [xx:xx:xx.xxx] Server LOG Pages Router isomorphic: This is a log message from render"
110
- ` )
111
- } , 5 * 1000 )
112
- } )
113
-
114
36
it ( 'should handle missing log file gracefully via MCP' , async ( ) => {
115
37
// This test should run in a clean state, but since other tests may have run first,
116
38
// we'll just verify the MCP tool responds correctly
117
- const logs = await callGetLogs ( 'test-no-logs' )
118
-
119
- // Should have some response (either logs or error message)
120
- expect ( logs ) . toBeDefined ( )
121
- expect ( typeof logs ) . toBe ( 'string' )
122
- } )
123
-
124
- it ( 'should return paginated results when many logs exist' , async ( ) => {
125
- // Generate logs by visiting multiple pages multiple times
126
- for ( let i = 0 ; i < 3 ; i ++ ) {
127
- await next . browser ( '/server' )
128
- await next . browser ( '/client' )
129
- await next . browser ( '/pages-router-page' )
130
- // Small delay between visits
131
- await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) )
132
- }
133
-
134
- let logs : string = ''
135
- await retry ( async ( ) => {
136
- const sessionId = 'test-pagination-' + Date . now ( )
137
- logs = await callGetLogs ( sessionId )
138
-
139
- // Should have log content
140
- expect ( logs ) . not . toBe (
141
- 'Log file is empty. No logs have been recorded yet.'
142
- )
143
- expect ( logs ) . not . toContain ( 'Log file not found at' )
144
- } )
145
-
146
- await retry ( async ( ) => {
147
- const sessionId = 'test-pagination-' + Date . now ( )
148
- logs = await callGetLogs ( sessionId )
149
- // Check that we have many log entries
150
- const lines = logs . split ( '\n' ) . length
151
- expect ( lines ) . toBeGreaterThan ( 30 )
152
-
153
- const normalizedLogs = filterOutPaginationHeaders (
154
- normalizeLogContent ( logs )
155
- )
39
+ const response = await callGetLogs ( 'test-no-logs' )
156
40
157
- // Assert each unique log line individually (multiple instances expected)
158
- expect ( normalizedLogs ) . toMatch (
159
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + L O G \s + P a g e s R o u t e r S S R : T h i s i s a l o g m e s s a g e f r o m g e t S e r v e r S i d e P r o p s /
160
- )
161
- expect ( normalizedLogs ) . toMatch (
162
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + E R R O R \s + P a g e s R o u t e r S S R : T h i s i s a n e r r o r m e s s a g e f r o m g e t S e r v e r S i d e P r o p s /
163
- )
164
- expect ( normalizedLogs ) . toMatch (
165
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + W A R N \s + P a g e s R o u t e r S S R : T h i s i s a w a r n i n g m e s s a g e f r o m g e t S e r v e r S i d e P r o p s /
166
- )
167
- expect ( normalizedLogs ) . toMatch (
168
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + L O G \s + P a g e s R o u t e r i s o m o r p h i c : T h i s i s a l o g m e s s a g e f r o m r e n d e r /
169
- )
170
- expect ( normalizedLogs ) . toMatch (
171
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + L O G \s + R S C : T h i s i s a l o g m e s s a g e f r o m s e r v e r c o m p o n e n t /
172
- )
173
- expect ( normalizedLogs ) . toMatch (
174
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + E R R O R \s + R S C : T h i s i s a n e r r o r m e s s a g e f r o m s e r v e r c o m p o n e n t /
175
- )
176
- expect ( normalizedLogs ) . toMatch (
177
- / \[ x x : x x : x x \. x x x \] \s + S e r v e r \s + W A R N \s + R S C : T h i s i s a w a r n i n g m e s s a g e f r o m s e r v e r c o m p o n e n t /
178
- )
179
- expect ( normalizedLogs ) . toMatch (
180
- / \[ x x : x x : x x \. x x x \] \s + B r o w s e r \s + L O G \s + C l i e n t : C o m p l e x c i r c u l a r o b j e c t : /
181
- )
182
- expect ( normalizedLogs ) . toMatch (
183
- / \[ x x : x x : x x \. x x x \] \s + B r o w s e r \s + E R R O R \s + C l i e n t : T h i s i s a n e r r o r m e s s a g e f r o m c l i e n t c o m p o n e n t /
184
- )
185
- expect ( normalizedLogs ) . toMatch (
186
- / \[ x x : x x : x x \. x x x \] \s + B r o w s e r \s + W A R N \s + C l i e n t : T h i s i s a w a r n i n g m e s s a g e f r o m c l i e n t c o m p o n e n t /
187
- )
188
- } )
41
+ expect ( response ) . toContain ( 'Log file not found at' )
42
+ expect ( response ) . not . toContain ( 'Next.js log file path:' )
189
43
} )
190
44
191
- it ( 'should show count of custom offset and lines parameters correctly' , async ( ) => {
192
- // Test with offset=10, lines=5 (should get lines 10-15 from the end)
193
- const logsWithOffset = await callGetLogs ( 'test-offset' , {
194
- offset : 10 ,
195
- lines : 5 ,
196
- } )
197
- const normalizedLogsWithOffset = normalizeLogContent ( logsWithOffset )
198
-
199
- expect ( normalizedLogsWithOffset ) . toMatch (
200
- / S h o w i n g l i n e s \d + - \d + o f \d + l o g e n t r i e s /
201
- )
202
-
203
- // Test with just lines=5 (should get last 5 lines)
204
- const logsWithLines = await callGetLogs ( 'test-lines' , { lines : 5 } )
205
- const normalizedLogsWithLines = normalizeLogContent ( logsWithLines )
206
-
207
- expect ( normalizedLogsWithLines ) . toMatch (
208
- / S h o w i n g l a s t 5 o f \d + l o g e n t r i e s : /
209
- )
210
-
211
- // Test with offset=0, lines=3 (should get last 3 lines)
212
- const logsWithBoth = await callGetLogs ( 'test-both' , { offset : 0 , lines : 3 } )
213
- const normalizedLogsWithBoth = normalizeLogContent ( logsWithBoth )
214
-
215
- expect ( normalizedLogsWithBoth ) . toMatch ( / S h o w i n g l a s t 3 o f \d + l o g e n t r i e s : / )
216
- } )
217
-
218
- it ( 'should show logs of custom offset and lines parameters' , async ( ) => {
219
- await retry ( async ( ) => {
220
- // Test with just lines=5 (should get last 5 lines)
221
- const logsWithLines = filterOutPaginationHeaders (
222
- await callGetLogs ( 'test-lines' , { lines : 5 } )
223
- )
224
- const normalizedLogsWithLines = normalizeLogContent ( logsWithLines )
225
-
226
- // The logs are 4 because the unstable noisy logs are filtered out
227
- expect ( normalizedLogsWithLines ) . toMatchInlineSnapshot ( `
228
- "[xx:xx:xx.xxx] Server LOG RSC: This is a log message from server component
229
- [xx:xx:xx.xxx] Server ERROR RSC: This is an error message from server component
230
- [xx:xx:xx.xxx] Server WARN RSC: This is a warning message from server component"
231
- ` )
232
- } )
45
+ it ( 'should return log file path via MCP get_logs tool' , async ( ) => {
46
+ // Generate some logs by visiting pages that create log entries
47
+ await next . browser ( '/server' )
48
+ await next . browser ( '/client' )
49
+ await next . browser ( '/pages-router-page' )
233
50
234
51
await retry ( async ( ) => {
235
- // Test with offset=0, lines=3 (should get last 3 lines)
236
- const logsWithBoth = filterOutPaginationHeaders (
237
- await callGetLogs ( 'test-both' , { offset : 0 , lines : 3 } )
238
- )
239
- const normalizedLogsWithBoth = normalizeLogContent ( logsWithBoth )
52
+ const sessionId = 'test-mcp-logs-' + Date . now ( )
53
+ const response = await callGetLogs ( sessionId )
240
54
241
- // The logs are 2 because the unstable noisy logs are filtered out
242
- expect ( normalizedLogsWithBoth ) . toMatchInlineSnapshot (
243
- `"[xx:xx:xx.xxx] Server WARN RSC: This is a warning message from server component"`
244
- )
55
+ // Should return the log file path
56
+ expect ( response ) . toContain ( 'Next.js log file path:' )
57
+ expect ( response ) . toContain ( 'logs/next-development.log' )
58
+ expect ( response ) . not . toContain ( 'Log file not found at' )
245
59
} )
246
60
} )
247
61
} )
0 commit comments