Skip to content

Commit f0c3a55

Browse files
fix(clerk-js): Ensure errors are being read to screen readers (#7111)
Co-authored-by: Jacek Radko <[email protected]>
1 parent c81065f commit f0c3a55

File tree

13 files changed

+132
-88
lines changed

13 files changed

+132
-88
lines changed

.changeset/puny-places-shine.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Add aria live region to ensure feedback messages are read to screen readers when feedback changes.

integration/tests/sign-in-flow.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f
128128
await u.po.signIn.continue();
129129
await u.po.signIn.setPassword('wrong-password');
130130
await u.po.signIn.continue();
131-
await expect(u.page.getByText(/password is incorrect/i)).toBeVisible();
131+
await expect(u.page.getByTestId('form-feedback-error')).toBeVisible();
132+
await expect(u.page.getByTestId('form-feedback-error')).toHaveText(/password is incorrect/i);
132133

133134
await u.po.expect.toBeSignedOut();
134135
});
@@ -142,7 +143,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign in f
142143
await u.po.signIn.setPassword('wrong-password');
143144
await u.po.signIn.continue();
144145

145-
await expect(u.page.getByText(/password is incorrect/i)).toBeVisible();
146+
await expect(u.page.getByTestId('form-feedback-error')).toBeVisible();
147+
await expect(u.page.getByTestId('form-feedback-error')).toHaveText(/password is incorrect/i);
146148

147149
await u.po.signIn.getUseAnotherMethodLink().click();
148150
await u.po.signIn.getAltMethodsEmailCodeButton().click();

integration/tests/sign-in-or-up-flow.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSignInOrUpFlow] })('sign-
142142
await u.po.signIn.continue();
143143
await u.po.signIn.setPassword('wrong-password');
144144
await u.po.signIn.continue();
145-
await expect(u.page.getByText(/password is incorrect/i)).toBeVisible();
145+
await expect(u.page.getByTestId('form-feedback-error')).toBeVisible();
146+
await expect(u.page.getByTestId('form-feedback-error')).toHaveText(/password is incorrect/i);
146147

147148
await u.po.expect.toBeSignedOut();
148149
});
@@ -156,7 +157,8 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withSignInOrUpFlow] })('sign-
156157
await u.po.signIn.setPassword('wrong-password');
157158
await u.po.signIn.continue();
158159

159-
await expect(u.page.getByText(/password is incorrect/i)).toBeVisible();
160+
await expect(u.page.getByTestId('form-feedback-error')).toBeVisible();
161+
await expect(u.page.getByTestId('form-feedback-error')).toHaveText(/password is incorrect/i);
160162

161163
await u.po.signIn.getUseAnotherMethodLink().click();
162164
await u.po.signIn.getAltMethodsEmailCodeButton().click();

integration/tests/sign-in-or-up-restricted-mode.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ test.describe('sign-in-or-up restricted mode @nextjs', () => {
3333
await expect(u.page.getByText(/continue to/i)).toBeHidden();
3434
await u.po.signIn.getIdentifierInput().fill(fakeUser.email);
3535
await u.po.signIn.continue();
36-
await expect(u.page.getByText(/Couldn't find your account\./i)).toBeVisible();
36+
await expect(u.page.getByTestId('form-feedback-error')).toBeVisible();
37+
await expect(u.page.getByTestId('form-feedback-error')).toHaveText(/Couldn't find your account\./i);
3738
});
3839
});

integration/tests/sign-up-flow.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withEmailCodes] })('sign up f
5454
});
5555

5656
// Check if password error is visible
57-
await expect(u.page.getByText(/your password must contain \d+ or more characters/i).first()).toBeVisible();
57+
await expect(u.page.getByTestId('form-feedback-error').first()).toBeVisible();
58+
await expect(u.page.getByTestId('form-feedback-error').first()).toHaveText(
59+
/your password must contain \d+ or more characters/i,
60+
);
5861

5962
// Check if user is signed out
6063
await u.po.expect.toBeSignedOut();

packages/clerk-js/src/ui/components/SignIn/__tests__/ResetPassword.test.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ describe('ResetPassword', () => {
3737

3838
const passwordField = screen.getByLabelText(/New password/i);
3939
fireEvent.focus(passwordField);
40-
await screen.findByText(/Your password must contain 8 or more characters/i);
40+
const infoElement = await screen.findByTestId('form-feedback-info');
41+
expect(infoElement).toHaveTextContent(/Your password must contain 8 or more characters/i);
4142
});
4243

4344
it('renders a hidden identifier field', async () => {
@@ -115,10 +116,12 @@ describe('ResetPassword', () => {
115116
await userEvent.type(screen.getByLabelText(/new password/i), 'testewrewr');
116117
const confirmField = screen.getByLabelText(/confirm password/i);
117118
await userEvent.type(confirmField, 'testrwerrwqrwe');
118-
await screen.findByText(`Passwords don't match.`);
119+
const errorElement = await screen.findByTestId('form-feedback-error');
120+
expect(errorElement).toHaveTextContent(/Passwords don't match/i);
119121

120122
await userEvent.clear(confirmField);
121-
await screen.findByText(`Passwords don't match.`);
123+
const errorElementAfterClear = await screen.findByTestId('form-feedback-error');
124+
expect(errorElementAfterClear).toHaveTextContent(/Passwords don't match/i);
122125
});
123126

124127
it('navigates to the root page upon pressing the back link', async () => {

packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOne.test.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ describe('SignInFactorOne', () => {
186186
const { userEvent } = render(<SignInFactorOne />, { wrapper });
187187
await userEvent.type(screen.getByLabelText('Password'), '123456');
188188
await userEvent.click(screen.getByText('Continue'));
189-
await screen.findByText('Incorrect Password');
189+
const errorElement = await screen.findByTestId('form-feedback-error');
190+
expect(errorElement).toHaveTextContent(/Incorrect Password/i);
190191
});
191192

192193
it('redirects back to sign-in if the user is locked', async () => {
@@ -558,7 +559,8 @@ describe('SignInFactorOne', () => {
558559
);
559560
const { userEvent } = render(<SignInFactorOne />, { wrapper });
560561
await userEvent.type(screen.getByLabelText(/Enter verification code/i), '123456');
561-
await screen.findByText('Incorrect code');
562+
const errorElement = await screen.findByTestId('form-feedback-error');
563+
expect(errorElement).toHaveTextContent(/Incorrect code/i);
562564
});
563565

564566
it('redirects back to sign-in if the user is locked', async () => {
@@ -663,7 +665,8 @@ describe('SignInFactorOne', () => {
663665
);
664666
const { userEvent } = render(<SignInFactorOne />, { wrapper });
665667
await userEvent.type(screen.getByLabelText(/Enter verification code/i), '123456');
666-
await screen.findByText('Incorrect phone code');
668+
const errorElement = await screen.findByTestId('form-feedback-error');
669+
expect(errorElement).toHaveTextContent(/Incorrect phone code/i);
667670
});
668671

669672
it('redirects back to sign-in if the user is locked', async () => {

packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorTwo.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ describe('SignInFactorTwo', () => {
185185
);
186186
const { userEvent } = render(<SignInFactorTwo />, { wrapper });
187187
await userEvent.type(screen.getByLabelText(/Enter verification code/i), '123456');
188-
expect(await screen.findByText('Incorrect phone code')).toBeDefined();
188+
expect(await screen.findByTestId('form-feedback-error')).toHaveTextContent(/Incorrect phone code/i);
189189
});
190190

191191
it('redirects back to sign-in if the user is locked', async () => {
@@ -274,7 +274,7 @@ describe('SignInFactorTwo', () => {
274274
);
275275
const { userEvent } = render(<SignInFactorTwo />, { wrapper });
276276
await userEvent.type(screen.getByLabelText(/Enter verification code/i), '123456');
277-
expect(await screen.findByText('Incorrect authenticator code')).toBeDefined();
277+
expect(await screen.findByTestId('form-feedback-error')).toHaveTextContent(/Incorrect authenticator code/i);
278278
});
279279
});
280280

@@ -367,7 +367,7 @@ describe('SignInFactorTwo', () => {
367367
const { userEvent, getByLabelText, getByText } = render(<SignInFactorTwo />, { wrapper });
368368
await userEvent.type(getByLabelText('Backup code'), '123456');
369369
await userEvent.click(getByText('Continue'));
370-
expect(await screen.findByText('Incorrect backup code')).toBeDefined();
370+
expect(await screen.findByTestId('form-feedback-error')).toHaveTextContent(/Incorrect backup code/i);
371371
});
372372

373373
it('redirects back to sign-in if the user is locked', async () => {

packages/clerk-js/src/ui/components/SignUp/__tests__/SignUpContinue.test.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,8 @@ describe('SignUpContinue', () => {
168168
await userEvent.click(button);
169169

170170
await waitFor(() => expect(fixtures.signUp.update).toHaveBeenCalled());
171-
await waitFor(() =>
172-
expect(screen.queryByText(/^Your username must be between 4 and 40 characters long./i)).toBeInTheDocument(),
173-
);
171+
const errorElement = await screen.findByTestId('form-feedback-error');
172+
expect(errorElement).toHaveTextContent(/Your username must be between 4 and 40 characters long/i);
174173
});
175174

176175
it('renders error for existing username', async () => {
@@ -203,9 +202,8 @@ describe('SignUpContinue', () => {
203202
await userEvent.click(button);
204203

205204
await waitFor(() => expect(fixtures.signUp.update).toHaveBeenCalled());
206-
await waitFor(() =>
207-
expect(screen.queryByText(/^This username is taken. Please try another./i)).toBeInTheDocument(),
208-
);
205+
const errorElement = await screen.findByTestId('form-feedback-error');
206+
expect(errorElement).toHaveTextContent(/This username is taken. Please try another/i);
209207
});
210208

211209
describe('Sign in Link', () => {

packages/clerk-js/src/ui/components/UserProfile/__tests__/PasswordSection.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ describe('PasswordSection', () => {
538538
await userEvent.type(confirmField, 'test');
539539
fireEvent.blur(confirmField);
540540
await waitFor(() => {
541-
screen.getByText(/or more/i);
541+
expect(screen.getByTestId('form-feedback-error')).toHaveTextContent(/or more/i);
542542
});
543543
});
544544

0 commit comments

Comments
 (0)