import { describe, expect, test, afterEach } from 'vitest'; import { mount } from './test-utils'; import { Test, TestWithData, TestWithPropListeners } from './test-utils/Test'; import { computed, state } from '../src/signals'; import { View } from '../src/View'; import { ViewMode } from '../src/ViewMode'; import Vanille from '../src/Vanille'; describe('View.tsx', () => { afterEach(() => { document.body.innerHTML = ''; }); describe('can render with different modes', () => { test('can render with default open mode', () => { const $component = mount(new Test()); const $el = $component.shadowRoot!.querySelector('[data-id="test"'); expect($el).toBeTruthy(); }); test('can render with default closed mode', () => { const $component = mount(new Test(ViewMode.CLOSED)); const $el = $component.querySelector('[data-id="test"'); expect($component.shadowRoot).toBeFalsy(); expect($el).toBeTruthy(); }); test('can render with default closed mode', () => { const $component = mount(new Test(ViewMode.NONE)); const $el = $component.shadowRoot!.querySelector('[data-id="test"'); expect($el).toBeTruthy(); }); }); describe('rendering as jsx template', () => { test('can render its own template with JSX', () => { const $component = mount(); const $el = $component.shadowRoot!.querySelector('[data-id="test"'); expect($el).toBeTruthy(); }); test('can render with attributes', () => { const name = 'vanille'; const $component = mount(); const $el = $component.shadowRoot!.querySelector('[data-id="name"]'); expect($el).toBeTruthy(); expect($el.textContent).toBe(name); }); test('can render with attributes as objects', () => { const user = { name: 'vanille' }; const $component = mount(); const $el = $component.shadowRoot!.querySelector('[data-id="user.name"]'); expect($el).toBeTruthy(); expect($el.textContent).toBe(user.name); }); }); describe('rendering as class', () => { test('can render its own template with JSX', () => { const $component = mount(Test); const $el = $component.shadowRoot!.querySelector('[data-id="test"'); expect($el).toBeTruthy(); }); }); describe('rendering with styles', () => { test('can with custom styles', () => { function App() { this.styles = () => { return ` div { color: red; } `; } return
; } const $component = mount(App); const $el = $component.root.children.item(0); expect($el!.innerHTML).toEqual(`div[${$component.$scopedId}] { color: red; }`); }); test('can with custom styles and global styles', () => { Vanille.setStyles( ` div { color: blue; } ` ); function App() { this.styles = () => { return ` div { color: red; } `; } return
; } const $component = mount(App); const $el = $component.root.children.item(0); expect($el!.innerHTML).toEqual(`div[${$component.$scopedId}] { color: red; } div[${$component.$scopedId}] { color: blue; }`); }); }); describe('rendering as function', () => { test('can render functional components', () => { function App(){ return
} const $component = mount(App); expect($component.root.querySelector('[data-test="app"]')).toBeTruthy(); }); }); describe('function def', () => { test('can rener functional components', () => { function App(){ return
} const $component = mount(App); expect($component.root.querySelector('[data-test="app"]')).toBeTruthy(); }); }); describe('function emit', () => { test('can emit primitive value', () => { let count = 0; function Child() { this.emitUp = () => { this.emit('oncount', 1); } return
} function App() { this.onCount = (value) => { count = value.detail; } return } const $component = mount(App); $component.refs.child.emitUp(); setTimeout(() => { expect(count).toBeTruthy(); expect(count).toEqual(1); }); }); test('can emit objects', () => { let count = {}; function Child() { this.emitUp = () => { this.emit('oncount', {count: 1}); } return
} function App() { this.onCount = (value) => { count = value.detail; } return } const $component = mount(App); $component.refs.child.emitUp(); setTimeout(() => { expect(count).toBeTruthy(); expect(count).toEqual({count: 1}); }); }); }); describe('getter refs', () => { test('dynamically queries DOM element as getter properties', () => { const $component = mount(); const $el = $component.refs.name; expect($el).toBeTruthy(); expect($el instanceof HTMLElement).toBeTruthy(); expect($el.textContent).toBe('vanille'); }); }); describe('function updateRender', () => { test('does a full refresh of the DOM template', () => { const $component = mount<{name: string}>(); let $el = $component.refs.name; $component.props.name = 'strawberry'; expect($el.textContent).toBe('vanille'); $component.updateRender(); $el = $component.refs.name; expect($el.textContent).toBe('strawberry'); }); }); describe('props', () => { test('trigger listeners when lower properties changed', () => { const user = state({ name: 'vanille' }); const $component = mount(); let $el = $component.refs.username; expect($el.textContent).toBe('vanille'); user.set({ name: 'strawberry' }); expect($el.textContent).toBe('strawberry'); }); }); describe('jsx template', () => { test('can assign events starting with ', () => { const user = { name: 'vanille' }; const $component = mount( user.name = 'strawberry'} />); expect($component.onclick).toBeDefined(); $component.onclick(); expect(user.name).toBe('strawberry'); }); test('can render html element as expressions', () => { const $p = document.createElement('p'); $p.setAttribute('ref', 'slotvanilla'); $p.textContent = 'slot vanilla'; const $component = mount( {$p} ); expect($component.querySelector('[ref="slotvanilla"]')).not.toBeNull(); expect($component.querySelector('[ref="slotvanilla"]').textContent).toBe('slot vanilla'); }); test('can render signal as expressions', () => { const name = state('name'); const $component = mount( {name} ); expect($component.textContent).toBe('name'); }); test('can render signal as reactive expressions', () => { const name = state('name'); const $component = mount( {name} ); expect($component.textContent).toBe('name'); name.set('new name'); expect($component.textContent).toBe('new name'); }); test('can render computed as expressions', () => { const name = state('name'); const nameFormatted = computed(() => `name: ${name.get()}`); const $component = mount( {nameFormatted} ); expect($component.textContent).toBe(`name: name`); }); test('can render computed as reactive expressions', () => { const name = state('name'); const nameFormatted = computed(() => `name: ${name.get()}`); const $component = mount( {nameFormatted} ); expect($component.textContent).toBe(`name: name`); name.set('new name'); expect($component.textContent).toBe(`name: new name`); }); test('can render computed as child function expressions', () => { const name = state('name'); const nameFormatted = () => `name: ${name.get()}`; const $component = mount( {nameFormatted} ); expect($component.textContent).toBe(`name: name`); }); test('can render computed as child reactive expressions', () => { const name = state('name'); const nameFormatted = () => `name: ${name.get()}`; const $component = mount( {nameFormatted} ); expect($component.textContent).toBe(`name: name`); name.set('new name'); expect($component.textContent).toBe(`name: new name`); }); test('can render signal as child function attributes', () => { const name = state('name'); const $component = mount(

); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`name`); }); test('can render signal as child reactive expressions', () => { const name = state('name'); const $component = mount(

); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`name`); name.set('new name'); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`new name`); }); test('can render computed as child function attributes', () => { const name = state('name'); const nameFormatted = () => `name: ${name.get()}`; const $component = mount(

); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`name: name`); }); test('can render computed as child reactive expressions', () => { const name = state('name'); const nameFormatted = () => `name: ${name.get()}`; const $component = mount(

); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`name: name`); name.set('new name'); expect($component.querySelector('p[test-id="computed"]')?.getAttribute('value')).toBe(`name: new name`); }); }); describe('rendering as web component class', () => { test('can render its own template with web component class', () => { const $component = mount(Test); const $el = $component.shadowRoot!.querySelector('[data-id="test"'); expect($el).toBeTruthy(); }); test('can render its own template with web component class', () => { const name = 'vanille'; const $component = mount(Test, { props: { name } }); const $el = $component.shadowRoot!.querySelector('[data-id="name"]'); expect($el).toBeTruthy(); expect($el.textContent).toBe(name); }); test('can render with attributes as objects', () => { const user = { name: 'vanille' }; const $component = mount(Test, { props: { user } }); const $el = $component.shadowRoot!.querySelector('[data-id="user.name"]'); expect($el).toBeTruthy(); expect($el.textContent).toBe(user.name); }); }); });