Skip to content

Commit

Permalink
test(jsx): add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
usualoma committed Apr 25, 2024
1 parent 901ed42 commit ba55e42
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 1 deletion.
52 changes: 52 additions & 0 deletions src/jsx/children.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Children } from './children'
import { createElement } from '.'

describe('map', () => {
it('should map children', () => {
const element = createElement('div', null, 1, 2, 3)
const result = Children.map(element.children, (child) => (child as number) * 2)
expect(result).toEqual([2, 4, 6])
})
})

describe('forEach', () => {
it('should iterate children', () => {
const element = createElement('div', null, 1, 2, 3)
const result: number[] = []
Children.forEach(element.children, (child) => {
result.push(child as number)
})
expect(result).toEqual([1, 2, 3])
})
})

describe('count', () => {
it('should count children', () => {
const element = createElement('div', null, 1, 2, 3)
const result = Children.count(element.children)
expect(result).toBe(3)
})
})

describe('only', () => {
it('should return the only child', () => {
const element = createElement('div', null, 1)
const result = Children.only(element.children)
expect(result).toBe(1)
})

it('should throw an error if there are multiple children', () => {
const element = createElement('div', null, 1, 2)
expect(() => Children.only(element.children)).toThrowError(
'Children.only() expects only one child'
)
})
})

describe('toArray', () => {
it('should convert children to an array', () => {
const element = createElement('div', null, 1, 2, 3)
const result = Children.toArray(element.children)
expect(result).toEqual([1, 2, 3])
})
})
56 changes: 55 additions & 1 deletion src/jsx/dom/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,59 @@ import type { FC } from '..'
// hono/jsx/jsx-runtime and hono/jsx/dom/jsx-runtime are tested in their respective settings
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { jsx, Fragment, createElement } from '..'
import DefaultExport from '..'
import type { RefObject } from '../hooks'
import { useState, useEffect, useLayoutEffect, useCallback, useRef, useMemo } from '../hooks'
import DefaultExport from '.'
import { memo, isValidElement, cloneElement } from '.'
import { render, createElement as createElementForDom, cloneElement as cloneElementForDom } from '.'

describe('Common', () => {
;[createElement, createElementForDom].forEach((createElement) => {
describe('createElement', () => {
it('simple', () => {
const element = createElement('div', { id: 'app' })
expect(element).toEqual(expect.objectContaining({ tag: 'div', props: { id: 'app' } }))
})

it('children', () => {
const element = createElement('div', { id: 'app' }, 'Hello')
expect(element).toEqual(
expect.objectContaining({ tag: 'div', props: { id: 'app', children: 'Hello' } })
)
})

it('multiple children', () => {
const element = createElement('div', { id: 'app' }, 'Hello', 'World')
expect(element).toEqual(
expect.objectContaining({
tag: 'div',
props: { id: 'app', children: ['Hello', 'World'] },
})
)
})

it('key', () => {
const element = createElement('div', { id: 'app', key: 'key' })
expect(element).toEqual(
expect.objectContaining({ tag: 'div', props: { id: 'app' }, key: 'key' })
)
})

it('ref', () => {
const ref = { current: null }
const element = createElement('div', { id: 'app', ref })
expect(element).toEqual(expect.objectContaining({ tag: 'div', props: { id: 'app', ref } }))
expect(element.ref).toBe(ref)
})

it('type', () => {
const element = createElement('div', { id: 'app' })
expect(element.type).toBe('div')
})
})
})
})

describe('DOM', () => {
beforeAll(() => {
global.requestAnimationFrame = (cb) => setTimeout(cb)
Expand Down Expand Up @@ -1475,6 +1522,10 @@ describe('default export', () => {
'useCallback',
'useReducer',
'useDebugValue',
'createRef',
'forwardRef',
'useImperativeHandle',
'useSyncExternalStore',
'use',
'startTransition',
'useTransition',
Expand All @@ -1484,6 +1535,9 @@ describe('default export', () => {
'useMemo',
'useLayoutEffect',
'Suspense',
'Fragment',
'flushSync',
'createPortal',
].forEach((key) => {
it(key, () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
94 changes: 94 additions & 0 deletions src/jsx/hooks/dom.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import {
useViewTransition,
useId,
useDebugValue,
createRef,
forwardRef,
useImperativeHandle,
useSyncExternalStore,
} from '.'

describe('Hooks', () => {
Expand Down Expand Up @@ -470,4 +474,94 @@ describe('Hooks', () => {
expect(spy).not.toBeCalled()
})
})

describe('createRef()', () => {
it('simple', () => {
const ref: { current: HTMLElement | null } = createRef<HTMLDivElement>()
const App = () => {
return <div ref={ref} />
}
render(<App />, root)
expect(root.innerHTML).toBe('<div></div>')
expect(ref.current).toBeInstanceOf(HTMLElement)
})
})

describe('forwardRef()', () => {
it('simple', () => {
const ref: { current: HTMLElement | null } = createRef<HTMLDivElement>()
const App = forwardRef((props, ref) => {
return <div {...props} ref={ref} />
})
render(<App ref={ref} />, root)
expect(root.innerHTML).toBe('<div></div>')
expect(ref.current).toBeInstanceOf(HTMLElement)
})
})

describe('useImperativeHandle()', () => {
it('simple', async () => {
const ref: { current: { focus: () => void } | null } = createRef()
const SubApp = () => {
useImperativeHandle(
ref,
() => ({
focus: () => {
console.log('focus')
},
}),
[]
)
return <div />
}
const App = () => {
const [show, setShow] = useState(true)
return (
<>
{show && <SubApp />}
<button onClick={() => setShow((s) => !s)}>toggle</button>
</>
)
}
render(<App />, root)
expect(ref.current).toBe(null)
await new Promise((r) => setTimeout(r))
expect(ref.current).toEqual({ focus: expect.any(Function) })
root.querySelector('button')?.click()
await new Promise((r) => setTimeout(r))
expect(ref.current).toBe(null)
})
})

describe('useSyncExternalStore()', () => {
it('simple', async () => {
let count = 0
const unsubscribe = vi.fn()
const subscribe = vi.fn(() => unsubscribe)
const getSnapshot = vi.fn(() => count++)
const SubApp = () => {
const count = useSyncExternalStore(subscribe, getSnapshot)
return <div>{count}</div>
}
const App = () => {
const [show, setShow] = useState(true)
return (
<>
{show && <SubApp />}
<button onClick={() => setShow((s) => !s)}>toggle</button>
</>
)
}
render(<App />, root)
expect(root.innerHTML).toBe('<div>0</div><button>toggle</button>')
await new Promise((r) => setTimeout(r))
root.querySelector('button')?.click()
await new Promise((r) => setTimeout(r))
expect(root.innerHTML).toBe('<button>toggle</button>')
expect(unsubscribe).toBeCalled()
root.querySelector('button')?.click()
await new Promise((r) => setTimeout(r))
expect(root.innerHTML).toBe('<div>1</div><button>toggle</button>')
})
})
})
4 changes: 4 additions & 0 deletions src/jsx/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,10 @@ describe('default export', () => {
'useCallback',
'useReducer',
'useDebugValue',
'createRef',
'forwardRef',
'useImperativeHandle',
'useSyncExternalStore',
'use',
'startTransition',
'useTransition',
Expand Down

0 comments on commit ba55e42

Please sign in to comment.