diff --git a/packages/renderless/src/ip-address/index.ts b/packages/renderless/src/ip-address/index.ts index 1fa05b1771..43aede9267 100644 --- a/packages/renderless/src/ip-address/index.ts +++ b/packages/renderless/src/ip-address/index.ts @@ -89,32 +89,31 @@ export const getValue = export const setValue = ({ api, props, state }: { api: IIpAddressApi; props: IIpAddressProps; state: IIpAddressState }) => (value: string) => { - if (value) { - /* istanbul ignore else */ - if (api?.ipValidator?.(value)) { - if (api.isIP6(props.type)) { - state.address = value.split(':').map((item) => ({ value: item })) - if (state.address.length < 8) { - let insertIndex = 0 - state.address.forEach((item, index) => { - if (item.value === '') { - item.value = '0000' - insertIndex = index - } - }) - for (let i = 0; i <= 8 - state.address.length; i++) { - state.address.splice(insertIndex, 0, { value: '0000' }) - } - } - } else { - state.address = value.split('.').map((item) => ({ value: item })) + if (!value || !api?.ipValidator?.(value)) { + const createValue = () => ({ value: '' }) + state.address = api.isIP6(props.type) + ? Array.from({ length: 8 }, createValue) + : Array.from({ length: 4 }, createValue) + + return + } + + if (api.isIP6(props.type)) { + state.address = value.split(':').map((item) => ({ value: item })) + if (state.address.length < 8) { + const missingCount = 8 - state.address.length + const emptyIndex = state.address.findIndex((item) => item.value === '') + const insertIndex = emptyIndex >= 0 ? emptyIndex : 0 + + if (emptyIndex >= 0) { + state.address[emptyIndex].value = '0000' } + + const newItems = Array(missingCount).fill({ value: '0000' }) + state.address.splice(insertIndex, 0, ...newItems) } } else { - const createValue = () => ({ value: '' }) - state.address = api.isIP6(props.type) - ? new Array(8).fill('').map(createValue) - : new Array(4).fill('').map(createValue) + state.address = value.split('.').map((item) => ({ value: item })) } } diff --git a/packages/vue/src/ip-address/__tests__/ip-address.test.tsx b/packages/vue/src/ip-address/__tests__/ip-address.test.tsx index 0cc90ecce3..d25751040a 100644 --- a/packages/vue/src/ip-address/__tests__/ip-address.test.tsx +++ b/packages/vue/src/ip-address/__tests__/ip-address.test.tsx @@ -2,6 +2,7 @@ import { mountPcMode } from '@opentiny-internal/vue-test-utils' import { describe, expect, test, vi } from 'vitest' import IpAddress from '@opentiny/vue-ip-address' import { nextTick } from 'vue' +import { iconBoat } from '@opentiny/vue-icon' let value = '' @@ -14,17 +15,64 @@ describe('PC Mode', () => { expect(wrapper.find('input').attributes()).toHaveProperty('readonly') }) - test.todo('delimiter ,设置IP段之间的分隔符,默认为 "." ') + describe('delimiter ,设置IP段之间的分隔符', () => { + test('默认为 "." ', async () => { + const wrapper = mount(() => ) + expect(wrapper.findAll('svg')).toHaveLength(3) + }) - test.todo('size ,设置组件大小;该属性的可选值为 medium / small / mini') + test('设置为 "-" ', async () => { + const wrapper = mount(() => ( + + - + + )) + expect(wrapper.findAll('span').map((i) => i.text())).toEqual(['-', '-', '-']) + }) - test.todo('disabled ,设置文本的禁用属性,默认为 false ') + test('设置为 icon', async () => { + const IconBoat = iconBoat() + const wrapper = mount(() => ) + expect(wrapper.findAll('svg')).toHaveLength(3) + }) + }) - test.todo('type ,设置IpAddress框的类型,默认是IPv4,当为IPv6时,只有一个IP端输入框,无分隔符') + describe('size, 设置组件大小', () => { + ;['medium', 'small', 'mini'].forEach((size) => { + test(size, async () => { + const wrapper = mount(() => ) + expect(wrapper.find('.tiny-ip-address__input').classes()).toContain(size) + }) + }) + }) - test.todo('value ,设置文本显示的默认值') + test('disabled ,设置文本的禁用属性,默认为 false ', async () => { + const wrapper = mount(() => ) + expect(wrapper.find('input').attributes()).toHaveProperty('disabled') + }) + + test('value ,设置文本显示的默认值', async () => { + value = '127.0.0.1' + const wrapper = mount(() => ) + expect(wrapper.findAll('input').map((inputEl) => inputEl.element.value)).toEqual(['127', '0', '0', '1']) + }) + + test('invalid value in ipv6', async () => { + value = '127.0.0.1' + const wrapper = mount(() => ) + const values = wrapper.findAll('input').map((inputEl) => inputEl.element.value) + expect(values).toHaveLength(8) + expect(values).toEqual(Array.from({ length: 8 }, () => '')) + }) + + test('invalid value in ipv4', async () => { + value = 'fe80::204:61ff:fe9d:f156' + const wrapper = mount(() => ) + const values = wrapper.findAll('input').map((inputEl) => inputEl.element.value) + expect(values).toHaveLength(4) + expect(values).toEqual(Array.from({ length: 4 }, () => '')) + }) - // slots test('default slot', async () => { const wrapper = mount(() => ( { v-slots={{ default: () => -- }} - > + /> )) expect(wrapper.find('i').text()).toBe('--') }) @@ -40,7 +88,7 @@ describe('PC Mode', () => { // events test('events', async () => { const focus = vi.fn() - const wrapper = mount(() => ) + const wrapper = mount(() => ) await wrapper.find('input').trigger('focus') await nextTick() expect(focus).toHaveBeenCalled()