1
+ /* eslint-disable max-lines-per-function */
1
2
import { mockRequest } from 'next/dist/server/lib/mock-request'
3
+ import { Options } from 'next/dist/server/next-server'
2
4
3
5
import { getNextServer , NextServerType , netlifyApiFetch } from './handlerUtils'
4
- import { NetlifyNextServer } from './server'
6
+ import { NetlifyNextServer , NetlifyConfig } from './server'
5
7
6
8
jest . mock ( './handlerUtils' , ( ) => {
7
9
const originalModule = jest . requireActual ( './handlerUtils' )
@@ -14,15 +16,35 @@ jest.mock('./handlerUtils', () => {
14
16
} )
15
17
const mockedApiFetch = netlifyApiFetch as jest . MockedFunction < typeof netlifyApiFetch >
16
18
19
+ const mocki18nConfig = {
20
+ i18n : {
21
+ defaultLocale : 'en' ,
22
+ locales : [ 'en' , 'fr' , 'de' ] ,
23
+ } ,
24
+ }
25
+
26
+ const mockTokenConfig = {
27
+ revalidateToken : 'test' ,
28
+ }
29
+
30
+ const mockBuildId = 'build-id'
31
+
17
32
jest . mock (
18
33
'prerender-manifest.json' ,
19
34
( ) => ( {
20
35
routes : {
21
- '/en/getStaticProps/with-revalidate' : {
22
- dataRoute : '/_next/data/en/getStaticProps/with-revalidate.json' ,
36
+ '/non-i18n/with-revalidate' : {
37
+ dataRoute : `/_next/data/${ mockBuildId } /non-i18n/with-revalidate.json` ,
38
+ } ,
39
+ '/en/i18n/with-revalidate' : {
40
+ dataRoute : `/_next/data/${ mockBuildId } /i18n/with-revalidate.json` ,
23
41
} ,
24
42
} ,
25
43
dynamicRoutes : {
44
+ '/posts/[title]' : {
45
+ routeRegex : '^/posts/([^/]+?)(?:/)?$' ,
46
+ dataRoute : `/_next/data/${ mockBuildId } /posts/[title].json` ,
47
+ } ,
26
48
'/blog/[author]/[slug]' : {
27
49
routeRegex : '^/blog/([^/]+?)/([^/]+?)(?:/)?$' ,
28
50
dataRoute : '/blog/[author]/[slug].rsc' ,
@@ -36,41 +58,52 @@ beforeAll(() => {
36
58
const NextServer : NextServerType = getNextServer ( )
37
59
jest . spyOn ( NextServer . prototype , 'getRequestHandler' ) . mockImplementation ( ( ) => ( ) => Promise . resolve ( ) )
38
60
39
- const MockNetlifyNextServerConstructor = function ( ) {
61
+ const MockNetlifyNextServerConstructor = function ( nextOptions : Options , netlifyConfig : NetlifyConfig ) {
40
62
this . distDir = '.'
41
- this . buildId = 'build-id'
42
- this . nextConfig = {
43
- i18n : {
44
- defaultLocale : 'en' ,
45
- locales : [ 'en' , 'fr' , 'de' ] ,
46
- } ,
47
- }
63
+ this . buildId = mockBuildId
64
+ this . nextConfig = nextOptions . conf
65
+ this . netlifyConfig = netlifyConfig
48
66
}
49
67
Object . setPrototypeOf ( NetlifyNextServer , MockNetlifyNextServerConstructor )
50
68
} )
51
69
52
70
describe ( 'the netlify next server' , ( ) => {
53
- it ( 'revalidates a request containing an `x-prerender-revalidate` header' , async ( ) => {
54
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
71
+ it ( 'does not revalidate a request without an `x-prerender-revalidate` header' , async ( ) => {
72
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { ...mockTokenConfig } )
73
+ const requestHandler = netlifyNextServer . getRequestHandler ( )
74
+
75
+ const { req : mockReq , res : mockRes } = mockRequest ( '/getStaticProps/with-revalidate/' , { } , 'GET' )
76
+ await requestHandler ( mockReq , mockRes )
77
+
78
+ expect ( mockedApiFetch ) . not . toHaveBeenCalled ( )
79
+ } )
80
+
81
+ it ( 'revalidates a static non-i18n route with an `x-prerender-revalidate` header' , async ( ) => {
82
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { ...mockTokenConfig } )
55
83
const requestHandler = netlifyNextServer . getRequestHandler ( )
56
84
57
85
const { req : mockReq , res : mockRes } = mockRequest (
58
- '/getStaticProps /with-revalidate/' ,
86
+ '/non-i18n /with-revalidate/' ,
59
87
{ 'x-prerender-revalidate' : 'test' } ,
60
88
'GET' ,
61
89
)
62
- const response = await requestHandler ( mockReq , mockRes )
90
+ await requestHandler ( mockReq , mockRes )
63
91
64
- expect ( mockedApiFetch ) . toHaveBeenCalled ( )
65
- expect ( response ) . toBe ( undefined )
92
+ expect ( mockedApiFetch ) . toHaveBeenCalledWith (
93
+ expect . objectContaining ( {
94
+ payload : expect . objectContaining ( {
95
+ paths : [ '/non-i18n/with-revalidate/' , `/_next/data/${ mockBuildId } /non-i18n/with-revalidate.json` ] ,
96
+ } ) ,
97
+ } ) ,
98
+ )
66
99
} )
67
100
68
- it ( 'matches a normalized static route to find the data route ' , async ( ) => {
69
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
101
+ it ( 'revalidates a static i18n route with an `x-prerender-revalidate` header ' , async ( ) => {
102
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { ... mocki18nConfig } } , { ... mockTokenConfig } )
70
103
const requestHandler = netlifyNextServer . getRequestHandler ( )
71
104
72
105
const { req : mockReq , res : mockRes } = mockRequest (
73
- '/getStaticProps /with-revalidate/' ,
106
+ '/i18n /with-revalidate/' ,
74
107
{ 'x-prerender-revalidate' : 'test' } ,
75
108
'GET' ,
76
109
)
@@ -79,14 +112,14 @@ describe('the netlify next server', () => {
79
112
expect ( mockedApiFetch ) . toHaveBeenCalledWith (
80
113
expect . objectContaining ( {
81
114
payload : expect . objectContaining ( {
82
- paths : [ '/getStaticProps /with-revalidate/' , ' /_next/data/build-id /en/getStaticProps /with-revalidate.json' ] ,
115
+ paths : [ '/i18n /with-revalidate/' , ` /_next/data/${ mockBuildId } /en/i18n /with-revalidate.json` ] ,
83
116
} ) ,
84
117
} ) ,
85
118
)
86
119
} )
87
120
88
- it ( 'matches a normalized dynamic route to find the data ' , async ( ) => {
89
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
121
+ it ( 'revalidates a dynamic non-i18n route with an `x-prerender-revalidate` header ' , async ( ) => {
122
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { ... mockTokenConfig } )
90
123
const requestHandler = netlifyNextServer . getRequestHandler ( )
91
124
92
125
const { req : mockReq , res : mockRes } = mockRequest ( '/blog/rob/hello' , { 'x-prerender-revalidate' : 'test' } , 'GET' )
@@ -101,8 +134,24 @@ describe('the netlify next server', () => {
101
134
)
102
135
} )
103
136
137
+ it ( 'revalidates a dynamic i18n route with an `x-prerender-revalidate` header' , async ( ) => {
138
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { ...mocki18nConfig } } , { ...mockTokenConfig } )
139
+ const requestHandler = netlifyNextServer . getRequestHandler ( )
140
+
141
+ const { req : mockReq , res : mockRes } = mockRequest ( '/fr/posts/hello' , { 'x-prerender-revalidate' : 'test' } , 'GET' )
142
+ await requestHandler ( mockReq , mockRes )
143
+
144
+ expect ( mockedApiFetch ) . toHaveBeenCalledWith (
145
+ expect . objectContaining ( {
146
+ payload : expect . objectContaining ( {
147
+ paths : [ '/fr/posts/hello' , `/_next/data/${ mockBuildId } /fr/posts/hello.json` ] ,
148
+ } ) ,
149
+ } ) ,
150
+ )
151
+ } )
152
+
104
153
it ( 'throws an error when route is not found in the manifest' , async ( ) => {
105
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
154
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , mockTokenConfig )
106
155
const requestHandler = netlifyNextServer . getRequestHandler ( )
107
156
108
157
const { req : mockReq , res : mockRes } = mockRequest (
@@ -111,34 +160,27 @@ describe('the netlify next server', () => {
111
160
'GET' ,
112
161
)
113
162
114
- await expect ( requestHandler ( mockReq , mockRes ) ) . rejects . toThrow ( 'could not find a route' )
163
+ await expect ( requestHandler ( mockReq , mockRes ) ) . rejects . toThrow ( 'not an ISR route' )
115
164
} )
116
165
117
166
it ( 'throws an error when paths are not found by the API' , async ( ) => {
118
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
167
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , mockTokenConfig )
119
168
const requestHandler = netlifyNextServer . getRequestHandler ( )
120
169
121
- const { req : mockReq , res : mockRes } = mockRequest (
122
- '/getStaticProps/with-revalidate/' ,
123
- { 'x-prerender-revalidate' : 'test' } ,
124
- 'GET' ,
125
- )
170
+ const { req : mockReq , res : mockRes } = mockRequest ( '/posts/hello/' , { 'x-prerender-revalidate' : 'test' } , 'GET' )
126
171
127
172
mockedApiFetch . mockResolvedValueOnce ( { code : 500 , message : 'Failed to revalidate' } )
128
173
await expect ( requestHandler ( mockReq , mockRes ) ) . rejects . toThrow ( 'Failed to revalidate' )
129
174
} )
130
175
131
176
it ( 'throws an error when the revalidate API is unreachable' , async ( ) => {
132
- const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , { } )
177
+ const netlifyNextServer = new NetlifyNextServer ( { conf : { } } , mockTokenConfig )
133
178
const requestHandler = netlifyNextServer . getRequestHandler ( )
134
179
135
- const { req : mockReq , res : mockRes } = mockRequest (
136
- '/getStaticProps/with-revalidate/' ,
137
- { 'x-prerender-revalidate' : 'test' } ,
138
- 'GET' ,
139
- )
180
+ const { req : mockReq , res : mockRes } = mockRequest ( '/posts/hello' , { 'x-prerender-revalidate' : 'test' } , 'GET' )
140
181
141
182
mockedApiFetch . mockRejectedValueOnce ( new Error ( 'Unable to connect' ) )
142
183
await expect ( requestHandler ( mockReq , mockRes ) ) . rejects . toThrow ( 'Unable to connect' )
143
184
} )
144
185
} )
186
+ /* eslint-enable max-lines-per-function */
0 commit comments