Files
next.js/test/development/pages-dir/client-navigation/head.test.ts
Arian Tron 61f56f997c
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
first commit
2026-03-10 19:37:31 +03:30

178 lines
5.3 KiB
TypeScript

/* eslint-env jest */
import { waitFor } from 'next-test-utils'
import path from 'path'
import { nextTestSetup } from 'e2e-utils'
describe('updating <Head /> while client routing', () => {
const { next } = nextTestSetup({
files: path.join(__dirname, 'fixture'),
})
it.each([true, false])(
'should handle boolean async prop in next/head client-side: %s',
async (bool) => {
const browser = await next.browser('/head')
const value = await browser.eval(
`document.querySelector('script[src="/test-async-${JSON.stringify(
bool
)}.js"]').async`
)
expect(value).toBe(bool)
}
)
it('should only execute async and defer scripts once', async () => {
const browser = await next.browser('/head')
await browser.waitForElementByCss('h1')
await waitFor(2000)
expect(Number(await browser.eval('window.__test_async_executions'))).toBe(1)
expect(Number(await browser.eval('window.__test_defer_executions'))).toBe(1)
await browser.elementByCss('#reverseScriptOrder').click()
await waitFor(2000)
expect(Number(await browser.eval('window.__test_async_executions'))).toBe(1)
expect(Number(await browser.eval('window.__test_defer_executions'))).toBe(1)
await browser.elementByCss('#toggleScript').click()
await waitFor(2000)
expect(Number(await browser.eval('window.__test_async_executions'))).toBe(1)
expect(Number(await browser.eval('window.__test_defer_executions'))).toBe(1)
})
it('should warn when stylesheets or scripts are in head', async () => {
const browser = await next.browser('/head')
await browser.waitForElementByCss('h1')
await waitFor(1000)
const browserLogs = await browser.log()
let foundStyles = false
let foundScripts = false
const logs = []
browserLogs.forEach(({ message }) => {
if (message.includes('Do not add stylesheets using next/head')) {
foundStyles = true
logs.push(message)
}
if (message.includes('Do not add <script> tags using next/head')) {
foundScripts = true
logs.push(message)
}
})
expect(foundStyles).toEqual(true)
expect(foundScripts).toEqual(true)
// Warnings are unique
expect(logs.length).toEqual(new Set(logs).size)
})
it('should warn when scripts are in head', async () => {
const browser = await next.browser('/head')
await browser.waitForElementByCss('h1')
await waitFor(1000)
const browserLogs = await browser.log()
let found = false
browserLogs.forEach((log) => {
if (log.message.includes('Use next/script instead')) {
found = true
}
})
expect(found).toEqual(true)
})
it('should not warn when application/ld+json scripts are in head', async () => {
const browser = await next.browser('/head-with-json-ld-snippet')
await browser.waitForElementByCss('h1')
await waitFor(1000)
const browserLogs = await browser.log()
let found = false
browserLogs.forEach((log) => {
if (log.message.includes('Use next/script instead')) {
found = true
}
})
expect(found).toEqual(false)
})
it('should update head during client routing', async () => {
const browser = await next.browser('/nav/head-1')
expect(
await browser
.elementByCss('meta[name="description"]')
.getAttribute('content')
).toBe('Head One')
await browser
.elementByCss('#to-head-2')
.click()
.waitForElementByCss('#head-2', 3000)
expect(
await browser
.elementByCss('meta[name="description"]')
.getAttribute('content')
).toBe('Head Two')
await browser
.elementByCss('#to-head-1')
.click()
.waitForElementByCss('#head-1', 3000)
expect(
await browser
.elementByCss('meta[name="description"]')
.getAttribute('content')
).toBe('Head One')
await browser
.elementByCss('#to-head-3')
.click()
.waitForElementByCss('#head-3', 3000)
expect(
await browser
.elementByCss('meta[name="description"]')
.getAttribute('content')
).toBe('Head Three')
expect(await browser.eval('document.title')).toBe('')
await browser
.elementByCss('#to-head-1')
.click()
.waitForElementByCss('#head-1', 3000)
expect(
await browser
.elementByCss('meta[name="description"]')
.getAttribute('content')
).toBe('Head One')
})
it('should update title during client routing', async () => {
const browser = await next.browser('/nav/head-1')
expect(await browser.eval('document.title')).toBe('this is head-1')
await browser
.elementByCss('#to-head-2')
.click()
.waitForElementByCss('#head-2', 3000)
expect(await browser.eval('document.title')).toBe('this is head-2')
await browser
.elementByCss('#to-head-1')
.click()
.waitForElementByCss('#head-1', 3000)
expect(await browser.eval('document.title')).toBe('this is head-1')
})
it('should update head when unmounting component', async () => {
const browser = await next.browser('/head-dynamic')
expect(await browser.eval('document.title')).toBe('B')
await browser.elementByCss('button').click()
expect(await browser.eval('document.title')).toBe('A')
await browser.elementByCss('button').click()
expect(await browser.eval('document.title')).toBe('B')
})
})