Skip to content

Commit

Permalink
fix(authenticator): Check first radio button from unverified user att…
Browse files Browse the repository at this point in the history
…ributes so that default value is selected (#5399)
  • Loading branch information
timngyn authored Jul 22, 2024
1 parent a024885 commit 98135df
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 22 deletions.
7 changes: 7 additions & 0 deletions .changeset/tricky-fishes-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@aws-amplify/ui-react": patch
"@aws-amplify/ui-vue": patch
"@aws-amplify/ui-angular": patch
---

fix(authenticator): Check first radio button from unverified user attributes so that default value is selected
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ <h3 class="amplify-heading amplify-heading--3">{{ this.headerText }}</h3>
<div
*ngFor="
let unverifiedUserAttribute of unverifiedUserAttributes | keyvalue
let i = index;
"
>
<input
name="unverifiedAttr"
type="radio"
[value]="unverifiedUserAttribute.key"
[id]="labelId"
[checked]="i === 0"
/>
<label [for]="labelId">{{
getLabel(unverifiedUserAttribute.key, unverifiedUserAttribute.value)
Expand Down
6 changes: 6 additions & 0 deletions packages/e2e/cypress/integration/common/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,9 @@ Then(
}).type(`{${key}}`, { force: true });
}
);

Then('I see the {string} radio button checked', (label: string) => {
cy.findByLabelText(new RegExp(`^${escapeRegExp(label)}`, 'i')).should(
'be.checked'
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ Feature: Verify User
Then I see "Footer Information"
Then I click the "Skip" button
Then I click the "Sign out" button


@angular @react @vue
Scenario: Redirect to "Verify" page and verify radio button is automatically selected
When I type my "email" with status "UNVERIFIED"
Then I type my password
Then I click the "Sign in" button
Then I see the "Email" radio button checked
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,24 @@ const {
const generateRadioGroup = (
attributes: UnverifiedUserAttributes
): JSX.Element[] => {
return Object.entries(attributes).map(([key, value]: [string, string]) => {
const verificationType = (
defaultFormFieldOptions[key] as { label: ContactMethod }
).label;
return (
<Radio name="unverifiedAttr" value={key} key={key}>
{translate(verificationType)}:{' '}
{censorContactMethod(verificationType, value)}
</Radio>
);
});
return Object.entries(attributes).map(
([key, value]: [string, string], index) => {
const verificationType = (
defaultFormFieldOptions[key] as { label: ContactMethod }
).label;
return (
<Radio
name="unverifiedAttr"
value={key}
key={key}
defaultChecked={index === 0}
>
{translate(verificationType)}:{' '}
{censorContactMethod(verificationType, value)}
</Radio>
);
}
);
};

export const VerifyUser = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as React from 'react';
import { render, screen } from '@testing-library/react';

import { useAuthenticator, UseAuthenticator } from '@aws-amplify/ui-react-core';

import { VerifyUser } from '..';

jest.mock('@aws-amplify/ui-react-core');

jest.mock('../../hooks/useFormHandlers', () => ({
useFormHandlers: () => ({ handleChange: jest.fn(), handleSubmit: jest.fn() }),
}));

jest.mock('../../hooks/useCustomComponents', () => ({
useCustomComponents: () => ({
components: {
Header: () => null,
Footer: () => null,
VerifyUser: { Header: () => null, Footer: () => null },
},
}),
}));

describe('VerifyUser', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('should select the first unverified attribute', async () => {
(useAuthenticator as jest.Mock).mockReturnValue({
isPending: false,
unverifiedUserAttributes: {
email: 'test@example.com',
},
} as UseAuthenticator);

render(<VerifyUser className="className" variation="default" />);

const radioInput = screen.getByRole('radio', {
name: (content) => content.startsWith('Email:'),
});

expect(radioInput).toBeChecked();
});

it('should select the first unverified attribute when there are multiple attributes', async () => {
(useAuthenticator as jest.Mock).mockReturnValue({
isPending: false,
unverifiedUserAttributes: {
phone_number: '+1234566789',
email: 'test@example.com',
},
} as UseAuthenticator);

render(<VerifyUser className="className" variation="default" />);

const phoneNumberRadioInput = screen.getByRole('radio', {
name: (content) => content.startsWith('Phone Number:'),
});

const emailRadioInput = screen.getByRole('radio', {
name: (content) => content.startsWith('Email:'),
});

expect(phoneNumberRadioInput).toBeChecked();
expect(emailRadioInput).not.toBeChecked();
});
});
33 changes: 24 additions & 9 deletions packages/vue/src/components/__tests__/verify-user.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,43 @@ describe('VerifyUser', () => {
mathRandomSpy.mockRestore();
});

it('sends change event on form input', async () => {
it('selects the first radio element as the default option', async () => {
render(VerifyUser, { global: { components } });

const radioField = await screen.findByLabelText('Email: t**t@example.com');

await fireEvent.click(radioField);
expect(updateFormSpy).toHaveBeenCalledWith({
name: 'unverifiedAttr',
value: 'email',
});
expect(radioField).toBeChecked();
});

it('sends submit event on form submit', async () => {
it('sends change event on form input', async () => {
useAuthenticatorSpy.mockReturnValueOnce(
reactive({
...baseMockServiceFacade,
route: 'verifyUser',
updateForm: updateFormSpy,
skipVerification: skipVerificationSpy,
submitForm: submitFormSpy,
unverifiedUserAttributes: {
email: 'test@example.com',
phone_number: '+1234567890',
},
})
);
render(VerifyUser, { global: { components } });

const radioField = await screen.findByLabelText('Email: t**t@example.com');
const radioField = await screen.getByRole('radio', {
name: (content) => content.startsWith('Phone Number:'),
});

await fireEvent.click(radioField);
expect(updateFormSpy).toHaveBeenCalledWith({
name: 'unverifiedAttr',
value: 'email',
value: 'phone_number',
});
});

it('sends submit event on form submit', async () => {
render(VerifyUser, { global: { components } });

const submitButton = await screen.findByRole('button', { name: 'Verify' });
await fireEvent.click(submitButton);
Expand Down
3 changes: 2 additions & 1 deletion packages/vue/src/components/verify-user.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const onSkipClicked = (): void => {
aria-labelledby="amplify-field-493c"
>
<template
v-for="(value, key) in unverifiedUserAttributes"
v-for="(value, key, index) in unverifiedUserAttributes"
:key="value"
>
<base-label
Expand All @@ -104,6 +104,7 @@ const onSkipClicked = (): void => {
data-amplify-verify-input
name="unverifiedAttr"
type="radio"
:checked="index === 0"
:value="key"
>
</base-input>
Expand Down

0 comments on commit 98135df

Please sign in to comment.