@furystack/shades
Version:
A lightweight UI framework for FuryStack with JSX support
179 lines • 9.08 kB
JavaScript
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { Shade } from './shade.js';
import { StyleManager } from './style-manager.js';
describe('StyleManager', () => {
beforeEach(() => {
StyleManager.clear();
});
afterEach(() => {
StyleManager.clear();
});
describe('registerComponentStyles', () => {
it('should register styles for a component', () => {
const result = StyleManager.registerComponentStyles('test-component', {
color: 'red',
padding: '10px',
});
expect(result).toBe(true);
expect(StyleManager.isRegistered('test-component')).toBe(true);
});
it('should inject CSS into a style element', () => {
StyleManager.registerComponentStyles('test-component', {
color: 'red',
});
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement).not.toBeNull();
expect(styleElement?.textContent).toContain('test-component');
expect(styleElement?.textContent).toContain('color: red');
});
it('should not register the same component twice', () => {
const result1 = StyleManager.registerComponentStyles('test-component', {
color: 'red',
});
const result2 = StyleManager.registerComponentStyles('test-component', {
color: 'blue',
});
expect(result1).toBe(true);
expect(result2).toBe(false);
// Should only have the first style
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('color: red');
expect(styleElement?.textContent).not.toContain('color: blue');
});
it('should handle pseudo-selectors', () => {
StyleManager.registerComponentStyles('test-button', {
backgroundColor: 'blue',
'&:hover': { backgroundColor: 'darkblue' },
});
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('test-button:hover');
expect(styleElement?.textContent).toContain('background-color: darkblue');
});
it('should return false for empty CSS object', () => {
const result = StyleManager.registerComponentStyles('empty-component', {});
expect(result).toBe(false);
expect(StyleManager.isRegistered('empty-component')).toBe(false);
});
it('should add comments with component name', () => {
StyleManager.registerComponentStyles('my-component', {
color: 'red',
});
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('/* my-component */');
});
it('should generate attribute selector for customized built-in elements', () => {
StyleManager.registerComponentStyles('my-link', {
color: 'blue',
textDecoration: 'none',
}, 'a');
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('a[is="my-link"]');
expect(styleElement?.textContent).toContain('color: blue');
expect(styleElement?.textContent).toContain('text-decoration: none');
});
it('should handle pseudo-selectors for customized built-in elements', () => {
StyleManager.registerComponentStyles('my-button', {
backgroundColor: 'gray',
'&:hover': { backgroundColor: 'darkgray' },
'&:active': { transform: 'scale(0.98)' },
}, 'button');
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('button[is="my-button"]');
expect(styleElement?.textContent).toContain('button[is="my-button"]:hover');
expect(styleElement?.textContent).toContain('button[is="my-button"]:active');
});
});
describe('isRegistered', () => {
it('should return true for registered components', () => {
StyleManager.registerComponentStyles('test-component', { color: 'red' });
expect(StyleManager.isRegistered('test-component')).toBe(true);
});
it('should return false for unregistered components', () => {
expect(StyleManager.isRegistered('unknown-component')).toBe(false);
});
});
describe('getRegisteredComponents', () => {
it('should return all registered component names', () => {
StyleManager.registerComponentStyles('component-a', { color: 'red' });
StyleManager.registerComponentStyles('component-b', { color: 'blue' });
const registered = StyleManager.getRegisteredComponents();
expect(registered.has('component-a')).toBe(true);
expect(registered.has('component-b')).toBe(true);
expect(registered.size).toBe(2);
});
it('should return empty set when no components registered', () => {
const registered = StyleManager.getRegisteredComponents();
expect(registered.size).toBe(0);
});
});
describe('clear', () => {
it('should clear all registered components', () => {
StyleManager.registerComponentStyles('test-component', { color: 'red' });
expect(StyleManager.isRegistered('test-component')).toBe(true);
StyleManager.clear();
expect(StyleManager.isRegistered('test-component')).toBe(false);
expect(StyleManager.getRegisteredComponents().size).toBe(0);
});
it('should remove style element on clear', () => {
StyleManager.registerComponentStyles('test-component', { color: 'red' });
let styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement).not.toBeNull();
StyleManager.clear();
styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement).toBeNull();
});
});
describe('reusing style element', () => {
it('should use the same style element for multiple components', () => {
StyleManager.registerComponentStyles('component-a', { color: 'red' });
StyleManager.registerComponentStyles('component-b', { color: 'blue' });
const styleElements = document.querySelectorAll('[data-shades-styles]');
expect(styleElements.length).toBe(1);
const styleElement = styleElements[0];
expect(styleElement?.textContent).toContain('component-a');
expect(styleElement?.textContent).toContain('component-b');
});
});
describe('Shade integration', () => {
it('should register CSS styles when Shade component is created with css property', () => {
Shade({
customElementName: 'shade-css-test-component',
css: {
color: 'red',
padding: '10px',
'&:hover': { color: 'blue' },
},
render: () => null,
});
expect(StyleManager.isRegistered('shade-css-test-component')).toBe(true);
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('shade-css-test-component');
expect(styleElement?.textContent).toContain('color: red');
expect(styleElement?.textContent).toContain('shade-css-test-component:hover');
});
it('should register CSS with attribute selector for customized built-in elements', () => {
Shade({
customElementName: 'shade-css-test-button',
elementBase: HTMLButtonElement,
elementBaseName: 'button',
css: {
backgroundColor: 'blue',
'&:hover': { backgroundColor: 'darkblue' },
},
render: () => null,
});
expect(StyleManager.isRegistered('shade-css-test-button')).toBe(true);
const styleElement = document.querySelector('[data-shades-styles]');
expect(styleElement?.textContent).toContain('button[is="shade-css-test-button"]');
expect(styleElement?.textContent).toContain('button[is="shade-css-test-button"]:hover');
});
it('should not register styles when Shade component has no css property', () => {
Shade({
customElementName: 'shade-no-css-component',
render: () => null,
});
expect(StyleManager.isRegistered('shade-no-css-component')).toBe(false);
});
});
});
//# sourceMappingURL=style-manager.spec.js.map