Skip to content

Commit 0401330

Browse files
feat:【ActionSheet】测试覆盖提升与组件功能自查
1 parent ac1d4ed commit 0401330

File tree

6 files changed

+926
-3
lines changed

6 files changed

+926
-3
lines changed

site/test-coverage.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
actionSheet: { statements: '5.26%', branches: '0%', functions: '0%', lines: '5.35%' },
2+
actionSheet: { statements: '100%', branches: '96.55%', functions: '100%', lines: '100%' },
33
avatar: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
44
backTop: { statements: '11.9%', branches: '0%', functions: '0%', lines: '12.82%' },
55
badge: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
@@ -24,7 +24,7 @@ module.exports = {
2424
form: { statements: '2.8%', branches: '0%', functions: '0%', lines: '2.96%' },
2525
grid: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
2626
guide: { statements: '3.46%', branches: '0%', functions: '0%', lines: '3.77%' },
27-
hooks: { statements: '69.04%', branches: '34.32%', functions: '71.87%', lines: '70%' },
27+
hooks: { statements: '73.8%', branches: '41.79%', functions: '75%', lines: '74.16%' },
2828
image: { statements: '97.72%', branches: '100%', functions: '92.3%', lines: '97.61%' },
2929
imageViewer: { statements: '8.47%', branches: '2.87%', functions: '0%', lines: '8.84%' },
3030
indexes: { statements: '95.65%', branches: '69.81%', functions: '100%', lines: '96.94%' },
@@ -55,7 +55,7 @@ module.exports = {
5555
steps: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
5656
sticky: { statements: '7.14%', branches: '0%', functions: '0%', lines: '7.27%' },
5757
swipeCell: { statements: '4.42%', branches: '0%', functions: '0%', lines: '4.67%' },
58-
swiper: { statements: '3.77%', branches: '0.9%', functions: '1.4%', lines: '3.89%' },
58+
swiper: { statements: '57.55%', branches: '37.1%', functions: '67.6%', lines: '59.74%' },
5959
switch: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
6060
tabBar: { statements: '10%', branches: '0%', functions: '0%', lines: '10.81%' },
6161
table: { statements: '100%', branches: '90%', functions: '100%', lines: '100%' },
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import React from 'react';
2+
import { describe, it, expect, render, vi, fireEvent, beforeEach } from '@test/utils';
3+
import { ActionSheetGrid } from '../ActionSheetGrid';
4+
5+
describe('ActionSheetGrid', () => {
6+
const mockOnSelected = vi.fn();
7+
8+
beforeEach(() => {
9+
vi.clearAllMocks();
10+
});
11+
12+
describe('props', () => {
13+
it(':items - should render string items', () => {
14+
const items = ['选项一', '选项二', '选项三'];
15+
const { queryByText } = render(<ActionSheetGrid items={items} onSelected={mockOnSelected} />);
16+
17+
expect(queryByText('选项一')).toBeInTheDocument();
18+
expect(queryByText('选项二')).toBeInTheDocument();
19+
expect(queryByText('选项三')).toBeInTheDocument();
20+
});
21+
22+
it(':items - should render object items', () => {
23+
const MockIcon = () => <span>Icon</span>;
24+
const items = [
25+
{ label: '选项一', icon: <MockIcon /> },
26+
{ label: '选项二', badge: { count: 5 } },
27+
];
28+
const { queryByText } = render(<ActionSheetGrid items={items} onSelected={mockOnSelected} />);
29+
30+
expect(queryByText('选项一')).toBeInTheDocument();
31+
expect(queryByText('选项二')).toBeInTheDocument();
32+
});
33+
34+
it(':count - should control items per page', () => {
35+
const items = Array.from({ length: 20 }, (_, i) => `选项${i + 1}`);
36+
const { container } = render(<ActionSheetGrid items={items} count={4} onSelected={mockOnSelected} />);
37+
38+
// Should create grid structure
39+
expect(container.querySelector('.t-action-sheet__grid')).toBeInTheDocument();
40+
});
41+
42+
it(':count - should use default count of 8', () => {
43+
const items = Array.from({ length: 10 }, (_, i) => `选项${i + 1}`);
44+
const { queryByText } = render(<ActionSheetGrid items={items} onSelected={mockOnSelected} />);
45+
46+
expect(queryByText('选项1')).toBeInTheDocument();
47+
expect(queryByText('选项10')).toBeInTheDocument();
48+
});
49+
50+
it('should handle empty items array', () => {
51+
const { container } = render(<ActionSheetGrid items={[]} onSelected={mockOnSelected} />);
52+
53+
expect(container.querySelector('.t-action-sheet__grid')).toBeInTheDocument();
54+
});
55+
56+
it('should handle undefined items', () => {
57+
const { container } = render(<ActionSheetGrid onSelected={mockOnSelected} />);
58+
59+
expect(container.querySelector('.t-action-sheet__grid')).toBeInTheDocument();
60+
});
61+
});
62+
63+
describe('pagination', () => {
64+
it('should create multiple pages when items exceed count', () => {
65+
const items = Array.from({ length: 20 }, (_, i) => `选项${i + 1}`);
66+
const { container } = render(<ActionSheetGrid items={items} count={8} onSelected={mockOnSelected} />);
67+
68+
const grid = container.querySelector('.t-action-sheet__grid');
69+
expect(grid).toHaveClass('t-action-sheet__grid--swiper');
70+
expect(grid).toHaveClass('t-action-sheet__dots');
71+
});
72+
73+
it('should not show pagination for single page', () => {
74+
const items = Array.from({ length: 4 }, (_, i) => `选项${i + 1}`);
75+
const { container } = render(<ActionSheetGrid items={items} count={8} onSelected={mockOnSelected} />);
76+
77+
const grid = container.querySelector('.t-action-sheet__grid');
78+
expect(grid).not.toHaveClass('t-action-sheet__grid--swiper');
79+
expect(grid).not.toHaveClass('t-action-sheet__dots');
80+
});
81+
});
82+
83+
describe('events', () => {
84+
it(':onSelected - should call onSelected with correct index', () => {
85+
const items = ['选项一', '选项二', '选项三'];
86+
const { container } = render(<ActionSheetGrid items={items} onSelected={mockOnSelected} />);
87+
88+
// Find grid items and click them
89+
const gridItems = container.querySelectorAll('.t-grid-item');
90+
if (gridItems.length > 0) {
91+
fireEvent.click(gridItems[0]);
92+
expect(mockOnSelected).toHaveBeenCalledWith(0);
93+
}
94+
});
95+
96+
it('should handle onSelected not provided', () => {
97+
const items = ['选项一'];
98+
const { container } = render(<ActionSheetGrid items={items} />);
99+
100+
expect(() => {
101+
const gridItem = container.querySelector('.t-grid-item');
102+
if (gridItem) {
103+
fireEvent.click(gridItem);
104+
}
105+
}).not.toThrow();
106+
});
107+
});
108+
109+
describe('swiper configuration', () => {
110+
it('should configure swiper for multiple pages', () => {
111+
const items = Array.from({ length: 20 }, (_, i) => `选项${i + 1}`);
112+
const { container } = render(<ActionSheetGrid items={items} count={8} onSelected={mockOnSelected} />);
113+
114+
const swiper = container.querySelector('.t-swiper');
115+
expect(swiper).toBeInTheDocument();
116+
});
117+
118+
it('should configure swiper for single page', () => {
119+
const items = Array.from({ length: 4 }, (_, i) => `选项${i + 1}`);
120+
const { container } = render(<ActionSheetGrid items={items} count={8} onSelected={mockOnSelected} />);
121+
122+
const swiper = container.querySelector('.t-swiper');
123+
expect(swiper).toBeInTheDocument();
124+
});
125+
});
126+
127+
describe('grid layout', () => {
128+
it('should render items in grid layout', () => {
129+
const items = Array.from({ length: 6 }, (_, i) => `选项${i + 1}`);
130+
const { container } = render(<ActionSheetGrid items={items} count={8} onSelected={mockOnSelected} />);
131+
132+
const grid = container.querySelector('.t-grid');
133+
expect(grid).toBeInTheDocument();
134+
});
135+
136+
it('should handle different count values', () => {
137+
const items = Array.from({ length: 10 }, (_, i) => `选项${i + 1}`);
138+
const { container } = render(<ActionSheetGrid items={items} count={6} onSelected={mockOnSelected} />);
139+
140+
const grid = container.querySelector('.t-grid');
141+
expect(grid).toBeInTheDocument();
142+
});
143+
});
144+
});
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import React from 'react';
2+
import { describe, it, expect, render, vi, fireEvent, screen, beforeEach } from '@test/utils';
3+
import { ActionSheetList } from '../ActionSheetList';
4+
5+
describe('ActionSheetList', () => {
6+
const mockOnSelected = vi.fn();
7+
8+
beforeEach(() => {
9+
vi.clearAllMocks();
10+
});
11+
12+
describe('props', () => {
13+
it(':items - should render string items', () => {
14+
const items = ['选项一', '选项二', '选项三'];
15+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
16+
17+
expect(queryByText('选项一')).toBeInTheDocument();
18+
expect(queryByText('选项二')).toBeInTheDocument();
19+
expect(queryByText('选项三')).toBeInTheDocument();
20+
});
21+
22+
it(':items - should render object items', () => {
23+
const items = [
24+
{ label: '选项一', color: '#ff0000' },
25+
{ label: '选项二', color: '#00ff00', disabled: true },
26+
];
27+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
28+
29+
expect(queryByText('选项一')).toBeInTheDocument();
30+
expect(queryByText('选项二')).toBeInTheDocument();
31+
});
32+
33+
it(':items - should render items with badges', () => {
34+
const items = [
35+
{
36+
label: '带徽标选项',
37+
badge: { count: 5, dot: false }
38+
},
39+
{
40+
label: '红点选项',
41+
badge: { dot: true }
42+
},
43+
];
44+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
45+
46+
expect(queryByText('带徽标选项')).toBeInTheDocument();
47+
expect(queryByText('红点选项')).toBeInTheDocument();
48+
});
49+
50+
it(':items - should render items with icons', () => {
51+
const MockIcon = () => <span data-testid="mock-icon">Icon</span>;
52+
const items = [
53+
{ label: '带图标选项', icon: <MockIcon /> },
54+
];
55+
const { queryByText, queryByTestId } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
56+
57+
expect(queryByText('带图标选项')).toBeInTheDocument();
58+
expect(queryByTestId('mock-icon')).toBeInTheDocument();
59+
});
60+
61+
it(':align - should apply left alignment', () => {
62+
const items = ['选项一'];
63+
const { container } = render(<ActionSheetList items={items} align="left" onSelected={mockOnSelected} />);
64+
65+
expect(container.querySelector('.t-action-sheet__list-item--left')).toBeInTheDocument();
66+
});
67+
68+
it('should handle empty items array', () => {
69+
const { container } = render(<ActionSheetList items={[]} onSelected={mockOnSelected} />);
70+
71+
const list = container.querySelector('.t-action-sheet__list');
72+
expect(list).toBeInTheDocument();
73+
expect(list?.children).toHaveLength(0);
74+
});
75+
76+
it('should handle undefined items', () => {
77+
const { container } = render(<ActionSheetList onSelected={mockOnSelected} />);
78+
79+
const list = container.querySelector('.t-action-sheet__list');
80+
expect(list).toBeInTheDocument();
81+
expect(list?.children).toHaveLength(0);
82+
});
83+
});
84+
85+
describe('events', () => {
86+
it(':onSelected - should call onSelected when item is clicked', () => {
87+
const items = ['选项一', '选项二'];
88+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
89+
90+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
91+
fireEvent.click(buttons[0]);
92+
expect(mockOnSelected).toHaveBeenCalledWith(0);
93+
94+
fireEvent.click(buttons[1]);
95+
expect(mockOnSelected).toHaveBeenCalledWith(1);
96+
});
97+
98+
it(':onSelected - should not call onSelected when disabled item is clicked', () => {
99+
const items = [
100+
{ label: '正常选项', disabled: false },
101+
{ label: '禁用选项', disabled: true },
102+
];
103+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
104+
105+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
106+
107+
// Disabled button should not trigger callback
108+
fireEvent.click(buttons[1]);
109+
expect(mockOnSelected).not.toHaveBeenCalled();
110+
111+
// Normal button should trigger callback
112+
fireEvent.click(buttons[0]);
113+
expect(mockOnSelected).toHaveBeenCalledWith(0);
114+
});
115+
116+
it('should handle onSelected not provided', () => {
117+
const items = ['选项一'];
118+
const { container } = render(<ActionSheetList items={items} />);
119+
120+
expect(() => {
121+
const button = container.querySelector('.t-action-sheet__list-item');
122+
if (button) {
123+
fireEvent.click(button);
124+
}
125+
}).not.toThrow();
126+
});
127+
});
128+
129+
describe('styling', () => {
130+
it('should apply custom colors to items', () => {
131+
const items = [
132+
{ label: '红色选项', color: '#ff0000' },
133+
{ label: '蓝色选项', color: '#0000ff' },
134+
];
135+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
136+
137+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
138+
expect(buttons[0]).toHaveStyle({ color: '#ff0000' });
139+
expect(buttons[1]).toHaveStyle({ color: '#0000ff' });
140+
});
141+
142+
it('should render disabled items with proper styling', () => {
143+
const items = [
144+
{ label: '禁用选项', disabled: true },
145+
];
146+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
147+
148+
const disabledButton = container.querySelector('.t-action-sheet__list-item');
149+
expect(disabledButton).toBeDisabled();
150+
});
151+
});
152+
153+
describe('badge functionality', () => {
154+
it('should render badge with count', () => {
155+
const items = [
156+
{
157+
label: '消息',
158+
badge: { count: 99, maxCount: 99 }
159+
},
160+
];
161+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
162+
163+
expect(queryByText('消息')).toBeInTheDocument();
164+
});
165+
166+
it('should render badge with dot', () => {
167+
const items = [
168+
{
169+
label: '通知',
170+
badge: { dot: true }
171+
},
172+
];
173+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
174+
175+
expect(queryByText('通知')).toBeInTheDocument();
176+
});
177+
178+
it('should render badge with custom content', () => {
179+
const items = [
180+
{
181+
label: '自定义',
182+
badge: { content: 'NEW', size: 'medium' as const }
183+
},
184+
];
185+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
186+
187+
expect(container.querySelector('.t-badge')).toBeInTheDocument();
188+
});
189+
});
190+
});

0 commit comments

Comments
 (0)