import { useRef } from 'react'
import type { PropsWithChildren } from 'react'
import { act, render, renderHook } from '@testing-library/react'
import { afterEach, describe, expect, it } from 'vitest'
import { UnityThemeProvider, useUnityTheme } from './unity-theme-provider'
afterEach(() => {
delete document.documentElement.dataset.uyTheme
})
describe('UnityThemeProvider', () => {
it('sets data-uy-theme on the html element when mounted', () => {
render(
child
,
)
expect(document.documentElement.dataset.uyTheme).toBe('rebrand')
})
it('defaults to legacy when no theme prop is provided', () => {
render(
child
,
)
expect(document.documentElement.dataset.uyTheme).toBe('legacy')
})
it('removes data-uy-theme on unmount', () => {
const { unmount } = render(
child
,
)
expect(document.documentElement.dataset.uyTheme).toBe('rebrand')
unmount()
expect(document.documentElement.dataset.uyTheme).toBeUndefined()
})
it('renders children unchanged', () => {
const { getByText } = render(
hello world
,
)
expect(getByText('hello world')).toBeTruthy()
})
describe('target', () => {
it('sets data-uy-theme on a custom element via CSS selector', () => {
const container = document.createElement('div')
container.id = 'theme-root'
document.body.appendChild(container)
render(
child
,
)
expect(container.dataset.uyTheme).toBe('rebrand')
expect(document.documentElement.dataset.uyTheme).toBeUndefined()
document.body.removeChild(container)
})
it('sets data-uy-theme on a custom element via ref', () => {
const targetEl = document.createElement('section')
document.body.appendChild(targetEl)
function TestComponent() {
const ref = useRef(targetEl)
return (
child
)
}
render()
expect(targetEl.dataset.uyTheme).toBe('rebrand')
expect(document.documentElement.dataset.uyTheme).toBeUndefined()
document.body.removeChild(targetEl)
})
})
})
describe('useUnityTheme', () => {
it('returns the theme value from the provider', () => {
const { result } = renderHook(() => useUnityTheme(), {
wrapper: ({ children }) => (
{children}
),
})
expect(result.current.theme).toBe('rebrand')
})
it('returns "legacy" when used outside a provider', () => {
const { result } = renderHook(() => useUnityTheme())
expect(result.current.theme).toBe('legacy')
})
it('does not throw when used outside a provider', () => {
expect(() => renderHook(() => useUnityTheme())).not.toThrow()
})
it('exposes setTheme to change the theme at runtime', () => {
const wrapper = ({ children }: PropsWithChildren) => (
{children}
)
const { result } = renderHook(() => useUnityTheme(), { wrapper })
expect(result.current.theme).toBe('legacy')
expect(document.documentElement.dataset.uyTheme).toBe('legacy')
act(() => {
result.current.setTheme('rebrand')
})
expect(result.current.theme).toBe('rebrand')
expect(document.documentElement.dataset.uyTheme).toBe('rebrand')
})
it('setTheme is a no-op outside a provider', () => {
const { result } = renderHook(() => useUnityTheme())
expect(() => {
act(() => {
result.current.setTheme('rebrand')
})
}).not.toThrow()
expect(result.current.theme).toBe('legacy')
})
})