diff --git a/src/features/settings/ui/SecuritySection.test.tsx b/src/features/settings/ui/SecuritySection.test.tsx
index b2fd5eb..7659eaa 100644
--- a/src/features/settings/ui/SecuritySection.test.tsx
+++ b/src/features/settings/ui/SecuritySection.test.tsx
@@ -1,9 +1,15 @@
-import { describe, it, expect } from 'vitest'
+import { describe, it, expect, beforeEach } from 'vitest'
import { render, screen } from '@/test/utils'
+import userEvent from '@testing-library/user-event'
+import { useChangePasswordDialogStore } from '@/shared/auth/change-password-dialog-store'
import { SecuritySection } from './SecuritySection'
describe('SecuritySection', () => {
+ beforeEach(() => {
+ useChangePasswordDialogStore.setState({ isChangePasswordDialogOpen: false })
+ })
+
it('renders section title and description', () => {
render(
)
expect(screen.getByText('Security')).toBeInTheDocument()
@@ -17,9 +23,30 @@ describe('SecuritySection', () => {
expect(screen.getByText('Key versions')).toBeInTheDocument()
})
- it('renders three separator dividers between action items', () => {
+ it('renders two separator dividers between action items', () => {
render(
)
const separators = screen.getAllByRole('separator')
expect(separators).toHaveLength(2)
})
+
+ it('opens change password dialog when clicking "Change password"', async () => {
+ const user = userEvent.setup()
+ render(
)
+
+ const changePasswordButton = screen.getByRole('button', { name: /Change password/i })
+ await user.click(changePasswordButton)
+
+ expect(useChangePasswordDialogStore.getState().isChangePasswordDialogOpen).toBe(true)
+ })
+
+ it('opens change password dialog with Space key', async () => {
+ const user = userEvent.setup()
+ render(
)
+
+ const changePasswordButton = screen.getByRole('button', { name: /Change password/i })
+ changePasswordButton.focus()
+ await user.keyboard(' ')
+
+ expect(useChangePasswordDialogStore.getState().isChangePasswordDialogOpen).toBe(true)
+ })
})
diff --git a/src/features/settings/ui/SecuritySection.tsx b/src/features/settings/ui/SecuritySection.tsx
index b44824d..a8a648b 100644
--- a/src/features/settings/ui/SecuritySection.tsx
+++ b/src/features/settings/ui/SecuritySection.tsx
@@ -4,14 +4,35 @@ import { ChevronRight, KeyRound, ShieldCheck, Fingerprint, type LucideIcon } fro
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/shared/ui/card'
import { Separator } from '@/shared/ui/separator'
+import { useChangePasswordDialogStore } from '@/shared/auth/change-password-dialog-store'
-const ITEMS: { icon: LucideIcon; labelKey: string }[] = [
- { icon: KeyRound, labelKey: 'security.changePassword' },
+const ITEMS: { icon: LucideIcon; labelKey: string; onClick?: () => void }[] = [
+ {
+ icon: KeyRound,
+ labelKey: 'security.changePassword',
+ onClick: () => useChangePasswordDialogStore.getState().openChangePasswordDialog(),
+ },
{ icon: ShieldCheck, labelKey: 'security.seedPhrase' },
{ icon: Fingerprint, labelKey: 'security.keyVersions' },
]
-function SecurityItem({ icon: Icon, label }: { icon: LucideIcon; label: string }) {
+function SecurityItem({ icon: Icon, label, onClick }: { icon: LucideIcon; label: string; onClick?: () => void }) {
+ if (onClick) {
+ return (
+
+ )
+ }
+
return (
@@ -36,7 +57,7 @@ function SecuritySection() {
{ITEMS.map((item, i) => (
{i > 0 && }
-
+
))}
diff --git a/src/features/vault/ui/VaultUnlockDialog.test.tsx b/src/features/vault/ui/VaultUnlockDialog.test.tsx
index a3ebc58..f204000 100644
--- a/src/features/vault/ui/VaultUnlockDialog.test.tsx
+++ b/src/features/vault/ui/VaultUnlockDialog.test.tsx
@@ -168,4 +168,28 @@ describe('VaultUnlockDialog', () => {
expect(useVaultDialogStore.getState().isUnlockDialogOpen).toBe(false)
})
+
+ it('hides close button and blocks Escape during submission', async () => {
+ let resolveUnlock: () => void = () => {}
+ mockUnlockVault.mockReturnValue(
+ new Promise((resolve) => {
+ resolveUnlock = resolve
+ }),
+ )
+ const user = userEvent.setup()
+ render()
+
+ await user.type(screen.getByLabelText(/password/i), 'my-password')
+ await user.click(screen.getByRole('button', { name: /unlock/i }))
+
+ // Close button should be hidden during submission
+ expect(screen.queryByRole('button', { name: /close/i })).not.toBeInTheDocument()
+
+ // Escape should not close the dialog
+ await user.keyboard('{Escape}')
+ expect(useVaultDialogStore.getState().isUnlockDialogOpen).toBe(true)
+
+ // Clean up: resolve the promise
+ resolveUnlock()
+ })
})
diff --git a/src/features/vault/ui/VaultUnlockDialog.tsx b/src/features/vault/ui/VaultUnlockDialog.tsx
index 11de96e..c9b9de9 100644
--- a/src/features/vault/ui/VaultUnlockDialog.tsx
+++ b/src/features/vault/ui/VaultUnlockDialog.tsx
@@ -70,7 +70,7 @@ function VaultUnlockDialog() {
}
return (
-