2022-12-12 03:46:29 +01:00
/* eslint-env jest */
2023-06-21 21:47:21 +02:00
import { sandbox } from 'development-sandbox'
import { FileRef , nextTestSetup } from 'e2e-utils'
2022-12-12 03:46:29 +01:00
import path from 'path'
2022-12-12 04:43:08 +01:00
import { check } from 'next-test-utils'
2023-06-21 21:47:21 +02:00
import { outdent } from 'outdent'
2022-12-12 03:46:29 +01:00
2023-06-21 21:47:21 +02:00
describe ( 'Error Overlay for server components' , ( ) = > {
const { next } = nextTestSetup ( {
2023-01-04 12:01:50 +01:00
files : new FileRef ( path . join ( __dirname , 'fixtures' , 'default-template' ) ) ,
dependencies : {
react : 'latest' ,
'react-dom' : 'latest' ,
} ,
skipStart : true ,
2023-06-21 21:47:21 +02:00
} )
describe ( 'createContext called in Server Component' , ( ) = > {
it ( 'should show error when React.createContext is called' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import React from 'react'
const Context = React . createContext ( )
export default function Page() {
return (
< >
< Context.Provider value = "hello" >
< h1 > Page < / h1 >
< / Context.Provider >
< / >
)
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-10 14:47:20 +01:00
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
2023-01-04 12:01:50 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
2022-12-12 03:46:29 +01:00
2023-06-21 21:47:21 +02:00
expect ( next . cliOutput ) . toContain (
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
)
2022-12-12 03:46:29 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
} )
2022-12-12 03:46:29 +01:00
2023-06-21 21:47:21 +02:00
it ( 'should show error when React.createContext is called in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const React = require ( 'react' )
module . exports = React . createContext ( )
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Context from 'my-package'
export default function Page() {
return (
< >
< Context.Provider value = "hello" >
< h1 > Page < / h1 >
< / Context.Provider >
< / >
)
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-10 14:47:20 +01:00
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
2023-01-04 12:01:50 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
)
2023-01-10 14:47:20 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
2023-01-04 12:01:50 +01:00
} )
2023-06-21 21:47:21 +02:00
it ( 'should show error when createContext is called in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const { createContext } = require ( 'react' )
module . exports = createContext ( )
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Context from 'my-package'
export default function Page() {
return (
< >
< Context.Provider value = "hello" >
< h1 > Page < / h1 >
< / Context.Provider >
< / >
)
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
2023-01-04 12:01:50 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
'createContext only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/context-in-server-component'
)
2023-01-04 12:01:50 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
} )
} )
describe ( 'React component hooks called in Server Component' , ( ) = > {
it ( 'should show error when React.<client-hook> is called' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import React from 'react'
export default function Page() {
const ref = React . useRef ( )
return "Hello world"
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-10 14:47:20 +01:00
'useRef only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
2023-01-04 12:01:50 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
2023-01-04 12:01:50 +01:00
2023-06-21 21:47:21 +02:00
expect ( next . cliOutput ) . toContain (
'useRef only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
)
2023-01-04 12:01:50 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
} )
2023-01-04 12:01:50 +01:00
2023-08-03 09:21:00 +02:00
it ( 'should show error when React.experiment_useOptimistic is called' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import React from 'react'
export default function Page() {
const optimistic = React . experimental_useOptimistic ( )
return "Hello world"
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
'experimental_useOptimistic only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
)
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
'experimental_useOptimistic only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
)
await cleanup ( )
} )
it ( 'should show error when React.experiment_useOptimistic is renamed in destructuring' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import { experimental_useOptimistic as useOptimistic } from 'react'
export default function Page() {
const optimistic = useOptimistic ( )
return "Hello world"
}
` ,
] ,
] )
)
await check ( async ( ) = > {
2023-09-16 18:53:51 +02:00
const html = await browser . eval ( 'document.documentElement.innerHTML' )
expect ( html ) . toContain ( 'experimental_useOptimistic' )
2023-08-03 09:21:00 +02:00
return 'success'
} , 'success' )
2023-09-16 18:53:51 +02:00
expect ( next . cliOutput ) . toContain ( 'experimental_useOptimistic' )
2023-08-03 09:21:00 +02:00
await cleanup ( )
} )
2023-06-21 21:47:21 +02:00
it ( 'should show error when React.<client-hook> is called in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const React = require ( 'react' )
module . exports = function Component() {
const [ state , useState ] = React . useState ( )
return "Hello world"
}
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Component from 'my-package'
export default function Page() {
return < Component / >
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
'useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
2023-01-04 12:01:50 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
2023-01-04 12:01:50 +01:00
2023-06-21 21:47:21 +02:00
expect ( next . cliOutput ) . toContain (
'useState only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
)
2023-01-10 14:47:20 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
2023-01-10 14:47:20 +01:00
} )
2023-06-21 21:47:21 +02:00
it ( 'should show error when React client hook is called in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const { useEffect } = require ( 'react' )
module . exports = function Component() {
useEffect ( ( ) = > { } , [ ] )
return "Hello world"
}
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Component from 'my-package'
export default function Page() {
return < Component / >
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
'useEffect only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
2023-01-10 14:47:20 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
2023-01-10 14:47:20 +01:00
2023-06-21 21:47:21 +02:00
expect ( next . cliOutput ) . toContain (
'useEffect only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component'
)
2023-01-10 14:47:20 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
} )
} )
describe ( 'Class component used in Server Component' , ( ) = > {
it ( 'should show error when Class Component is used' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import React from 'react'
export default class Page extends React . Component {
render() {
return < p > Hello world < / p >
}
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-12 17:15:28 +01:00
'This might be caused by a React Class Component being rendered in a Server Component'
2023-01-10 14:47:20 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
2023-01-10 14:47:20 +01:00
2023-06-21 21:47:21 +02:00
expect ( next . cliOutput ) . toContain (
'This might be caused by a React Class Component being rendered in a Server Component'
)
await cleanup ( )
} )
2023-01-04 12:01:50 +01:00
2023-06-21 21:47:21 +02:00
it ( 'should show error when React.PureComponent is rendered in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const React = require ( 'react' )
module . exports = class extends React . PureComponent {
render() {
return "Hello world"
}
}
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Component from 'my-package'
export default function Page() {
return < Component / >
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-12 17:15:28 +01:00
'This might be caused by a React Class Component being rendered in a Server Component'
2022-12-12 04:43:08 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
'This might be caused by a React Class Component being rendered in a Server Component'
)
2022-12-12 04:43:08 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
2022-12-12 03:46:29 +01:00
} )
2023-01-06 03:21:56 +01:00
2023-06-21 21:47:21 +02:00
it ( 'should show error when Component is rendered in external package' , async ( ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'node_modules/my-package/index.js' ,
outdent `
const { Component } = require ( 'react' )
module . exports = class extends Component {
render() {
return "Hello world"
}
}
` ,
] ,
[
'node_modules/my-package/package.json' ,
outdent `
{
"name" : "my-package" ,
"version" : "0.0.1"
}
` ,
] ,
[
'app/page.js' ,
outdent `
import Component from 'my-package'
export default function Page() {
return < Component / >
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
'This might be caused by a React Class Component being rendered in a Server Component'
2023-01-06 03:21:56 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
'This might be caused by a React Class Component being rendered in a Server Component'
)
2023-01-06 03:21:56 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
} )
} )
describe ( 'Next.js component hooks called in Server Component' , ( ) = > {
it . each ( [
// TODO-APP: add test for useParams
// ["useParams"],
[ 'useRouter' ] ,
[ 'useSearchParams' ] ,
[ 'useSelectedLayoutSegment' ] ,
[ 'useSelectedLayoutSegments' ] ,
[ 'usePathname' ] ,
] ) ( 'should show error when %s is called' , async ( hook : string ) = > {
const { browser , cleanup } = await sandbox (
next ,
new Map ( [
[
'app/page.js' ,
outdent `
import { $ { hook } } from 'next/navigation'
export default function Page() {
$ { hook } ( )
return "Hello world"
}
` ,
] ,
] )
)
await check ( async ( ) = > {
expect (
await browser
. waitForElementByCss ( '#nextjs__container_errors_desc' )
. text ( )
) . toContain (
2023-01-10 14:47:20 +01:00
` Error: ${ hook } only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component `
2023-01-06 03:21:56 +01:00
)
2023-06-21 21:47:21 +02:00
return 'success'
} , 'success' )
expect ( next . cliOutput ) . toContain (
` Error: ${ hook } only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: https://nextjs.org/docs/messages/react-client-hook-in-server-component `
)
2023-01-06 03:21:56 +01:00
2023-06-21 21:47:21 +02:00
await cleanup ( )
2023-01-06 03:21:56 +01:00
} )
2023-06-21 21:47:21 +02:00
} )
} )