-
Notifications
You must be signed in to change notification settings - Fork 210
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(settings): Update 2FA Settings Row
Because: * We are preparing to add a new recovery method for 2FA and are updating some design pieces This commit: * Update the 2FA settings row design * Add new SubRowBackupMethods component * Updates stories, tests, l10n Closes #FXA-10206
- Loading branch information
1 parent
c494968
commit 5cc246e
Showing
14 changed files
with
695 additions
and
326 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...ges/fxa-settings/src/components/Icons/icon_information_circle_outline_black.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,20 +7,14 @@ import { screen } from '@testing-library/react'; | |
import Security from '.'; | ||
import { mockAppContext, renderWithRouter } from '../../../models/mocks'; | ||
import { Account, AppContext } from '../../../models'; | ||
import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils'; | ||
import { FluentBundle } from '@fluent/bundle'; | ||
import { MOCK_EMAIL } from '../../../pages/mocks'; | ||
|
||
describe('Security', () => { | ||
let bundle: FluentBundle; | ||
beforeAll(async () => { | ||
bundle = await getFtlBundle('settings'); | ||
}); | ||
|
||
it('renders "fresh load" <Security/> with correct content', async () => { | ||
const account = { | ||
avatar: { url: null, id: null }, | ||
primaryEmail: { | ||
email: '[email protected]', | ||
email: MOCK_EMAIL, | ||
}, | ||
emails: [], | ||
displayName: 'Jody', | ||
|
@@ -40,15 +34,15 @@ describe('Security', () => { | |
expect(await screen.findByText('Account recovery key')).toBeTruthy(); | ||
expect(await screen.findByText('Two-step authentication')).toBeTruthy(); | ||
|
||
const result = await screen.findAllByText('Not Set'); | ||
expect(result).toHaveLength(2); | ||
expect(await screen.findAllByText('Not Set')).toHaveLength(1); | ||
expect(await screen.findAllByText('Disabled')).toHaveLength(1); | ||
}); | ||
|
||
it('renders "enabled two factor" and "account recovery key present" <Security/> with correct content', async () => { | ||
const account = { | ||
avatar: { url: null, id: null }, | ||
primaryEmail: { | ||
email: '[email protected]', | ||
email: MOCK_EMAIL, | ||
}, | ||
emails: [], | ||
displayName: 'Jody', | ||
|
@@ -72,7 +66,7 @@ describe('Security', () => { | |
recoveryKey: { exists: false }, | ||
totp: { exists: false }, | ||
primaryEmail: { | ||
email: '[email protected]', | ||
email: MOCK_EMAIL, | ||
}, | ||
passwordCreated: 1234567890, | ||
hasPassword: true, | ||
|
@@ -85,10 +79,6 @@ describe('Security', () => { | |
); | ||
const passwordRouteLink = screen.getByTestId('password-unit-row-route'); | ||
|
||
testAllL10n(screen, bundle, { | ||
date: createDate, | ||
}); | ||
|
||
await screen.findByText('••••••••••••••••••'); | ||
await screen.findByText(`Created ${createDate}`); | ||
|
||
|
@@ -104,7 +94,7 @@ describe('Security', () => { | |
recoveryKey: { exists: false }, | ||
totp: { exists: false }, | ||
primaryEmail: { | ||
email: '[email protected]', | ||
email: MOCK_EMAIL, | ||
}, | ||
passwordCreated: 0, | ||
hasPassword: false, | ||
|
@@ -118,7 +108,8 @@ describe('Security', () => { | |
const passwordRouteLink = screen.getByTestId('password-unit-row-route'); | ||
|
||
await screen.findByText('Set a password', { exact: false }); | ||
expect(await screen.findAllByText('Not Set')).toHaveLength(3); | ||
expect(await screen.findAllByText('Not Set')).toHaveLength(2); | ||
expect(await screen.findAllByText('Disabled')).toHaveLength(1); | ||
|
||
expect(passwordRouteLink).toHaveTextContent('Create'); | ||
expect(passwordRouteLink).toHaveAttribute( | ||
|
63 changes: 63 additions & 0 deletions
63
packages/fxa-settings/src/components/Settings/SubRowBackupMethods/index.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import React from 'react'; | ||
import { Meta, StoryFn } from '@storybook/react'; | ||
import BackupMethodSubRow, { | ||
BackupCodesAvailable, | ||
BackupCodesUnavailable, | ||
BackupRowProps, | ||
} from './index'; | ||
import { action } from '@storybook/addon-actions'; | ||
import { CheckmarkGreenIcon, AlertIcon } from '../../Icons'; | ||
|
||
export default { | ||
title: 'Components/Settings/SubRowBackupMethods', | ||
component: BackupMethodSubRow, | ||
} as Meta; | ||
|
||
const Template: StoryFn<BackupRowProps> = (args) => ( | ||
<BackupMethodSubRow {...args} /> | ||
); | ||
|
||
export const AvailableMethod = Template.bind({}); | ||
AvailableMethod.args = { | ||
title: 'Method available', | ||
icon: ( | ||
<CheckmarkGreenIcon mode="enabled" className="grow-0 shrink-0 scale-50" /> | ||
), | ||
message: ( | ||
<> | ||
<CheckmarkGreenIcon className="grow-0 shrink-0 me-2" mode="enabled" /> | ||
<p>Method is available</p> | ||
</> | ||
), | ||
ctaMessage: 'Use method', | ||
onCtaClick: action('Use method clicked'), | ||
isAvailable: true, | ||
moreInfoMessage: 'This method is available for use.', | ||
}; | ||
|
||
export const UnavailableMethod = Template.bind({}); | ||
UnavailableMethod.args = { | ||
title: 'Method unavailable', | ||
icon: <AlertIcon mode="attention" className="grow-0 shrink-0 scale-50" />, | ||
message: ( | ||
<> | ||
<AlertIcon className="grow-0 shrink-0 me-1" mode="attention" /> | ||
<p>Method is unavailable</p> | ||
</> | ||
), | ||
ctaMessage: 'Enable method', | ||
onCtaClick: action('Enable method clicked'), | ||
isAvailable: false, | ||
moreInfoMessage: 'This method is currently unavailable.', | ||
}; | ||
|
||
export const BackupCodesAvailableStory: StoryFn = () => ( | ||
<BackupCodesAvailable | ||
numCodesAvailable={5} | ||
onCtaClick={action('Get new codes clicked')} | ||
/> | ||
); | ||
|
||
export const BackupCodesUnavailableStory: StoryFn = () => ( | ||
<BackupCodesUnavailable onCtaClick={action('Add clicked')} /> | ||
); |
89 changes: 89 additions & 0 deletions
89
packages/fxa-settings/src/components/Settings/SubRowBackupMethods/index.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import React from 'react'; | ||
import { render, screen, fireEvent } from '@testing-library/react'; | ||
import BackupMethodSubRow, { | ||
BackupCodesAvailable, | ||
BackupCodesUnavailable, | ||
} from './index'; | ||
|
||
describe('BackupMethodSubRow', () => { | ||
const defaultProps = { | ||
title: 'Backup codes', | ||
icon: <div>Icon</div>, | ||
message: <div>Message</div>, | ||
ctaMessage: 'Get new codes', | ||
onCtaClick: jest.fn(), | ||
isAvailable: true, | ||
moreInfoMessage: 'More info message', | ||
}; | ||
|
||
it('renders correctly when available', () => { | ||
render(<BackupMethodSubRow {...defaultProps} />); | ||
expect(screen.getByText('Backup codes')).toBeInTheDocument(); | ||
expect(screen.getByText('Message')).toBeInTheDocument(); | ||
expect(screen.getByText('Get new codes')).toBeInTheDocument(); | ||
expect(screen.getByText('More info message')).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders correctly when unavailable', () => { | ||
render(<BackupMethodSubRow {...defaultProps} isAvailable={false} />); | ||
expect(screen.getByText('Backup codes')).toBeInTheDocument(); | ||
expect(screen.getByText('Message')).toBeInTheDocument(); | ||
expect(screen.getByText('Get new codes')).toBeInTheDocument(); | ||
expect(screen.getByText('More info message')).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls onCtaClick when CTA button is clicked', () => { | ||
render(<BackupMethodSubRow {...defaultProps} />); | ||
fireEvent.click(screen.getByText('Get new codes')); | ||
expect(defaultProps.onCtaClick).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe('BackupCodesAvailable', () => { | ||
const defaultProps = { | ||
numCodesAvailable: 5, | ||
onCtaClick: jest.fn(), | ||
}; | ||
|
||
it('renders correctly', () => { | ||
render(<BackupCodesAvailable {...defaultProps} />); | ||
expect(screen.getByText('Backup codes')).toBeInTheDocument(); | ||
expect(screen.getByText('5 codes remaining')).toBeInTheDocument(); | ||
expect(screen.getByText('Get new codes')).toBeInTheDocument(); | ||
expect( | ||
screen.getByText( | ||
'This is the safest recovery method if you canʼt access your mobile device or authenticator app.' | ||
) | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls onCtaClick when CTA button is clicked', () => { | ||
render(<BackupCodesAvailable {...defaultProps} />); | ||
fireEvent.click(screen.getByText('Get new codes')); | ||
expect(defaultProps.onCtaClick).toHaveBeenCalled(); | ||
}); | ||
}); | ||
|
||
describe('BackupCodesUnavailable', () => { | ||
const defaultProps = { | ||
onCtaClick: jest.fn(), | ||
}; | ||
|
||
it('renders correctly', () => { | ||
render(<BackupCodesUnavailable {...defaultProps} />); | ||
expect(screen.getByText('Backup codes')).toBeInTheDocument(); | ||
expect(screen.getByText('No codes available')).toBeInTheDocument(); | ||
expect(screen.getByText('Add')).toBeInTheDocument(); | ||
expect( | ||
screen.getByText( | ||
'This is the safest recovery method if you canʼt access your mobile device or authenticator app.' | ||
) | ||
).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls onCtaClick when CTA button is clicked', () => { | ||
render(<BackupCodesUnavailable {...defaultProps} />); | ||
fireEvent.click(screen.getByText('Add')); | ||
expect(defaultProps.onCtaClick).toHaveBeenCalled(); | ||
}); | ||
}); |
Oops, something went wrong.