import { nextTestSetup } from 'e2e-utils' import { createMultiDomMatcher, createMultiHtmlMatcher, getTitle, retry, } from 'next-test-utils' describe('app dir - metadata navigation', () => { const { next } = nextTestSetup({ files: __dirname, }) describe('navigation', () => { it('should render root not-found with default metadata', async () => { const $ = await next.render$('/does-not-exist') // Should contain default metadata and noindex tag const matchHtml = createMultiHtmlMatcher($) expect($('meta[charset="utf-8"]').length).toBe(1) matchHtml('meta', 'name', 'content', { viewport: 'width=device-width, initial-scale=1', robots: 'noindex', // not found metadata description: 'Root not found description', }) expect(await $('title').text()).toBe('Root not found') }) it('should support notFound in generateMetadata', async () => { const res = await next.fetch('/async/not-found') // metadata is suspended in SSR, it won't affect the response status expect(res.status).toBe(200) const $ = await next.render$('/async/not-found') // TODO-APP: support render custom not-found in SSR for generateMetadata. // Check contains root not-found payload in flight response for now. const flightDataPrefix = 'self.__next_f.push([1,"' const flightDataSuffix = '"])' let flightText = '' for (const el of $('script').toArray()) { const text = $(el).text() if (text.startsWith(flightDataPrefix)) { flightText += text.slice( flightDataPrefix.length, -flightDataSuffix.length ) } } expect(flightText).toContain('Local found boundary') // Should contain default metadata and noindex tag const matchHtml = createMultiHtmlMatcher($) expect($('meta[charset="utf-8"]').length).toBe(1) matchHtml('meta', 'name', 'content', { viewport: 'width=device-width, initial-scale=1', robots: 'noindex', }) const browser = await next.browser('/async/not-found') expect(await browser.elementByCss('h2').text()).toBe( 'Local found boundary' ) const matchMultiDom = createMultiDomMatcher(browser) await matchMultiDom('meta', 'name', 'content', { viewport: 'width=device-width, initial-scale=1', keywords: 'parent', robots: 'noindex', // not found metadata description: 'Local not found description', }) expect(await getTitle(browser)).toBe('Local not found') }) it('should support redirect in generateMetadata', async () => { const res = await next.fetch('/async/redirect', { redirect: 'manual', }) // metadata is suspended in SSR, it won't affect the response status expect(res.status).toBe(200) const browser = await next.browser('/async/redirect') await retry(async () => { expect(await browser.elementByCss('p').text()).toBe( 'redirect dest page' ) }) }) it('should show the index title', async () => { const browser = await next.browser('/parallel-route') expect(await getTitle(browser)).toBe('Home Layout') }) it('should show target page metadata after navigation', async () => { const browser = await next.browser('/parallel-route') await browser.elementByCss('#product-link').click() await browser.waitForElementByCss('#product-title') expect(await getTitle(browser)).toBe('Product Layout') }) it('should show target page metadata after navigation with back', async () => { const browser = await next.browser('/parallel-route') await browser.elementByCss('#product-link').click() await browser.waitForElementByCss('#product-title') await browser.elementByCss('#home-link').click() await browser.waitForElementByCss('#home-title') expect(await getTitle(browser)).toBe('Home Layout') }) }) describe('server action', () => { it('should not render fallback noindex metadata if request is initiated from server action', async () => { const browser = await next.browser('/server-action/not-found') // collect server action requests let isActionSent = false browser.on('request', (req) => { if ( req.method() === 'POST' && req.url().endsWith('/server-action/not-found') ) { isActionSent = true } }) // trigger not-found action and wait until the server action is performed await browser.elementByCss('#trigger-not-found').click() await retry(async () => { expect(isActionSent).toBe(true) }) expect(await browser.elementsByCss('meta[name="robots"]')).toHaveLength(1) expect( await browser .elementByCss('meta[name="robots"]') .getAttribute('content') ).toBe('noindex, nofollow') }) }) })