import { Hono } from '../../hono.ts' import { jsx, memo, Fragment } from './index.ts' describe('JSX middleware', () => { const app = new Hono() it('Should render HTML strings', async () => { app.get('/', (c) => { return c.html(

Hello

) }) const res = await app.request('http://localhost/') expect(res.status).toBe(200) expect(res.headers.get('Content-Type')).toBe('text/html; charset=UTF-8') expect(await res.text()).toBe('

Hello

') }) }) describe('render to string', () => { it('Nested array', () => { const template = (

{[[['a']], [['b']]].map((item1) => item1.map((item2) => item2.map((item3) => {item3})) )}

) expect(template.toString()).toBe('

ab

') }) it('Empty elements are rended withtout closing tag', () => { const template = () expect(template.toString()).toBe('') }) it('Props value is null', () => { const template = Hello expect(template.toString()).toBe('Hello') }) it('Props value is undefined', () => { const template = Hello expect(template.toString()).toBe('Hello') }) describe('dangerouslySetInnerHTML', () => { it('Should render dangerouslySetInnerHTML', () => { const template = expect(template.toString()).toBe('" is allowed here') }) it('Should get an error if both dangerouslySetInnerHTML and children are specified', () => { expect(() => ( Hello )).toThrow() }) }) // https://en.reactjs.org/docs/jsx-in-depth.html#booleans-null-and-undefined-are-ignored describe('Booleans, Null, and Undefined Are Ignored', () => { it.each([true, false, undefined, null])('%s', (item) => { expect(({item}).toString()).toBe('') }) it('falsy value', () => { const template = {0} expect(template.toString()).toBe('0') }) }) // https://en.reactjs.org/docs/jsx-in-depth.html#props-default-to-true describe('Props Default to “True”', () => { it('default prop value', () => { const template = Hello expect(template.toString()).toBe('Hello') }) }) // https://en.reactjs.org/docs/jsx-in-depth.html#functions-as-children describe('Functions as Children', () => { it('Function', () => { function Repeat(props: any) { const items = [] for (let i = 0; i < props.numTimes; i++) { items.push((props.children as Function)(i)) } return
{items}
} function ListOfTenThings() { return ( {(index: string) =>
This is item {index} in the list
}
) } const template = expect(template.toString()).toBe( '
This is item 0 in the list
This is item 1 in the list
This is item 2 in the list
This is item 3 in the list
This is item 4 in the list
This is item 5 in the list
This is item 6 in the list
This is item 7 in the list
This is item 8 in the list
This is item 9 in the list
' ) }) }) }) describe('memo', () => { it('memoized', () => { let counter = 0 const Header = memo(() => Test Site {counter}) const Body = () => {counter} let template = (
) expect(template.toString()).toBe( 'Test Site 00' ) counter++ template = (
) expect(template.toString()).toBe( 'Test Site 01' ) }) it('props are updated', () => { const Body = memo(({ counter }: { counter: number }) => {counter}) let template = expect(template.toString()).toBe('0') template = expect(template.toString()).toBe('1') }) it('custom propsAreEqual', () => { const Body = memo( ({ counter }: { counter: number; refresh?: boolean }) => {counter}, (_, nextProps) => (typeof nextProps.refresh == 'undefined' ? true : !nextProps.refresh) ) let template = expect(template.toString()).toBe('0') template = expect(template.toString()).toBe('0') template = expect(template.toString()).toBe('2') }) }) describe('Fragment', () => { it('Should render children', () => { const template = ( <>

1

2

) expect(template.toString()).toBe('

1

2

') }) it('Should render nothing for empty Fragment', () => { const template = <> expect(template.toString()).toBe('') }) it('Should render nothing for undefined', () => { const template = <>{undefined} expect(template.toString()).toBe('') }) })