import { describe } from 'vitest' import { candidate, css, fetchStyles, js, json, retryAssertion, test } from '../utils' test( 'production build', { fs: { 'package.json': json` { "dependencies": { "react": "^18", "react-dom": "^18", "next": "^14" }, "devDependencies": { "@tailwindcss/postcss": "workspace:^", "tailwindcss": "workspace:^" } } `, 'postcss.config.mjs': js` export default { plugins: { '@tailwindcss/postcss': {}, }, } `, 'next.config.mjs': js`export default {}`, 'app/layout.js': js` import './globals.css' export default function RootLayout({ children }) { return ( {children} ) } `, 'app/page.js': js` import styles from './page.module.css' export default function Page() { return (

Hello, Next.js!

) } `, 'app/page.module.css': css` @reference './globals.css'; .heading { @apply text-red-500 animate-ping; } `, 'app/globals.css': css` @reference 'tailwindcss/theme'; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, exec, expect }) => { await exec('pnpm next build') let files = await fs.glob('.next/static/css/**/*.css') expect(files).toHaveLength(2) let globalCss: string | null = null let moduleCss: string | null = null for (let [filename, content] of files) { if (content.includes('@keyframes page_ping')) moduleCss = filename else globalCss = filename } await fs.expectFileToContain(globalCss!, [ candidate`underline`, candidate`font-bold`, candidate`text-3xl`, ]) await fs.expectFileToContain(moduleCss!, [ 'color:var(--color-red-500,oklch(.637 .237 25.331)', 'animation:var(--animate-ping,ping 1s cubic-bezier(0,0,.2,1) infinite)', /@keyframes page_ping.*{75%,to{transform:scale\(2\);opacity:0}/, ]) }, ) describe.each(['turbo', 'webpack'])('%s', (bundler) => { test( 'dev mode', { fs: { 'package.json': json` { "dependencies": { "react": "^18", "react-dom": "^18", "next": "^14" }, "devDependencies": { "@tailwindcss/postcss": "workspace:^", "tailwindcss": "workspace:^" } } `, 'postcss.config.mjs': js` export default { plugins: { '@tailwindcss/postcss': {}, }, } `, 'next.config.mjs': js`export default {}`, 'app/layout.js': js` import './globals.css' export default function RootLayout({ children }) { return ( {children} ) } `, 'app/page.js': js` import styles from './page.module.css' export default function Page() { return

Hello, Next.js!

} `, 'app/page.module.css': css` @reference './globals.css'; .heading { @apply text-red-500 animate-ping content-['module']; } `, 'app/globals.css': css` @reference 'tailwindcss/theme'; @import 'tailwindcss/utilities'; `, }, }, async ({ fs, spawn, expect }) => { let process = await spawn(`pnpm next dev ${bundler === 'turbo' ? '--turbo' : ''}`) let url = '' await process.onStdout((m) => { let match = /Local:\s*(http.*)/.exec(m) if (match) url = match[1] return Boolean(url) }) await process.onStdout((m) => m.includes('Ready in')) await retryAssertion(async () => { let css = await fetchStyles(url) expect(css).toContain(candidate`underline`) expect(css).toContain('content: var(--tw-content)') expect(css).toContain('@keyframes') }) await fs.write( 'app/page.js', js` import styles from './page.module.css' export default function Page() { return

Hello, Next.js!

} `, ) await process.onStdout((m) => m.includes('Compiled in')) await retryAssertion(async () => { let css = await fetchStyles(url) expect(css).toContain(candidate`underline`) expect(css).toContain(candidate`bg-red-500`) expect(css).toContain('content: var(--tw-content)') expect(css).toContain('@keyframes') }) }, ) }) test( 'should scan dynamic route segments', { fs: { 'package.json': json` { "dependencies": { "react": "^18", "react-dom": "^18", "next": "^14" }, "devDependencies": { "@tailwindcss/postcss": "workspace:^", "tailwindcss": "workspace:^" } } `, 'postcss.config.mjs': js` export default { plugins: { '@tailwindcss/postcss': {}, }, } `, 'next.config.mjs': js`export default {}`, 'app/a/[slug]/page.js': js` export default function Page() { return

Hello, Next.js!

} `, 'app/b/[...slug]/page.js': js` export default function Page() { return

Hello, Next.js!

} `, 'app/c/[[...slug]]/page.js': js` export default function Page() { return

Hello, Next.js!

} `, 'app/d/(theme)/page.js': js` export default function Page() { return

Hello, Next.js!

} `, 'app/layout.js': js` import './globals.css' export default function RootLayout({ children }) { return ( {children} ) } `, 'app/globals.css': css` @import 'tailwindcss/utilities' source(none); @source './**/*.{js,ts,jsx,tsx,mdx}'; `, }, }, async ({ fs, exec, expect }) => { await exec('pnpm next build') let files = await fs.glob('.next/static/css/**/*.css') expect(files).toHaveLength(1) let [filename] = files[0] await fs.expectFileToContain(filename, [ candidate`content-['[slug]']`, candidate`content-['[...slug]']`, candidate`content-['[[...slug]]']`, candidate`content-['(theme)']`, ]) }, )