import { fireEvent, render, waitFor } from '@testing-library/react-native'
import React, { useState } from 'react'
import { View } from 'react-native'
import { Provider } from 'react-redux'
import TextInput from 'src/components/TextInput'
import { RecipientType } from 'src/recipients/recipient'
import { resolveId } from 'src/recipients/resolve-id'
import {
ResolutionKind,
mergeRecipients,
useMapResolutionsToRecipients,
useResolvedRecipients,
useSendRecipients,
useUniqueSearchRecipient,
type NameResolution,
} from 'src/send/hooks'
import { createMockStore } from 'test/utils'
import {
mockAccount,
mockAddressToE164Number,
mockE164NumberToAddress,
mockInvitableRecipient2,
mockInvitableRecipient3,
mockPhoneRecipientCache,
mockRecipient,
mockRecipient2,
mockRecipient3,
mockRecipient4,
} from 'test/values'
jest.mock('src/recipients/resolve-id')
const getStore = (phoneNumberVerified: boolean = true) =>
createMockStore({
app: {
phoneNumberVerified,
},
send: {
recentRecipients: [mockRecipient, mockRecipient2],
},
recipients: {
phoneRecipientCache: mockPhoneRecipientCache,
},
identity: {
addressToE164Number: mockAddressToE164Number,
e164NumberToAddress: mockE164NumberToAddress,
},
})
describe('useResolvedRecipients', () => {
beforeEach(() => {
jest.mocked(resolveId).mockImplementation(async (id) => {
return {
resolutions:
id === '5555555555'
? [
{
kind: ResolutionKind.Address,
address: mockAccount,
},
]
: [],
}
})
})
async function renderHook() {
const result = jest.fn()
function TestComponent() {
const [searchQuery, setSearchQuery] = useState('')
const recipients = useResolvedRecipients(searchQuery)
if (recipients.length) {
result(recipients)
}
return (
)
}
return {
...render(
),
result,
}
}
it('resolves and maps recipient', async () => {
const { result, getByTestId } = await renderHook()
expect(getByTestId('loading')).toBeTruthy()
fireEvent.changeText(getByTestId('searchInput'), '55555555')
fireEvent.changeText(getByTestId('searchInput'), '555555555')
fireEvent.changeText(getByTestId('searchInput'), '5555555555')
await waitFor(() => {
expect(getByTestId('complete')).toBeTruthy()
})
expect(resolveId).toHaveBeenCalledTimes(2)
expect(resolveId).toHaveBeenCalledWith('')
expect(resolveId).toHaveBeenCalledWith('5555555555')
expect(result).toHaveBeenCalledWith([
{
address: mockAccount.toLowerCase(),
name: 'John Doe',
thumbnailPath: undefined,
contactId: 'contactId',
e164PhoneNumber: '+14155550000',
displayNumber: '14155550000',
recipientType: RecipientType.Address,
},
])
})
})
describe('useSendRecipients', () => {
function renderHook(phoneVerified: boolean) {
const result = jest.fn()
function TestComponent() {
const recipients = useSendRecipients()
result(recipients)
return null
}
render(
)
return result
}
it('gets sorted contact and recent recipients', () => {
const result = renderHook(true)
expect(result.mock.calls[0][0]).toEqual({
recentRecipients: [mockRecipient, mockRecipient2],
contactRecipients: [mockInvitableRecipient3, mockInvitableRecipient2, mockRecipient],
})
})
it('excludes contact recipients if phone number is not verified', () => {
const result = renderHook(false)
expect(result.mock.calls[0][0]).toEqual({
recentRecipients: [mockRecipient, mockRecipient2],
contactRecipients: [],
})
})
})
describe('mergeRecipients', () => {
it('orders recipients correctly without duplicates', () => {
const resolvedRecipients = [mockRecipient3]
const recentRecipients = [mockRecipient2]
const contactRecipients = [
mockRecipient,
{
...mockRecipient3,
name: 'some other name',
},
]
const mergedRecipients = mergeRecipients({
contactRecipients,
recentRecipients,
resolvedRecipients,
uniqueSearchRecipient: mockRecipient4,
})
expect(mergedRecipients).toEqual([mockRecipient3, mockRecipient2, mockRecipient])
})
it('uses the unique recipient if none other available', () => {
const mergedRecipients = mergeRecipients({
contactRecipients: [],
recentRecipients: [],
resolvedRecipients: [],
uniqueSearchRecipient: mockRecipient4,
})
expect(mergedRecipients).toEqual([mockRecipient4])
})
it('returns empty list when no recipients available', () => {
const mergedRecipients = mergeRecipients({
contactRecipients: [],
recentRecipients: [],
resolvedRecipients: [],
})
expect(mergedRecipients).toEqual([])
})
it('does not dedpulicate undefined address', () => {
const mergedRecipients = mergeRecipients({
contactRecipients: [
{
...mockRecipient,
address: undefined,
},
],
recentRecipients: [
{
...mockRecipient2,
e164PhoneNumber: 'fake phone number',
address: undefined,
},
],
resolvedRecipients: [],
})
expect(mergedRecipients).toEqual([
{
...mockRecipient2,
e164PhoneNumber: 'fake phone number',
address: undefined,
},
{
...mockRecipient,
address: undefined,
},
])
})
it('does not dedpulicate undefined phone number', () => {
const mergedRecipients = mergeRecipients({
contactRecipients: [
{
...mockRecipient,
e164PhoneNumber: undefined,
},
],
recentRecipients: [
{
...mockRecipient2,
e164PhoneNumber: undefined,
address: 'some fake address',
},
],
resolvedRecipients: [],
})
expect(mergedRecipients).toEqual([
{
...mockRecipient2,
address: 'some fake address',
e164PhoneNumber: undefined,
},
{
...mockRecipient,
e164PhoneNumber: undefined,
},
])
})
})
describe('useUniqueSearchRecipient', () => {
function renderHook(searchQuery: string) {
const result = jest.fn()
function TestComponent() {
const recipient = useUniqueSearchRecipient(searchQuery)
result(recipient)
return null
}
render(
)
return result
}
it('returns unique phone number recipient', () => {
const result = renderHook('7255555555')
expect(result.mock.calls[0][0]).toEqual({
displayNumber: '(725) 555-5555',
e164PhoneNumber: '+17255555555',
recipientType: RecipientType.PhoneNumber,
})
})
it('returns unique address recipient', () => {
const mockAddress = '0x000000000000000000000000000000000000ABCD'
const result = renderHook(mockAddress)
expect(result.mock.calls[0][0]).toEqual({
address: mockAddress.toLowerCase(),
recipientType: RecipientType.Address,
})
})
it('returns no results', () => {
const result = renderHook('neither address nor phone number')
expect(result.mock.calls[0][0]).toBe(undefined)
})
})
describe('useMapResolutionsToRecipients', () => {
function renderHook(searchQuery: string, resolutions: NameResolution[]) {
const result = jest.fn()
function TestComponent() {
const recipients = useMapResolutionsToRecipients(searchQuery, resolutions)
result(recipients)
return null
}
render(
)
return result
}
it('returns recipient for address-based resolution', () => {
const mockResolutions = [
{
kind: ResolutionKind.Address,
address: mockAccount,
},
]
const result = renderHook('some query', mockResolutions)
expect(result.mock.calls[0][0][0]).toEqual({
address: mockAccount.toLowerCase(),
name: 'John Doe',
thumbnailPath: undefined,
contactId: 'contactId',
e164PhoneNumber: '+14155550000',
displayNumber: '14155550000',
recipientType: RecipientType.Address,
})
})
it('returns recipient for nom-based resolution', () => {
const mockResolutions = [
{
kind: ResolutionKind.Nom,
address: mockAccount,
name: 'Nom Handle',
},
]
const result = renderHook('some query', mockResolutions)
expect(result.mock.calls[0][0][0]).toEqual({
address: mockAccount.toLowerCase(),
name: 'nomSpaceRecipient, {"name":"Nom Handle"}',
recipientType: RecipientType.Nomspace,
})
})
it('returns recipient for nom-based resolution with missing name', () => {
const mockResolutions = [
{
kind: ResolutionKind.Nom,
address: mockAccount,
},
]
const result = renderHook('some query', mockResolutions)
expect(result.mock.calls[0][0][0]).toEqual({
address: mockAccount.toLowerCase(),
name: 'nomSpaceRecipient, {"name":"some query"}',
recipientType: RecipientType.Nomspace,
})
})
})