fix app-action deploy tests (#66846)

- Fixed redirects tests not working when deployed because they were
`POST` requests to a static page
- Skipped 404 test for a similar reason: a `POST` to the static not
found page is handled differently, and we won't have access to the
runtime logs anyway
- Refactored interception routes test to not rely on runtime logs
- Fixed revalidation test & removed comment about flakiness

<details>
<summary>Validated Run Summary</summary>

![CleanShot 2024-06-13 at 13 45
32@2x](https://github.com/vercel/next.js/assets/1939140/8b85cb60-b389-451c-b449-41067f86a8d3)

</details>
This commit is contained in:
Zack Tanner 2024-06-13 14:20:43 -07:00 committed by GitHub
parent 46441387be
commit b9d542183e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 85 additions and 55 deletions

View file

@ -49,7 +49,6 @@
"test/e2e/new-link-behavior/stitches.test.ts",
"test/e2e/next-image-forward-ref/index.test.ts",
"test/e2e/react-compiler/react-compiler.test.ts",
"test/e2e/app-dir/actions/app-action.test.ts",
"test/e2e/app-dir/i18n-hybrid/i18n-hybrid.test.js",
"test/e2e/app-dir/metadata/metadata.test.ts",
"test/e2e/app-dir/rsc-basic/rsc-basic.test.ts",

View file

@ -483,40 +483,48 @@ describe('app-dir action handling', () => {
await check(() => browser.elementByCss('h1').text(), 'Transition is: idle')
})
it('should 404 when POSTing an invalid server action', async () => {
const cliOutputPosition = next.cliOutput.length
const res = await next.fetch('/non-existent-route', {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: 'foo=bar',
// This is disabled when deployed because the 404 page will be served as a static route
// which will not support POST requests, and will return a 405 instead.
if (!isNextDeploy) {
it('should 404 when POSTing an invalid server action', async () => {
const cliOutputPosition = next.cliOutput.length
const res = await next.fetch('/non-existent-route', {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: 'foo=bar',
})
const cliOutput = next.cliOutput.slice(cliOutputPosition)
expect(cliOutput).not.toContain('TypeError')
expect(cliOutput).not.toContain(
'Missing `origin` header from a forwarded Server Actions request'
)
expect(res.status).toBe(404)
})
}
const cliOutput = next.cliOutput.slice(cliOutputPosition)
// This is disabled when deployed because it relies on checking runtime logs,
// and only build time logs will be available.
if (!isNextDeploy) {
it('should log a warning when a server action is not found but an id is provided', async () => {
await next.fetch('/server', {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'next-action': 'abc123',
},
body: 'foo=bar',
})
expect(cliOutput).not.toContain('TypeError')
expect(cliOutput).not.toContain(
'Missing `origin` header from a forwarded Server Actions request'
)
expect(res.status).toBe(404)
})
it('should log a warning when a server action is not found but an id is provided', async () => {
await next.fetch('/server', {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
'next-action': 'abc123',
},
body: 'foo=bar',
await check(
() => next.cliOutput,
/Failed to find Server Action "abc123". This request might be from an older or newer deployment./
)
})
await check(
() => next.cliOutput,
/Failed to find Server Action "abc123". This request might be from an older or newer deployment./
)
})
}
it('should be possible to catch network errors', async () => {
const browser = await next.browser('/catching-error', {
@ -979,14 +987,10 @@ describe('app-dir action handling', () => {
const justPutIt = await browser.elementByCss('#justputit').text()
await browser.elementByCss('#revalidate-justputit').click()
// TODO: investigate flakiness when deployed
if (!isNextDeploy) {
await check(async () => {
const newJustPutIt = await browser.elementByCss('#justputit').text()
expect(newJustPutIt).not.toBe(justPutIt)
return 'success'
}, 'success')
}
await retry(async () => {
const newJustPutIt = await browser.elementByCss('#justputit').text()
expect(newJustPutIt).not.toBe(justPutIt)
})
const newJustPutIt = await browser.elementByCss('#justputit').text()
@ -1179,9 +1183,11 @@ describe('app-dir action handling', () => {
// Submit the action
await browser.elementById('submit-intercept-action').click()
let responseElement = await browser.waitForElementByCss(
'#submit-intercept-action-response'
)
// Action log should be in server console
await check(() => next.cliOutput, /Action Submitted \(Intercepted\)/)
expect(await responseElement.text()).toBe('Action Submitted (Intercepted)')
await browser.refresh()
@ -1194,8 +1200,11 @@ describe('app-dir action handling', () => {
// Submit the action
await browser.elementById('submit-page-action').click()
// Action log should be in server console
await check(() => next.cliOutput, /Action Submitted \(Page\)/)
responseElement = await browser.waitForElementByCss(
'#submit-page-action-response'
)
expect(await responseElement.text()).toBe('Action Submitted (Page)')
})
describe('encryption', () => {

View file

@ -1,16 +1,16 @@
import { Form } from '../../../form'
export default function TestPageIntercepted() {
async function action(data) {
'use server'
console.log('Action Submitted (Intercepted)')
return 'Action Submitted (Intercepted)'
}
return (
<form action={action}>
<div id="modal-data">
in "modal"
<button type="submit" id="submit-intercept-action">
Test
</button>
</form>
<Form action={action} id="submit-intercept-action" />
</div>
)
}

View file

@ -0,0 +1,18 @@
'use client'
import { useFormState } from 'react-dom'
export function Form({ id, action }) {
const [state, formAction] = useFormState(action, '')
return (
<>
{state && <div id={`${id}-response`}>{state}</div>}
<form action={formAction}>
<button type="submit" id={id}>
Test
</button>
</form>
</>
)
}

View file

@ -1,16 +1,16 @@
import { Form } from '../form'
export default function TestPage() {
async function action(data) {
'use server'
console.log('Action Submitted (Page)')
return 'Action Submitted (Page)'
}
return (
<form action={action} id="children-data">
<div id="children-data">
in "page"
<button type="submit" id="submit-page-action">
Test
</button>
</form>
<Form action={action} id="submit-page-action" />
</div>
)
}

View file

@ -1,3 +1,7 @@
// This page is forced into dynamic rendering because POST requests to
// a static/ISR page will cause an error when deployed.
export const dynamic = 'force-dynamic'
export default function Home() {
return (
<main id="redirect-page">