-
Notifications
You must be signed in to change notification settings - Fork 0
test: add component test case #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Caution Review failedThe pull request is closed. Walkthrough该 PR 大量新增组件与工具函数的单元测试;对少量源码做调整:ConfigProvider 将 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor App
participant ConfigProvider
participant ConfigContext as ConfigContext.Provider
participant Child as Consumer
App->>ConfigProvider: render({ prefixCls?, iconPrefix?, size?, componentConfig? })
ConfigProvider->>ConfigContext: value = providerValue (仅排除 children)
Note right of ConfigContext: providerValue 现在包含 iconPrefix
Child->>ConfigContext: useContext()
ConfigContext-->>Child: { prefixCls, iconPrefix, size, componentConfig }
sequenceDiagram
autonumber
actor App
participant Tooltip
participant Popup
App->>Tooltip: render({ theme?, rootClassName?, classNames?, ... })
Tooltip->>Tooltip: useMergeProps -> { theme, rootClassName, classNames, ... }
Tooltip->>Popup: render with clsx(prefixCls-tooltip, prefixCls-tooltip-${theme}, rootClassName)
Popup-->>App: DOM with merged root classes
Note over Tooltip,Popup: rootClassName 被合成并透传到 Popup 根节点
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Nitpick comments (52)
packages/sqi-web/src/checkbox/type.ts (1)
35-35
: 拓宽 options 类型对混合数组更友好,LGTM;可进一步兼容只读数组当前改动允许 (string | number)[],与 CheckboxGroup 内部格式化逻辑吻合。建议进一步支持只读数组以提升类型适配度:
- options?: CheckboxOptions[] | string[] | number[] | (string | number)[]; + options?: readonly (CheckboxOptions | string | number)[];packages/sqi-web/src/grid/__tests__/util.ts (1)
3-17
: 为 matchMedia 提供 mock 是必要的;建议可配置与还原方法以避免跨用例污染改进点:
- 将 defineProperty 的 configurable 设为 true,便于用例后还原;
- 导出 resetMockMatchMedia 以恢复原始实现;
- 可选:提供触发 change 的辅助方法,便于测试响应式断点逻辑。
示例调整:
export const mockMatchMedia = () => { - Object.defineProperty(window, 'matchMedia', { - writable: true, - value: vi.fn().mockImplementation((query) => ({ + const impl = vi.fn().mockImplementation((query) => ({ matches: false, media: query, onchange: null, addListener: vi.fn(), // deprecated removeListener: vi.fn(), // deprecated addEventListener: vi.fn(), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), - })), - }); + })); + Object.defineProperty(window, 'matchMedia', { writable: true, configurable: true, value: impl }); + return impl; }; + +export const resetMockMatchMedia = () => { + // 若环境原本无 matchMedia,可删除;若有,则应在 mock 前缓存原实现并还原 + // 这里以删除为例,具体策略视项目测试环境而定 + // @ts-expect-error + delete window.matchMedia; +};packages/sqi-web/src/grid/__tests__/row.test.tsx (1)
1-89
: 用例覆盖面良好;建议改进 afterEach 及断言可读性
- 仅调用 vi.clearAllMocks 不会还原被替换的全局实现,建议在 afterEach 配合 resetMockMatchMedia 或 vi.restoreAllMocks,避免跨测试污染。(需配合 util.ts 导出重置函数)
- “自定义样式”用例建议使用 toHaveStyle 提升断言稳定性,避免依赖 style 字符串格式。
微调示例:
- afterEach(() => { - vi.clearAllMocks(); - }); + afterEach(() => { + vi.clearAllMocks(); + // 若 util.ts 暴露 reset 方法: + // resetMockMatchMedia(); + vi.restoreAllMocks(); + });- expect((container.firstChild as HTMLDivElement).getAttribute('style')).toContain('red'); + expect(container.firstChild).toHaveStyle('background-color: red');packages/sqi-web/src/divider/__tests__/divider.test.tsx (3)
57-72
: 补充互斥断言,防止对齐类名残留
建议在切换对齐后同时断言不应存在其它对齐类,避免实现层面类名叠加未清理导致误通过。可以这样增强:
// Left alignment const { container: leftContainer, rerender } = render(<Divider align="left">Left Text</Divider>); expect(leftContainer.firstChild).toHaveClass('sqi-divider-with-text-left'); + expect(leftContainer.firstChild).not.toHaveClass('sqi-divider-with-text-right', 'sqi-divider-with-text-center'); // Right alignment rerender(<Divider align="right">Right Text</Divider>); expect(leftContainer.firstChild).toHaveClass('sqi-divider-with-text-right'); + expect(leftContainer.firstChild).not.toHaveClass('sqi-divider-with-text-left', 'sqi-divider-with-text-center');
82-88
: 使用 toHaveStyle 提升可读性与稳定性
比直接断言 style 字符串片段更稳健。- expect((container.firstChild as HTMLDivElement).getAttribute('style')).toContain('red'); + expect(container.firstChild).toHaveStyle({ color: 'red' });
10-13
: 控制快照数量,聚焦语义断言
当前快照较多、差异易碎。建议仅对「结构明显不同」的场景保留快照,其余用类名与属性断言替代,降低维护成本。Also applies to: 19-22, 27-29, 38-39, 47-48, 54-55, 70-72, 79-80, 87-88, 96-97
packages/sqi-web/src/_util/__tests__/dom.test.ts (4)
69-73
: 用例标题与断言不一致(null vs undefined)
标题写的是 “undefined”,断言是toBeNull()
。为避免困惑,请统一为“null”。- it('should return undefined when current is falsy', () => { + it('should return null when current is falsy', () => {
57-61
: 措辞微调以贴合实现
标题中的 “currentElement.currentElement” 容易误导,实际结构是ref.current.currentElement
。-it('should return currentElement.currentElement for special refs', () => { +it('should return ref.current.currentElement for special refs', () => {
83-91
: 避免字符串 ref,使用对象/回调 ref 更符合最佳实践
字符串 ref 已不推荐。这里可以用对象 ref 验证 React 19 分支逻辑。- // Test React 19+ behavior (ref in props) - versionSpy.mockReturnValue('19.0.0'); - const divWithRefProp = React.createElement('div', { ref: 'test-ref' }); - expect(getReactNodeRef(divWithRefProp)).toBe('test-ref'); + // Test React 19+ behavior (ref in props) + versionSpy.mockReturnValue('19.0.0'); + const objRef = React.createRef<HTMLDivElement>(); + const divWithRefProp = React.createElement('div', { ref: objRef }); + expect(getReactNodeRef(divWithRefProp)).toBe(objRef);
26-49
: 冗余场景可合并,减少噪音
getDOM
中非 DOM 输入与缺少currentElement
的对象断言可合并为参数化用例,提升可读性。packages/sqi-web/src/trigger/__tests__/trigger.test.tsx (2)
73-96
: 参数化用例更清晰,减少重复渲染与遗留节点
可以用it.each
/test.each
表达多位置断言,并在每次结束后确保清理,避免跨迭代干扰。
20-23
: 多余的 act 包裹可移除
@testing-library/react
的fireEvent
已内置act
,重复包裹增加噪音。- act(() => { - fireEvent.mouseEnter(...); - }); + fireEvent.mouseEnter(...);(另外两处 click/focus 同理)
Also applies to: 42-45, 64-67
packages/sqi-web/src/input/__tests__/input.test.tsx (4)
79-85
: 只断言属性字符串略显脆弱,建议断言属性布尔值
readonly
更适合用 DOM 属性断言,可读性更好。- expect(input).toHaveAttribute('readonly'); + expect((input as HTMLInputElement).readOnly).toBe(true);
86-99
: 清除按钮查询可更稳健
querySelector('button')
可能与其他按钮混淆。若组件有可访问名/标识,建议用getByRole('button', { name: /clear/i })
或特定类名查询,降低误匹配。
173-182
: maxLength 对象配置覆盖合理
同时校验计数与错误类,LGTM。可考虑追加“非 errorOnly”场景,验证类名不出现但计数仍显示。
61-70
: onChange 断言再补一刀更稳
在回调断言外,也可断言 DOM 值确实变更,防止仅回调但未更新 UI。fireEvent.change(input!, { target: { value: 'new value' } }); expect(onChange).toHaveBeenCalledTimes(1); expect(onChange).toHaveBeenCalledWith('new value', expect.any(Object)); +expect(input).toHaveValue('new value');
packages/sqi-web/src/_util/__tests__/toArray.test.ts (1)
5-17
: 可补充布尔值处理用例(可选)
Children.toArray
会忽略布尔值与 null/undefined。可追加 true/false 的断言,进一步锁死边界。expect(toArray(true as any)).toEqual([]); expect(toArray(false as any)).toEqual([]);packages/sqi-web/src/_util/__tests__/ref.test.tsx (1)
10-18
: 在导入后才声明vi.mock('react')
可能导致 mock 顺序不稳定,建议使用 hoist 提前注册虽然 Vitest 会对
vi.mock
做一定的提升,但为避免因为导入顺序或缓存导致的偶发失败,建议将 React 的 mock 以 hoisted 方式放到文件最顶层,且通过 setter 改写版本值,而不是直接复用同一可变变量。示例改法如下(更健壮,且避免与模块初始化竞态):+// 顶部:使用 hoisted 提前 mock 并暴露 setter +const { setReactVersion } = vi.hoisted(() => { + let __mockReactVersion = '18.0.0'; + vi.mock('react', async () => { + const actualReact = await vi.importActual<typeof import('react')>('react'); + return { + ...actualReact, + get version() { + return __mockReactVersion; + }, + }; + }); + return { + setReactVersion: (v: string) => { + __mockReactVersion = v; + }, + }; +}); - -import * as React from 'react'; +import * as React from 'react'; -// 创建一个变量来保存模拟的React版本 -let mockReactVersion = '18.0.0'; +// 删除可变的全局变量,统一使用 setReactVersion随后把文件内对
mockReactVersion = 'x.y.z'
的赋值替换为setReactVersion('x.y.z')
(见下方相关用例行)。- beforeEach(() => { - mockReactVersion = '18.0.0'; - }); + beforeEach(() => { + setReactVersion('18.0.0'); + });- mockReactVersion = '19.0.0'; + setReactVersion('19.0.0');packages/sqi-web/src/grid/__tests__/col.test.tsx (2)
13-16
: 补充恢复 window.matchMedia 的逻辑,避免对其它用例造成全局污染当前仅
vi.clearAllMocks()
,未恢复window.matchMedia
到原始实现。建议在 beforeEach 记录原值,在 afterEach 恢复,确保隔离性。import { mockMatchMedia } from './util'; describe('Col', () => { - beforeEach(() => { - mockMatchMedia(); - }); + let originalMatchMedia: typeof window.matchMedia; + beforeEach(() => { + originalMatchMedia = window.matchMedia; + mockMatchMedia(); + }); afterEach(() => { - vi.clearAllMocks(); + window.matchMedia = originalMatchMedia; + vi.restoreAllMocks(); });
102-111
: 使用 toHaveStyle 更直观地断言 style当前通过字符串包含判断颜色,略显脆弱。建议直接用
toHaveStyle
。- expect((container.firstChild as HTMLDivElement).getAttribute('style')).toContain('blue'); + expect(container.firstChild).toHaveStyle('background-color: blue');packages/sqi-web/src/_util/__tests__/reposeive.test.ts (3)
1-1
: 文件名存在拼写错误:建议更名为responsive.test.ts
当前为
reposeive.test.ts
,容易影响检索与一致性。- packages/sqi-web/src/_util/__tests__/reposeive.test.ts + packages/sqi-web/src/_util/__tests__/responsive.test.ts
83-101
: 注册监听的次数断言可以更精确当前用单一
mockMql
复用,addListener
的调用次数与断点数量一致能通过,但无法区分为每个断点都创建了“独立”的 MQL。可考虑按断点分别返回不同 mock 并逐一校验(虽然非必须)。
178-186
: “无订阅者返回 false” 的分支覆盖到位,但建议避免跨用例共享状态带来的偶发干扰由于
responsiveObserve
是单例,其他用例若遗漏unsubscribe
可能影响此断言。可在此用例内先确保无订阅者(例如先订阅后立即全部unsubscribe
,或使用vi.isolateModules
重新导入模块)以提升稳健性。packages/sqi-web/src/alert/__tests__/alert.test.tsx (3)
52-54
: 隐藏图标的断言更稳健的写法直接定位
.sqi-alert-icon
是否存在更加明确,避免依赖 DOM 子节点顺序。- expect(noIconAlert.firstChild?.firstChild).not.toHaveClass('sqi-alert-icon'); + expect(noIconAlert.querySelector('.sqi-alert-icon')).toBeNull();
68-77
: 动作区域断言建议去除对子节点索引的依赖通过类选择器断言更不易受结构调整影响。
- expect((container.firstChild as any)?.children[2]).toHaveClass('sqi-alert-action'); + expect(container.querySelector('.sqi-alert-action')).toBeInTheDocument();
85-98
: 关闭动效用例基本正确,可考虑使用更语义化的等待可以用
waitForElementToBeRemoved
针对role="alert"
的元素等待卸载,使断言更语义化(可选)。-import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { render, screen, fireEvent, waitFor, waitForElementToBeRemoved } from '@testing-library/react'; @@ - await waitFor( - () => { - expect(container.firstChild).not.toBeInTheDocument(); - }, - { timeout: 500 }, - ); + await waitForElementToBeRemoved(() => screen.queryByRole('alert'), { timeout: 500 });packages/sqi-web/src/radio/__tests__/radio-group.test.tsx (1)
61-75
: 交互断言有效,但可考虑使用@testing-library/user-event
提升贴近真实交互
fireEvent.click
可工作,但userEvent.click
能更真实地触发事件序列(例如焦点管理)。此处属于优化建议。packages/sqi-web/src/radio/__tests__/radio.test.tsx (5)
36-44
: 补强断言:校验回调次数与参数形状,避免隐性重复触发当前仅断言“被调用”不足以防止多次触发或参数异常。建议补充调用次数与入参结构断言(BaseCheckbox 事件为 { target, event },type 应为 'radio')。
fireEvent.click(input); - expect(handleChange).toBeCalled(); + expect(handleChange).toHaveBeenCalledTimes(1); + const { target, event } = handleChange.mock.calls[0][0]; + expect(target).toEqual( + expect.objectContaining({ checked: true, type: 'radio' }), + ); + expect(event).toBeDefined();fireEvent.click(radios[1]); - expect(handleChange).toBeCalled(); + expect(handleChange).toHaveBeenCalledTimes(1);Also applies to: 75-89
91-100
: 增强“函数子节点”用例:验证点击 label 驱动隐藏 input该场景的关键路径是 label.onClick 触发 input.click。当前仅检查隐藏样式,建议新增一次点击 label 的交互用例(非受控),验证选中切换。
test('should support function as children', () => { - const { container, getByText } = render( - <Radio checked>{({ checked }) => <span>{checked ? 'Checked' : 'Unchecked'}</span>}</Radio>, - ); + const { container, getByText } = render( + <Radio defaultChecked={false}> + {({ checked }) => <span>{checked ? 'Checked' : 'Unchecked'}</span>} + </Radio>, + ); - expect(getByText('Checked')).toBeInTheDocument(); + expect(getByText('Unchecked')).toBeInTheDocument(); // <label> <span style='display:none;'> <input/> </span> </label> expect(container.firstChild?.firstChild).toHaveStyle({ display: 'none' }); + // 点击 label 触发隐藏 input 切换 + fireEvent.click(container.firstChild as HTMLElement); + expect(getByText('Checked')).toBeInTheDocument(); expect(container).toMatchSnapshot(); });
23-25
: 查询建议:优先基于角色而非选择器对单个 Radio 建议使用 getByRole('radio') 替代 querySelector('input'),增强可读性与可访问性语义。
-const input = container.querySelector('input')!; +const input = container.querySelector('input')!; // 兼容保留 +// 或: +// const input = getByRole('radio') as HTMLInputElement;Also applies to: 31-33, 41-44, 55-58
102-106
: 避免依赖私有属性 IS_BUTTON,改用公开 API测试不应直接依赖私有属性。可通过 RadioGroup appearance="button" 生成 Button 样式以覆盖相同路径。
- test('should support button style when _IS_BUTTON_ is true', () => { - const { container } = render(<Radio _IS_BUTTON_>Button Radio</Radio>); - expect(container.querySelector('.sqi-radio-button-wrapper')).toBeInTheDocument(); - expect(container.firstChild).toMatchSnapshot(); - }); + test('should support button style via RadioGroup appearance', () => { + const { container, getByText } = render( + <RadioGroup appearance="button" defaultValue="a"> + <Radio value="a">A</Radio> + </RadioGroup>, + ); + expect(container.querySelector('.sqi-radio-button-wrapper')).toBeInTheDocument(); + expect(getByText('A')).toBeInTheDocument(); + expect(container.firstChild).toMatchSnapshot(); + });
12-13
: 快照数量偏多,建议聚焦关键结构当前几乎每个用例都拍快照,维护成本高且脆弱。建议保留代表性场景(首次渲染、分组、Button 外观)快照,其他用例以精确断言代替。
Also applies to: 20-21, 26-27, 33-34, 72-73, 88-89, 99-100, 105-106
packages/sqi-web/src/space/__tests__/space.test.tsx (4)
31-50
: 补充 vertical 方向的样式断言已验证类名,但未验证 vertical 时使用 margin-bottom 的样式差异。建议新增断言,防止回归。
const { container: verticalContainer } = render( <Space direction="vertical"> <div>Item 1</div> <div>Item 2</div> </Space>, ); @@ expect(horizontalContainer.firstChild).toHaveClass('sqi-space-direction-horizontal'); expect(verticalContainer.firstChild).toHaveClass('sqi-space-direction-vertical'); + // 校验第一个 item 在 vertical 下有 margin-bottom + const vItem = verticalContainer.querySelector('.space-item')!; + expect(vItem).toHaveStyle('margin-bottom: 16px');
112-124
: 更严谨的多项间距校验当前仅检查第一个 .space-item。建议同时检查非末尾与末尾元素,确保逻辑“最后一个无右间距”在不同 size 下均成立。
-const smItem = smContainer.querySelector('.space-item'); -const mdItem = mdContainer.querySelector('.space-item'); -const lgItem = lgContainer.querySelector('.space-item'); +const smItems = smContainer.querySelectorAll('.space-item'); +const mdItems = mdContainer.querySelectorAll('.space-item'); +const lgItems = lgContainer.querySelectorAll('.space-item'); +const [smItem, smLast] = [smItems[0], smItems[smItems.length - 1]]; +const [mdItem, mdLast] = [mdItems[0], mdItems[mdItems.length - 1]]; +const [lgItem, lgLast] = [lgItems[0], lgItems[lgItems.length - 1]]; @@ expect(smItem).toHaveStyle('margin-right: 8px'); expect(mdItem).toHaveStyle('margin-right: 16px'); expect(lgItem).toHaveStyle('margin-right: 24px'); +expect(smLast).not.toHaveStyle('margin-right: 8px'); +expect(mdLast).not.toHaveStyle('margin-right: 16px'); +expect(lgLast).not.toHaveStyle('margin-right: 24px');
139-151
: 数组间距在 wrap=false 情况下的回归保护目前数组间距仅在 wrap 下断言。建议再补一例 wrap=false,验证仅水平方向生效。
it('handles array size values for horizontal and vertical spacing', () => { const { container } = render( <Space size={[10, 20]} wrap> <div>Item 1</div> <div>Item 2</div> </Space>, ); @@ expect(item).toHaveStyle('margin-right: 10px'); expect(item).toHaveStyle('margin-bottom: 20px'); expect(container.firstChild).toMatchSnapshot(); }); + +it('applies only horizontal gap when wrap=false with array size', () => { + const { container } = render( + <Space size={[10, 20]}> + <div>Item 1</div> + <div>Item 2</div> + </Space>, + ); + const item = container.querySelector('.space-item')!; + expect(item).toHaveStyle('margin-right: 10px'); + expect(item).not.toHaveStyle('margin-bottom: 20px'); +});
15-16
: 快照适度收敛快照覆盖面较广,建议保留关键结构(如含 split、wrap、不同 size 的其中一例),其余改用精确断言,降低噪音与维护成本。
Also applies to: 26-29, 48-50, 60-62, 72-74, 85-88, 121-124, 136-137, 150-151, 164-165
packages/sqi-web/src/switch/__tests__/switch.test.tsx (3)
27-35
: 补充无障碍断言:role 与 aria-checkedSwitch 已设置 role="switch" 与 aria-checked,建议在交互后断言其值切换,增强可访问性保障。
const { container } = render(<Switch onChange={handleChange} />); fireEvent.click(container.firstChild!); expect(handleChange).toHaveBeenCalledWith(true, expect.any(Object)); + expect(container.firstChild).toHaveAttribute('role', 'switch'); + expect(container.firstChild).toHaveAttribute('aria-checked', 'true'); expect(container.firstChild).toHaveClass('sqi-switch-checked');fireEvent.click(container.firstChild!); expect(handleChange).toHaveBeenCalledWith(false, expect.any(Object)); + expect(container.firstChild).toHaveAttribute('aria-checked', 'false');
// Only when the checked prop changes, the component updates rerender(<Switch checked={true} onChange={handleChange} />); expect(container.firstChild).toHaveClass('sqi-switch-checked'); + expect(container.firstChild).toHaveAttribute('aria-checked', 'true');
Also applies to: 57-70, 94-110
27-35
: 更严格的回调次数断言与 N 次调用参数校验为避免重复触发未被发现,建议补充调用次数与序号化参数断言。
fireEvent.click(container.firstChild!); - expect(handleChange).toHaveBeenCalledWith(true, expect.any(Object)); + expect(handleChange).toHaveBeenCalledTimes(1); + expect(handleChange).toHaveBeenNthCalledWith(1, true, expect.any(Object));fireEvent.click(container.firstChild!); - expect(handleChange).toHaveBeenCalledWith(false, expect.any(Object)); + expect(handleChange).toHaveBeenCalledTimes(2); + expect(handleChange).toHaveBeenNthCalledWith(2, false, expect.any(Object));fireEvent.click(container.firstChild!); - expect(handleChange).not.toHaveBeenCalled(); + expect(handleChange).not.toHaveBeenCalled();Also applies to: 37-45, 47-55, 79-92, 94-110
72-77
: 补充“loadingIcon 在 loading=false 时不渲染”的负例加强约束,避免误渲染自定义 loadingIcon。
it('should render custom loading icon when provided', () => { const { container } = render(<Switch loading loadingIcon={<div data-testid="custom-loading">loading</div>} />); expect(container.querySelector('[data-testid="custom-loading"]')).toBeTruthy(); expect(container.firstChild).toMatchSnapshot(); }); + +it('should not render custom loading icon when loading is false', () => { + const { container } = render(<Switch loadingIcon={<div data-testid="custom-loading">loading</div>} />); + expect(container.querySelector('[data-testid="custom-loading"]')).toBeFalsy(); +});packages/sqi-web/src/config-provider/type.ts (1)
17-38
: 建议:为 iconPrefix 增加一条回归用例(可在已有测试集成)虽已有相关测试,但可在 ConfigProvider 嵌套场景下断言 iconPrefix 透传与覆盖,保证未来重构不回退。
packages/sqi-web/src/tooltip/type.ts (1)
3-9
: 将 rootClassName 纳入 TooltipProps 很好;建议补充 JSDoc 以便文档生成器展示由于属性来自父接口,Tooltip 的文档页可能不直接展示 rootClassName 描述。可在此处重复声明并补充注释,便于使用者发现。
export interface TooltipProps extends PopupProps { + /** + * @description Tooltip 根节点自定义 className,透传至 Popup.rootClassName + */ + rootClassName?: PopupProps['rootClassName']; /** * @description 文字提示风格 * @default default */ theme?: 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'light'; }packages/sqi-web/src/config-provider/ConfigProvider.tsx (1)
12-12
: 将 iconPrefix 纳入上下文 OK,但建议避免 providerValue 每次渲染都变更当前每次 render 都会创建新的 providerValue,对所有使用 ConfigContext 的组件造成级联重渲染。可用 useMemo 包一层,减少不必要更新;同时建议为 IconContext.Provider 的 value 也做稳定化。
import { ConfigContext, defaultConfigProps } from './context'; import type { ConfigProviderProps } from './type'; export default function ConfigProvider(baseProps: ConfigProviderProps) { const props = useMergeProps(baseProps, defaultConfigProps); const { iconPrefix, children } = props; - const providerValue = omit(props, ['children']); + const providerValue = React.useMemo(() => omit(props, ['children']), [props]); + const iconCtxValue = React.useMemo(() => ({ prefixCls: iconPrefix }), [iconPrefix]); const IconProviderPlaceholder = iconPrefix ? IconContext.Provider : Fragment; return ( <ConfigContext.Provider value={providerValue}> - <IconProviderPlaceholder value={{ prefixCls: iconPrefix }}>{children}</IconProviderPlaceholder> + <IconProviderPlaceholder value={iconCtxValue}>{children}</IconProviderPlaceholder> </ConfigContext.Provider> ); }另外请确认 ConfigContext 的类型定义已包含 iconPrefix,避免类型不一致(测试已覆盖此点但类型仍需同步)。
packages/sqi-web/src/checkbox/__tests__/checkbox.test.tsx (3)
57-60
: “indeterminate” 断言定位不稳,建议直接查找状态类当前断言指向第一个子节点(通常是 input),但“半选”样式多出现于外层容器或 inner 节点,易脆弱。
- expect(container.firstChild?.firstChild).toHaveClass('sqi-checkbox-indeterminate'); + expect(container.querySelector('.sqi-checkbox-indeterminate')).toBeInTheDocument();
74-77
: 点击文本触发不一定可靠,建议直接点击第二个 input不同实现下文本可能不是 label 或未绑定事件,导致用例易波动。
- // Click second checkbox - fireEvent.click(getByText('Option 2')); + // Click second checkbox input(更稳健) + const secondInput = container.querySelectorAll('input')[1]!; + fireEvent.click(secondInput);
94-104
: 样式断言对象应为外层容器而非 input;避免颜色标准化导致的断言失败BaseCheckbox 将 style 挂载在外层容器上;对颜色用属性包含判断更稳健。
expect(container.firstChild).toHaveClass('custom-class'); - // expect(container.firstChild).toHaveStyle('color: red'); - expect((container.firstChild?.firstChild as HTMLInputElement)?.getAttribute('style')).toContain('color: red'); + // 使用属性断言以避免颜色标准化差异;样式挂在外层容器上 + expect((container.firstChild as HTMLElement).getAttribute('style')).toContain('color: red');packages/sqi-web/src/popup/__tests__/popup.test.tsx (3)
8-12
: 事件触发目标建议从 container.firstChild 切换为按钮文本节点,表达更清晰且更稳健直接基于“Hover me”按钮触发 hover,更贴近期望行为并减少对内部结构的耦合。
- const { container, queryByTestId } = render( + const { container, queryByTestId, getByText } = render( <Popup content={<div data-testid="popup-test-id">Popup content</div>}> <button type="button">Hover me</button> </Popup>, ); @@ - act(() => { - fireEvent.mouseEnter(container.firstChild!); - }); + act(() => { + fireEvent.mouseEnter(getByText('Hover me')); + }); @@ - act(() => { - fireEvent.mouseLeave(container.firstChild!); - }); + act(() => { + fireEvent.mouseLeave(getByText('Hover me')); + });Also applies to: 22-24, 32-34
48-53
: 用例标题与断言内容不符:应为“string content”而非“string children”此用例验证的是 content 为字符串而不是 children。
- test('should support string children', async () => { + test('should support string content', async () => {
104-108
: 验证隐藏箭头应在再次显示 Popup 时断言,以避免“关闭态本就不存在箭头”的伪通过当前在关闭态检查不到箭头属必然成立。建议切回 hover 打开后再断言箭头确实不渲染,同时去除冗余的双重断言。
- await waitFor(() => { - const arrowEl = document.querySelector('.sqi-popup-arrow'); - expect(arrowEl).toBeNull(); - expect(arrowEl).not.toBeInTheDocument(); - }); + // 重新 hover 打开后检查箭头已隐藏 + act(() => { + fireEvent.mouseEnter(queryByTestId('hover-trigger')!); + }); + await waitFor(() => { + expect(document.querySelector('.sqi-popup-arrow')).toBeNull(); + });packages/sqi-web/src/checkbox/__tests__/checkbox-group.test.tsx (3)
30-33
: 使用可访问性查询替代 querySelectorAll,提高稳定性与可读性这些断言依赖 'input' 标签选择器,容易与实现细节耦合。建议改为通过角色查询复选框。
- const inputs = container.querySelectorAll('input'); + const inputs = screen.getAllByRole('checkbox');并在文件顶部补充导入:
-import { render, fireEvent } from '@testing-library/react'; +import { render, fireEvent, screen } from '@testing-library/react';对其它相同位置同样替换。
Also applies to: 43-46, 100-103, 158-161
48-64
: 加强 onChange 断言以验证调用次数与顺序当前仅断言最后一次参数,建议同时校验调用次数与序号,以避免回归。
// Click first checkbox fireEvent.click(getByText('Option 1')); - expect(onChange).toHaveBeenCalledWith(['1']); + expect(onChange).toHaveBeenCalledWith(['1']); // Click second checkbox fireEvent.click(getByText('Option 2')); - expect(onChange).toHaveBeenCalledWith(['1', '2']); + expect(onChange).toHaveBeenCalledWith(['1', '2']); + expect(onChange).toHaveBeenCalledTimes(2); + expect(onChange).toHaveBeenNthCalledWith(1, ['1']); + expect(onChange).toHaveBeenNthCalledWith(2, ['1', '2']);
132-148
: 受控模式下补充 UI 不变性的断言该用例只检查回调参数,建议再断言 UI 勾选状态未随点击变化(因 value 受控),以防内部 state 误改。
- const { getByText } = render( + const { getByText } = render( <CheckboxGroup value={['1']} onChange={onChange}> <Checkbox value="1">Option 1</Checkbox> <Checkbox value="2">Option 2</Checkbox> </CheckboxGroup>, ); // Uncheck first checkbox fireEvent.click(getByText('Option 1')); expect(onChange).toHaveBeenCalledWith([]); + expect(screen.getByRole('checkbox', { name: 'Option 1' })).toBeChecked(); + expect(screen.getByRole('checkbox', { name: 'Option 2' })).not.toBeChecked(); // Check second checkbox fireEvent.click(getByText('Option 2')); expect(onChange).toHaveBeenCalledWith(['1', '2']); + expect(screen.getByRole('checkbox', { name: 'Option 1' })).toBeChecked(); + expect(screen.getByRole('checkbox', { name: 'Option 2' })).not.toBeChecked();packages/sqi-web/src/config-provider/__tests__/config-provider.test.tsx (1)
112-122
: 补充嵌套覆盖对 iconPrefix 的断言当前仅验证了 prefixCls 的覆盖,建议一并验证 iconPrefix 的覆盖以匹配提供者值变更。
it('should work with nested ConfigProviders', () => { const { getByTestId } = render( - <ConfigProvider prefixCls="outer"> - <ConfigProvider prefixCls="inner"> + <ConfigProvider prefixCls="outer" iconPrefix="outer-icon"> + <ConfigProvider prefixCls="inner" iconPrefix="inner-icon"> <TestComponent /> </ConfigProvider> </ConfigProvider>, ); expect(getByTestId('prefixCls').textContent).toBe('inner'); + expect(getByTestId('iconPrefix').textContent).toBe('inner-icon'); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (12)
packages/sqi-web/src/alert/__tests__/__snapshots__/alert.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/checkbox/__tests__/__snapshots__/checkbox-group.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/checkbox/__tests__/__snapshots__/checkbox.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/divider/__tests__/__snapshots__/divider.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/grid/__tests__/__snapshots__/col.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/grid/__tests__/__snapshots__/row.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/input/__tests__/__snapshots__/input.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/radio/__tests__/__snapshots__/radio-group.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/radio/__tests__/__snapshots__/radio.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/space/__tests__/__snapshots__/space.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/switch/__tests__/__snapshots__/switch.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/tooltip/__tests__/__snapshots__/tooltip.test.tsx.snap
is excluded by!**/*.snap
📒 Files selected for processing (28)
packages/sqi-web/src/_util/__tests__/dom.test.ts
(1 hunks)packages/sqi-web/src/_util/__tests__/ref.test.tsx
(1 hunks)packages/sqi-web/src/_util/__tests__/reposeive.test.ts
(1 hunks)packages/sqi-web/src/_util/__tests__/toArray.test.ts
(1 hunks)packages/sqi-web/src/alert/__tests__/alert.test.tsx
(1 hunks)packages/sqi-web/src/checkbox/__tests__/checkbox-group.test.tsx
(1 hunks)packages/sqi-web/src/checkbox/__tests__/checkbox.test.tsx
(1 hunks)packages/sqi-web/src/checkbox/type.ts
(1 hunks)packages/sqi-web/src/config-provider/ConfigProvider.tsx
(1 hunks)packages/sqi-web/src/config-provider/__tests__/config-provider.test.tsx
(1 hunks)packages/sqi-web/src/config-provider/type.ts
(1 hunks)packages/sqi-web/src/divider/Divider.tsx
(1 hunks)packages/sqi-web/src/divider/__tests__/divider.test.tsx
(1 hunks)packages/sqi-web/src/grid/__tests__/col.test.tsx
(1 hunks)packages/sqi-web/src/grid/__tests__/row.test.tsx
(1 hunks)packages/sqi-web/src/grid/__tests__/util.ts
(1 hunks)packages/sqi-web/src/input/Input.tsx
(2 hunks)packages/sqi-web/src/input/__tests__/input.test.tsx
(1 hunks)packages/sqi-web/src/popup/Popup.tsx
(1 hunks)packages/sqi-web/src/popup/__tests__/popup.test.tsx
(1 hunks)packages/sqi-web/src/radio/__tests__/radio-group.test.tsx
(1 hunks)packages/sqi-web/src/radio/__tests__/radio.test.tsx
(1 hunks)packages/sqi-web/src/space/__tests__/space.test.tsx
(1 hunks)packages/sqi-web/src/switch/__tests__/switch.test.tsx
(1 hunks)packages/sqi-web/src/tooltip/Tooltip.tsx
(1 hunks)packages/sqi-web/src/tooltip/__tests__/tooltip.test.tsx
(1 hunks)packages/sqi-web/src/tooltip/type.ts
(1 hunks)packages/sqi-web/src/trigger/__tests__/trigger.test.tsx
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (28)
packages/sqi-web/src/input/Input.tsx (1)
packages/sqi-web/src/input/type.ts (1)
InputProps
(38-134)
packages/sqi-web/src/_util/__tests__/reposeive.test.ts (1)
packages/sqi-web/src/_util/responsiveObserve.ts (5)
register
(55-74)matches
(57-62)bp
(56-73)subscribe
(44-50)screen
(76-80)
packages/sqi-web/src/trigger/__tests__/trigger.test.tsx (3)
packages/sqi-web/src/trigger/index.ts (1)
Trigger
(5-5)packages/sqi-web/src/trigger/type.ts (2)
TriggerPlacement
(10-10)TriggerProps
(14-101)packages/sqi-web/src/trigger/Trigger.tsx (1)
popper
(195-222)
packages/sqi-web/src/input/__tests__/input.test.tsx (2)
packages/sqi-web/src/input/index.ts (1)
Input
(5-5)packages/sqi-web/src/input/type.ts (1)
InputProps
(38-134)
packages/sqi-web/src/grid/__tests__/row.test.tsx (3)
packages/sqi-web/src/grid/__tests__/util.ts (1)
mockMatchMedia
(3-17)packages/sqi-web/src/grid/type.ts (1)
RowProps
(7-28)packages/sqi-web/src/grid/Row.tsx (1)
baseProps
(20-117)
packages/sqi-web/src/radio/__tests__/radio-group.test.tsx (3)
packages/sqi-web/src/radio/index.ts (2)
RadioGroup
(17-17)Radio
(16-16)packages/sqi-web/src/radio/type.ts (3)
RadioGroupProps
(23-71)RadioGroupContextState
(9-17)RadioProps
(84-120)packages/sqi-web/src/radio/RadioGroup.tsx (1)
baseProps
(19-107)
packages/sqi-web/src/_util/__tests__/toArray.test.ts (1)
packages/sqi-web/src/_util/toArray.ts (1)
toArray
(4-22)
packages/sqi-web/src/checkbox/__tests__/checkbox.test.tsx (2)
packages/sqi-web/src/checkbox/index.ts (2)
Checkbox
(12-12)CheckboxGroup
(13-13)packages/sqi-web/src/_common/BaseCheckbox.tsx (2)
CheckboxChangeEventTarget
(11-13)props
(25-84)
packages/sqi-web/src/divider/__tests__/divider.test.tsx (5)
packages/sqi-web/src/divider/index.ts (1)
Divider
(5-5)packages/sqi-web/src/divider/demos/with-text.tsx (1)
Demo
(8-21)packages/sqi-web/src/divider/demos/vertical.tsx (1)
Demo
(4-16)packages/sqi-web/src/divider/demos/base.tsx (1)
Demo
(8-19)packages/sqi-web/src/divider/type.ts (1)
DividerProps
(3-25)
packages/sqi-web/src/checkbox/type.ts (3)
packages/sqi-web/src/checkbox/CheckboxGroup.tsx (3)
options
(53-59)item
(54-59)baseProps
(12-128)packages/sqi-web/src/checkbox/demos/options.tsx (1)
Demo
(5-42)packages/sqi-web/src/checkbox/Checkbox.tsx (1)
args
(57-60)
packages/sqi-web/src/switch/__tests__/switch.test.tsx (3)
packages/sqi-web/src/switch/index.ts (1)
Switch
(5-5)packages/sqi-web/src/switch/type.ts (1)
SwitchProps
(10-47)packages/sqi-web/src/switch/Switch.tsx (1)
baseProps
(15-74)
packages/sqi-web/src/config-provider/type.ts (2)
packages/sqi-icons/src/components/Context.tsx (1)
IconContextProps
(3-5)packages/sqi-icons/src/components/Icon.tsx (1)
IconProps
(8-13)
packages/sqi-web/src/config-provider/__tests__/config-provider.test.tsx (2)
packages/sqi-web/src/config-provider/context.ts (1)
ConfigContext
(10-10)packages/sqi-web/src/config-provider/ConfigProvider.tsx (1)
ConfigProvider
(9-21)
packages/sqi-web/src/space/__tests__/space.test.tsx (2)
packages/sqi-web/src/space/Space.tsx (1)
baseProps
(23-96)packages/sqi-web/src/space/type.ts (1)
SpaceProps
(6-32)
packages/sqi-web/src/radio/__tests__/radio.test.tsx (3)
packages/sqi-web/src/_common/__tests__/base-checkbox.test.tsx (2)
it
(7-84)fn
(35-44)packages/sqi-web/src/radio/type.ts (2)
RadioProps
(84-120)RadioGroupProps
(23-71)packages/sqi-web/src/radio/RadioGroup.tsx (1)
baseProps
(19-107)
packages/sqi-web/src/tooltip/__tests__/tooltip.test.tsx (1)
packages/sqi-web/src/tooltip/type.ts (1)
TooltipProps
(3-9)
packages/sqi-web/src/_util/__tests__/ref.test.tsx (1)
packages/sqi-web/src/_util/ref.ts (5)
T
(18-24)T
(6-16)T
(26-32)RefAttributes
(64-66)ref
(12-14)
packages/sqi-web/src/checkbox/__tests__/checkbox-group.test.tsx (3)
packages/sqi-web/src/checkbox/index.ts (2)
CheckboxGroup
(13-13)Checkbox
(12-12)packages/sqi-web/src/checkbox/CheckboxGroup.tsx (1)
baseProps
(12-128)packages/sqi-web/src/checkbox/Checkbox.tsx (1)
baseProps
(16-112)
packages/sqi-web/src/grid/__tests__/col.test.tsx (2)
packages/sqi-web/src/grid/__tests__/util.ts (1)
mockMatchMedia
(3-17)packages/sqi-web/src/grid/index.ts (2)
Col
(7-7)Row
(6-6)
packages/sqi-web/src/tooltip/type.ts (1)
packages/sqi-web/src/popup/type.ts (1)
PopupProps
(23-56)
packages/sqi-web/src/popup/__tests__/popup.test.tsx (3)
packages/sqi-web/src/popup/index.ts (1)
Popup
(5-5)packages/sqi-web/src/popup/type.ts (1)
PopupProps
(23-56)packages/sqi-web/src/_common/__tests__/portal.test.tsx (2)
TestComponent
(74-105)it
(6-106)
packages/sqi-web/src/tooltip/Tooltip.tsx (2)
packages/sqi-hooks/src/useMergeProps.ts (1)
useMergeProps
(3-22)packages/sqi-web/src/popup/type.ts (1)
PopupProps
(23-56)
packages/sqi-web/src/alert/__tests__/alert.test.tsx (3)
packages/sqi-web/src/alert/index.ts (1)
Alert
(5-5)packages/sqi-web/src/alert/Alert.tsx (1)
baseProps
(28-71)packages/sqi-web/src/alert/type.ts (1)
AlertProps
(3-40)
packages/sqi-web/src/_util/__tests__/dom.test.ts (1)
packages/sqi-web/src/_util/dom.ts (4)
isDOM
(3-6)getDOM
(13-25)getRefDom
(32-39)getReactNodeRef
(41-52)
packages/sqi-web/src/config-provider/ConfigProvider.tsx (2)
packages/sqi-utils/src/omit.ts (1)
omit
(1-11)packages/sqi-icons/src/components/Context.tsx (1)
IconContextProps
(3-5)
packages/sqi-web/src/divider/Divider.tsx (3)
packages/sqi-hooks/src/useMergeProps.ts (1)
useMergeProps
(3-22)packages/sqi-web/src/divider/type.ts (1)
DividerProps
(3-25)packages/sqi-web/src/space/Space.tsx (1)
baseProps
(23-96)
packages/sqi-web/src/grid/__tests__/util.ts (1)
packages/sqi-web/src/_util/responsiveObserve.ts (1)
matches
(57-62)
packages/sqi-web/src/popup/Popup.tsx (1)
packages/sqi-web/src/popup/type.ts (1)
PopupProps
(23-56)
🔇 Additional comments (32)
packages/sqi-web/src/input/Input.tsx (1)
250-275
: 我未在样式文件或 CSS-in-JS 定义中发现对外层包装元素的display
属性做显式约束。请手动确认组件样式(如wrapperClasses
对应的样式)是否已将容器设为inline-flex
或其他非默认block
行为,以确保从span
切换到div
不会引入布局损坏。packages/sqi-web/src/divider/Divider.tsx (2)
14-18
: 就地解构合并 props 简洁清晰,保持行为不变直接从 useMergeProps 解构所需属性,减少中间变量,改善可读性且不影响逻辑。
23-33
: clsx 组装方式更直观,类名条件判断正确
- with-text 相关类仅在非 vertical 且存在内容时添加,符合预期。
- dashed 使用布尔转义无副作用。
packages/sqi-web/src/divider/__tests__/divider.test.tsx (2)
6-14
: 默认渲染覆盖充分,断言清晰,赞!
用例校验了基础类名与快照,符合预期。
31-39
: 「带文案」场景断言合理
类名与文本节点同时校验,降低了对快照的依赖,挺好。packages/sqi-web/src/trigger/__tests__/trigger.test.tsx (1)
116-121
: 无效子节点用例很到位
能够覆盖早返回分支,LGTM。packages/sqi-web/src/input/__tests__/input.test.tsx (5)
6-15
: 基础渲染断言全面
尺寸、变体、对齐与快照覆盖到位。
129-146
: 密码可见性切换用例很细致
覆盖了切换两次与快照,LGTM。
166-171
: maxLength 数值裁剪断言准确
这一条很关键,保证非受控默认值也会裁剪。
198-211
: 聚焦样式的断言清晰
事件回调与样式类协同校验,LGTM。
213-223
: ref 能力覆盖到位
校验了方法与宿主元素类型,LGTM。packages/sqi-web/src/_util/__tests__/toArray.test.ts (1)
46-53
: 覆盖面很广,断言到位
数组扁平化、Fragment 解包、混合内容等场景均有覆盖,LGTM。Also applies to: 70-82, 84-94, 96-107, 109-118, 120-137
packages/sqi-web/src/_util/__tests__/ref.test.tsx (4)
112-119
: useComposeRef 的稳定性断言合理对“依赖未变返回同一 ref、依赖变化返回新 ref”的行为覆盖到位,可有效防回归。
40-42
: 对空 ref 的健壮性校验很有价值确认
fillRef(null, node)
不抛异常,匹配工具函数的容错期望。
55-89
: composeRef 组合多种 ref 的场景覆盖完整包含函数 ref、对象 ref 与混合情形,能较好保障组合逻辑正确性。
138-144
: 无需改动:supportRef
/supportNodeRef
在函数内部动态读取version
,无导入时缓存packages/sqi-web/src/grid/__tests__/col.test.tsx (4)
42-46
: 数值型 flex 测试覆盖到位断言
flex: 1 1 auto
与实现的formatFlexStyle
约定一致。
48-52
: 基础与字符串型 flex 覆盖充分对
basis
字符串与完整flex
字符串两类输入的断言合理。Also applies to: 54-58
60-71
: 响应式断点类名断言准确覆盖
xs/sm/md/lg
的类名生成,能较好保障genScreenClassName
的输出稳定。
87-100
: gutter 样式断言清晰,但建议增强断言可读性断言四个 padding 值很好。可补充断言 Row/Col 结构的快照(已有)即可。
packages/sqi-web/src/_util/__tests__/reposeive.test.ts (1)
10-23
: matchMedia 的 mock/恢复流程规范每次用例前清空 handlers 并 mock,结束后恢复原始
matchMedia
,隔离性良好。Also applies to: 25-27
packages/sqi-web/src/alert/__tests__/alert.test.tsx (1)
6-13
: 基础渲染与结构断言清晰覆盖类名、文本与快照,基础行为验证到位。
packages/sqi-web/src/radio/__tests__/radio-group.test.tsx (3)
47-59
: 禁用态用例覆盖完整组级
disabled
影响子项的断言正确。
90-100
: 尺寸与按钮形态类名断言准确
wrapper-size-lg
与wrapper-filled
的类名检测匹配实现,快照辅助回归检测。Also applies to: 152-162
109-125
: options / renderOption 的多形态渲染覆盖良好对象、字符串与自定义渲染三类路径均有覆盖,并包含禁用项断言。
Also applies to: 127-136, 138-150
packages/sqi-web/src/config-provider/type.ts (1)
33-36
: 文档默认值更新与运行时一致性校验通过将 iconPrefix 的 @default 调整为 'sqi' 与当前实现一致,变更合理,无破坏性影响。
packages/sqi-web/src/popup/Popup.tsx (1)
3-7
: 导入重排与 type-only import 合理,符合 Tree-shaking 最佳实践仅为组织结构调整,不改变运行时行为。LGTM。
packages/sqi-web/src/tooltip/Tooltip.tsx (2)
21-25
: 解构 rootClassName 并纳入合并 props:合理将 rootClassName 放入 useMergeProps 的结果中,有利于全局配置与实例 props 一致合并。LGTM。
29-35
: rootClassName 合并顺序正确,用户样式优先级在最后clsx 顺序为基础类 → 主题类 → 外部 rootClassName,满足可扩展性与覆盖预期。可保持现状。
packages/sqi-web/src/config-provider/__tests__/config-provider.test.tsx (1)
32-41
: 默认值用例清晰、覆盖到位验证了 prefixCls 与 iconPrefix 的默认值,符合实现预期。
packages/sqi-web/src/tooltip/__tests__/tooltip.test.tsx (2)
27-39
: rootClassName 用例合理校验了基础类与自定义根类的合并,断言充分。
41-64
: 自定义箭头与内容类名用例妥当覆盖了箭头与内容类名定制,断言与快照均合适。
expect(container.firstChild).toHaveClass('custom-group'); | ||
// expect(container.firstChild).toHaveStyle('background-color: red'); | ||
expect((container.firstChild as HTMLInputElement)?.getAttribute('style')).toContain('color: red'); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
修复断言错误:样式键名与期望不一致,且类型断言错误
此处传入的是 style={{ backgroundColor: 'red' }},但断言却检查了 'color: red';同时 firstChild 实际是 div,不是 HTMLInputElement。应直接使用 toHaveStyle 并修正类型。
- expect(container.firstChild).toHaveClass('custom-group');
- // expect(container.firstChild).toHaveStyle('background-color: red');
- expect((container.firstChild as HTMLInputElement)?.getAttribute('style')).toContain('color: red');
+ expect(container.firstChild).toHaveClass('custom-group');
+ expect(container.firstChild as HTMLElement).toHaveStyle({ backgroundColor: 'red' });
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
expect(container.firstChild).toHaveClass('custom-group'); | |
// expect(container.firstChild).toHaveStyle('background-color: red'); | |
expect((container.firstChild as HTMLInputElement)?.getAttribute('style')).toContain('color: red'); | |
}); | |
expect(container.firstChild).toHaveClass('custom-group'); | |
expect(container.firstChild as HTMLElement).toHaveStyle({ backgroundColor: 'red' }); |
🤖 Prompt for AI Agents
In packages/sqi-web/src/checkbox/__tests__/checkbox-group.test.tsx around lines
112 to 115, the test asserts the wrong style key and incorrectly casts
firstChild as HTMLInputElement; update the assertion to check for
backgroundColor by using the toHaveStyle matcher on the element (no manual
getAttribute or HTMLInputElement cast) and ensure the expected style string
matches the component prop (e.g., 'background-color: red' or the equivalent
toHaveStyle({ backgroundColor: 'red' })) so the test validates the actual div
style correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
package.json (1)
36-36
: 确认兼容 v3,无需调整配置;建议添加根级 test/coverage 脚本
扫描packages/sqi-web/vitest.config.ts
,仅使用environment
、setupFiles
、coverage
等 v3 支持的字段,未发现pool
、globals
、isolate
、browser
等 v4 独有配置;测试文件中仅使用describe
、it
、expect
、vi
等 v3 API。
建议在根package.json
的scripts
中新增:"scripts": { // ... + "test": "turbo test --filter=./packages/**", + "coverage": "turbo test --filter=./packages/** -- --coverage" },
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (3)
packages/sqi-web/src/alert/__tests__/__snapshots__/alert.test.tsx.snap
is excluded by!**/*.snap
packages/sqi-web/src/tooltip/__tests__/__snapshots__/tooltip.test.tsx.snap
is excluded by!**/*.snap
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
package.json
(2 hunks)packages/sqi-web/src/_util/__tests__/toArray.test.ts
(1 hunks)packages/sqi-web/src/alert/__tests__/alert.test.tsx
(1 hunks)packages/sqi-web/src/checkbox/__tests__/checkbox-group.test.tsx
(1 hunks)packages/sqi-web/src/tooltip/__tests__/tooltip.test.tsx
(1 hunks)packages/sqi-web/src/trigger/__tests__/trigger.test.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/sqi-web/src/trigger/tests/trigger.test.tsx
- packages/sqi-web/src/alert/tests/alert.test.tsx
- packages/sqi-web/src/checkbox/tests/checkbox-group.test.tsx
- packages/sqi-web/src/tooltip/tests/tooltip.test.tsx
- packages/sqi-web/src/_util/tests/toArray.test.ts
🔇 Additional comments (1)
package.json (1)
26-26
: 确认 coverage provider 为 v8:在 packages/sqi-web/vitest.config.ts 中,coverage 配置仅包含 include/exclude,未指定 provider;请确认默认 provider 是否为 v8,或显式添加provider: 'v8'
。
Summary by CodeRabbit
新功能
重构
文档
测试
其他