Skip to content

Commit 5a6219c

Browse files
authored
chore: add unit test to high frequency hooks (langgenius#17617)
1 parent 4124e80 commit 5a6219c

File tree

3 files changed

+185
-2
lines changed

3 files changed

+185
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { renderHook } from '@testing-library/react'
2+
import { useLanguage } from './hooks'
3+
import { useContext } from 'use-context-selector'
4+
import { after } from 'node:test'
5+
6+
jest.mock('swr', () => ({
7+
__esModule: true,
8+
default: jest.fn(), // mock useSWR
9+
useSWRConfig: jest.fn(),
10+
}))
11+
12+
// mock use-context-selector
13+
jest.mock('use-context-selector', () => ({
14+
useContext: jest.fn(),
15+
}))
16+
17+
// mock service/common functions
18+
jest.mock('@/service/common', () => ({
19+
fetchDefaultModal: jest.fn(),
20+
fetchModelList: jest.fn(),
21+
fetchModelProviderCredentials: jest.fn(),
22+
fetchModelProviders: jest.fn(),
23+
getPayUrl: jest.fn(),
24+
}))
25+
26+
// mock context hooks
27+
jest.mock('@/context/i18n', () => ({
28+
__esModule: true,
29+
default: jest.fn(),
30+
}))
31+
32+
jest.mock('@/context/provider-context', () => ({
33+
useProviderContext: jest.fn(),
34+
}))
35+
36+
jest.mock('@/context/modal-context', () => ({
37+
useModalContextSelector: jest.fn(),
38+
}))
39+
40+
jest.mock('@/context/event-emitter', () => ({
41+
useEventEmitterContextContext: jest.fn(),
42+
}))
43+
44+
// mock plugins
45+
jest.mock('@/app/components/plugins/marketplace/hooks', () => ({
46+
useMarketplacePlugins: jest.fn(),
47+
}))
48+
49+
jest.mock('@/app/components/plugins/marketplace/utils', () => ({
50+
getMarketplacePluginsByCollectionId: jest.fn(),
51+
}))
52+
53+
jest.mock('./provider-added-card', () => {
54+
// eslint-disable-next-line no-labels, ts/no-unused-expressions
55+
UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST: []
56+
})
57+
58+
after(() => {
59+
jest.resetModules()
60+
jest.clearAllMocks()
61+
})
62+
63+
describe('useLanguage', () => {
64+
it('should replace hyphen with underscore in locale', () => {
65+
(useContext as jest.Mock).mockReturnValue({
66+
locale: 'en-US',
67+
})
68+
const { result } = renderHook(() => useLanguage())
69+
expect(result.current).toBe('en_US')
70+
})
71+
72+
it('should return locale as is if no hyphen exists', () => {
73+
(useContext as jest.Mock).mockReturnValue({
74+
locale: 'enUS',
75+
})
76+
77+
const { result } = renderHook(() => useLanguage())
78+
expect(result.current).toBe('enUS')
79+
})
80+
81+
it('should handle multiple hyphens', () => {
82+
// Mock the I18n context return value
83+
(useContext as jest.Mock).mockReturnValue({
84+
locale: 'zh-Hans-CN',
85+
})
86+
87+
const { result } = renderHook(() => useLanguage())
88+
expect(result.current).toBe('zh_Hans-CN')
89+
})
90+
})

web/hooks/use-breakpoints.spec.ts

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { act, renderHook } from '@testing-library/react'
2+
import useBreakpoints, { MediaType } from './use-breakpoints'
3+
4+
describe('useBreakpoints', () => {
5+
const originalInnerWidth = window.innerWidth
6+
7+
// Mock the window resize event
8+
const fireResize = (width: number) => {
9+
window.innerWidth = width
10+
act(() => {
11+
window.dispatchEvent(new Event('resize'))
12+
})
13+
}
14+
15+
// Restore the original innerWidth after tests
16+
afterAll(() => {
17+
window.innerWidth = originalInnerWidth
18+
})
19+
20+
it('should return mobile for width <= 640px', () => {
21+
// Mock window.innerWidth for mobile
22+
Object.defineProperty(window, 'innerWidth', {
23+
writable: true,
24+
configurable: true,
25+
value: 640,
26+
})
27+
28+
const { result } = renderHook(() => useBreakpoints())
29+
expect(result.current).toBe(MediaType.mobile)
30+
})
31+
32+
it('should return tablet for width > 640px and <= 768px', () => {
33+
// Mock window.innerWidth for tablet
34+
Object.defineProperty(window, 'innerWidth', {
35+
writable: true,
36+
configurable: true,
37+
value: 768,
38+
})
39+
40+
const { result } = renderHook(() => useBreakpoints())
41+
expect(result.current).toBe(MediaType.tablet)
42+
})
43+
44+
it('should return pc for width > 768px', () => {
45+
// Mock window.innerWidth for pc
46+
Object.defineProperty(window, 'innerWidth', {
47+
writable: true,
48+
configurable: true,
49+
value: 1024,
50+
})
51+
52+
const { result } = renderHook(() => useBreakpoints())
53+
expect(result.current).toBe(MediaType.pc)
54+
})
55+
56+
it('should update media type when window resizes', () => {
57+
// Start with desktop
58+
Object.defineProperty(window, 'innerWidth', {
59+
writable: true,
60+
configurable: true,
61+
value: 1024,
62+
})
63+
64+
const { result } = renderHook(() => useBreakpoints())
65+
expect(result.current).toBe(MediaType.pc)
66+
67+
// Resize to tablet
68+
fireResize(768)
69+
expect(result.current).toBe(MediaType.tablet)
70+
71+
// Resize to mobile
72+
fireResize(600)
73+
expect(result.current).toBe(MediaType.mobile)
74+
})
75+
76+
it('should clean up event listeners on unmount', () => {
77+
// Spy on addEventListener and removeEventListener
78+
const addEventListenerSpy = jest.spyOn(window, 'addEventListener')
79+
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener')
80+
81+
const { unmount } = renderHook(() => useBreakpoints())
82+
83+
// Unmount should trigger cleanup
84+
unmount()
85+
86+
expect(addEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function))
87+
expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', expect.any(Function))
88+
89+
// Clean up spies
90+
addEventListenerSpy.mockRestore()
91+
removeEventListenerSpy.mockRestore()
92+
})
93+
})

web/jest.config.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const config: Config = {
9898

9999
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
100100
moduleNameMapper: {
101-
'^@/components/(.*)$': '<rootDir>/components/$1',
101+
'^@/(.*)$': '<rootDir>/$1',
102102
'^lodash-es$': 'lodash',
103103
},
104104

@@ -133,7 +133,7 @@ const config: Config = {
133133
// restoreMocks: false,
134134

135135
// The root directory that Jest should scan for tests and modules within
136-
// rootDir: undefined,
136+
rootDir: './',
137137

138138
// A list of paths to directories that Jest should use to search for files in
139139
// roots: [

0 commit comments

Comments
 (0)