eslint-plugin-vanilla-extract/src/css-rules/no-px-unit/_tests_/no-px-unit.test.ts
Ante Budimir 85d106dc1d feat 🥁: add no-px-unit rule
- Add new rule `no-px-unit` that disallows `px` units in vanilla-extract styles with an allowlist option
- Provides fix suggestions for string literals and simple template literals (no expressions)
2025-11-04 08:42:47 +02:00

166 lines
4.4 KiB
TypeScript

import tsParser from '@typescript-eslint/parser';
import { run } from 'eslint-vitest-rule-tester';
import noPxUnitRule from '../rule-definition.js';
run({
name: 'vanilla-extract/no-px-unit',
rule: noPxUnitRule,
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
},
valid: [
{
code: `
import { style } from '@vanilla-extract/css';
const myStyle = style({
margin: '1rem',
padding: 8,
width: '100%',
color: vars.color.primary,
});
`,
name: 'allows rem, numbers, and token references',
},
{
code: `
import { style } from '@vanilla-extract/css';
const myStyle = style({
borderWidth: '1px',
outlineOffset: '2px',
});
`,
options: [{ allow: ['border-width', 'outline-offset', 'borderWidth', 'outlineOffset'] }],
name: 'respects allowlist for kebab and camelCase',
},
{
code: `
import { recipe } from '@vanilla-extract/css';
const myRecipe = recipe({
base: { margin: '1rem' },
variants: {
size: {
sm: { padding: '0.5rem' },
},
},
});
`,
name: 'passes when no px in recipe base/variants',
},
{
code: `
import { style } from '@vanilla-extract/css';
const s = style({
border: '1px solid',
borderWidth: '2px'
});
`,
options: [{ allow: ['borderWidth', 'border'] }],
name: 'does not report whitelisted properties',
},
],
invalid: [
{
code: `
import { style } from '@vanilla-extract/css';
const myStyle = style({
margin: '10px',
padding: '2px',
});
`,
errors: [{ messageId: 'noPxUnit' }, { messageId: 'noPxUnit' }],
},
{
code: `
import { style } from '@vanilla-extract/css';
const s = style({
'@media': {
'(min-width: 768px)': {
lineHeight: '12px',
}
},
selectors: {
'&:hover': { gap: '4px' }
}
});
`,
errors: [{ messageId: 'noPxUnit' }, { messageId: 'noPxUnit' }],
name: 'reports within nested @media and selectors',
},
{
code: `
import { recipe } from '@vanilla-extract/css';
const r = recipe({
base: { marginTop: '3px' },
variants: { size: { md: { paddingBottom: '6px' } } }
});
`,
errors: [{ messageId: 'noPxUnit' }, { messageId: 'noPxUnit' }],
name: 'reports within recipe base and variants',
},
{
code: `
import { fontFace } from '@vanilla-extract/css';
fontFace({ sizeAdjust: '10px' });
`,
errors: [{ messageId: 'noPxUnit' }],
name: 'reports in fontFace() first-arg object (covers fontFace branch)',
},
{
code: `
import { globalFontFace } from '@vanilla-extract/css';
globalFontFace('MyFont', { lineGapOverride: '12px' });
`,
errors: [{ messageId: 'noPxUnit' }],
name: 'reports in globalFontFace() second-arg object (covers globalFontFace branch)',
},
{
code: `
import { globalStyle } from '@vanilla-extract/css';
globalStyle('html', { boxShadow: '0 1px 2px black' });
`,
errors: [{ messageId: 'noPxUnit' }],
name: 'reports in globalStyle() second-arg object (covers globalStyle branch)',
},
{
code: `
import { globalKeyframes } from '@vanilla-extract/css';
globalKeyframes('fade', {
from: { margin: '5px' },
to: { padding: '3px' }
});
`,
errors: [{ messageId: 'noPxUnit' }, { messageId: 'noPxUnit' }],
name: 'reports in globalKeyframes() frames (covers globalKeyframes branch)',
},
{
code:
`
import { style } from '@vanilla-extract/css';
const s = style({
margin: ` +
'`10px`' +
`,
});
`,
errors: [{ messageId: 'noPxUnit' }],
name: 'reports for simple template literal with px',
},
{
code:
`
import { style } from '@vanilla-extract/css';
const s = style({
margin: ` +
'`${token}px`' +
`,
});
`,
errors: [{ messageId: 'noPxUnit' }],
name: 'reports for complex template literals with expressions containing px',
},
],
});