Add integration tests for multi-root builds (#14564)

When your Vite or postcss project has multiple Tailwind CSS roots with
different configs, they should not influence each other (with the
exception of the same candidates being used).
This commit is contained in:
Philipp Spiess 2024-10-01 17:00:20 +02:00 committed by GitHub
parent 3813f03b79
commit 3f85b74611
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 214 additions and 0 deletions

View File

@ -0,0 +1,50 @@
import { candidate, css, html, js, json, test } from '../utils'
test(
'production build',
{
fs: {
'package.json': json`
{
"dependencies": {
"postcss": "^8",
"postcss-cli": "^10",
"tailwindcss": "workspace:^",
"@tailwindcss/postcss": "workspace:^"
}
}
`,
'postcss.config.js': js`
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
}
`,
'index.html': html`
<div class="one:underline two:underline"></div>
`,
'src/shared.css': css`
@import 'tailwindcss/theme' theme(reference);
@import 'tailwindcss/utilities';
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
`,
},
},
async ({ fs, exec }) => {
await exec('pnpm postcss src/*.css -d dist')
await fs.expectFileToContain('dist/root1.css', [candidate`one:underline`])
await fs.expectFileNotToContain('dist/root1.css', [candidate`two:underline`])
await fs.expectFileNotToContain('dist/root2.css', [candidate`one:underline`])
await fs.expectFileToContain('dist/root2.css', [candidate`two:underline`])
},
)

View File

@ -0,0 +1,164 @@
import { expect } from 'vitest'
import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils'
test(
`production build`,
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^5.3.5"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import path from 'node:path'
import { defineConfig } from 'vite'
export default defineConfig({
build: {
cssMinify: false,
rollupOptions: {
input: {
root1: path.resolve(__dirname, 'root1.html'),
root2: path.resolve(__dirname, 'root2.html'),
},
},
},
plugins: [tailwindcss()],
})
`,
'root1.html': html`
<head>
<link rel="stylesheet" href="./src/root1.css" />
</head>
<body>
<div class="one:underline two:underline">Hello, world!</div>
</body>
`,
'src/shared.css': css`
@import 'tailwindcss/theme' theme(reference);
@import 'tailwindcss/utilities';
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
`,
'root2.html': html`
<head>
<link rel="stylesheet" href="./src/root2.css" />
</head>
<body>
<div class="one:underline two:underline">Hello, world!</div>
</body>
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
`,
},
},
async ({ fs, exec }) => {
await exec('pnpm vite build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(2)
let root1 = files.find(([filename]) => filename.includes('root1'))
let root2 = files.find(([filename]) => filename.includes('root2'))
expect(root1).toBeDefined()
expect(root2).toBeDefined()
expect(root1![1]).toContain(candidate`one:underline`)
expect(root1![1]).not.toContain(candidate`two:underline`)
expect(root2![1]).not.toContain(candidate`one:underline`)
expect(root2![1]).toContain(candidate`two:underline`)
},
)
test(
`dev mode`,
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^5.3.5"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import path from 'node:path'
import { defineConfig } from 'vite'
export default defineConfig({
build: { cssMinify: false },
plugins: [tailwindcss()],
})
`,
'root1.html': html`
<head>
<link rel="stylesheet" href="./src/root1.css" />
</head>
<body>
<div class="one:underline two:underline">Hello, world!</div>
</body>
`,
'src/shared.css': css`
@import 'tailwindcss/theme' theme(reference);
@import 'tailwindcss/utilities';
`,
'src/root1.css': css`
@import './shared.css';
@variant one (&:is([data-root='1']));
`,
'root2.html': html`
<head>
<link rel="stylesheet" href="./src/root2.css" />
</head>
<body>
<div class="one:underline two:underline">Hello, world!</div>
</body>
`,
'src/root2.css': css`
@import './shared.css';
@variant two (&:is([data-root='2']));
`,
},
},
async ({ root, spawn, getFreePort, fs }) => {
let port = await getFreePort()
await spawn(`pnpm vite dev --port ${port}`)
// Candidates are resolved lazily, so the first visit of index.html
// will only have candidates from this file.
await retryAssertion(async () => {
let styles = await fetchStyles(port, '/root1.html')
expect(styles).toContain(candidate`one:underline`)
expect(styles).not.toContain(candidate`two:underline`)
})
// Going to about.html will extend the candidate list to include
// candidates from about.html.
await retryAssertion(async () => {
let styles = await fetchStyles(port, '/root2.html')
expect(styles).not.toContain(candidate`one:underline`)
expect(styles).toContain(candidate`two:underline`)
})
},
)