Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 22 additions & 23 deletions packages/renderless/src/ip-address/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }))
}
}

Expand Down
64 changes: 56 additions & 8 deletions packages/vue/src/ip-address/__tests__/ip-address.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ''

Expand All @@ -14,33 +15,80 @@ describe('PC Mode', () => {
expect(wrapper.find('input').attributes()).toHaveProperty('readonly')
})

test.todo('delimiter ,设置IP段之间的分隔符,默认为 "." ')
describe('delimiter ,设置IP段之间的分隔符', () => {
test('默认为 "." ', async () => {
const wrapper = mount(() => <IpAddress v-model={value} />)
expect(wrapper.findAll('svg')).toHaveLength(3)
})

test.todo('size ,设置组件大小;该属性的可选值为 medium / small / mini')
test('设置为 "-" ', async () => {
const wrapper = mount(() => (
<IpAddress v-model={value}>
<span>-</span>
</IpAddress>
))
expect(wrapper.findAll('span').map((i) => i.text())).toEqual(['-', '-', '-'])
})

test.todo('disabled ,设置文本的禁用属性,默认为 false ')
test('设置为 icon', async () => {
const IconBoat = iconBoat()
const wrapper = mount(() => <IpAddress v-model={value} delimiter={IconBoat} />)
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(() => <IpAddress v-model={value} size={size} />)
expect(wrapper.find('.tiny-ip-address__input').classes()).toContain(size)
})
})
})

test.todo('value ,设置文本显示的默认值')
test('disabled ,设置文本的禁用属性,默认为 false ', async () => {
const wrapper = mount(() => <IpAddress v-model={value} disabled={true} />)
expect(wrapper.find('input').attributes()).toHaveProperty('disabled')
})

test('value ,设置文本显示的默认值', async () => {
value = '127.0.0.1'
const wrapper = mount(() => <IpAddress v-model={value} />)
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(() => <IpAddress v-model={value} type={'ipv6'} />)
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(() => <IpAddress v-model={value} />)
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(() => (
<IpAddress
v-model={value}
v-slots={{
default: () => <i>--</i>
}}
></IpAddress>
/>
))
expect(wrapper.find('i').text()).toBe('--')
})

// events
test('events', async () => {
const focus = vi.fn()
const wrapper = mount(() => <IpAddress v-model={value} onFocus={focus}></IpAddress>)
const wrapper = mount(() => <IpAddress v-model={value} onFocus={focus} />)
await wrapper.find('input').trigger('focus')
await nextTick()
expect(focus).toHaveBeenCalled()
Expand Down