diff --git a/packages/varlet-ui/src/bottom-navigation/__tests__/index.spec.js b/packages/varlet-ui/src/bottom-navigation/__tests__/index.spec.js index e950685f8cf..4408b3935ec 100644 --- a/packages/varlet-ui/src/bottom-navigation/__tests__/index.spec.js +++ b/packages/varlet-ui/src/bottom-navigation/__tests__/index.spec.js @@ -145,6 +145,38 @@ describe('test bottom-navigation events', () => { wrapper.unmount() }) + test('bottom-navigation before-change rejects update', async () => { + const handleBeforeChange = vi.fn(() => [true, false]) + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + data: () => ({ + active: 0, + }), + methods: { + handleBeforeChange, + onUpdateActive, + }, + template: ` + + + + + `, + }) + + await delay(16) + await trigger(wrapper.findAll('.var-bottom-navigation-item')[1], 'click') + await delay(16) + expect(handleBeforeChange).toHaveBeenCalledTimes(1) + expect(onUpdateActive).not.toHaveBeenCalled() + + wrapper.unmount() + }) + test('bottom-navigation fab-click event', async () => { const handleFabClick = vi.fn() const wrapper = mount({ @@ -177,6 +209,184 @@ describe('test bottom-navigation events', () => { }) describe('test bottom-navigation component props', () => { + test('bottom-navigation active boundary for non-number', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + `, + methods: { + onUpdateActive, + }, + }) + + await delay(16) + expect(onUpdateActive).not.toHaveBeenCalled() + wrapper.unmount() + }) + + test('bottom-navigation active boundary clamps', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + `, + methods: { + onUpdateActive, + }, + }) + + await delay(16) + expect(onUpdateActive).toHaveBeenCalledWith(0) + wrapper.unmount() + + const onUpdateActiveMax = vi.fn() + const wrapperMax = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + `, + methods: { + onUpdateActiveMax, + }, + }) + + await delay(16) + expect(onUpdateActiveMax).toHaveBeenCalledWith(1) + wrapperMax.unmount() + }) + + test('bottom-navigation clamps active above max', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + methods: { + onUpdateActive, + }, + }) + + await delay(16) + expect(onUpdateActive).toHaveBeenCalledWith(0) + wrapper.unmount() + }) + + test('bottom-navigation ignores NaN active', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + data: () => ({ + active: Number.NaN, + }), + methods: { + onUpdateActive, + }, + template: ` + + + + + `, + }) + + await delay(16) + expect(onUpdateActive).not.toHaveBeenCalled() + wrapper.unmount() + }) + + test('bottom-navigation clamps negative active on length change', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + data: () => ({ + active: -1, + showItems: false, + }), + methods: { + onUpdateActive, + }, + template: ` + + + + + `, + }) + + await delay(16) + expect(onUpdateActive).not.toHaveBeenCalled() + + await wrapper.setData({ showItems: true }) + await delay(16) + expect(onUpdateActive).toHaveBeenCalledWith(0) + + wrapper.unmount() + }) + + test('bottom-navigation active boundary clamps on length change', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + data: () => ({ + showItems: false, + }), + methods: { + onUpdateActive, + }, + template: ` + + + + + `, + }) + + await delay(16) + expect(onUpdateActive).not.toHaveBeenCalled() + + await wrapper.setData({ showItems: true }) + await delay(16) + expect(onUpdateActive).toHaveBeenCalledWith(1) + + wrapper.unmount() + }) + test('bottom-navigation fixed', async () => { const wrapper = mount(Wrapper, { props: { @@ -331,4 +541,211 @@ describe('test bottom-navigation component props', () => { expect(wrapper.html()).toMatchSnapshot() wrapper.unmount() }) + + test('bottom-navigation adds right-space class for odd items with fab', async () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + + + `, + }) + + await delay(16) + const items = wrapper.findAll('.var-bottom-navigation-item') + expect(items[2].classes()).toContain('var-bottom-navigation-item--right-space') + wrapper.unmount() + }) +}) + +test('bottom-navigation-item renders badge with icon', async () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + }) + + await new Promise((resolve) => setTimeout(resolve, 16)) + const item = wrapper.find('.var-bottom-navigation-item') + expect(item.find('.var-badge').exists()).toBe(true) + expect(item.find('.var-badge').find('.var-icon-home').exists()).toBe(true) + const badge = wrapper.findComponent({ name: 'VarBadge' }) + expect(badge.props('type')).toBe('danger') + expect(badge.props('dot')).toBe(true) + wrapper.unmount() +}) + +test('bottom-navigation-item badge without icon', async () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + }) + + await new Promise((resolve) => setTimeout(resolve, 16)) + const item = wrapper.find('.var-bottom-navigation-item') + expect(item.find('.var-badge').exists()).toBe(true) + expect(item.find('.var-icon').exists()).toBe(false) + wrapper.unmount() +}) + +test('bottom-navigation-item renders icon without badge', () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + }) + + const item = wrapper.find('.var-bottom-navigation-item') + expect(item.find('.var-badge').exists()).toBe(false) + expect(item.find('.var-icon-home').exists()).toBe(true) + wrapper.unmount() +}) + +test('bottom-navigation-item supports custom icon slot', () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + + `, + }) + + expect(wrapper.find('.custom-icon').exists()).toBe(true) + wrapper.unmount() +}) + +test('bottom-navigation-item active by name', () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + `, + }) + + expect(wrapper.findAll('.var-bottom-navigation-item')[0].classes()).toContain('var-bottom-navigation-item--active') + wrapper.unmount() +}) + +test('bottom-navigation-item active by index', async () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + + `, + }) + + await new Promise((resolve) => setTimeout(resolve, 16)) + expect(wrapper.findAll('.var-bottom-navigation-item')[1].classes()).toContain('var-bottom-navigation-item--active') + wrapper.unmount() +}) + +test('bottom-navigation-item click triggers update', async () => { + const onUpdateActive = vi.fn() + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + methods: { + onUpdateActive, + }, + template: ` + + + + + `, + }) + + await new Promise((resolve) => setTimeout(resolve, 16)) + await wrapper.findAll('.var-bottom-navigation-item')[1].trigger('click') + expect(onUpdateActive).toHaveBeenCalledWith(1) + wrapper.unmount() +}) + +test('bottom-navigation-item renders empty icon when none provided', () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + }) + + const item = wrapper.find('.var-bottom-navigation-item') + expect(item.find('.var-icon').exists()).toBe(false) + expect(item.find('.custom-icon').exists()).toBe(false) + wrapper.unmount() +}) + +test('bottom-navigation-item badge uses custom props', () => { + const wrapper = mount({ + components: { + [VarBottomNavigation.name]: VarBottomNavigation, + [VarBottomNavigationItem.name]: VarBottomNavigationItem, + }, + template: ` + + + + `, + }) + + const badge = wrapper.findComponent({ name: 'VarBadge' }) + expect(badge.props('type')).toBe('success') + expect(badge.props('dot')).toBe(false) + expect(badge.props('value')).toBe(9) + wrapper.unmount() })