Skip to content

Commit ff3e415

Browse files
authored
test(v4): add test case for async chunks and CSS splitting (#94)
This PR adds a test case to verify that CSS splitting and async chunks work correctly with Tailwind CSS v4 in Rsbuild. It ensures that common styles are deduplicated and separate chunks are generated for async components.
1 parent 2c83f6d commit ff3e415

File tree

5 files changed

+109
-1
lines changed

5 files changed

+109
-1
lines changed

test/async-chunks/index.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { dirname } from 'node:path';
2+
import { fileURLToPath } from 'node:url';
3+
import { expect, test } from '@playwright/test';
4+
import { createRsbuild } from '@rsbuild/core';
5+
import { pluginTailwindCSS } from '../../src';
6+
7+
const __dirname = dirname(fileURLToPath(import.meta.url));
8+
9+
test('should split CSS and reuse common parts', async ({ page }) => {
10+
const rsbuild = await createRsbuild({
11+
cwd: __dirname,
12+
rsbuildConfig: {
13+
plugins: [pluginTailwindCSS()],
14+
},
15+
});
16+
17+
await rsbuild.build();
18+
const { server, urls } = await rsbuild.preview();
19+
20+
await page.goto(urls[0]);
21+
22+
// Check main chunk styles
23+
const mainDiv = page.locator('.flex.bg-red-500');
24+
await expect(mainDiv).toHaveCSS('display', 'flex');
25+
// Check that background color is set (exact value might vary by browser/environment)
26+
const mainBgColor = await mainDiv.evaluate(
27+
(el) => getComputedStyle(el).backgroundColor,
28+
);
29+
expect(mainBgColor).not.toBe('rgba(0, 0, 0, 0)');
30+
expect(mainBgColor).not.toBe('transparent');
31+
32+
// Wait for async chunk
33+
const asyncDiv = page.locator('.flex.text-center.bg-blue-500');
34+
await expect(asyncDiv).toHaveCSS('display', 'flex');
35+
await expect(asyncDiv).toHaveCSS('text-align', 'center');
36+
const asyncBgColor = await asyncDiv.evaluate(
37+
(el) => getComputedStyle(el).backgroundColor,
38+
);
39+
expect(asyncBgColor).not.toBe('rgba(0, 0, 0, 0)');
40+
expect(asyncBgColor).not.toBe('transparent');
41+
42+
// Analyze CSS files to check for splitting and deduplication
43+
const linkTags = await page.locator('link[rel="stylesheet"]').all();
44+
45+
// Fetch all CSS content
46+
const cssContents: string[] = [];
47+
for (const link of linkTags) {
48+
const href = await link.getAttribute('href');
49+
if (href) {
50+
const response = await page.request.get(
51+
new URL(href, urls[0]).toString(),
52+
);
53+
cssContents.push(await response.text());
54+
}
55+
}
56+
57+
// Check if .flex is defined
58+
let flexCount = 0;
59+
for (const css of cssContents) {
60+
// Simple check for .flex definition
61+
if (css.includes('.flex{') || css.includes('.flex {')) {
62+
flexCount++;
63+
}
64+
}
65+
66+
// We expect at least 2 CSS files (main + async)
67+
expect(cssContents.length).toBeGreaterThanOrEqual(2);
68+
69+
// We expect .flex to be defined exactly once (deduplicated)
70+
// or if not deduplicated, it might be 2. Ideally 1.
71+
// Let's assert it exists first.
72+
expect(flexCount).toBeGreaterThan(0);
73+
74+
// Check for Preflight duplication (checking for a common reset rule)
75+
// Tailwind preflight usually includes `box-sizing: border-box` on `*, ::before, ::after`.
76+
let preflightCount = 0;
77+
for (const css of cssContents) {
78+
if (css.includes('box-sizing:border-box')) {
79+
preflightCount++;
80+
}
81+
}
82+
83+
// Preflight should be deduplicated (only in main chunk)
84+
expect(preflightCount).toBe(1);
85+
86+
await server.close();
87+
});

test/async-chunks/src/async.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default function asyncFn() {
2+
const el = document.createElement('div');
3+
el.className = 'flex text-center bg-blue-500';
4+
document.body.appendChild(el);
5+
}

test/async-chunks/src/index.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@theme {
2+
--color-red-500: #ef4444;
3+
--color-blue-500: #3b82f6;
4+
}

test/async-chunks/src/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import './index.css';
2+
3+
const el = document.createElement('div');
4+
el.className = 'flex bg-red-500';
5+
document.body.appendChild(el);
6+
7+
import('./async').then(({ default: asyncFn }) => {
8+
asyncFn();
9+
});

test/static-assets/index.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ test('should not interfere with static asset queries (?url, ?raw)', async ({
3030

3131
// Check ?raw
3232
// It should contain the original CSS content, NOT Tailwind's injected content (like @tailwind base etc.)
33-
const originalCss = readFileSync(resolve(__dirname, 'src/index.css'), 'utf-8');
33+
const originalCss = readFileSync(
34+
resolve(__dirname, 'src/index.css'),
35+
'utf-8',
36+
);
3437
expect(cssRaw.trim()).toBe(originalCss.trim());
3538

3639
await server.close();

0 commit comments

Comments
 (0)