-
Notifications
You must be signed in to change notification settings - Fork 297
refactor(popover): v16适配 #3492
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
base: feat_v4.x
Are you sure you want to change the base?
refactor(popover): v16适配 #3492
Changes from all commits
3329762
da24c2c
033f713
e893795
40ffbfe
1270145
92f8c1e
f26cda2
dcd6aef
5d88bad
ec52608
68f8959
8cd485f
d1661c5
9476baf
8e1951c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1033,7 +1033,7 @@ | |
| "v15": 1, | ||
| "author": "lzz", | ||
| "dd": true, | ||
| "v16": false | ||
| "v16": true | ||
| }, | ||
| { | ||
| "version": "3.0.0", | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -67,12 +67,12 @@ test('render popover content', async () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test('render popover content dark', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { container } = render( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Popover visible list={itemListOne} theme="dark" location="right"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Popover visible list={itemListOne} location="right"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button type="primary">基础用法</Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const content = document.querySelectorAll('.nut-popover')[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content.className).toContain('nut-popover-dark') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content.className).toContain('nut-popover--status') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(container).toMatchSnapshot() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -95,30 +95,37 @@ test('render popover position with arrowOffset', async () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const checkArrowStyles = (location: FullPosition, expectedStyles: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const checkArrowStyles = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| location: FullPosition, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expectedStyles: string | null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rerender( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Popover visible list={itemList} location={location} arrowOffset={20}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button type="primary">基础用法</Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content = document.querySelectorAll('.nut-popover-arrow')[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content).toHaveAttribute('style', expectedStyles) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (expectedStyles === null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content.getAttribute('style')).toBeNull() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content).toHaveAttribute('style', expectedStyles) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let content = document.querySelectorAll('.nut-popover-arrow')[0] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content).toHaveAttribute('style', 'left: 36px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('bottom', 'left: calc(50% + 20px);') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('bottom-right', 'right: -4px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left', 'top: calc(50% - 20px);') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left-bottom', 'bottom: 36px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left-top', 'top: -4px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right', 'top: calc(50% - 20px);') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right-bottom', 'bottom: 36px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right-top', 'top: -4px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top-right', 'right: -4px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top-left', 'left: 36px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top', 'left: calc(50% + 20px);') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(content).toHaveAttribute('style', 'left: 20px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('bottom', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('bottom-right', 'right: 20px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left-bottom', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('left-top', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right-bottom', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('right-top', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top-right', 'right: 20px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top-left', 'left: 20px;') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| checkArrowStyles('top', null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test('render position fixed ', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -187,6 +194,37 @@ test('should not emit select event when the action is disabled', async () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await waitFor(() => expect(choose).not.toBeCalled()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test('should auto show on mount when autoShow is true', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const open = vi.fn() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| render( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Popover autoShow visible={false} list={itemList} onOpen={open}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button type="primary">自动弹出</Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(open).toBeCalled() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test('should auto close after duration', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.useFakeTimers() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const close = vi.fn() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const click = vi.fn() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| render( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Popover | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| visible | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| duration={5000} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| list={itemList} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClose={close} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={click} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <Button type="primary">自动关闭</Button> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </Popover> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.advanceTimersByTime(5000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(close).toBeCalled() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(click).toBeCalled() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vi.useRealTimers() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+207
to
+226
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major 🧩 Analysis chain🏁 Script executed: # First, let's look at the test file structure
cat -n src/packages/popover/__tests__/popover.spec.tsx | sed -n '207,226p'Repository: jdf2e/nutui-react Length of output: 1917 🏁 Script executed: # Also check the Popover component implementation to understand how duration works
fd -t f "popover" --type f -e ts -e tsx src/packages/popover/ | grep -v "spec\|test" | head -5Repository: jdf2e/nutui-react Length of output: 1917 🏁 Script executed: # Let's look at the broader test file context
wc -l src/packages/popover/__tests__/popover.spec.tsxRepository: jdf2e/nutui-react Length of output: 1917 🌐 Web query:
💡 Result: Best-practice cleanup pattern for Vitest fake timers (vi.useFakeTimers) is: always restore real timers in a finally/afterEach, and clear any scheduled timers before switching back. Recommended pattern (per test) try { vi.useFakeTimers //...test code that schedules timers // optionally: vi.advanceTimersByTime(...), vi.runAllTimers, etc. } finally { vi.clearAllTimers vi.useRealTimers } Why this pattern 1) vi.useFakeTimers keeps faking timers until you call vi.useRealTimers. [1] 2) vi.clearAllTimers “removes all timers that are scheduled to run” so they will never run later (prevents leakage into subsequent tests). [1] 3) vi.useRealTimers restores mocked timers back to their original implementations; timers scheduled before switching back are discarded. [2] Notes / variations - If you only need a subset of timer APIs, pass options like vi.useFakeTimers({ toFake: [...] }) or vi.useFakeTimers({ toNotFake: [...] }). [1] - Dates: with fake timers, Date.now is mocked, and to control Date you can use vi.setSystemTime; when done you should restore with vi.useRealTimers in afterEach/cleanup. [3] Example using beforeEach/afterEach instead of per-test try/finally beforeEach( => { vi.useFakeTimers }) afterEach( => { vi.clearAllTimers vi.useRealTimers }) This is consistent with Vitest’s timer APIs: useFakeTimers wraps timer calls until useRealTimers, and clearAllTimers drops queued timers so they don’t affect later tests. [1][2] Citations:
🌐 Web query:
💡 Result: When using Vitest fake timers with React Testing Library (RTL), you should generally wrap calls to vi.advanceTimersByTime in act [1][2][3]. This ensures that any React state updates triggered by the timer advancement are processed and flushed, preventing "not wrapped in act" warnings and ensuring your assertions reflect the updated component state [2][3]. Why act is required React processes state updates in batches [4]. When you manually advance timers using vi.advanceTimersByTime, the callbacks associated with those timers (such as setTimeout or setInterval) execute outside of React's standard update cycle [3]. Without act, React may not be aware of the state updates triggered by these callbacks, leading to warnings or race conditions where your assertions run before the component has finished re-rendering [2][3]. Recommended Usage Pattern To correctly advance timers and update the component, wrap the call in act: import { act, render, screen } from ' Citations:
在 Line 207-226 增强定时器用例隔离,避免测试串扰 当前测试缺少两个关键的最佳实践:
建议使用 建议修改 test('should auto close after duration', () => {
vi.useFakeTimers()
const close = vi.fn()
const click = vi.fn()
- render(
- <Popover
- visible
- duration={5000}
- list={itemList}
- onClose={close}
- onClick={click}
- >
- <Button type="primary">自动关闭</Button>
- </Popover>
- )
- vi.advanceTimersByTime(5000)
- expect(close).toBeCalled()
- expect(click).toBeCalled()
- vi.useRealTimers()
+ try {
+ render(
+ <Popover
+ visible
+ duration={5000}
+ list={itemList}
+ onClose={close}
+ onClick={click}
+ >
+ <Button type="primary">自动关闭</Button>
+ </Popover>
+ )
+ act(() => {
+ vi.advanceTimersByTime(5000)
+ })
+ expect(close).toBeCalled()
+ expect(click).toBeCalled()
+ } finally {
+ vi.clearAllTimers()
+ vi.useRealTimers()
+ }
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test('click event', async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const close = vi.fn() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const close1 = vi.fn() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
版本锁定策略不一致
@nutui/icons-react保持范围符^3.0.2-beta.6(允许小版本更新),而@nutui/icons-react-taro改为精确版本3.0.2-beta.6(移除了^)。这样的不一致可能导致 H5 和 Taro 版本的图标依赖在不同环境中出现版本分歧。请说明为什么需要这样的差异,或统一为相同的版本策略。
🤖 Prompt for AI Agents