Trim whitespace in URL form items (#2884)

This commit is contained in:
Christian Byrne
2025-03-06 09:17:24 -07:00
committed by GitHub
parent 49964b1c2f
commit f0ba48ea22
2 changed files with 72 additions and 7 deletions

View File

@@ -44,14 +44,17 @@ const emit = defineEmits<{
const validationState = ref<ValidationState>(ValidationState.IDLE)
const cleanInput = (value: string): string =>
value ? value.replace(/\s+/g, '') : ''
// Add internal value state
const internalValue = ref(props.modelValue)
const internalValue = ref(cleanInput(props.modelValue))
// Watch for external modelValue changes
watch(
() => props.modelValue,
async (newValue: string) => {
internalValue.value = newValue
internalValue.value = cleanInput(newValue)
await validateUrl(newValue)
}
)
@@ -67,14 +70,24 @@ onMounted(async () => {
const handleInput = (value: string) => {
// Update internal value without emitting
internalValue.value = value
internalValue.value = cleanInput(value)
// Reset validation state when user types
validationState.value = ValidationState.IDLE
}
const handleBlur = async () => {
const input = cleanInput(internalValue.value)
let normalizedUrl = input
try {
const url = new URL(input)
normalizedUrl = url.toString()
} catch {
// If URL parsing fails, just use the cleaned input
}
// Emit the update only on blur
emit('update:modelValue', internalValue.value)
emit('update:modelValue', normalizedUrl)
}
// Default validation implementation
@@ -90,7 +103,7 @@ const defaultValidateUrl = async (url: string): Promise<boolean> => {
const validateUrl = async (value: string) => {
if (validationState.value === ValidationState.LOADING) return
const url = value.trim()
const url = cleanInput(value)
// Reset state
validationState.value = ValidationState.IDLE

View File

@@ -42,11 +42,11 @@ describe('UrlInput', () => {
})
const input = wrapper.find('input')
await input.setValue('https://test.com')
await input.setValue('https://test.com/')
await input.trigger('blur')
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([
'https://test.com'
'https://test.com/'
])
})
@@ -155,4 +155,56 @@ describe('UrlInput', () => {
expect(validationCount).toBe(1) // Only the initial validation should occur
})
describe('input cleaning functionality', () => {
it('trims whitespace when user types', async () => {
const wrapper = mountComponent({
modelValue: '',
placeholder: 'Enter URL'
})
const input = wrapper.find('input')
// Test leading whitespace
await input.setValue(' https://leading-space.com')
await input.trigger('input')
await nextTick()
expect(wrapper.vm.internalValue).toBe('https://leading-space.com')
// Test trailing whitespace
await input.setValue('https://trailing-space.com ')
await input.trigger('input')
await nextTick()
expect(wrapper.vm.internalValue).toBe('https://trailing-space.com')
// Test both leading and trailing whitespace
await input.setValue(' https://both-spaces.com ')
await input.trigger('input')
await nextTick()
expect(wrapper.vm.internalValue).toBe('https://both-spaces.com')
// Test whitespace in the middle of the URL
await input.setValue('https:// middle-space.com')
await input.trigger('input')
await nextTick()
expect(wrapper.vm.internalValue).toBe('https://middle-space.com')
})
it('trims whitespace when value set externally', async () => {
const wrapper = mountComponent({
modelValue: ' https://initial-value.com ',
placeholder: 'Enter URL'
})
// Check initial value is trimmed
expect(wrapper.vm.internalValue).toBe('https://initial-value.com')
// Update props with whitespace
await wrapper.setProps({ modelValue: ' https://updated-value.com ' })
await nextTick()
// Check updated value is trimmed
expect(wrapper.vm.internalValue).toBe('https://updated-value.com')
})
})
})