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:
parent
46441387be
commit
b9d542183e
6 changed files with 85 additions and 55 deletions
|
@ -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",
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
18
test/e2e/app-dir/actions/app/interception-routes/form.js
Normal file
18
test/e2e/app-dir/actions/app/interception-routes/form.js
Normal 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>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in a new issue