Skip to content

Commit c712452

Browse files
authored
Merge pull request #267 from duyet/chore/ui
feat: add jest for unittest
2 parents 67d2ff0 + bbd3570 commit c712452

File tree

9 files changed

+1793
-22
lines changed

9 files changed

+1793
-22
lines changed

.github/workflows/test.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,41 @@ jobs:
130130
browser: ${{ matrix.browser }}
131131
parallel: true
132132
record: true
133+
134+
135+
unittest:
136+
runs-on: ubuntu-latest
137+
138+
strategy:
139+
fail-fast: false
140+
matrix:
141+
node: [20, 21]
142+
143+
steps:
144+
- name: Checkout
145+
uses: actions/checkout@v4
146+
147+
- name: Setup Node
148+
uses: actions/setup-node@v4
149+
with:
150+
node-version: ${{ matrix.node }}
151+
cache: yarn
152+
153+
- name: Restore cache
154+
uses: actions/cache@v4
155+
with:
156+
path: |
157+
.next/cache
158+
# Generate a new cache whenever packages or source files change.
159+
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
160+
# If source files changed but packages didn't, rebuild from a prior cache.
161+
restore-keys: |
162+
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
163+
164+
- name: Install dependencies
165+
run: |
166+
yarn install
167+
168+
- name: Jest
169+
run: |
170+
yarn test

components/ui/navigation-menu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const NavigationMenuContent = React.forwardRef<
7272
<NavigationMenuPrimitive.Content
7373
ref={ref}
7474
className={cn(
75-
'left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ',
75+
'left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto',
7676
className
7777
)}
7878
{...props}

jest.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
};

lib/clickhouse.test.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { afterAll, expect, jest } from '@jest/globals'
2+
import { getClickHouseHosts, getClient } from './clickhouse'
3+
4+
import { createClient } from '@clickhouse/client'
5+
import { createClient as createClientWeb } from '@clickhouse/client-web'
6+
7+
jest.mock('@clickhouse/client', () => ({
8+
createClient: jest.fn(),
9+
}))
10+
11+
jest.mock('@clickhouse/client-web', () => ({
12+
createClient: jest.fn(),
13+
}))
14+
15+
describe('getClickHouseHosts', () => {
16+
const originalEnv = process.env
17+
18+
beforeEach(() => {
19+
jest.resetModules() // Clears the module cache
20+
process.env = { ...originalEnv } // Restores the original environment variables
21+
})
22+
23+
afterAll(() => {
24+
process.env = originalEnv // Restores the original environment variables
25+
})
26+
27+
it('should return an empty array if CLICKHOUSE_HOST is not set', () => {
28+
delete process.env.CLICKHOUSE_HOST
29+
const result = getClickHouseHosts()
30+
expect(result).toEqual([])
31+
})
32+
33+
it('should return an array with a single host', () => {
34+
process.env.CLICKHOUSE_HOST = 'localhost'
35+
const result = getClickHouseHosts()
36+
expect(result).toEqual(['localhost'])
37+
})
38+
39+
it('should return an array with multiple hosts', () => {
40+
process.env.CLICKHOUSE_HOST = 'host1,host2,host3'
41+
const result = getClickHouseHosts()
42+
expect(result).toEqual(['host1', 'host2', 'host3'])
43+
})
44+
45+
it('should trim hosts and filter out empty values', () => {
46+
process.env.CLICKHOUSE_HOST = ' host1 , , host2 , , host3 '
47+
const result = getClickHouseHosts()
48+
expect(result).toEqual(['host1', 'host2', 'host3'])
49+
})
50+
51+
it('should handle environment variable with only spaces', () => {
52+
process.env.CLICKHOUSE_HOST = ' '
53+
const result = getClickHouseHosts()
54+
expect(result).toEqual([])
55+
})
56+
57+
it('should handle environment variable with empty values', () => {
58+
process.env.CLICKHOUSE_HOST = ',,,'
59+
const result = getClickHouseHosts()
60+
expect(result).toEqual([])
61+
})
62+
})
63+
64+
describe('getClient', () => {
65+
const originalEnv = process.env
66+
67+
beforeEach(() => {
68+
jest.resetModules() // Clears the module cache
69+
process.env = { ...originalEnv } // Restores the original environment variables
70+
})
71+
72+
afterAll(() => {
73+
process.env = originalEnv // Restores the original environment variables
74+
})
75+
76+
it('should create a ClickHouse client using the standard library', () => {
77+
process.env.CLICKHOUSE_HOST = 'localhost'
78+
const mockClient = {}
79+
;(createClient as jest.Mock).mockReturnValue(mockClient)
80+
81+
const client = getClient({ web: false })
82+
83+
expect(createClient).toHaveBeenCalledWith({
84+
host: 'localhost',
85+
username: 'default',
86+
password: '',
87+
clickhouse_settings: {
88+
max_execution_time: 60,
89+
},
90+
})
91+
expect(client).toBe(mockClient)
92+
})
93+
94+
it('should create a ClickHouse client using the web library', () => {
95+
process.env.CLICKHOUSE_HOST = 'localhost'
96+
const mockClient = {}
97+
;(createClientWeb as jest.Mock).mockReturnValue(mockClient)
98+
99+
const client = getClient({ web: true })
100+
101+
expect(createClientWeb).toHaveBeenCalledWith({
102+
host: 'localhost',
103+
username: 'default',
104+
password: '',
105+
clickhouse_settings: {
106+
max_execution_time: 60,
107+
},
108+
})
109+
expect(client).toBe(mockClient)
110+
})
111+
112+
it('should use environment variables for username, password, and max_execution_time', () => {
113+
process.env.CLICKHOUSE_HOST = 'localhost'
114+
process.env.CLICKHOUSE_USER = 'testuser'
115+
process.env.CLICKHOUSE_PASSWORD = 'testpassword'
116+
process.env.CLICKHOUSE_MAX_EXECUTION_TIME = '120'
117+
const mockClient = {}
118+
;(createClient as jest.Mock).mockReturnValue(mockClient)
119+
120+
const client = getClient({ web: false })
121+
122+
expect(createClient).toHaveBeenCalledWith({
123+
host: 'localhost',
124+
username: 'testuser',
125+
password: 'testpassword',
126+
clickhouse_settings: {
127+
max_execution_time: 120,
128+
},
129+
})
130+
expect(client).toBe(mockClient)
131+
})
132+
})

lib/format-readable.test.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { expect } from '@jest/globals'
2+
import { formatReadableQuantity, formatReadableSize } from './format-readable'
3+
4+
describe('formatReadableSize', () => {
5+
it('should format 0 bytes correctly', () => {
6+
const result = formatReadableSize(0)
7+
expect(result).toBe('0 Bytes')
8+
})
9+
10+
it('should format bytes correctly', () => {
11+
const result = formatReadableSize(512)
12+
expect(result).toBe('512 Bytes')
13+
})
14+
15+
it('should format kilobytes correctly', () => {
16+
const result = formatReadableSize(1024)
17+
expect(result).toBe('1 KiB')
18+
})
19+
20+
it('should format megabytes correctly', () => {
21+
const result = formatReadableSize(1048576)
22+
expect(result).toBe('1 MiB')
23+
})
24+
25+
it('should format gigabytes correctly', () => {
26+
const result = formatReadableSize(1073741824)
27+
expect(result).toBe('1 GiB')
28+
})
29+
30+
it('should format with specified decimal places', () => {
31+
const result = formatReadableSize(1500, 2)
32+
expect(result).toBe('1.46 KiB')
33+
})
34+
35+
it('should handle large sizes correctly', () => {
36+
const result = formatReadableSize(1.5e15)
37+
expect(result).toBe('1.3 PiB')
38+
})
39+
})
40+
41+
describe('formatReadableQuantity', () => {
42+
it('should format a number to a human readable short quantity', () => {
43+
const result = formatReadableQuantity(123456789)
44+
expect(result).toBe('123M')
45+
})
46+
47+
it('should format a number to a human readable short quantity explicitly', () => {
48+
const result = formatReadableQuantity(123456789, 'short')
49+
expect(result).toBe('123M')
50+
})
51+
52+
it('should format a number to a human readable long quantity', () => {
53+
const result = formatReadableQuantity(123456789, 'long')
54+
expect(result).toBe('123,456,789')
55+
})
56+
57+
it('should handle small numbers correctly', () => {
58+
const result = formatReadableQuantity(1234)
59+
expect(result).toBe('1.2K')
60+
})
61+
62+
it('should handle small numbers in long format correctly', () => {
63+
const result = formatReadableQuantity(1234, 'long')
64+
expect(result).toBe('1,234')
65+
})
66+
67+
it('should handle zero correctly', () => {
68+
const result = formatReadableQuantity(0)
69+
expect(result).toBe('0')
70+
})
71+
72+
it('should handle negative numbers correctly', () => {
73+
const result = formatReadableQuantity(-123456789)
74+
expect(result).toBe('-123M')
75+
})
76+
77+
it('should handle negative numbers in long format correctly', () => {
78+
const result = formatReadableQuantity(-123456789, 'long')
79+
expect(result).toBe('-123,456,789')
80+
})
81+
})

0 commit comments

Comments
 (0)