UNPKG

@ordojs/core

Version:

Core compiler and runtime for OrdoJS framework

155 lines (115 loc) 6.08 kB
/** * @fileoverview Tests for the CSS Scoper */ import { describe, expect, it } from 'vitest'; import { OrdoJSCSSParser } from './css-parser.js'; import { OrdoJSCSSScoper } from './css-scoper.js'; describe('OrdoJSCSSScoper', () => { it('should scope a simple CSS rule', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = `.button { color: red; }`; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'ButtonComponent'); const scopedCSS = scoper.generateScopedCSS(scopedStyleBlock); expect(scopedStyleBlock.rules[0].selector).toContain('[data-ordojs-buttoncomponent-'); expect(scopedCSS).toContain('.button[data-ordojs-buttoncomponent-'); }); it('should scope multiple selectors', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = `.button, .btn { color: red; }`; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'ButtonComponent'); const scopedCSS = scoper.generateScopedCSS(scopedStyleBlock); expect(scopedStyleBlock.rules[0].selector).toContain('.button[data-ordojs-buttoncomponent-'); expect(scopedStyleBlock.rules[0].selector).toContain('.btn[data-ordojs-buttoncomponent-'); expect(scopedCSS).toContain('.button[data-ordojs-buttoncomponent-'); expect(scopedCSS).toContain('.btn[data-ordojs-buttoncomponent-'); }); it('should handle pseudo-classes and pseudo-elements', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = ` .button:hover { color: blue; } .input::placeholder { color: gray; } `; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'FormComponent'); expect(scopedStyleBlock.rules[0].selector).toContain('.button[data-ordojs-formcomponent-'); expect(scopedStyleBlock.rules[0].selector).toContain(':hover'); expect(scopedStyleBlock.rules[1].selector).toContain('.input[data-ordojs-formcomponent-'); expect(scopedStyleBlock.rules[1].selector).toContain('::placeholder'); }); it('should not scope global selectors like :root, html, body', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = ` :root { --primary-color: blue; } html { font-size: 16px; } body { margin: 0; } `; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'AppComponent'); expect(scopedStyleBlock.rules[0].selector).toBe(':root'); expect(scopedStyleBlock.rules[1].selector).toBe('html'); expect(scopedStyleBlock.rules[2].selector).toBe('body'); }); it('should handle complex selectors with combinators', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = ` .parent > .child { margin: 10px; } .sibling + .adjacent { padding: 5px; } .list ~ .item { border: 1px solid black; } `; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'LayoutComponent'); expect(scopedStyleBlock.rules[0].selector).toContain('.parent[data-ordojs-layoutcomponent-'); expect(scopedStyleBlock.rules[0].selector).toContain('> .child[data-ordojs-layoutcomponent-'); expect(scopedStyleBlock.rules[1].selector).toContain('.sibling[data-ordojs-layoutcomponent-'); expect(scopedStyleBlock.rules[1].selector).toContain('+ .adjacent[data-ordojs-layoutcomponent-'); expect(scopedStyleBlock.rules[2].selector).toContain('.list[data-ordojs-layoutcomponent-'); expect(scopedStyleBlock.rules[2].selector).toContain('~ .item[data-ordojs-layoutcomponent-'); }); it('should use class-based scoping when configured', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper({ useDataAttributes: false }); const css = `.button { color: red; }`; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'ButtonComponent'); const scopedCSS = scoper.generateScopedCSS(scopedStyleBlock); expect(scopedStyleBlock.rules[0].selector).toContain('.button.ordoica-buttoncomponent-'); expect(scopedCSS).toContain('.button.ordoica-buttoncomponent-'); }); it('should preserve original selectors when configured', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper({ preserveOriginalSelectors: true }); const css = `.button { color: red; }`; const styleBlock = parser.parse(css, true); const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'ButtonComponent'); const scopedCSS = scoper.generateScopedCSS(scopedStyleBlock); expect(scopedStyleBlock.rules[0].selector).toContain('.button, .button[data-ordojs-buttoncomponent-'); expect(scopedCSS).toContain('.button, .button[data-ordojs-buttoncomponent-'); }); it('should not scope styles when scoped flag is false', () => { const parser = new OrdoJSCSSParser(); const scoper = new OrdoJSCSSScoper(); const css = `.button { color: red; }`; const styleBlock = parser.parse(css, false); // scoped = false const scopedStyleBlock = scoper.scopeStyles(styleBlock, 'ButtonComponent'); expect(scopedStyleBlock.rules[0].selector).toBe('.button'); }); it('should generate consistent scope IDs for the same component', () => { const scoper = new OrdoJSCSSScoper(); const attr1 = scoper.generateScopeAttribute('ButtonComponent'); const attr2 = scoper.generateScopeAttribute('ButtonComponent'); expect(attr1).toBe(attr2); }); it('should generate different scope IDs for different components', () => { const scoper = new OrdoJSCSSScoper(); const attr1 = scoper.generateScopeAttribute('ButtonComponent'); const attr2 = scoper.generateScopeAttribute('InputComponent'); expect(attr1).not.toBe(attr2); }); });