@@ -69,3 +69,146 @@ test('json data rewrite works', async ({ middlewarePages }) => {
69
69
70
70
expect ( data . pageProps . message ) . toBeDefined ( )
71
71
} )
72
+
73
+ // those tests use `fetch` instead of `page.goto` intentionally to avoid potential client rendering
74
+ // hiding any potential edge/server issues
75
+ test . describe ( 'Middleware with i18n and excluded paths' , ( ) => {
76
+ const DEFAULT_LOCALE = 'en'
77
+
78
+ // those tests hit paths ending with `/json` which has special handling in middleware
79
+ // to return JSON response from middleware itself
80
+ test . describe ( 'Middleware response path' , ( ) => {
81
+ test ( 'should match on non-localized not excluded page path' , async ( {
82
+ middlewareI18nExcludedPaths,
83
+ } ) => {
84
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /json` )
85
+
86
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . toBe ( 'true' )
87
+ expect ( response . status ) . toBe ( 200 )
88
+
89
+ const { nextUrlPathname, nextUrlLocale } = await response . json ( )
90
+
91
+ expect ( nextUrlPathname ) . toBe ( '/json' )
92
+ expect ( nextUrlLocale ) . toBe ( DEFAULT_LOCALE )
93
+ } )
94
+
95
+ test ( 'should match on localized not excluded page path' , async ( {
96
+ middlewareI18nExcludedPaths,
97
+ } ) => {
98
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /fr/json` )
99
+
100
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . toBe ( 'true' )
101
+ expect ( response . status ) . toBe ( 200 )
102
+
103
+ const { nextUrlPathname, nextUrlLocale } = await response . json ( )
104
+
105
+ expect ( nextUrlPathname ) . toBe ( '/json' )
106
+ expect ( nextUrlLocale ) . toBe ( 'fr' )
107
+ } )
108
+ } )
109
+
110
+ // those tests hit paths that don't end with `/json` so they should be passed through to origin
111
+ // if they match middleware matcher OR skip middleware and go to origin directly if they don't
112
+ // match middleware matcher
113
+ test . describe ( 'Middleware passthrough' , ( ) => {
114
+ function extractDataFromHtml ( html : string ) : Record < string , any > {
115
+ const match = html . match ( / < p r e > (?< rawInput > [ ^ < ] + ) < \/ p r e > / )
116
+ if ( ! match || ! match . groups ?. rawInput ) {
117
+ console . error ( '<pre> not found in html input' , {
118
+ html,
119
+ } )
120
+ throw new Error ( 'Failed to extract data from HTML' )
121
+ }
122
+
123
+ const { rawInput } = match . groups
124
+ const unescapedInput = rawInput . replaceAll ( '"' , '"' )
125
+ try {
126
+ return JSON . parse ( unescapedInput )
127
+ } catch ( originalError ) {
128
+ console . error ( 'Failed to parse JSON' , {
129
+ originalError,
130
+ rawInput,
131
+ unescapedInput,
132
+ } )
133
+ }
134
+ throw new Error ( 'Failed to extract data from HTML' )
135
+ }
136
+
137
+ test ( 'should match on non-localized not excluded page path' , async ( {
138
+ middlewareI18nExcludedPaths,
139
+ } ) => {
140
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /html` )
141
+
142
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . toBe ( 'true' )
143
+ expect ( response . status ) . toBe ( 200 )
144
+ expect ( response . headers . get ( 'content-type' ) ) . toMatch ( / t e x t \/ h t m l / )
145
+
146
+ const html = await response . text ( )
147
+ const { locale, params } = extractDataFromHtml ( html )
148
+
149
+ expect ( params ) . toMatchObject ( { catchall : [ 'html' ] } )
150
+ expect ( locale ) . toBe ( DEFAULT_LOCALE )
151
+ } )
152
+
153
+ test ( 'should match on localized not excluded page path' , async ( {
154
+ middlewareI18nExcludedPaths,
155
+ } ) => {
156
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /fr/html` )
157
+
158
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . toBe ( 'true' )
159
+ expect ( response . status ) . toBe ( 200 )
160
+ expect ( response . headers . get ( 'content-type' ) ) . toMatch ( / t e x t \/ h t m l / )
161
+
162
+ const html = await response . text ( )
163
+ const { locale, params } = extractDataFromHtml ( html )
164
+
165
+ expect ( params ) . toMatchObject ( { catchall : [ 'html' ] } )
166
+ expect ( locale ) . toBe ( 'fr' )
167
+ } )
168
+
169
+ test ( 'should NOT match on non-localized excluded API path' , async ( {
170
+ middlewareI18nExcludedPaths,
171
+ } ) => {
172
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /api/html` )
173
+
174
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . not . toBe ( 'true' )
175
+ expect ( response . status ) . toBe ( 200 )
176
+
177
+ const { params } = await response . json ( )
178
+
179
+ expect ( params ) . toMatchObject ( { catchall : [ 'html' ] } )
180
+ } )
181
+
182
+ test ( 'should NOT match on non-localized excluded page path' , async ( {
183
+ middlewareI18nExcludedPaths,
184
+ } ) => {
185
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /excluded` )
186
+
187
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . not . toBe ( 'true' )
188
+ expect ( response . status ) . toBe ( 200 )
189
+ expect ( response . headers . get ( 'content-type' ) ) . toMatch ( / t e x t \/ h t m l / )
190
+
191
+ const html = await response . text ( )
192
+ const { locale, params } = extractDataFromHtml ( html )
193
+
194
+ expect ( params ) . toMatchObject ( { catchall : [ 'excluded' ] } )
195
+ expect ( locale ) . toBe ( DEFAULT_LOCALE )
196
+ } )
197
+
198
+ test ( 'should NOT match on localized excluded page path' , async ( {
199
+ middlewareI18nExcludedPaths,
200
+ } ) => {
201
+ const response = await fetch ( `${ middlewareI18nExcludedPaths . url } /fr/excluded` )
202
+
203
+ expect ( response . headers . get ( 'x-test-used-middleware' ) ) . not . toBe ( 'true' )
204
+ expect ( response . status ) . toBe ( 200 )
205
+ expect ( response . headers . get ( 'content-type' ) ) . toMatch ( / t e x t \/ h t m l / )
206
+
207
+ const html = await response . text ( )
208
+ const { locale, params } = extractDataFromHtml ( html )
209
+
210
+ expect ( params ) . toMatchObject ( { catchall : [ 'excluded' ] } )
211
+ expect ( locale ) . toBe ( 'fr' )
212
+ } )
213
+ } )
214
+ } )
0 commit comments