import type { Injector } from '@furystack/inject'
import { createInjector } from '@furystack/inject'
import { describe, expect, it, vi } from 'vitest'
import './jsx.js'
import { createComponent } from './shade-component.js'
import { flushUpdates, Shade } from './shade.js'
describe('Shades Component Factory', () => {
describe('HTML Elements', () => {
it('Should create a simple component', () => {
const component =
test
expect(component).toBeInstanceOf(HTMLDivElement)
expect(component.innerHTML).toBe('test')
expect(component.outerHTML).toBe('test
')
})
it('Should apply styles', () => {
const component = a
expect(component).toBeInstanceOf(HTMLDivElement)
expect(component.style.color).toBe('red')
})
it('Should apply data attributes', () => {
const component = a
expect(component).toBeInstanceOf(HTMLDivElement)
expect(component.getAttribute('data-testid')).toBe('asd-123')
})
it('Should apply aria attributes', () => {
const component = (
a
)
expect(component).toBeInstanceOf(HTMLDivElement)
expect(component.getAttribute('aria-label')).toBe('My label')
expect(component.getAttribute('aria-hidden')).toBe('true')
})
it('Should create a nested component', () => {
const component = (
Hi, I'm a header
paragraph... {['a', 'b', 'c']}
link
)
expect(component).toBeInstanceOf(HTMLDivElement)
expect(component.childElementCount).toBe(3)
expect(component.innerHTML).toBe(
`Hi, I'm a header
paragraph... abc
link`,
)
})
it('Should attach listeners', () => {
const onclick = vi.fn()
const component =
expect(component.onclick).toBe(onclick)
})
})
describe('Shade components', () => {
it('Should render a basic component', () => {
const Example = Shade({ customElementName: 'example-basic', render: () => })
const component = (
)
const shade = component.firstElementChild as JSX.Element
expect(shade.props).toEqual({})
expect(shade.shadeChildren).toEqual([])
})
it('Should render a component with props', async () => {
const Example = Shade<{ foo: string; injector: Injector }>({
customElementName: 'example-with-props',
render: ({ props }) => {props.foo}
,
})
const component = (
)
const shade = component.firstElementChild as JSX.Element<{ foo: string }>
shade.updateComponent()
await flushUpdates()
expect(shade.props.foo).toEqual('example')
expect(shade.shadeChildren).toEqual([])
expect(shade.innerHTML).toBe('example
')
})
it('Should render a component with state', async () => {
const Example = Shade({
customElementName: 'example-with-state',
render: ({ useState }) => {
useState('foo', 'example')
return
},
})
const component = (
)
const shade = component.firstElementChild as JSX.Element
shade.updateComponent()
await flushUpdates()
expect(shade.resourceManager.stateObservers.get('foo')?.getValue()).toEqual('example')
expect(shade.shadeChildren).toEqual([])
})
})
})