Skip to content

Commit

Permalink
test: migrate dev error tests into separate sandbox test (#66666)
Browse files Browse the repository at this point in the history
### What

Keep `test/e2e/app-dir/metadata-dynamic-routes/index.test.ts` with
successful build cases, move the dev error tests into separate test

### Why

x-ref:
https://github.com/vercel/next.js/actions/runs/9429301722/job/25975574075?pr=66286

Before the moving the tests, the error is flaky with turbopack since the
error will fail the hmr. Error observed with turbopack when seeing build
failed cases. So I moved the tests into the separate dev tests, running
inside sandboxes. Then each error test doesn't effect each other.

```
 ⨯ ./app/metadata-base/unset/icon--metadata.js:1:1
  Module not found: Can't resolve './icon.tsx'
  > 1 | import { generateImageMetadata } from "./icon.tsx"
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    2 | import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route'
    3 |
    4 | const imageModule = { generateImageMetadata }

```
  • Loading branch information
huozhi authored Jun 10, 2024
1 parent 891a30c commit 6cad923
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 108 deletions.
104 changes: 104 additions & 0 deletions test/development/acceptance-app/dynamic-metadata-error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* eslint-env jest */
import path from 'path'
import { sandbox } from 'development-sandbox'
import { FileRef, nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'

describe('dynamic metadata error', () => {
const { next } = nextTestSetup({
files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')),
skipStart: true,
})

it('should error when id is missing in generateImageMetadata', async () => {
const iconFilePath = 'app/metadata-base/unset/icon.tsx'
const contentMissingIdProperty = `
import { ImageResponse } from 'next/og'
export async function generateImageMetadata() {
return [
{
contentType: 'image/png',
size: { width: 48, height: 48 },
// id: 100,
},
{
contentType: 'image/png',
size: { width: 48, height: 48 },
id: 101,
},
]
}
export default function icon() {
return new ImageResponse(<div>icon</div>)
}
`
const { cleanup } = await sandbox(
next,
new Map([[iconFilePath, contentMissingIdProperty]]),
'/metadata-base/unset/icon/100'
)

await retry(async () => {
expect(next.cliOutput).toContain(
`id property is required for every item returned from generateImageMetadata`
)
})

await cleanup()
})

it('should error when id is missing in generateSitemaps', async () => {
const sitemapFilePath = 'app/metadata-base/unset/sitemap.tsx'
const contentMissingIdProperty = `
import { MetadataRoute } from 'next'
export async function generateSitemaps() {
return [
{ },
]
}
export default function sitemap({ id }): MetadataRoute.Sitemap {
return [
{
url: 'https://example.com/',
lastModified: '2021-01-01',
},
]
}`

const { cleanup } = await sandbox(
next,
new Map([[sitemapFilePath, contentMissingIdProperty]]),
'/metadata-base/unset/sitemap/100'
)

await retry(async () => {
expect(next.cliOutput).toContain(
`id property is required for every item returned from generateSitemaps`
)
})

await cleanup()
})

it('should error if the default export of dynamic image is missing', async () => {
const ogImageFilePath = 'app/opengraph-image.tsx'
const ogImageFileContentWithoutDefaultExport = `
// Missing default export
export function foo() {}
`

const { cleanup } = await sandbox(
next,
new Map([[ogImageFilePath, ogImageFileContentWithoutDefaultExport]]),
'/opengraph-image'
)
await retry(async () => {
expect(next.cliOutput).toContain(`Default export is missing in`)
})

await cleanup()
})
})
108 changes: 0 additions & 108 deletions test/e2e/app-dir/metadata-dynamic-routes/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,114 +438,6 @@ describe('app dir - metadata dynamic routes', () => {
expect(twitterImage).toMatch(/\/metadata-base\/unset\/twitter-image\.png/)
})

if (isNextDev) {
it('should error when id is missing in generateImageMetadata', async () => {
const iconFilePath = 'app/metadata-base/unset/icon.tsx'
const contentMissingIdProperty = `
import { ImageResponse } from 'next/og'
export async function generateImageMetadata() {
return [
{
contentType: 'image/png',
size: { width: 48, height: 48 },
// id: 100,
},
{
contentType: 'image/png',
size: { width: 48, height: 48 },
id: 101,
},
]
}
export default function icon() {
return new ImageResponse(<div>icon</div>)
}
`

const originalOutputIndex = next.cliOutput.length

await next.patchFile(iconFilePath, contentMissingIdProperty)
await next.fetch('/metadata-base/unset/icon/100')

try {
await check(async () => {
expect(next.cliOutput.substring(originalOutputIndex)).toContain(
`id property is required for every item returned from generateImageMetadata`
)
return 'success'
}, /success/)
} finally {
await next.deleteFile(iconFilePath)
await next.fetch('/metadata-base/unset/icon/100')
}
})

it('should error when id is missing in generateSitemaps', async () => {
const sitemapFilePath = 'app/metadata-base/unset/sitemap.tsx'
const contentMissingIdProperty = `
import { MetadataRoute } from 'next'
export async function generateSitemaps() {
return [
{ },
]
}
export default function sitemap({ id }): MetadataRoute.Sitemap {
return [
{
url: 'https://example.com/',
lastModified: '2021-01-01',
},
]
}`

const originalOutputIndex = next.cliOutput.length

await next.patchFile(sitemapFilePath, contentMissingIdProperty)
await next.fetch('/metadata-base/unset/sitemap/0')

try {
await check(async () => {
expect(next.cliOutput.substring(originalOutputIndex)).toContain(
`id property is required for every item returned from generateSitemaps`
)
return 'success'
}, /success/)
} finally {
await next.deleteFile(sitemapFilePath)
await next.fetch('/metadata-base/unset/sitemap/0')
}
})

it('should error if the default export of dynamic image is missing', async () => {
const ogImageFilePath = 'app/opengraph-image.tsx'
const ogImageFileContent = await next.readFile(ogImageFilePath)
const ogImageFileContentWithoutDefaultExport = ogImageFileContent.replace(
'export default function',
'export function'
)

try {
await next.patchFile(
ogImageFilePath,
ogImageFileContentWithoutDefaultExport
)
const currentNextCliOutputLength = next.cliOutput.length

await check(async () => {
await next.fetch('/opengraph-image')
const output = next.cliOutput.slice(currentNextCliOutputLength)
expect(output).toContain(`Default export is missing in`)
return 'success'
}, /success/)
} finally {
await next.patchFile(ogImageFilePath, ogImageFileContent)
}
})
}

if (isNextStart) {
it('should support edge runtime of image routes', async () => {
const middlewareManifest = JSON.parse(
Expand Down

0 comments on commit 6cad923

Please sign in to comment.