1
+ import {
2
+ matchMiddleware ,
3
+ stripLocale ,
4
+ matchesRedirect ,
5
+ matchesRewrite ,
6
+ patchNextFiles ,
7
+ unpatchNextFiles ,
8
+ } from "../../packages/runtime/src/helpers/files"
9
+ import {
10
+ readFileSync ,
11
+ copy ,
12
+ ensureDir ,
13
+ } from "fs-extra"
14
+ import path from "path"
15
+ import { dirname } from "path"
16
+ import { join } from "pathe"
17
+ import { Rewrites } from "../../packages/runtime/src/helpers/types"
18
+
19
+ const REDIRECTS : Rewrites = [
20
+ {
21
+ source : '/:file((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+)/' ,
22
+ destination : '/:file' ,
23
+ locale : false ,
24
+ internal : true ,
25
+ statusCode : 308 ,
26
+ regex : '^(?:/((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/]+\\.\\w+))/$' ,
27
+ } ,
28
+ {
29
+ source : '/:notfile((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+)' ,
30
+ destination : '/:notfile/' ,
31
+ locale : false ,
32
+ internal : true ,
33
+ statusCode : 308 ,
34
+ regex : '^(?:/((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+))$' ,
35
+ } ,
36
+ {
37
+ source : '/en/redirectme' ,
38
+ destination : '/' ,
39
+ statusCode : 308 ,
40
+ regex : '^(?!/_next)/en/redirectme(?:/)?$' ,
41
+ } ,
42
+ {
43
+ source : '/:nextInternalLocale(en|es|fr)/redirectme' ,
44
+ destination : '/:nextInternalLocale/' ,
45
+ statusCode : 308 ,
46
+ regex : '^(?!/_next)(?:/(en|es|fr))/redirectme(?:/)?$' ,
47
+ } ,
48
+ ]
49
+
50
+ const REWRITES : Rewrites = [
51
+ {
52
+ source : '/:nextInternalLocale(en|es|fr)/old/:path*' ,
53
+ destination : '/:nextInternalLocale/:path*' ,
54
+ regex : '^(?:/(en|es|fr))/old(?:/((?:[^/]+?)(?:/(?:[^/]+?))*))?(?:/)?$' ,
55
+ statusCode : 308 ,
56
+ } ,
57
+ ]
58
+
59
+ describe ( 'files utility functions' , ( ) => {
60
+ test ( 'middleware tester matches correct paths' , ( ) => {
61
+ const middleware = [ 'middle' , 'sub/directory' ]
62
+ const paths = [
63
+ 'middle.html' ,
64
+ 'middle' ,
65
+ 'middle/' ,
66
+ 'middle/ware' ,
67
+ 'sub/directory' ,
68
+ 'sub/directory.html' ,
69
+ 'sub/directory/child' ,
70
+ 'sub/directory/child.html' ,
71
+ ]
72
+ for ( const path of paths ) {
73
+ expect ( matchMiddleware ( middleware , path ) ) . toBeTruthy ( )
74
+ }
75
+ } )
76
+
77
+ test ( 'middleware tester does not match incorrect paths' , ( ) => {
78
+ const middleware = [ 'middle' , 'sub/directory' ]
79
+ const paths = [
80
+ 'middl' ,
81
+ '' ,
82
+ 'somethingelse' ,
83
+ 'another.html' ,
84
+ 'another/middle.html' ,
85
+ 'sub/anotherdirectory.html' ,
86
+ 'sub/directoryelse' ,
87
+ 'sub/directoryelse.html' ,
88
+ ]
89
+ for ( const path of paths ) {
90
+ expect ( matchMiddleware ( middleware , path ) ) . toBeFalsy ( )
91
+ }
92
+ } )
93
+
94
+ test ( 'middleware tester matches root middleware' , ( ) => {
95
+ const middleware = [ '' ]
96
+ const paths = [
97
+ 'middl' ,
98
+ '' ,
99
+ 'somethingelse' ,
100
+ 'another.html' ,
101
+ 'another/middle.html' ,
102
+ 'sub/anotherdirectory.html' ,
103
+ 'sub/directoryelse' ,
104
+ 'sub/directoryelse.html' ,
105
+ ]
106
+ for ( const path of paths ) {
107
+ expect ( matchMiddleware ( middleware , path ) ) . toBeTruthy ( )
108
+ }
109
+ } )
110
+
111
+ test ( 'middleware tester matches root middleware' , ( ) => {
112
+ const paths = [
113
+ 'middl' ,
114
+ '' ,
115
+ 'somethingelse' ,
116
+ 'another.html' ,
117
+ 'another/middle.html' ,
118
+ 'sub/anotherdirectory.html' ,
119
+ 'sub/directoryelse' ,
120
+ 'sub/directoryelse.html' ,
121
+ ]
122
+ for ( const path of paths ) {
123
+ expect ( matchMiddleware ( undefined , path ) ) . toBeFalsy ( )
124
+ }
125
+ } )
126
+
127
+ test ( 'stripLocale correctly strips matching locales' , ( ) => {
128
+ const locales = [ 'en' , 'fr' , 'en-GB' ]
129
+ const paths = [
130
+ [ 'en/file.html' , 'file.html' ] ,
131
+ [ 'fr/file.html' , 'file.html' ] ,
132
+ [ 'en-GB/file.html' , 'file.html' ] ,
133
+ [ 'file.html' , 'file.html' ] ,
134
+ ]
135
+
136
+ for ( const [ path , expected ] of paths ) {
137
+ expect ( stripLocale ( path , locales ) ) . toEqual ( expected )
138
+ }
139
+ } )
140
+
141
+ test ( 'stripLocale does not touch non-matching matching locales' , ( ) => {
142
+ const locales = [ 'en' , 'fr' , 'en-GB' ]
143
+ const paths = [ 'de/file.html' , 'enfile.html' , 'en-US/file.html' ]
144
+ for ( const path of paths ) {
145
+ expect ( stripLocale ( path , locales ) ) . toEqual ( path )
146
+ }
147
+ } )
148
+
149
+ test ( 'matchesRedirect correctly matches paths with locales' , ( ) => {
150
+ const paths = [ 'en/redirectme.html' , 'en/redirectme.json' , 'fr/redirectme.html' , 'fr/redirectme.json' ]
151
+ paths . forEach ( ( path ) => {
152
+ expect ( matchesRedirect ( path , REDIRECTS ) ) . toBeTruthy ( )
153
+ } )
154
+ } )
155
+
156
+ test ( "matchesRedirect doesn't match paths with invalid locales" , ( ) => {
157
+ const paths = [ 'dk/redirectme.html' , 'dk/redirectme.json' , 'gr/redirectme.html' , 'gr/redirectme.json' ]
158
+ paths . forEach ( ( path ) => {
159
+ expect ( matchesRedirect ( path , REDIRECTS ) ) . toBeFalsy ( )
160
+ } )
161
+ } )
162
+
163
+ test ( "matchesRedirect doesn't match internal redirects" , ( ) => {
164
+ const paths = [ 'en/notrailingslash' ]
165
+ paths . forEach ( ( path ) => {
166
+ expect ( matchesRedirect ( path , REDIRECTS ) ) . toBeFalsy ( )
167
+ } )
168
+ } )
169
+
170
+ it ( 'matchesRewrite matches array of rewrites' , ( ) => {
171
+ expect ( matchesRewrite ( 'en/old/page.html' , REWRITES ) ) . toBeTruthy ( )
172
+ } )
173
+
174
+ it ( 'matchesRewrite matches beforeFiles rewrites' , ( ) => {
175
+ expect ( matchesRewrite ( 'en/old/page.html' , { beforeFiles : REWRITES } ) ) . toBeTruthy ( )
176
+ } )
177
+
178
+ it ( "matchesRewrite doesn't match afterFiles rewrites" , ( ) => {
179
+ expect ( matchesRewrite ( 'en/old/page.html' , { afterFiles : REWRITES } ) ) . toBeFalsy ( )
180
+ } )
181
+
182
+ it ( 'matchesRewrite matches various paths' , ( ) => {
183
+ const paths = [ 'en/old/page.html' , 'fr/old/page.html' , 'en/old/deep/page.html' , 'en/old.html' ]
184
+ paths . forEach ( ( path ) => {
185
+ expect ( matchesRewrite ( path , REWRITES ) ) . toBeTruthy ( )
186
+ } )
187
+ } )
188
+
189
+ test ( 'patches Next server files' , async ( ) => {
190
+ const root = path . resolve ( dirname ( __dirname ) )
191
+ await copy ( join ( root , 'package.json' ) , path . join ( process . cwd ( ) , 'package.json' ) )
192
+ await ensureDir ( path . join ( process . cwd ( ) , 'node_modules' ) )
193
+ await copy ( path . join ( root , 'node_modules' , 'next' ) , path . join ( process . cwd ( ) , 'node_modules' , 'next' ) )
194
+
195
+ await patchNextFiles ( process . cwd ( ) )
196
+ const serverFile = path . resolve ( process . cwd ( ) , 'node_modules' , 'next' , 'dist' , 'server' , 'base-server.js' )
197
+ const patchedData = await readFileSync ( serverFile , 'utf8' )
198
+ expect ( patchedData . includes ( '_REVALIDATE_SSG' ) ) . toBeTruthy ( )
199
+ expect ( patchedData . includes ( 'private: isPreviewMode && cachedData' ) ) . toBeTruthy ( )
200
+
201
+ await unpatchNextFiles ( process . cwd ( ) )
202
+
203
+ const unPatchedData = await readFileSync ( serverFile , 'utf8' )
204
+ expect ( unPatchedData . includes ( '_REVALIDATE_SSG' ) ) . toBeFalsy ( )
205
+ expect ( unPatchedData . includes ( 'private: isPreviewMode && cachedData' ) ) . toBeFalsy ( )
206
+ } )
207
+ } )
0 commit comments