@@ -8,14 +8,17 @@ import path from 'path'
8
8
const isReact18 = parseInt ( process . env . NEXT_TEST_REACT_VERSION ) === 18
9
9
10
10
describe ( 'Client Navigation rendering <Head />' , ( ) => {
11
- describe . each ( [ [ false ] , [ true ] ] ) (
11
+ describe . each ( [ [ false ] , [ true ] , [ undefined ] ] ) (
12
12
'with strictNextHead=%s' ,
13
13
( strictNextHead ) => {
14
14
const { next } = nextTestSetup ( {
15
15
files : path . join ( __dirname , 'fixture' ) ,
16
- env : {
17
- TEST_STRICT_NEXT_HEAD : String ( strictNextHead ) ,
18
- } ,
16
+ env :
17
+ strictNextHead !== undefined
18
+ ? {
19
+ TEST_STRICT_NEXT_HEAD : String ( strictNextHead ) ,
20
+ }
21
+ : { } ,
19
22
} )
20
23
21
24
function render (
@@ -37,7 +40,7 @@ describe('Client Navigation rendering <Head />', () => {
37
40
test ( 'header renders default charset' , async ( ) => {
38
41
const html = await render ( '/default-head' )
39
42
expect ( html ) . toContain (
40
- strictNextHead
43
+ strictNextHead !== false
41
44
? '<meta charSet="utf-8" data-next-head=""/>'
42
45
: '<meta charSet="utf-8"/>'
43
46
)
@@ -47,7 +50,7 @@ describe('Client Navigation rendering <Head />', () => {
47
50
test ( 'header renders default viewport' , async ( ) => {
48
51
const html = await render ( '/default-head' )
49
52
expect ( html ) . toContain (
50
- strictNextHead
53
+ strictNextHead !== false
51
54
? '<meta name="viewport" content="width=device-width" data-next-head=""/>'
52
55
: '<meta name="viewport" content="width=device-width"/>'
53
56
)
@@ -56,17 +59,17 @@ describe('Client Navigation rendering <Head />', () => {
56
59
test ( 'header helper renders header information' , async ( ) => {
57
60
const html = await render ( '/head' )
58
61
expect ( html ) . toContain (
59
- strictNextHead
62
+ strictNextHead !== false
60
63
? '<meta charSet="iso-8859-5" data-next-head=""/>'
61
64
: '<meta charSet="iso-8859-5"/>'
62
65
)
63
66
expect ( html ) . toContain (
64
- strictNextHead
67
+ strictNextHead !== false
65
68
? '<meta content="my meta" data-next-head=""/>'
66
69
: '<meta content="my meta"/>'
67
70
)
68
71
expect ( html ) . toContain (
69
- strictNextHead
72
+ strictNextHead !== false
70
73
? '<meta name="viewport" content="width=device-width,initial-scale=1" data-next-head=""/>'
71
74
: '<meta name="viewport" content="width=device-width,initial-scale=1"/>'
72
75
)
@@ -76,17 +79,17 @@ describe('Client Navigation rendering <Head />', () => {
76
79
test ( 'header helper dedupes tags' , async ( ) => {
77
80
const html = await render ( '/head' )
78
81
expect ( html ) . toContain (
79
- strictNextHead
82
+ strictNextHead !== false
80
83
? '<meta charSet="iso-8859-5" data-next-head=""/>'
81
84
: '<meta charSet="iso-8859-5"/>'
82
85
)
83
86
expect ( html ) . not . toContain (
84
- strictNextHead
87
+ strictNextHead !== false
85
88
? '<meta charSet="utf-8" data-next-head=""/>'
86
89
: '<meta charSet="utf-8"/>'
87
90
)
88
91
expect ( html ) . toContain (
89
- strictNextHead
92
+ strictNextHead !== false
90
93
? '<meta name="viewport" content="width=device-width,initial-scale=1" data-next-head=""/>'
91
94
: '<meta name="viewport" content="width=device-width,initial-scale=1"/>'
92
95
)
@@ -96,24 +99,25 @@ describe('Client Navigation rendering <Head />', () => {
96
99
'<meta name="viewport" content="width=device-width"'
97
100
)
98
101
expect ( html ) . toContain (
99
- strictNextHead
102
+ strictNextHead !== false
100
103
? '<meta content="my meta" data-next-head=""/>'
101
104
: '<meta content="my meta"/>'
102
105
)
103
106
expect ( html ) . toContain (
104
- strictNextHead
107
+ strictNextHead !== false
105
108
? '<link rel="stylesheet" href="/dup-style.css" data-next-head=""/><link rel="stylesheet" href="/dup-style.css" data-next-head=""/>'
106
109
: '<link rel="stylesheet" href="/dup-style.css"/><link rel="stylesheet" href="/dup-style.css"/>'
107
110
)
108
- const dedupeLink = strictNextHead
109
- ? '<link rel="stylesheet" href="dedupe-style.css" data-next-head=""/>'
110
- : '<link rel="stylesheet" href="dedupe-style.css"/>'
111
+ const dedupeLink =
112
+ strictNextHead !== false
113
+ ? '<link rel="stylesheet" href="dedupe-style.css" data-next-head=""/>'
114
+ : '<link rel="stylesheet" href="dedupe-style.css"/>'
111
115
expect ( html ) . toContain ( dedupeLink )
112
116
expect (
113
117
html . substring ( html . indexOf ( dedupeLink ) + dedupeLink . length )
114
118
) . not . toContain ( '<link rel="stylesheet" href="dedupe-style.css"' )
115
119
expect ( html ) . toContain (
116
- strictNextHead
120
+ strictNextHead !== false
117
121
? '<link rel="alternate" hrefLang="en" href="/last/en" data-next-head=""/>'
118
122
: '<link rel="alternate" hrefLang="en" href="/last/en"/>'
119
123
)
@@ -129,12 +133,12 @@ describe('Client Navigation rendering <Head />', () => {
129
133
// Expect exactly one `viewport`
130
134
expect ( ( html . match ( / n a m e = " v i e w p o r t " / g) || [ ] ) . length ) . toBe ( 1 )
131
135
expect ( html ) . toContain (
132
- strictNextHead
136
+ strictNextHead !== false
133
137
? '<meta charSet="iso-8859-1" data-next-head=""/>'
134
138
: '<meta charSet="iso-8859-1"/>'
135
139
)
136
140
expect ( html ) . toContain (
137
- strictNextHead
141
+ strictNextHead !== false
138
142
? '<meta name="viewport" content="width=500" data-next-head=""/>'
139
143
: '<meta name="viewport" content="width=500"/>'
140
144
)
@@ -144,98 +148,98 @@ describe('Client Navigation rendering <Head />', () => {
144
148
const html = await render ( '/head' )
145
149
console . log ( html )
146
150
expect ( html ) . toContain (
147
- strictNextHead
151
+ strictNextHead !== false
148
152
? '<meta property="article:tag" content="tag1" data-next-head=""/>'
149
153
: '<meta property="article:tag" content="tag1"/>'
150
154
)
151
155
expect ( html ) . toContain (
152
- strictNextHead
156
+ strictNextHead !== false
153
157
? '<meta property="article:tag" content="tag2" data-next-head=""/>'
154
158
: '<meta property="article:tag" content="tag2"/>'
155
159
)
156
160
expect ( html ) . not . toContain ( '<meta property="dedupe:tag" content="tag3"' )
157
161
expect ( html ) . toContain (
158
- strictNextHead
162
+ strictNextHead !== false
159
163
? '<meta property="dedupe:tag" content="tag4" data-next-head=""/>'
160
164
: '<meta property="dedupe:tag" content="tag4"/>'
161
165
)
162
166
expect ( html ) . toContain (
163
- strictNextHead
167
+ strictNextHead !== false
164
168
? '<meta property="og:image" content="ogImageTag1" data-next-head=""/>'
165
169
: '<meta property="og:image" content="ogImageTag1"/>'
166
170
)
167
171
expect ( html ) . toContain (
168
- strictNextHead
172
+ strictNextHead !== false
169
173
? '<meta property="og:image" content="ogImageTag2" data-next-head=""/>'
170
174
: '<meta property="og:image" content="ogImageTag2"/>'
171
175
)
172
176
expect ( html ) . toContain (
173
- strictNextHead
177
+ strictNextHead !== false
174
178
? '<meta property="og:image:alt" content="ogImageAltTag1" data-next-head=""/>'
175
179
: '<meta property="og:image:alt" content="ogImageAltTag1"/>'
176
180
)
177
181
expect ( html ) . toContain (
178
- strictNextHead
182
+ strictNextHead !== false
179
183
? '<meta property="og:image:alt" content="ogImageAltTag2" data-next-head=""/>'
180
184
: '<meta property="og:image:alt" content="ogImageAltTag2"/>'
181
185
)
182
186
expect ( html ) . toContain (
183
- strictNextHead
187
+ strictNextHead !== false
184
188
? '<meta property="og:image:width" content="ogImageWidthTag1" data-next-head=""/>'
185
189
: '<meta property="og:image:width" content="ogImageWidthTag1"/>'
186
190
)
187
191
expect ( html ) . toContain (
188
- strictNextHead
192
+ strictNextHead !== false
189
193
? '<meta property="og:image:width" content="ogImageWidthTag2" data-next-head=""/>'
190
194
: '<meta property="og:image:width" content="ogImageWidthTag2"/>'
191
195
)
192
196
expect ( html ) . toContain (
193
- strictNextHead
197
+ strictNextHead !== false
194
198
? '<meta property="og:image:height" content="ogImageHeightTag1" data-next-head=""/>'
195
199
: '<meta property="og:image:height" content="ogImageHeightTag1"/>'
196
200
)
197
201
expect ( html ) . toContain (
198
- strictNextHead
202
+ strictNextHead !== false
199
203
? '<meta property="og:image:height" content="ogImageHeightTag2" data-next-head=""/>'
200
204
: '<meta property="og:image:height" content="ogImageHeightTag2"/>'
201
205
)
202
206
expect ( html ) . toContain (
203
- strictNextHead
207
+ strictNextHead !== false
204
208
? '<meta property="og:image:type" content="ogImageTypeTag1" data-next-head=""/>'
205
209
: '<meta property="og:image:type" content="ogImageTypeTag1"/>'
206
210
)
207
211
expect ( html ) . toContain (
208
- strictNextHead
212
+ strictNextHead !== false
209
213
? '<meta property="og:image:type" content="ogImageTypeTag2" data-next-head=""/>'
210
214
: '<meta property="og:image:type" content="ogImageTypeTag2"/>'
211
215
)
212
216
expect ( html ) . toContain (
213
- strictNextHead
217
+ strictNextHead !== false
214
218
? '<meta property="og:image:secure_url" content="ogImageSecureUrlTag1" data-next-head=""/>'
215
219
: '<meta property="og:image:secure_url" content="ogImageSecureUrlTag1"/>'
216
220
)
217
221
expect ( html ) . toContain (
218
- strictNextHead
222
+ strictNextHead !== false
219
223
? '<meta property="og:image:secure_url" content="ogImageSecureUrlTag2" data-next-head=""/>'
220
224
: '<meta property="og:image:secure_url" content="ogImageSecureUrlTag2"/>'
221
225
)
222
226
expect ( html ) . toContain (
223
- strictNextHead
227
+ strictNextHead !== false
224
228
? '<meta property="og:image:url" content="ogImageUrlTag1" data-next-head=""/>'
225
229
: '<meta property="og:image:url" content="ogImageUrlTag1"/>'
226
230
)
227
231
expect ( html ) . toContain (
228
- strictNextHead
232
+ strictNextHead !== false
229
233
? '<meta property="og:image:url" content="ogImageUrlTag2" data-next-head=""/>'
230
234
: '<meta property="og:image:url" content="ogImageUrlTag2"/>'
231
235
)
232
236
expect ( html ) . toContain (
233
- strictNextHead
237
+ strictNextHead !== false
234
238
? '<meta property="fb:pages" content="fbpages1" data-next-head=""/>'
235
239
: '<meta property="fb:pages" content="fbpages1"/>'
236
240
)
237
241
expect ( html ) . toContain (
238
- strictNextHead
242
+ strictNextHead !== false
239
243
? '<meta property="fb:pages" content="fbpages2" data-next-head=""/>'
240
244
: '<meta property="fb:pages" content="fbpages2"/>'
241
245
)
@@ -244,12 +248,12 @@ describe('Client Navigation rendering <Head />', () => {
244
248
test ( 'header helper avoids dedupe of meta tags with the same name if they use unique keys' , async ( ) => {
245
249
const html = await render ( '/head' )
246
250
expect ( html ) . toContain (
247
- strictNextHead
251
+ strictNextHead !== false
248
252
? '<meta name="citation_author" content="authorName1" data-next-head=""/>'
249
253
: '<meta name="citation_author" content="authorName1"/>'
250
254
)
251
255
expect ( html ) . toContain (
252
- strictNextHead
256
+ strictNextHead !== false
253
257
? '<meta name="citation_author" content="authorName2" data-next-head=""/>'
254
258
: '<meta name="citation_author" content="authorName2"/>'
255
259
)
@@ -258,12 +262,12 @@ describe('Client Navigation rendering <Head />', () => {
258
262
test ( 'header helper renders Fragment children' , async ( ) => {
259
263
const html = await render ( '/head' )
260
264
expect ( html ) . toContain (
261
- strictNextHead
265
+ strictNextHead !== false
262
266
? '<title data-next-head="">Fragment title</title>'
263
267
: '<title>Fragment title</title>'
264
268
)
265
269
expect ( html ) . toContain (
266
- strictNextHead
270
+ strictNextHead !== false
267
271
? '<meta content="meta fragment" data-next-head=""/>'
268
272
: '<meta content="meta fragment"/>'
269
273
)
@@ -272,27 +276,28 @@ describe('Client Navigation rendering <Head />', () => {
272
276
test ( 'header helper renders boolean attributes correctly children' , async ( ) => {
273
277
const html = await render ( '/head' )
274
278
expect ( html ) . toContain (
275
- strictNextHead
279
+ strictNextHead !== false
276
280
? '<script src="/test-async-false.js" data-next-head="">'
277
281
: '<script src="/test-async-false.js">'
278
282
)
279
283
expect ( html ) . toContain (
280
- strictNextHead
284
+ strictNextHead !== false
281
285
? '<script src="/test-async-true.js" async="" data-next-head="">'
282
286
: ''
283
287
)
284
288
expect ( html ) . toContain (
285
- strictNextHead
289
+ strictNextHead !== false
286
290
? '<script src="/test-defer.js" defer="" data-next-head="">'
287
291
: ''
288
292
)
289
293
} )
290
294
291
295
it ( 'should place charset element at the top of <head>' , async ( ) => {
292
296
const html = await render ( '/head-priority' )
293
- const nextHeadElement = strictNextHead
294
- ? '<meta charSet="iso-8859-5" data-next-head=""/><meta name="viewport" content="width=device-width,initial-scale=1" data-next-head=""/><meta name="title" content="head title" data-next-head=""/>'
295
- : '<meta charSet="iso-8859-5"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="title" content="head title"/><meta name="next-head-count" content="3"/>'
297
+ const nextHeadElement =
298
+ strictNextHead !== false
299
+ ? '<meta charSet="iso-8859-5" data-next-head=""/><meta name="viewport" content="width=device-width,initial-scale=1" data-next-head=""/><meta name="title" content="head title" data-next-head=""/>'
300
+ : '<meta charSet="iso-8859-5"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="title" content="head title"/><meta name="next-head-count" content="3"/>'
296
301
const documentHeadElement =
297
302
'<meta name="keywords" content="document head test"/>'
298
303
@@ -304,6 +309,35 @@ describe('Client Navigation rendering <Head />', () => {
304
309
: `<head>${ nextHeadElement } ${ documentHeadElement } `
305
310
)
306
311
} )
312
+
313
+ test ( 'custom meta properties are rendered only once' , async ( ) => {
314
+ const browser = await next . browser ( '/head-with-custom-metadata' )
315
+
316
+ // Check that title appears only once
317
+ const titleElements = await browser . elementsByCss ( 'title' )
318
+ expect ( titleElements ) . toHaveLength ( 1 )
319
+ const titleText = await browser . elementByCss ( 'title' ) . text ( )
320
+ expect ( titleText ) . toBe ( 'Title Page' )
321
+
322
+ // Check that each meta property appears only once
323
+ const ogTitleElements = await browser . elementsByCss (
324
+ 'meta[property="og:title"]'
325
+ )
326
+ expect ( ogTitleElements ) . toHaveLength ( 1 )
327
+ const ogTitleContent = await browser
328
+ . elementByCss ( 'meta[property="og:title"]' )
329
+ . getAttribute ( 'content' )
330
+ expect ( ogTitleContent ) . toBe ( 'Title Content' )
331
+
332
+ const descriptionElements = await browser . elementsByCss (
333
+ 'meta[name="description"]'
334
+ )
335
+ expect ( descriptionElements ) . toHaveLength ( 1 )
336
+ const descriptionContent = await browser
337
+ . elementByCss ( 'meta[name="description"]' )
338
+ . getAttribute ( 'content' )
339
+ expect ( descriptionContent ) . toBe ( 'Description Content' )
340
+ } )
307
341
}
308
342
)
309
343
} )
0 commit comments