Skip to content

Commit

Permalink
fix: AddressField onChange callback (#503)
Browse files Browse the repository at this point in the history
  • Loading branch information
Melisa Anabella Rossi authored Jan 24, 2024
1 parent e245938 commit 22e3b05
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 24 deletions.
75 changes: 71 additions & 4 deletions src/components/AddressField/AddressField.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { RenderResult, render, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Props } from './AddressField.types'
import { AddressFieldErrors, Props } from './AddressField.types'
import AddressField from './AddressField'
import { shorten } from './utils'

Expand All @@ -13,13 +13,16 @@ const address = '0x89805E5f0698Cb4dB57f0E389f2a75259f78CC22'
const name = 'test.dcl.eth'
let screen: RenderResult
let resolveNameMock: jest.Mock
let onChangeMock: jest.Mock

describe('when user inputs an address', () => {
beforeEach(async () => {
resolveNameMock = jest.fn()
onChangeMock = jest.fn()
screen = renderAddressField({
resolveName: resolveNameMock,
placeholder: 'test address'
placeholder: 'test address',
onChange: onChangeMock
})
const addressInput = screen.getByPlaceholderText('test address')
userEvent.type(addressInput, address)
Expand All @@ -39,15 +42,24 @@ describe('when user inputs an address', () => {
it('should not show the resolved address', () => {
expect(screen.queryByTestId('resolved-address')).not.toBeInTheDocument()
})

it('should call onChange callback with address', () => {
expect(onChangeMock).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ value: address, error: undefined })
)
})
})

describe('when user inputs a name', () => {
describe('and the name resolves correctly to an address', () => {
beforeEach(async () => {
resolveNameMock = jest.fn().mockResolvedValue(address)
onChangeMock = jest.fn()
screen = renderAddressField({
resolveName: resolveNameMock,
placeholder: 'test address'
placeholder: 'test address',
onChange: onChangeMock
})
const addressInput = screen.getByPlaceholderText('test address')
userEvent.type(addressInput, name)
Expand All @@ -67,14 +79,23 @@ describe('when user inputs a name', () => {
it('should show the cropped address', () => {
expect(screen.queryByText(shorten(address))).toBeInTheDocument()
})

it('should call onChange callback with resolved address', () => {
expect(onChangeMock).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ value: address, error: undefined })
)
})
})

describe("and the name doesn't resolve to an address", () => {
beforeEach(async () => {
resolveNameMock = jest.fn().mockResolvedValue(undefined)
onChangeMock = jest.fn()
screen = renderAddressField({
resolveName: resolveNameMock,
placeholder: 'test address'
placeholder: 'test address',
onChange: onChangeMock
})
const addressInput = screen.getByPlaceholderText('test address')
userEvent.type(addressInput, name)
Expand All @@ -91,5 +112,51 @@ describe('when user inputs a name', () => {
).toBeInTheDocument()
)
})

it('should call onChange callback with the invalid address/name', async () => {
await waitFor(() => {
expect(onChangeMock).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
value: name,
error: new Error(AddressFieldErrors.INVALID_ADDRESS_OR_NAME)
})
)
})
})
})
})

describe('when there is an error resolving the name', () => {
beforeEach(async () => {
resolveNameMock = jest.fn().mockRejectedValue(new Error('Some ERROR'))
onChangeMock = jest.fn()
screen = renderAddressField({
resolveName: resolveNameMock,
placeholder: 'test address',
onChange: onChangeMock
})
const addressInput = screen.getByPlaceholderText('test address')
userEvent.type(addressInput, name)
})

it('should show an error', async () => {
await waitFor(() =>
expect(
screen.getByText('This is not a valid name or address')
).toBeInTheDocument()
)
})

it('should call onChange callback with error', async () => {
await waitFor(() => {
expect(onChangeMock).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
value: name,
error: new Error(AddressFieldErrors.ERROR_RESOLVING_NAME)
})
)
})
})
})
43 changes: 23 additions & 20 deletions src/components/AddressField/AddressField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { InputOnChangeData } from 'semantic-ui-react/dist/commonjs/elements/Inpu
import Popup from 'semantic-ui-react/dist/commonjs/modules/Popup'
import { Field } from '../Field/Field'
import { shorten, isValid } from './utils'
import { Props } from './AddressField.types'
import { AddressFieldErrors, Props } from './AddressField.types'
import './AddressField.css'

export default function AddressField(props: Props) {
Expand Down Expand Up @@ -40,31 +40,34 @@ export default function AddressField(props: Props) {
}

timeout.current = setTimeout(async () => {
let address = data.value
let error = undefined

if (isValid(data.value)) {
setValid(true)
if (onChange) {
onChange(evt, data)
}
return
}

setLoading(true)
try {
const resolvedAddress = await resolveName(data.value)
if (resolvedAddress) {
setValid(true)
setAddress(resolvedAddress)
if (onChange) {
onChange(evt, { value: resolvedAddress })
} else {
// If address is not valid try to resolve it as a name
setLoading(true)
try {
const resolvedAddress = await resolveName(data.value)
if (resolvedAddress) {
setValid(true)
setAddress(resolvedAddress)
address = resolvedAddress
} else {
setValid(false)
error = new Error(AddressFieldErrors.INVALID_ADDRESS_OR_NAME)
}
} else {
} catch (e) {
error = new Error(AddressFieldErrors.ERROR_RESOLVING_NAME)
setValid(false)
}
} catch (e) {
console.error('Error resolving address', e)
setValid(false)
setLoading(false)
}

if (onChange) {
onChange(evt, { ...data, value: address, error })
}
setLoading(false)
}, 800)
},
[onChange]
Expand Down
5 changes: 5 additions & 0 deletions src/components/AddressField/AddressField.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export type Props = FieldProps & {
i18n?: { errorMessage: string }
resolveName: (address: string) => Promise<string | undefined>
}

export enum AddressFieldErrors {
INVALID_ADDRESS_OR_NAME = 'Invalid address or name',
ERROR_RESOLVING_NAME = 'Error resolving name'
}

1 comment on commit 22e3b05

@vercel
Copy link

@vercel vercel bot commented on 22e3b05 Jan 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

decentraland-ui – ./

decentraland-ui-git-master-decentraland1.vercel.app
decentraland-ui-decentraland1.vercel.app

Please sign in to comment.