import { nextTestSetup } from 'e2e-utils'
describe('next/dynamic with CSP nonce', () => {
const { next } = nextTestSetup({
files: __dirname,
})
it('should include nonce attribute on preload links generated by next/dynamic', async () => {
const $ = await next.render$('/')
// Check that preload links have the nonce attribute
const preloadLinks = $('link[rel="preload"]')
const dynamicPreloadLinks = preloadLinks.filter((_, element) => {
const $element = $(element)
const href = $element.attr('href')
return href && /_next\/static\/(immutable\/)?chunks\//.test(href)
})
// There should be at least one preload link for dynamic chunks
expect(dynamicPreloadLinks.length).toBeGreaterThan(0)
dynamicPreloadLinks.each((_, element) => {
const $element = $(element)
const href = $element.attr('href')
// Only check preload links for dynamic chunks
if (href && /_next\/static\/(immutable\/)?chunks\//.test(href)) {
expect($element.attr('nonce')).toBe('test-nonce')
}
})
})
it('should not generate CSP violations when using next/dynamic with nonce', async () => {
const browser = await next.browser('/')
// Wait for the dynamic component to load
await browser.waitForElementByCss('#dynamic-component-loaded')
// OPTIMIZATION: Get both text values concurrently
const [pageTitle, componentText] = await Promise.all([
browser.elementByCss('#page-title').then((el) => el.text()),
browser.elementByCss('#dynamic-component-loaded').then((el) => el.text()),
])
expect(pageTitle).toBe('CSP Nonce Test Page')
expect(componentText).toBe('Dynamic component loaded successfully')
// Check for CSP violations in Chrome (most expensive operation)
if (global.browserName === 'chrome') {
const logs = await browser.log()
const cspViolations = logs.filter(
(log) =>
log.source === 'security' &&
log.message.includes('Content Security Policy')
)
expect(cspViolations).toEqual([])
}
})
})