Added tests for Address Book import validations (#2393)
* Added tests and utils file * Minor changes
This commit is contained in:
parent
add406c42b
commit
a130fdd4cb
|
@ -5,9 +5,9 @@ import { Text } from '@gnosis.pm/safe-react-components'
|
|||
import { Modal } from 'src/components/Modal'
|
||||
import { CSVReader } from 'react-papaparse'
|
||||
import { AddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
import { checksumAddress } from 'src/utils/checksumAddress'
|
||||
import HelpInfo from 'src/routes/safe/components/AddressBook/HelpInfo'
|
||||
import { validateCsvData, validateFile } from 'src/routes/safe/components/AddressBook/utils'
|
||||
|
||||
const ImportContainer = styled.div`
|
||||
flex-direction: column;
|
||||
|
@ -28,15 +28,6 @@ const InfoContainer = styled.div`
|
|||
margin-top: 16px;
|
||||
`
|
||||
|
||||
const WRONG_FILE_EXTENSION_ERROR = 'Only CSV files are allowed'
|
||||
const FILE_SIZE_TOO_BIG = 'The size of the file is over 1 MB'
|
||||
const FILE_BYTES_LIMIT = 1000000
|
||||
const IMPORT_SUPPORTED_FORMATS = [
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'text/csv',
|
||||
]
|
||||
|
||||
type ImportEntriesModalProps = {
|
||||
importEntryModalHandler: (addressList: AddressBookEntry[]) => void
|
||||
isOpen: boolean
|
||||
|
@ -76,36 +67,6 @@ const ImportEntriesModal = ({ importEntryModalHandler, isOpen, onClose }: Import
|
|||
setCsvLoaded(true)
|
||||
}
|
||||
|
||||
const validateFile = (file) => {
|
||||
if (!IMPORT_SUPPORTED_FORMATS.includes(file.type)) {
|
||||
return WRONG_FILE_EXTENSION_ERROR
|
||||
}
|
||||
|
||||
if (file.size >= FILE_BYTES_LIMIT) {
|
||||
return FILE_SIZE_TOO_BIG
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const validateCsvData = (data) => {
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
const entry = data[index]
|
||||
if (!entry.data[0] || !entry.data[1] || !entry.data[2]) {
|
||||
return `Invalid amount of columns on row ${index + 1}`
|
||||
}
|
||||
// Verify address properties
|
||||
const address = entry.data[0].toLowerCase()
|
||||
if (!isValidAddress(address)) {
|
||||
return `Invalid address on row ${index + 1}`
|
||||
}
|
||||
if (isNaN(entry.data[2])) {
|
||||
return `Invalid chain id on row ${index + 1}`
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const handleOnError = (error) => {
|
||||
setImportError(error.message)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
WRONG_FILE_EXTENSION_ERROR,
|
||||
FILE_SIZE_TOO_BIG_ERROR,
|
||||
IMPORT_SUPPORTED_FORMATS,
|
||||
validateFile,
|
||||
validateCsvData,
|
||||
CsvDataType,
|
||||
} from '../utils'
|
||||
|
||||
describe('Address Book file validations', () => {
|
||||
it('Should return wrong file extension error if file extension is not the allowed', () => {
|
||||
const file = new File([''], 'file.txt', { type: 'text/plain' })
|
||||
const result = validateFile(file)
|
||||
expect(result).toBe(WRONG_FILE_EXTENSION_ERROR)
|
||||
})
|
||||
|
||||
it('Should return file size error if file size is over the allowed', () => {
|
||||
const file = new File([''], 'file.csv', { type: IMPORT_SUPPORTED_FORMATS[0] })
|
||||
Object.defineProperty(file, 'size', { value: 1024 * 1024 + 1 })
|
||||
const result = validateFile(file)
|
||||
expect(result).toBe(FILE_SIZE_TOO_BIG_ERROR)
|
||||
})
|
||||
|
||||
it('Should return undefined if extension and file size are valid', () => {
|
||||
const file = new File([''], 'file.csv', { type: IMPORT_SUPPORTED_FORMATS[0] })
|
||||
const result = validateFile(file)
|
||||
expect(result).toBe(undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Address Book CSV data validations', () => {
|
||||
const validAddress = '0x4362527986c3fD47f498eF24B4D01e6AAD7aBcb2'
|
||||
const noHexAddress = '4362527986c3fD47f498eF24B4D01e6AAD7aBcb2'
|
||||
const invalidAddress = '0xC1912fEE45d61C87Cc5EA59DaE31190FFFFfff2'
|
||||
const validName = 'Name'
|
||||
const validChainId = '4'
|
||||
it('Should return an error if the amount of columns is not valid', () => {
|
||||
const data: CsvDataType = [{ data: [validAddress, validName] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid amount of columns on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if name is empty', () => {
|
||||
const data = [{ data: [validAddress, '', validChainId] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid amount of columns on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if address is empty', () => {
|
||||
const data = [{ data: ['', validName, validChainId] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid amount of columns on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if chainId is empty', () => {
|
||||
const data = [{ data: [validAddress, validName, ''] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid amount of columns on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if address is not hex strict', () => {
|
||||
const data = [{ data: [noHexAddress, validName, validChainId] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid address on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if address is not valid', () => {
|
||||
const data = [{ data: [invalidAddress, validName, validChainId] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid address on row 1')
|
||||
})
|
||||
|
||||
it('Should return an error if chainId is not valid', () => {
|
||||
const data = [{ data: [validAddress, validName, 'notAChainId'] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe('Invalid chain id on row 1')
|
||||
})
|
||||
|
||||
it('Should return undefined if all elements are valid', () => {
|
||||
const data = [{ data: [validAddress, validName, validChainId] }]
|
||||
const result = validateCsvData(data)
|
||||
expect(result).toBe(undefined)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,49 @@
|
|||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
|
||||
export const WRONG_FILE_EXTENSION_ERROR = 'Only CSV files are allowed'
|
||||
export const FILE_SIZE_TOO_BIG_ERROR = 'The size of the file is over 1 MB'
|
||||
export const FILE_BYTES_LIMIT = 1000000
|
||||
export const IMPORT_SUPPORTED_FORMATS = [
|
||||
'text/csv',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
]
|
||||
|
||||
export type CsvDataType = { data: string[] }[]
|
||||
|
||||
export const validateFile = (file: File): string | undefined => {
|
||||
if (!IMPORT_SUPPORTED_FORMATS.includes(file.type)) {
|
||||
return WRONG_FILE_EXTENSION_ERROR
|
||||
}
|
||||
|
||||
if (file.size >= FILE_BYTES_LIMIT) {
|
||||
return FILE_SIZE_TOO_BIG_ERROR
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
export const validateCsvData = (data: CsvDataType): string | undefined => {
|
||||
for (let index = 0; index < data.length; index++) {
|
||||
const entry = data[index]
|
||||
const [address, name, chainId] = entry.data
|
||||
if (entry.data.length !== 3) {
|
||||
return `Invalid amount of columns on row ${index + 1}`
|
||||
}
|
||||
if (typeof address !== 'string' || typeof name !== 'string' || typeof chainId !== 'string') {
|
||||
return `Invalid amount of columns on row ${index + 1}`
|
||||
}
|
||||
if (!address.trim() || !name.trim() || !chainId.trim()) {
|
||||
return `Invalid amount of columns on row ${index + 1}`
|
||||
}
|
||||
// Verify address properties
|
||||
const lowerCaseAddress = address.toLowerCase()
|
||||
if (!isValidAddress(lowerCaseAddress)) {
|
||||
return `Invalid address on row ${index + 1}`
|
||||
}
|
||||
if (isNaN(parseInt(chainId))) {
|
||||
return `Invalid chain id on row ${index + 1}`
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Loading…
Reference in New Issue