diff --git a/.changelog/1752.feature.md b/.changelog/1752.feature.md new file mode 100644 index 0000000000..d3b051164c --- /dev/null +++ b/.changelog/1752.feature.md @@ -0,0 +1 @@ +Add remove account feature diff --git a/playwright/tests/toolbar.spec.ts b/playwright/tests/toolbar.spec.ts index 1fad82e1db..d8e574a571 100644 --- a/playwright/tests/toolbar.spec.ts +++ b/playwright/tests/toolbar.spec.ts @@ -1,5 +1,5 @@ -import { test, expect } from '@playwright/test' -import { password, privateKey, privateKeyAddress } from '../utils/test-inputs' +import { test, expect, Page } from '@playwright/test' +import { mnemonic, mnemonicAddress0, password, privateKey, privateKeyAddress } from '../utils/test-inputs' import { fillPrivateKeyAndPassword } from '../utils/fillPrivateKey' import { warnSlowApi } from '../utils/warnSlowApi' import { mockApi } from '../utils/mockApi' @@ -75,4 +75,49 @@ test.describe('My Accounts tab', () => { await page.getByText('I understand, reveal my private key').click() await expect(page.getByText(privateKey)).toBeVisible() }) + + test('should not be able to remove an account', async ({ page }) => { + await page.goto('/open-wallet/private-key') + await fillPrivateKeyAndPassword(page) + await page.getByTestId('account-selector').click() + await page.getByText('Manage').click() + await expect(page.getByText('Delete Account')).toBeDisabled() + }) + + async function openAccountSelectorWithMultipleItems(page: Page) { + await page.goto('/open-wallet/mnemonic') + await page.getByPlaceholder('Enter your keyphrase here').fill(mnemonic) + await page.getByRole('button', { name: /Import my wallet/ }).click() + const uncheckedAccounts = page.getByRole('checkbox', { name: /oasis1/, checked: false }) + await expect(uncheckedAccounts).toHaveCount(3) + for (const account of await uncheckedAccounts.elementHandles()) await account.click() + await page.getByRole('button', { name: /Open/ }).click() + await page.getByTestId('account-selector').click() + await expect(page.getByTestId('account-choice')).toHaveCount(4) + } + + test('should remove currently selected account and switch to the first one in account list', async ({ + page, + }) => { + await openAccountSelectorWithMultipleItems(page) + await page.getByText('Manage').nth(0).click() + await page.getByText('Delete Account').click() + await page.getByRole('textbox').fill('foo') + await page.getByRole('button', { name: 'Yes, delete' }).click() + expect(page.getByText("Type 'delete'")).toBeVisible() + await page.getByRole('textbox').fill('delete') + await page.getByRole('button', { name: 'Yes, delete' }).click() + await expect(page).not.toHaveURL(new RegExp(`/account/${mnemonicAddress0}`)) + await expect(page.getByTestId('account-choice')).toHaveCount(3) + }) + + test('should remove not currently selected account', async ({ page }) => { + await openAccountSelectorWithMultipleItems(page) + await page.getByText('Manage').nth(1).click() + await page.getByText('Delete Account').click() + await page.getByRole('textbox').fill('delete') + await page.getByRole('button', { name: 'Yes, delete' }).click() + await expect(page).toHaveURL(new RegExp(`/account/${mnemonicAddress0}`)) + await expect(page.getByTestId('account-choice')).toHaveCount(3) + }) }) diff --git a/src/app/components/DeleteInputForm/index.tsx b/src/app/components/DeleteInputForm/index.tsx new file mode 100644 index 0000000000..e815ac786f --- /dev/null +++ b/src/app/components/DeleteInputForm/index.tsx @@ -0,0 +1,40 @@ +import { ReactNode } from 'react' +import { Box } from 'grommet/es6/components/Box' +import { Button } from 'grommet/es6/components/Button' +import { useTranslation } from 'react-i18next' +import { TextInput } from 'grommet/es6/components/TextInput' +import { Form } from 'grommet/es6/components/Form' +import { FormField } from 'grommet/es6/components/FormField' + +interface DeleteInputFormProps { + children: ReactNode + onCancel: () => void + onConfirm: () => void +} + +export function DeleteInputForm({ children, onCancel, onConfirm }: DeleteInputFormProps) { + const { t } = useTranslation() + + return ( +
+ {children} + + !value || value.toLowerCase() !== t('deleteForm.confirmationKeyword', 'delete').toLowerCase() + ? t('deleteForm.hint', `Type '{{confirmationKeyword}}'`, { + confirmationKeyword: t('deleteForm.confirmationKeyword', 'delete'), + }) + : undefined + } + > + + + + +