Skip to content

Commit 6654f6b

Browse files
Migrate CLI test to the new integration test setup
1 parent 002cb77 commit 6654f6b

File tree

12 files changed

+153
-78
lines changed

12 files changed

+153
-78
lines changed

integrations/cli/index.test.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import path from 'node:path'
2+
import { expect } from 'vitest'
3+
import { css, html, js, json, stripTailwindComment, test, yaml } from '../utils'
4+
5+
test(
6+
'works with production builds',
7+
{
8+
fs: {
9+
'package.json': json` {} `,
10+
'pnpm-workspace.yaml': yaml`
11+
#
12+
packages:
13+
- a
14+
`,
15+
'a/package.json': json`
16+
{
17+
"dependencies": {
18+
"tailwindcss": "workspace:^",
19+
"@tailwindcss/cli": "workspace:^"
20+
}
21+
}
22+
`,
23+
'a/index.html': html`
24+
<div
25+
class="underline 2xl:font-bold hocus:underline inverted:flex"
26+
></div>
27+
`,
28+
'a/plugin.js': js`
29+
module.exports = function ({ addVariant }) {
30+
addVariant('inverted', '@media (inverted-colors: inverted)')
31+
addVariant('hocus', ['&:focus', '&:hover'])
32+
}
33+
`,
34+
'a/src/index.css': css`
35+
@import 'tailwindcss/utilities';
36+
@content '../../b/src/**/*.js';
37+
@plugin '../plugin.js';
38+
`,
39+
'a/src/index.js': js`
40+
const className = "content-['a/src/index.js']"
41+
module.exports = { className }
42+
`,
43+
'b/src/index.js': js`
44+
const className = "content-['b/src/index.js']"
45+
module.exports = { className }
46+
`,
47+
},
48+
},
49+
async ({ root, fs, exec }) => {
50+
await exec('pnpm tailwindcss --input src/index.css --output dist/out.css', {
51+
cwd: path.join(root, 'a'),
52+
})
53+
54+
expect(stripTailwindComment(await fs.read('a/dist/out.css'))).toMatchInlineSnapshot(`
55+
".underline {
56+
text-decoration-line: underline;
57+
}
58+
.content-\\[\\'a\\/src\\/index\\.js\\'\\] {
59+
--tw-content: 'a/src/index.js';
60+
content: var(--tw-content);
61+
}
62+
.content-\\[\\'b\\/src\\/index\\.js\\'\\] {
63+
--tw-content: 'b/src/index.js';
64+
content: var(--tw-content);
65+
}
66+
.inverted\\:flex {
67+
@media (inverted-colors: inverted) {
68+
display: flex;
69+
}
70+
}
71+
.hocus\\:underline {
72+
&:focus {
73+
text-decoration-line: underline;
74+
}
75+
&:hover {
76+
text-decoration-line: underline;
77+
}
78+
}
79+
@supports (-moz-orient: inline) {
80+
@layer base {
81+
*, ::before, ::after, ::backdrop {
82+
--tw-content: "";
83+
}
84+
}
85+
}
86+
@property --tw-content {
87+
syntax: "*";
88+
inherits: false;
89+
initial-value: "";
90+
}"
91+
`)
92+
},
93+
)

integrations/utils.ts

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,38 @@ import { test as defaultTest } from 'vitest'
1111
export let css = dedent
1212
export let html = dedent
1313
export let ts = dedent
14+
export let js = dedent
1415
export let json = dedent
16+
export let yaml = dedent
1517

1618
const REPO_ROOT = path.join(__dirname, '..')
19+
const PUBLIC_PACKAGES = (await fs.readdir(path.join(REPO_ROOT, 'dist'))).map((name) =>
20+
name.replace('tailwindcss-', '@tailwindcss/').replace('.tgz', ''),
21+
)
1722

1823
interface SpawnedProcess {
1924
dispose: () => void
2025
onStdout: (predicate: (message: string) => boolean) => Promise<void>
2126
onStderr: (predicate: (message: string) => boolean) => Promise<void>
2227
}
2328

29+
interface ChildProcessOptions {
30+
cwd?: string
31+
}
32+
2433
interface TestConfig {
2534
fs: {
2635
[filePath: string]: string
2736
}
2837
}
2938
interface TestContext {
30-
exec(command: string): Promise<string>
31-
spawn(command: string): Promise<SpawnedProcess>
39+
root: string
40+
exec(command: string, options?: ChildProcessOptions): Promise<string>
41+
spawn(command: string, options?: ChildProcessOptions): Promise<SpawnedProcess>
3242
getFreePort(): Promise<number>
3343
fs: {
3444
write(filePath: string, content: string): Promise<void>
45+
read(filePath: string): Promise<string>
3546
glob(pattern: string): Promise<[string, string][]>
3647
}
3748
}
@@ -59,7 +70,7 @@ export function test(
5970
let full = path.join(root, filename)
6071

6172
if (filename.endsWith('package.json')) {
62-
content = overwriteVersionsInPackageJson(content)
73+
content = await overwriteVersionsInPackageJson(content)
6374
}
6475

6576
// Ensure that files written on Windows use \r\n line ending
@@ -92,10 +103,15 @@ export function test(
92103
options.onTestFinished(dispose)
93104

94105
let context = {
95-
async exec(command: string) {
96-
return execSync(command, { cwd: root }).toString()
106+
root,
107+
async exec(command: string, childProcessOptions: ChildProcessOptions = {}) {
108+
return execSync(command, {
109+
cwd: root,
110+
stdio: 'pipe',
111+
...childProcessOptions,
112+
}).toString()
97113
},
98-
async spawn(command: string) {
114+
async spawn(command: string, childProcessOptions: ChildProcessOptions = {}) {
99115
let resolveDisposal: (() => void) | undefined
100116
let rejectDisposal: ((error: Error) => void) | undefined
101117
let disposePromise = new Promise<void>((resolve, reject) => {
@@ -109,6 +125,7 @@ export function test(
109125
env: {
110126
...process.env,
111127
},
128+
...childProcessOptions,
112129
})
113130

114131
function dispose() {
@@ -217,6 +234,9 @@ export function test(
217234
},
218235
fs: {
219236
write,
237+
async read(filePath: string) {
238+
return await fs.readFile(path.join(root, filePath), 'utf8')
239+
},
220240
async glob(pattern: string) {
221241
let files = await fastGlob(pattern, { cwd: root })
222242
return Promise.all(
@@ -242,26 +262,30 @@ function pkgToFilename(name: string) {
242262
return `${name.replace('@', '').replace('/', '-')}.tgz`
243263
}
244264

245-
function overwriteVersionsInPackageJson(content: string): string {
265+
async function overwriteVersionsInPackageJson(content: string): Promise<string> {
246266
let json = JSON.parse(content)
247267

248268
// Resolve all workspace:^ versions to local tarballs
249-
;['dependencies', 'devDependencies', 'peerDependencies'].forEach((key) => {
250-
let dependencies = json[key] || {}
251-
for (let dependency in dependencies) {
252-
if (dependencies[dependency] === 'workspace:^') {
253-
dependencies[dependency] = resolveVersion(dependency)
269+
;['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'].forEach(
270+
(key) => {
271+
let dependencies = json[key] || {}
272+
for (let dependency in dependencies) {
273+
if (dependencies[dependency] === 'workspace:^') {
274+
dependencies[dependency] = resolveVersion(dependency)
275+
}
254276
}
255-
}
256-
})
277+
},
278+
)
257279

258280
// Inject transitive dependency overwrite. This is necessary because
259281
// @tailwindcss/vite internally depends on a specific version of
260282
// @tailwindcss/oxide and we instead want to resolve it to the locally built
261283
// version.
262284
json.pnpm ||= {}
263285
json.pnpm.overrides ||= {}
264-
json.pnpm.overrides['@tailwindcss/oxide'] = resolveVersion('@tailwindcss/oxide')
286+
for (let pkg of PUBLIC_PACKAGES) {
287+
json.pnpm.overrides[pkg] = resolveVersion(pkg)
288+
}
265289

266290
return JSON.stringify(json, null, 2)
267291
}

packages/@tailwindcss-cli/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
"picocolors": "^1.0.1",
3737
"postcss": "8.4.24",
3838
"postcss-import": "^16.1.0",
39-
"tailwindcss": "workspace:^",
40-
"internal-postcss-fix-relative-paths": "workspace:^"
39+
"tailwindcss": "workspace:^"
4140
},
4241
"devDependencies": {
43-
"@types/postcss-import": "^14.0.3"
42+
"@types/postcss-import": "^14.0.3",
43+
"internal-postcss-fix-relative-paths": "workspace:^"
4444
}
4545
}

packages/@tailwindcss-cli/src/commands/build/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import watcher from '@parcel/watcher'
22
import { clearCache, scanDir, type ChangedContent, type GlobEntry } from '@tailwindcss/oxide'
33
import fixRelativePathsPlugin from 'internal-postcss-fix-relative-paths'
44
import { Features, transform } from 'lightningcss'
5+
import { createRequire } from 'module'
56
import { existsSync } from 'node:fs'
67
import fs from 'node:fs/promises'
78
import path from 'node:path'
@@ -20,6 +21,7 @@ import {
2021
} from '../../utils/renderer'
2122
import { resolve } from '../../utils/resolve'
2223
import { drainStdin, outputFile } from './utils'
24+
const require = createRequire(import.meta.url)
2325

2426
const css = String.raw
2527

packages/@tailwindcss-cli/src/fixtures/example-project/index.html

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/@tailwindcss-cli/src/fixtures/example-project/plugin.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

packages/@tailwindcss-cli/src/fixtures/example-project/src/index.css

Lines changed: 0 additions & 2 deletions
This file was deleted.

packages/@tailwindcss-cli/src/fixtures/example-project/src/index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/@tailwindcss-cli/src/fixtures/other-project/src/index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

packages/@tailwindcss-cli/src/index.test.ts

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)