tailwindcss/integrations/cli/upgrade.test.ts
Robin Malfait d869442a54
Add CSS codemod for missing @layer (#14504)
This PR adds a codemod that ensures that some parts of your stylesheet
are wrapped in an `@layer`.

This is a follow-up PR of #14411, in that PR we migrate `@tailwind`
directives to imports.

As a quick summary, that will turn this:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

Into:
```css
@import 'tailwindcss';
```

But there are a few issues with that _if_ we have additional CSS on the
page. For example let's imagine we had this:
```css
@tailwind base;

body {
  background-color: red;
}

@tailwind components;

.btn {}

@tailwind utilities;
```

This will now be turned into:
```css
@import 'tailwindcss';

body {
  background-color: red;
}

.btn {}
```

But in v4 we use real layers, in v3 we used to replace the directive
with the result of that layer. This means that now the `body` and `.btn`
styles are in the incorrect spot.

To solve this, we have to wrap them in a layer. The `body` should go in
an `@layer base`, and the `.btn` should be in an `@layer components` to
make sure it's in the same spot as it was before.

That's what this PR does, the original input will now be turned into:

```css
@import 'tailwindcss';

@layer base {
  body {
    background-color: red;
  }
}

@layer components {
  .btn {
  }
}
```

There are a few internal refactors going on as well, but those are less
important.
2024-09-24 16:32:50 +00:00

165 lines
2.9 KiB
TypeScript

import { css, json, test } from '../utils'
test(
'migrate @apply',
{
fs: {
'package.json': json`
{
"dependencies": {
"tailwindcss": "workspace:^",
"@tailwindcss/upgrade": "workspace:^"
}
}
`,
'src/index.css': css`
@import 'tailwindcss';
.a {
@apply flex;
}
.b {
@apply !flex;
}
.c {
@apply !flex flex-col! items-center !important;
}
`,
},
},
async ({ fs, exec }) => {
await exec('npx @tailwindcss/upgrade')
await fs.expectFileToContain(
'src/index.css',
css`
.a {
@apply flex;
}
.b {
@apply flex!;
}
.c {
@apply flex! flex-col! items-center!;
}
`,
)
},
)
test(
'migrate `@tailwind` directives',
{
fs: {
'package.json': json`
{
"dependencies": {
"tailwindcss": "workspace:^",
"@tailwindcss/upgrade": "workspace:^"
}
}
`,
'src/index.css': css`
@tailwind base;
html {
color: #333;
}
@tailwind components;
.btn {
color: red;
}
@tailwind utilities;
`,
},
},
async ({ fs, exec }) => {
await exec('npx @tailwindcss/upgrade')
await fs.expectFileToContain('src/index.css', css`@import 'tailwindcss';`)
await fs.expectFileToContain(
'src/index.css',
css`
@layer base {
html {
color: #333;
}
}
`,
)
await fs.expectFileToContain(
'src/index.css',
css`
@layer components {
.btn {
color: red;
}
}
`,
)
},
)
test(
'migrate `@layer utilities` and `@layer components`',
{
fs: {
'package.json': json`
{
"dependencies": {
"tailwindcss": "workspace:^",
"@tailwindcss/upgrade": "workspace:^"
}
}
`,
'src/index.css': css`
@import 'tailwindcss';
@layer components {
.btn {
@apply rounded-md px-2 py-1 bg-blue-500 text-white;
}
}
@layer utilities {
.no-scrollbar::-webkit-scrollbar {
display: none;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
}
`,
},
},
async ({ fs, exec }) => {
await exec('npx @tailwindcss/upgrade')
await fs.expectFileToContain(
'src/index.css',
css`
@utility btn {
@apply rounded-md px-2 py-1 bg-blue-500 text-white;
}
@utility no-scrollbar {
&::-webkit-scrollbar {
display: none;
}
-ms-overflow-style: none;
scrollbar-width: none;
}
`,
)
},
)