Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tests: add csv import tests #3232

Merged
merged 2 commits into from
Feb 9, 2024
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
81 changes: 63 additions & 18 deletions cypress/e2e/pages/address_book.page.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,86 @@
export const acceptSelection = 'Save settings'
export const addressBook = 'Address book'
const createEntryBtn = 'Create entry'
import * as main from '../pages/main.page'

export const addressBookRecipient = '[data-testid="address-book-recipient"]'
const beameriFrameContainer = '#beamerOverlay .iframeCointaner'
const beamerInput = 'input[id="beamer"]'
const nameInput = 'input[name="name"]'
const addressInput = 'input[name="address"]'
export const addressBookRecipient = '[data-testid="address-book-recipient"]'
const saveBtn = 'Save'
const exportModalBtn = '[data-testid="export-modal-btn"]'
export const editEntryBtn = 'button[aria-label="Edit entry"]'
export const deleteEntryBtn = 'button[aria-label="Delete entry"]'
export const deleteEntryModalBtnSection = '.MuiDialogActions-root'
const tableContainer = '[data-testid="table-container"]'
const tableRow = '[data-testid="table-row"]'
const importBtn = '[data-testid="import-btn"]'
const cancelImportBtn = '[data-testid="cancel-btn"]'
const uploadErrorMsg = '[data-testid="error-message"]'
const modalSummaryMessage = '[data-testid="summary-message"]'

export const acceptSelection = 'Save settings'
export const addressBook = 'Address book'
const createEntryBtn = 'Create entry'
export const delteEntryModaldeleteBtn = 'Delete'
const importBtn = 'Import'
const exportBtn = 'Export'
const exportModalBtn = '[data-testid="export-modal-btn"]'
const saveBtn = 'Save'
const whatsNewBtnStr = "What's new"
const beamrCookiesStr = 'accept the "Beamer" cookies'
const headerImportBtnStr = 'Import'

export const emptyCSVFile = '../fixtures/address_book_empty_test.csv'
export const nonCSVFile = '../fixtures/balances.json'
export const duplicatedCSVFile = 'address_book_duplicated.csv'
export const validCSVFile = '../fixtures/address_book_test.csv'
export const networksCSVFile = '../fixtures/address_book_networks.csv'
export const addedSafesCSVFile = '../fixtures/address_book_addedsafes.csv'

export const entries = [
'0x6E834E9D04ad6b26e1525dE1a37BFd9b215f40B7',
'test-sepolia-3',
'0xf405BC611F4a4c89CCB3E4d083099f9C36D966f8',
'sepolia-test-4',
'0x03042B890b99552b60A073F808100517fb148F60',
'sepolia-test-5',
'0xBd69b0a9DC90eB6F9bAc3E4a5875f437348b6415',
'assets-test-sepolia',
]

export function verifyModalSummaryMessage(entryCount, chainCount) {
cy.get(modalSummaryMessage).should(
'contain',
`Found ${entryCount} entries on ${chainCount} ${chainCount > 1 ? 'chains' : 'chain'}`,
)
}
export const uploadErrorMessages = {
fileType: 'File type must be text/csv',
emptyFile: 'No entries found in address book',
}

export function verifyUploadExportMessage(msg) {
main.verifyValuesExist(uploadErrorMsg, msg)
}

export function verifyImportBtnStatus(status) {
main.verifyElementsStatus([importBtn], status)
}

export function verifyNumberOfRows(number) {
main.verifyElementsCount(tableRow, number)
}

export function clickOnImportFileBtn() {
cy.contains(importBtn).click()
cy.contains(headerImportBtnStr).click()
}

export function importFile() {
cy.get('[type="file"]').attachFile('../fixtures/address_book_test.csv')
// Import button should be enabled
cy.get('.MuiDialogActions-root').contains('Import').should('not.be.disabled')
cy.get('.MuiDialogActions-root').contains('Import').click()
export function importCSVFile(file) {
cy.get('[type="file"]').attachFile(file)
}

export function verifyImportModalIsClosed() {
cy.get('Import address book').should('not.exist')
export function clickOnImportBtn() {
cy.get(importBtn).click()
}

export function verifyDataImported(name, address) {
cy.contains(name).should('exist')
cy.contains(address).should('exist')
export function verifyDataImported(data) {
main.verifyValuesExist(tableContainer, data)
}

export function clickOnExportFileBtn() {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/pages/sidebar.pages.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const currencySection = '[data-testid="currency-section"]'
const missingSignatureInfo = '[data-testid="missing-signature-info"]'
const queuedTxInfo = '[data-testid="queued-tx-info"]'

export const addedSafesGnosis = ['0x17b3...98C8', '0x11A6...F1BB', '0xB8d7...642A']
export const addedSafesEth = ['0x8675...a19b']
export const addedSafesSepolia = ['0x6d0b...6dC1', '0x5912...fFdb', '0x0637...708e', '0xD157...DE9a']
export const sideBarListItems = ['Home', 'Assets', 'Transactions', 'Address book', 'Apps', 'Settings']
export const testSafeHeaderDetails = ['2/2', constants.SEPOLIA_TEST_SAFE_13_SHORT]
Expand Down
38 changes: 36 additions & 2 deletions cypress/e2e/regression/address_book.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import * as constants from '../../support/constants'
import * as addressBook from '../../e2e/pages/address_book.page'
import * as main from '../../e2e/pages/main.page'
import * as ls from '../../support/localstorage_data.js'
import * as sidebar from '../pages/sidebar.pages.js'

const NAME = 'Owner1'
const EDITED_NAME = 'Edited Owner1'
const importedSafe = 'imported-safe'

describe('Address book tests', () => {
beforeEach(() => {
Expand Down Expand Up @@ -51,8 +53,7 @@ describe('Address book tests', () => {
cy.contains(constants.GNO_CSV_ENTRY.address).should('exist')
})

// TODO: Change title in Testrail. New title "...exported"
it('Verify the address book file can be downloaded', () => {
it('Verify the address book file can be exported', () => {
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.dataSet).then(() => {
main
.isItemInLocalstorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.dataSet)
Expand All @@ -72,4 +73,37 @@ describe('Address book tests', () => {
})
})
})

it('Verify that importing a csv file does not alter addresses in the Address book not present in the file', () => {
main
.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.sepoliaAddress1)
.then(() => {
main
.isItemInLocalstorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.sepoliaAddress1)
.then(() => {
cy.wait(1000)
cy.reload()
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.validCSVFile)
addressBook.clickOnImportBtn()
addressBook.verifyDataImported([constants.RECIPIENT_ADDRESS])
})
})
})

it('Verify Safe name changes after uploading a csv file', () => {
main.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addedSafes, ls.addedSafes.set4).then(() => {
main
.addToLocalStorage(constants.localStorageKeys.SAFE_v2__addressBook, ls.addressBookData.addedSafesImport)
.then(() => {
cy.wait(1000)
cy.reload()
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.addedSafesCSVFile)
addressBook.clickOnImportBtn()
sidebar.openSidebar()
sidebar.verifyAddedSafesExist([importedSafe])
})
})
})
})
15 changes: 7 additions & 8 deletions cypress/e2e/regression/sidebar_2.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import * as ls from '../../support/localstorage_data.js'
import * as assets from '../pages/assets.pages.js'

const newSafeName = 'Added safe 3'
const oldSafeName = 'Added safe 900'
const staticSafe100 = 'Added safe 100'
const addedSafe900 = 'Added safe 900'
const staticSafe200 = 'Added safe 200'

describe('Sidebar added sidebar tests', () => {
Expand All @@ -21,31 +20,31 @@ describe('Sidebar added sidebar tests', () => {

it('Verify the safe added are listed in the sidebar', () => {
sideBar.openSidebar()
sideBar.verifyAddedSafesExist(sideBar.addedSafesGnosis, sideBar.addedSafesSepolia)
sideBar.verifyAddedSafesExist(sideBar.addedSafesSepolia)
})

it('Verify Safes are separated by networks', () => {
sideBar.openSidebar()
sideBar.verifySafesByNetwork(constants.networks.gnosis, sideBar.addedSafesGnosis)
sideBar.verifySafesByNetwork(constants.networks.ethereum, sideBar.addedSafesEth)
sideBar.verifySafesByNetwork(constants.networks.sepolia, sideBar.addedSafesSepolia)
})

it('Verify a safe can be renamed', () => {
sideBar.openSidebar()
sideBar.renameSafeItem(oldSafeName, newSafeName)
sideBar.renameSafeItem(addedSafe900, newSafeName)
sideBar.clickOnSaveBtn()
sideBar.verifySafeNameExists(newSafeName)
})

it('Verify a safe can be removed', () => {
sideBar.openSidebar()
sideBar.removeSafeItem(oldSafeName)
sideBar.verifySafeRemoved([oldSafeName])
sideBar.removeSafeItem(addedSafe900)
sideBar.verifySafeRemoved([addedSafe900])
})

it('Verify the "Read only" tag if the connected user is not an owner of a safe', () => {
sideBar.openSidebar()
sideBar.verifySafeReadOnlyState(staticSafe100)
sideBar.verifySafeReadOnlyState(addedSafe900)
})

it('Verify Fiat currency changes when edited in the assets tab', () => {
Expand Down
39 changes: 36 additions & 3 deletions cypress/e2e/smoke/address_book.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as ls from '../../support/localstorage_data.js'

const NAME = 'Owner1'
const EDITED_NAME = 'Edited Owner1'
const duplicateEntry = 'test-sepolia-90'

describe('[SMOKE] Address book tests', () => {
beforeEach(() => {
Expand Down Expand Up @@ -37,8 +38,40 @@ describe('[SMOKE] Address book tests', () => {

it('[SMOKE] Verify csv file can be imported', () => {
addressBook.clickOnImportFileBtn()
addressBook.importFile()
addressBook.verifyImportModalIsClosed()
addressBook.verifyDataImported(constants.SEPOLIA_CSV_ENTRY.name, constants.SEPOLIA_CSV_ENTRY.address)
addressBook.importCSVFile(addressBook.validCSVFile)
addressBook.verifyImportBtnStatus(constants.enabledStates.enabled)
addressBook.clickOnImportBtn()
addressBook.verifyDataImported(addressBook.entries)
addressBook.verifyNumberOfRows(4)
})

it('[SMOKE] Import a csv file with an empty address/name/network in one row', () => {
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.emptyCSVFile)
addressBook.verifyImportBtnStatus(constants.enabledStates.disabled)
addressBook.verifyUploadExportMessage([addressBook.uploadErrorMessages.emptyFile])
})

it('[SMOKE] Import a non-csv file', () => {
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.nonCSVFile)
addressBook.verifyImportBtnStatus(constants.enabledStates.disabled)
addressBook.verifyUploadExportMessage([addressBook.uploadErrorMessages.fileType])
})

it('[SMOKE] Import a csv file with a repeated address and same network', () => {
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.duplicatedCSVFile)
addressBook.verifyImportBtnStatus(constants.enabledStates.enabled)
addressBook.clickOnImportBtn()
addressBook.verifyDataImported([duplicateEntry])
addressBook.verifyNumberOfRows(1)
})

it('[SMOKE] Verify modal shows the amount of entries and networks detected', () => {
addressBook.clickOnImportFileBtn()
addressBook.importCSVFile(addressBook.networksCSVFile)
addressBook.verifyImportBtnStatus(constants.enabledStates.enabled)
addressBook.verifyModalSummaryMessage(4, 3)
})
})
2 changes: 2 additions & 0 deletions cypress/fixtures/address_book_addedsafes.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
address,name,chainId
0x6d0b6F96f665Bb4490f9ddb2e450Da2f7e546dC1,imported-safe,11155111
3 changes: 3 additions & 0 deletions cypress/fixtures/address_book_duplicated.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
address,name,chainId
0x6E834E9D04ad6b26e1525dE1a37BFd9b215f40B7,test-sepolia-9,11155111
0x6E834E9D04ad6b26e1525dE1a37BFd9b215f40B7,test-sepolia-90,11155111
1 change: 1 addition & 0 deletions cypress/fixtures/address_book_empty_test.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
address,name,chainId
5 changes: 5 additions & 0 deletions cypress/fixtures/address_book_networks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
address,name,chainId
0x8675B754342754A30A2AeF474D114d8460bca19b,"mainnet safe ",1
0xB8d760a90a5ed54D3c2b3EFC231277e99188642A,"xDai Safe B8", 100
0x91e11585c114129f3Ec940Aa648A4ac13668d0c2,"Biance safe91", 56
0x61a0c717d18232711bC788F19C9Cd56a43cc8872,"MM account 1", 1
20 changes: 4 additions & 16 deletions cypress/support/localstorage_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,8 @@ export const addressBookData = {
},
},
addedSafes: {
100: {
'0x17b34aEf1428A358bA2eA360a098b8A3BEb698C8': 'Added safe 1',
'0x11A6B41322C57Bd0e56cEe06abB11A1E5c1FF1BB': 'Added safe 900',
'0xB8d760a90a5ed54D3c2b3EFC231277e99188642A': 'Added safe 100',
1: {
'0x8675B754342754A30A2AeF474D114d8460bca19b': 'Added safe 900',
},
11155111: {
'0x0A0EEb6fBCc7c82259E548Fc4617175A357b3e71': 'Added safe 200',
Expand Down Expand Up @@ -529,22 +527,12 @@ export const addedSafes = {
ethBalance: '0',
},
},
100: {
'0x17b34aEf1428A358bA2eA360a098b8A3BEb698C8': {
1: {
'0x8675B754342754A30A2AeF474D114d8460bca19b': {
owners: [{ value: '0x11B1D54B66e5e226D6f89069c21A569A22D98cfd' }],
threshold: 1,
ethBalance: '0.001000002',
},
'0x11A6B41322C57Bd0e56cEe06abB11A1E5c1FF1BB': {
owners: [{ value: '0x7724b234c9099C205F03b458944942bcEBA13408' }],
threshold: 1,
ethBalance: '0',
},
'0xB8d760a90a5ed54D3c2b3EFC231277e99188642A': {
owners: [{ value: '0x11B1D54B66e5e226D6f89069c21A569A22D98cfd' }],
threshold: 1,
ethBalance: '0.92132507668989',
},
},
},
set3: {
Expand Down
14 changes: 11 additions & 3 deletions src/components/address-book/ImportDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ const ImportDialog = ({ handleClose }: { handleClose: () => void }): ReactElemen
name: acceptedFile.name,
additionalInfo: formatFileSize(acceptedFile.size),
summary: [
<Typography key="abSummary">
<Typography data-testid="summary-message" key="abSummary">
{`Found ${entryCount} entries on ${chainCount} ${chainCount > 1 ? 'chains' : 'chain'}`}
</Typography>,
],
Expand Down Expand Up @@ -163,8 +163,16 @@ const ImportDialog = ({ handleClose }: { handleClose: () => void }): ReactElemen
</Typography>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={handleImport} variant="contained" disableElevation disabled={!csvData || !!error}>
<Button data-testid="cancel-btn" onClick={handleClose}>
Cancel
</Button>
<Button
data-testid="import-btn"
onClick={handleImport}
variant="contained"
disableElevation
disabled={!csvData || !!error}
>
Import
</Button>
</DialogActions>
Expand Down
3 changes: 2 additions & 1 deletion src/components/common/EnhancedTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,14 @@ function EnhancedTable({ rows, headCells, mobileVariant }: EnhancedTableProps) {

return (
<Box sx={{ width: '100%' }}>
<TableContainer component={Paper} sx={{ width: '100%', mb: 2 }}>
<TableContainer data-testid="table-container" component={Paper} sx={{ width: '100%', mb: 2 }}>
<Table aria-labelledby="tableTitle" className={mobileVariant ? css.mobileColumn : undefined}>
<EnhancedTableHead headCells={headCells} order={order} orderBy={orderBy} onRequestSort={handleRequestSort} />
<TableBody>
{pagedRows.length > 0 ? (
pagedRows.map((row, index) => (
<TableRow
data-testid="table-row"
tabIndex={-1}
key={row.key ?? index}
selected={row.selected}
Expand Down
2 changes: 1 addition & 1 deletion src/components/tx/ErrorMessage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const ErrorMessage = ({
}

return (
<div className={classNames(css.container, css[level], className, 'errorMessage')}>
<div data-testid="error-message" className={classNames(css.container, css[level], className, 'errorMessage')}>
<div className={css.message}>
<SvgIcon
component={level === 'info' ? InfoIcon : WarningIcon}
Expand Down
Loading