Skip to content

Commit 22848d5

Browse files
feat:【ActionSheet】测试覆盖提升与组件功能自查 (#777)
* feat:【ActionSheet】测试覆盖提升与组件功能自查 * fix: fix lint --------- Co-authored-by: anlyyao <[email protected]>
1 parent 5420435 commit 22848d5

File tree

7 files changed

+951
-31
lines changed

7 files changed

+951
-31
lines changed

site/test-coverage.js

Lines changed: 5 additions & 4 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: '100%', branches: '100%', functions: '100%', lines: '100%' },
55
badge: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
@@ -24,9 +24,9 @@ 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: '70.7%', branches: '44.7%', functions: '73.68%', lines: '70.66%' },
2828
image: { statements: '97.72%', branches: '100%', functions: '92.3%', lines: '97.61%' },
29-
imageViewer: { statements: '8.47%', branches: '2.87%', functions: '0%', lines: '8.84%' },
29+
imageViewer: { statements: '8.33%', branches: '2.83%', functions: '0%', lines: '8.69%' },
3030
indexes: { statements: '95.65%', branches: '69.81%', functions: '100%', lines: '96.94%' },
3131
input: { statements: '3.57%', branches: '0%', functions: '0%', lines: '3.7%' },
3232
layout: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
@@ -55,7 +55,7 @@ module.exports = {
5555
steps: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
5656
sticky: { statements: '67.85%', branches: '30%', functions: '85.71%', lines: '69.09%' },
5757
swipeCell: { statements: '100%', branches: '100%', functions: '100%', lines: '100%' },
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%' },
@@ -65,4 +65,5 @@ module.exports = {
6565
toast: { statements: '98.73%', branches: '100%', functions: '94.11%', lines: '98.66%' },
6666
treeSelect: { statements: '5.4%', branches: '0%', functions: '0%', lines: '5.88%' },
6767
upload: { statements: '4.28%', branches: '0%', functions: '0%', lines: '4.47%' },
68+
watermark: { statements: '96%', branches: '74.46%', functions: '100%', lines: '98.59%' },
6869
};
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: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import React from 'react';
2+
import { describe, it, expect, render, vi, fireEvent, 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 = [{ label: '带图标选项', icon: <MockIcon /> }];
53+
const { queryByText, queryByTestId } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
54+
55+
expect(queryByText('带图标选项')).toBeInTheDocument();
56+
expect(queryByTestId('mock-icon')).toBeInTheDocument();
57+
});
58+
59+
it(':align - should apply left alignment', () => {
60+
const items = ['选项一'];
61+
const { container } = render(<ActionSheetList items={items} align="left" onSelected={mockOnSelected} />);
62+
63+
expect(container.querySelector('.t-action-sheet__list-item--left')).toBeInTheDocument();
64+
});
65+
66+
it('should handle empty items array', () => {
67+
const { container } = render(<ActionSheetList items={[]} onSelected={mockOnSelected} />);
68+
69+
const list = container.querySelector('.t-action-sheet__list');
70+
expect(list).toBeInTheDocument();
71+
expect(list?.children).toHaveLength(0);
72+
});
73+
74+
it('should handle undefined items', () => {
75+
const { container } = render(<ActionSheetList onSelected={mockOnSelected} />);
76+
77+
const list = container.querySelector('.t-action-sheet__list');
78+
expect(list).toBeInTheDocument();
79+
expect(list?.children).toHaveLength(0);
80+
});
81+
});
82+
83+
describe('events', () => {
84+
it(':onSelected - should call onSelected when item is clicked', () => {
85+
const items = ['选项一', '选项二'];
86+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
87+
88+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
89+
fireEvent.click(buttons[0]);
90+
expect(mockOnSelected).toHaveBeenCalledWith(0);
91+
92+
fireEvent.click(buttons[1]);
93+
expect(mockOnSelected).toHaveBeenCalledWith(1);
94+
});
95+
96+
it(':onSelected - should not call onSelected when disabled item is clicked', () => {
97+
const items = [
98+
{ label: '正常选项', disabled: false },
99+
{ label: '禁用选项', disabled: true },
100+
];
101+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
102+
103+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
104+
105+
// Disabled button should not trigger callback
106+
fireEvent.click(buttons[1]);
107+
expect(mockOnSelected).not.toHaveBeenCalled();
108+
109+
// Normal button should trigger callback
110+
fireEvent.click(buttons[0]);
111+
expect(mockOnSelected).toHaveBeenCalledWith(0);
112+
});
113+
114+
it('should handle onSelected not provided', () => {
115+
const items = ['选项一'];
116+
const { container } = render(<ActionSheetList items={items} />);
117+
118+
expect(() => {
119+
const button = container.querySelector('.t-action-sheet__list-item');
120+
if (button) {
121+
fireEvent.click(button);
122+
}
123+
}).not.toThrow();
124+
});
125+
});
126+
127+
describe('styling', () => {
128+
it('should apply custom colors to items', () => {
129+
const items = [
130+
{ label: '红色选项', color: '#ff0000' },
131+
{ label: '蓝色选项', color: '#0000ff' },
132+
];
133+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
134+
135+
const buttons = container.querySelectorAll('.t-action-sheet__list-item');
136+
expect(buttons[0]).toHaveStyle({ color: '#ff0000' });
137+
expect(buttons[1]).toHaveStyle({ color: '#0000ff' });
138+
});
139+
140+
it('should render disabled items with proper styling', () => {
141+
const items = [{ label: '禁用选项', disabled: true }];
142+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
143+
144+
const disabledButton = container.querySelector('.t-action-sheet__list-item');
145+
expect(disabledButton).toBeDisabled();
146+
});
147+
});
148+
149+
describe('badge functionality', () => {
150+
it('should render badge with count', () => {
151+
const items = [
152+
{
153+
label: '消息',
154+
badge: { count: 99, maxCount: 99 },
155+
},
156+
];
157+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
158+
159+
expect(queryByText('消息')).toBeInTheDocument();
160+
});
161+
162+
it('should render badge with dot', () => {
163+
const items = [
164+
{
165+
label: '通知',
166+
badge: { dot: true },
167+
},
168+
];
169+
const { queryByText } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
170+
171+
expect(queryByText('通知')).toBeInTheDocument();
172+
});
173+
174+
it('should render badge with custom content', () => {
175+
const items = [
176+
{
177+
label: '自定义',
178+
badge: { content: 'NEW', size: 'medium' as const },
179+
},
180+
];
181+
const { container } = render(<ActionSheetList items={items} onSelected={mockOnSelected} />);
182+
183+
expect(container.querySelector('.t-badge')).toBeInTheDocument();
184+
});
185+
});
186+
});

0 commit comments

Comments
 (0)