Skip to content

Commit 829d517

Browse files
authored
refactor: rewrite tests to use renderHook when possible (#285)
1 parent 615b754 commit 829d517

1 file changed

Lines changed: 79 additions & 81 deletions

File tree

next-themes/__tests__/index.test.tsx

Lines changed: 79 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// @vitest-environment jsdom
22

33
import * as React from 'react'
4-
import { act, render, screen } from '@testing-library/react'
4+
import { act, render, renderHook, screen } from '@testing-library/react'
55
import { vi, beforeAll, beforeEach, afterEach, afterAll, describe, test, it, expect } from 'vitest'
66
import { cleanup } from '@testing-library/react'
77

88
import { ThemeProvider, useTheme } from '../src/index'
9+
import { ThemeProviderProps } from '../src/types'
910

1011
let originalLocalStorage: Storage
1112
const localStorageMock: Storage = (() => {
@@ -90,86 +91,81 @@ afterAll(() => {
9091
window.localStorage = originalLocalStorage
9192
})
9293

94+
function makeWrapper(props: ThemeProviderProps) {
95+
return ({ children }: { children: React.ReactNode }) => (
96+
<ThemeProvider {...props}>{children}</ThemeProvider>
97+
)
98+
}
99+
93100
describe('defaultTheme', () => {
94-
test('should return system when no default-theme is set', () => {
95-
render(
96-
<ThemeProvider>
97-
<HelperComponent />
98-
</ThemeProvider>
99-
)
100-
101-
expect(screen.getByTestId('theme').textContent).toBe('system')
101+
test('should return system-theme when no default-theme is set', () => {
102+
setDeviceTheme('light')
103+
104+
const { result } = renderHook(() => useTheme(), {
105+
wrapper: makeWrapper({})
106+
})
107+
expect(result.current.theme).toBe('system')
108+
expect(result.current.systemTheme).toBe('light')
109+
expect(result.current.resolvedTheme).toBe('light')
102110
})
103111

104112
test('should return light when no default-theme is set and enableSystem=false', () => {
105-
render(
106-
<ThemeProvider enableSystem={false}>
107-
<HelperComponent />
108-
</ThemeProvider>
109-
)
113+
const { result } = renderHook(() => useTheme(), {
114+
wrapper: makeWrapper({ enableSystem: false })
115+
})
110116

111-
expect(screen.getByTestId('theme').textContent).toBe('light')
117+
expect(result.current.theme).toBe('light')
118+
expect(result.current.resolvedTheme).toBe('light')
112119
})
113120

114121
test('should return light when light is set as default-theme', () => {
115-
render(
116-
<ThemeProvider defaultTheme="light">
117-
<HelperComponent />
118-
</ThemeProvider>
119-
)
122+
const { result } = renderHook(() => useTheme(), {
123+
wrapper: makeWrapper({ defaultTheme: 'light' })
124+
})
120125

121-
expect(screen.getByTestId('theme').textContent).toBe('light')
126+
expect(result.current.theme).toBe('light')
127+
expect(result.current.resolvedTheme).toBe('light')
122128
})
123129

124130
test('should return dark when dark is set as default-theme', () => {
125-
render(
126-
<ThemeProvider defaultTheme="dark">
127-
<HelperComponent />
128-
</ThemeProvider>
129-
)
130-
131-
expect(screen.getByTestId('theme').textContent).toBe('dark')
131+
const { result } = renderHook(() => useTheme(), {
132+
wrapper: makeWrapper({ defaultTheme: 'dark' })
133+
})
134+
expect(result.current.theme).toBe('dark')
135+
expect(result.current.resolvedTheme).toBe('dark')
132136
})
133137
})
134138

135139
describe('provider', () => {
136140
it('ignores nested ThemeProviders', () => {
137-
act(() => {
138-
render(
141+
const { result } = renderHook(() => useTheme(), {
142+
wrapper: ({ children }) => (
139143
<ThemeProvider defaultTheme="dark">
140-
<ThemeProvider defaultTheme="light">
141-
<HelperComponent />
142-
</ThemeProvider>
144+
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>
143145
</ThemeProvider>
144146
)
145147
})
146148

147-
expect(screen.getByTestId('theme').textContent).toBe('dark')
149+
expect(result.current.theme).toBe('dark')
150+
expect(result.current.resolvedTheme).toBe('dark')
148151
})
149152
})
150153

151154
describe('storage', () => {
152155
test('should not set localStorage with default value', () => {
153-
act(() => {
154-
render(
155-
<ThemeProvider defaultTheme="dark">
156-
<HelperComponent />
157-
</ThemeProvider>
158-
)
156+
renderHook(() => useTheme(), {
157+
wrapper: makeWrapper({ defaultTheme: 'dark' })
159158
})
160159

161160
expect(window.localStorage.setItem).toBeCalledTimes(0)
162161
expect(window.localStorage.getItem('theme')).toBeNull()
163162
})
164163

165164
test('should set localStorage when switching themes', () => {
166-
act(() => {
167-
render(
168-
<ThemeProvider>
169-
<HelperComponent forceSetTheme="dark" />
170-
</ThemeProvider>
171-
)
165+
const { result } = renderHook(() => useTheme(), {
166+
wrapper: makeWrapper({})
172167
})
168+
result.current.setTheme('dark')
173169

174170
expect(window.localStorage.setItem).toBeCalledTimes(1)
175171
expect(window.localStorage.getItem('theme')).toBe('dark')
@@ -290,47 +286,40 @@ describe('forcedTheme', () => {
290286
test('should render saved theme when no forcedTheme is set', () => {
291287
localStorageMock.setItem('theme', 'dark')
292288

293-
render(
294-
<ThemeProvider>
295-
<HelperComponent />
296-
</ThemeProvider>
297-
)
289+
const { result } = renderHook(() => useTheme(), {
290+
wrapper: makeWrapper({})
291+
})
298292

299-
expect(screen.getByTestId('theme').textContent).toBe('dark')
300-
expect(screen.getByTestId('forcedTheme').textContent).toBe('')
293+
expect(result.current.theme).toBe('dark')
294+
expect(result.current.forcedTheme).toBeUndefined()
301295
})
302296

303297
test('should render light theme when forcedTheme is set to light', () => {
304298
localStorageMock.setItem('theme', 'dark')
305299

306-
act(() => {
307-
render(
308-
<ThemeProvider forcedTheme="light">
309-
<HelperComponent />
310-
</ThemeProvider>
311-
)
300+
const { result } = renderHook(() => useTheme(), {
301+
wrapper: makeWrapper({
302+
forcedTheme: 'light'
303+
})
312304
})
313305

314-
expect(screen.getByTestId('theme').textContent).toBe('dark')
315-
expect(screen.getByTestId('forcedTheme').textContent).toBe('light')
306+
expect(result.current.theme).toBe('dark')
307+
expect(result.current.forcedTheme).toBe('light')
316308
})
317309
})
318310

319-
describe('system', () => {
311+
describe('system theme', () => {
320312
test('resolved theme should be set', () => {
321313
setDeviceTheme('dark')
322314

323-
act(() => {
324-
render(
325-
<ThemeProvider>
326-
<HelperComponent />
327-
</ThemeProvider>
328-
)
315+
const { result } = renderHook(() => useTheme(), {
316+
wrapper: makeWrapper({})
329317
})
330318

331-
expect(screen.getByTestId('theme').textContent).toBe('system')
332-
expect(screen.getByTestId('forcedTheme').textContent).toBe('')
333-
expect(screen.getByTestId('resolvedTheme').textContent).toBe('dark')
319+
expect(result.current.theme).toBe('system')
320+
expect(result.current.systemTheme).toBe('dark')
321+
expect(result.current.resolvedTheme).toBe('dark')
322+
expect(result.current.forcedTheme).toBeUndefined()
334323
})
335324

336325
test('system theme should be set, even if theme is not system', () => {
@@ -353,18 +342,14 @@ describe('system', () => {
353342
test('system theme should not be set if enableSystem is false', () => {
354343
setDeviceTheme('dark')
355344

356-
act(() => {
357-
render(
358-
<ThemeProvider defaultTheme="light" enableSystem={false}>
359-
<HelperComponent />
360-
</ThemeProvider>
361-
)
345+
const { result } = renderHook(() => useTheme(), {
346+
wrapper: makeWrapper({ enableSystem: false, defaultTheme: 'light' })
362347
})
363348

364-
expect(screen.getByTestId('theme').textContent).toBe('light')
365-
expect(screen.getByTestId('forcedTheme').textContent).toBe('')
366-
expect(screen.getByTestId('resolvedTheme').textContent).toBe('light')
367-
expect(screen.getByTestId('systemTheme').textContent).toBe('')
349+
expect(result.current.theme).toBe('light')
350+
expect(result.current.systemTheme).toBeUndefined()
351+
expect(result.current.resolvedTheme).toBe('light')
352+
expect(result.current.forcedTheme).toBeUndefined()
368353
})
369354
})
370355

@@ -407,3 +392,16 @@ describe('color-scheme', () => {
407392
expect(document.documentElement.style.colorScheme).toBe('dark')
408393
})
409394
})
395+
396+
describe('setTheme', () => {
397+
test('setTheme(<literal>)', () => {
398+
const { result, rerender } = renderHook(() => useTheme(), {
399+
wrapper: ({ children }) => <ThemeProvider defaultTheme="light">{children}</ThemeProvider>
400+
})
401+
expect(result.current?.setTheme).toBeDefined()
402+
expect(result.current.resolvedTheme).toBe('light')
403+
result.current.setTheme('dark')
404+
rerender()
405+
expect(result.current.resolvedTheme).toBe('dark')
406+
})
407+
})

0 commit comments

Comments
 (0)