test: Add comprehensive wrapper function test coverage

This commit is contained in:
seongminn 2025-06-15 23:38:50 +09:00
parent 0b05bfa9cf
commit 090f90e3a2
5 changed files with 1138 additions and 1 deletions

View file

@ -0,0 +1,199 @@
import tsParser from '@typescript-eslint/parser';
import { run } from 'eslint-vitest-rule-tester';
import alphabeticalOrderRule from '../rule-definition.js';
run({
name: 'vanilla-extract/alphabetical-order/style',
rule: alphabeticalOrderRule,
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
},
valid: [
// Basic style object with alphabetical ordering
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
alignItems: 'center',
backgroundColor: 'red',
color: 'blue',
display: 'flex',
margin: '10px',
padding: '20px',
zIndex: 1
});
`,
// Style with nested selectors
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
alignItems: 'center',
backgroundColor: 'red',
color: 'blue',
selectors: {
'&:hover': {
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
],
invalid: [
// Basic style object with incorrect ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
backgroundColor: 'red',
alignItems: 'center',
padding: '20px',
color: 'blue',
margin: '10px',
display: 'flex',
zIndex: 1
});
`,
errors: [{ messageId: 'alphabeticalOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
alignItems: 'center',
backgroundColor: 'red',
color: 'blue',
display: 'flex',
margin: '10px',
padding: '20px',
zIndex: 1
});
`,
},
// Style with nested selectors having incorrect ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
backgroundColor: 'red',
alignItems: 'center',
color: 'blue',
selectors: {
'&:hover': {
color: 'white',
backgroundColor: 'blue'
}
}
});
`,
errors: [{ messageId: 'alphabeticalOrder' }, { messageId: 'alphabeticalOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
alignItems: 'center',
backgroundColor: 'red',
color: 'blue',
selectors: {
'&:hover': {
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
},
],
});

View file

@ -0,0 +1,217 @@
import tsParser from '@typescript-eslint/parser';
import { run } from 'eslint-vitest-rule-tester';
import concentricOrderRule from '../rule-definition.js';
run({
name: 'vanilla-extract/concentric-order/style-custom',
rule: concentricOrderRule,
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
},
valid: [
// Basic style object with concentric ordering through wrapper function
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
boxSizing: 'border-box',
position: 'relative',
zIndex: 1,
display: 'flex',
alignItems: 'center',
transform: 'none',
opacity: 1,
margin: '1rem',
border: '1px solid black',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
backgroundColor: 'red',
padding: '2rem',
width: '10rem',
height: '10rem',
color: 'blue',
fontSize: '16rem'
});
`,
// Style with nested selectors
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
position: 'relative',
display: 'flex',
alignItems: 'center',
backgroundColor: 'red',
color: 'blue',
selectors: {
'&:hover': {
position: 'relative',
opacity: 0.8,
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
],
invalid: [
// Basic style object with incorrect concentric ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
color: 'blue',
width: '10rem',
display: 'flex',
backgroundColor: 'red',
margin: '1rem',
position: 'relative'
});
`,
errors: [{ messageId: 'incorrectOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
position: 'relative',
display: 'flex',
margin: '1rem',
backgroundColor: 'red',
width: '10rem',
color: 'blue'
});
`,
},
// Style with nested selectors having incorrect ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
color: 'blue',
display: 'flex',
backgroundColor: 'red',
position: 'relative',
selectors: {
'&:hover': {
color: 'white',
position: 'relative',
backgroundColor: 'blue'
}
}
});
`,
errors: [{ messageId: 'incorrectOrder' }, { messageId: 'incorrectOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
position: 'relative',
display: 'flex',
backgroundColor: 'red',
color: 'blue',
selectors: {
'&:hover': {
position: 'relative',
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
},
],
});

View file

@ -0,0 +1,379 @@
import tsParser from '@typescript-eslint/parser';
import { run } from 'eslint-vitest-rule-tester';
import customOrderRule from '../rule-definition.js';
run({
name: 'vanilla-extract/custom-order/style-custom',
rule: customOrderRule,
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
},
valid: [
// Basic style object with custom group ordering through wrapper function
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
// dimensions group first
width: '10rem',
height: '5rem',
// margin group second
margin: '1rem',
// font group third
fontFamily: 'sans-serif',
// border group fourth
border: '1px solid black',
// boxShadow group fifth
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
// remaining properties in concentric order
position: 'relative',
display: 'flex',
backgroundColor: 'red',
padding: '2rem',
color: 'blue'
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'concentric',
},
],
},
// Style with nested selectors
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
width: '10rem',
margin: '1rem',
fontFamily: 'sans-serif',
border: '1px solid black',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
position: 'relative',
backgroundColor: 'red',
selectors: {
'&:hover': {
width: '12rem',
margin: '2rem',
fontFamily: 'serif',
border: '2px solid blue',
boxShadow: '0 4px 8px rgba(0,0,0,0.2)',
position: 'absolute',
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'concentric',
},
],
},
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{ '@layer': { [layerMap[layer]]: rule } },
debugId,
);
const myStyle = layerStyle('component', {
// dimensions group first
width: '10rem',
height: '10rem',
// margin group second
margin: '1rem',
// font group third
fontFamily: 'sans-serif',
// border group fourth
border: '1px solid black',
// boxShadow group fifth
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
// remaining properties in alphabetical order
backgroundColor: 'red',
color: 'blue',
display: 'flex',
padding: '2rem',
position: 'relative'
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'alphabetical',
},
],
},
],
invalid: [
// Basic style object with incorrect custom group ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
position: 'relative',
border: '1px solid black',
width: '10rem',
color: 'blue',
margin: '1rem',
fontFamily: 'sans-serif',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
backgroundColor: 'red'
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'concentric',
},
],
errors: [{ messageId: 'incorrectOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
width: '10rem',
margin: '1rem',
fontFamily: 'sans-serif',
border: '1px solid black',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
position: 'relative',
backgroundColor: 'red',
color: 'blue'
});
`,
},
// Style with nested selectors having incorrect ordering
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
border: '1px solid black',
width: '10rem',
position: 'relative',
margin: '1rem',
selectors: {
'&:hover': {
color: 'white',
width: '12rem',
border: '2px solid blue',
margin: '1.2rem',
backgroundColor: 'blue'
}
}
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'concentric',
},
],
errors: [{ messageId: 'incorrectOrder' }, { messageId: 'incorrectOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
width: '10rem',
margin: '1rem',
border: '1px solid black',
position: 'relative',
selectors: {
'&:hover': {
width: '12rem',
margin: '1.2rem',
border: '2px solid blue',
backgroundColor: 'blue',
color: 'white'
}
}
});
`,
},
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
position: 'relative',
border: '1px solid black',
width: '10rem',
padding: '2rem',
color: 'blue',
margin: '1rem',
display: 'flex',
fontFamily: 'sans-serif',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
backgroundColor: 'red'
});
`,
options: [
{
groupOrder: ['dimensions', 'margin', 'font', 'border', 'boxShadow'],
sortRemainingProperties: 'alphabetical',
},
],
errors: [{ messageId: 'incorrectOrder' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
width: '10rem',
margin: '1rem',
fontFamily: 'sans-serif',
border: '1px solid black',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
backgroundColor: 'red',
color: 'blue',
display: 'flex',
padding: '2rem',
position: 'relative'
});
`,
},
],
});

View file

@ -55,13 +55,22 @@ describe('isEffectivelyEmptyStylesObject', () => {
parent: null as unknown as TSESTree.Node,
});
it('should return true for an object with empty selectors, media, or supports objects', () => {
it('should return false for an object with real CSS properties and empty nested objects', () => {
const object = createObjectExpression([
createProperty('color', createLiteral('blue')),
createProperty('selectors', createObjectExpression([])),
createProperty('@media', createObjectExpression([])),
createProperty('@supports', createObjectExpression([])),
]);
expect(isEffectivelyEmptyStylesObject(object)).toBe(false);
});
it('should return true for an object with only empty nested objects', () => {
const object = createObjectExpression([
createProperty('selectors', createObjectExpression([])),
createProperty('@media', createObjectExpression([])),
createProperty('@supports', createObjectExpression([])),
]);
expect(isEffectivelyEmptyStylesObject(object)).toBe(true);
});

View file

@ -0,0 +1,333 @@
import tsParser from '@typescript-eslint/parser';
import { run } from 'eslint-vitest-rule-tester';
import noEmptyBlocksRule from '../rule-definition.js';
run({
name: 'vanilla-extract/no-empty-blocks/style-custom',
rule: noEmptyBlocksRule,
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaVersion: 2022,
sourceType: 'module',
},
},
valid: [
// Basic non-empty style through wrapper function
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
color: 'blue',
margin: '10px'
});
`,
// Style with comments (not empty)
`
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myStyle = layerStyle('component', {
/* This is a comment */
color: 'blue'
});
`,
],
invalid: [
// Empty style object through wrapper function
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const emptyStyle = layerStyle('component', {});
`,
errors: [{ messageId: 'emptyStyleDeclaration' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
`,
},
// Empty exported style object
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
export const emptyStyle = layerStyle('component', {});
`,
errors: [{ messageId: 'emptyStyleDeclaration' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
`,
},
// Style with empty nested selectors
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const styleWithComments = layerStyle('component', {
/* This is an empty style */
});
`,
errors: [{ messageId: 'emptyStyleDeclaration' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
`,
},
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
export const emptyStyle1 = layerStyle('component', {});
export const emptyStyle2 = layerStyle('component', {});
`,
errors: [{ messageId: 'emptyStyleDeclaration' }, { messageId: 'emptyStyleDeclaration' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
`,
},
// Export of variable with empty style
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
const myEmptyStyle = layerStyle('component', {});
export { myEmptyStyle };
`,
errors: [{ messageId: 'emptyStyleDeclaration' }],
output: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
export { myEmptyStyle };
`,
},
// Style in a callback or nested function
{
code: `
import { style } from '@vanilla-extract/css';
export const layerStyle = (
layer: 'reset' | 'theme' | 'component' | 'utilities',
rule: StyleRule,
debugId?: string,
) =>
style(
{
'@layer': {
[layerMap[layer]]: rule,
},
},
debugId,
);
[1, 2, 3].forEach(() => {
layerStyle('component', {});
});
`,
errors: [{ messageId: 'emptyStyleDeclaration' }],
},
// Variable declaration with empty style
// {
// code: `
// import { style } from '@vanilla-extract/css';
// export const layerStyle = (
// layer: 'reset' | 'theme' | 'component' | 'utilities',
// rule: StyleRule,
// debugId?: string,
// ) =>
// style(
// {
// '@layer': {
// [layerMap[layer]]: rule,
// },
// },
// debugId,
// );
// const { className } = layerStyle('component', {});
// `,
// errors: [{ messageId: 'emptyStyleDeclaration' }],
// output: `
// import { style } from '@vanilla-extract/css';
// `,
// },
],
});