From 785382acce6e4800812d3fe7068b2e2c14ab2e85 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 15 Jan 2024 12:22:25 +0200 Subject: [PATCH] test(clerk-js): Remove skipped tests from PasswordSection (#2582) --- .changeset/twelve-lions-remain.md | 2 + .../components/UserProfile/PasswordForm.tsx | 1 + .../__tests__/PasswordSection.test.tsx | 477 +++++++++++------- .../__tests__/SecurityPage.test.tsx | 17 +- 4 files changed, 315 insertions(+), 182 deletions(-) create mode 100644 .changeset/twelve-lions-remain.md diff --git a/.changeset/twelve-lions-remain.md b/.changeset/twelve-lions-remain.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/twelve-lions-remain.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/clerk-js/src/ui/components/UserProfile/PasswordForm.tsx b/packages/clerk-js/src/ui/components/UserProfile/PasswordForm.tsx index d1efdecff0..f0fc069847 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/PasswordForm.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/PasswordForm.tsx @@ -135,6 +135,7 @@ export const PasswordForm = withCardStateProvider((props: PasswordFormProps) => {/* For password managers */} { f.withUser({ password_enabled: true }); }); -//TODO-RETHEME -describe.skip('PasswordSection', () => { - it('renders the component', async () => { +describe('PasswordSection', () => { + it('renders the section with set button', async () => { const { wrapper } = await createFixtures(initConfig); - render(, { wrapper }); + const { getByText, getByRole } = render( + + + , + { wrapper }, + ); + getByText(/^Password/i); + getByRole('button', { name: /set password/i }); }); - it('shows the title', async () => { - const { wrapper } = await createFixtures(initConfig); - - render(, { wrapper }); + it('renders the section with change button', async () => { + const { wrapper } = await createFixtures(changePasswordConfig); - screen.getByRole('heading', { name: /Set password/i }); - expect(screen.queryByRole(/current password/i)).not.toBeInTheDocument(); + const { getByText, getByRole } = render( + + + , + { wrapper }, + ); + getByText(/^Password/i); + getByRole('button', { name: /change password/i }); }); - it('shows setup of changing password', async () => { - const { wrapper } = await createFixtures(changePasswordConfig); + describe('Set password', () => { + it('renders the set password screen', async () => { + const { wrapper } = await createFixtures(initConfig); - render(, { wrapper }); + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); - screen.getByRole('heading', { name: /change password/i }); - screen.getByLabelText(/current password/i); - }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); - it('renders a hidden identifier field', async () => { - const identifier = 'test@clerk.com'; - const { wrapper } = await createFixtures(f => { - f.startSignInWithEmailAddress({ identifier }); + getByLabelText(/new password/i); + getByLabelText(/confirm password/i); + getByLabelText(/Sign out of all other devices/i); + getByLabelText(/It is advised to logout of all other devices that may user an old password/i); }); - render(, { wrapper }); - const identifierField: HTMLInputElement = screen.getByTestId('hidden-identifier'); - expect(identifierField.value).toBe(identifier); - }); + it('sets a new password and calls the appropriate function and closes', async () => { + const { wrapper, fixtures } = await createFixtures(initConfig); - describe('with SAML', () => { - it('prevents adding a password if user has active enterprise connections', async () => { - const emailAddress = 'george@jungle.com'; - - const config = createFixtures.config(f => { - f.withEmailAddress(); - f.withSaml(); - f.withUser({ - email_addresses: [emailAddress], - saml_accounts: [ - { - id: 'samlacc_foo', - provider: 'saml_okta', - active: true, - email_address: emailAddress, - }, - ], - }); + const { getByRole, userEvent, getByLabelText, queryByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); + + await userEvent.type(getByLabelText(/new password/i), 'testtest'); + await userEvent.type(getByLabelText(/confirm password/i), 'testtest'); + await userEvent.click(getByRole('button', { name: /save$/i })); + expect(fixtures.clerk.user?.updatePassword).toHaveBeenCalledWith({ + newPassword: 'testtest', + signOutOfOtherSessions: true, }); + await waitFor(() => getByRole('button', { name: /set password/i })); + expect(queryByRole('heading', { name: /set password/i })).not.toBeInTheDocument(); + }); + + it('renders a hidden identifier field', async () => { + const { wrapper } = await createFixtures(initConfig); + const { getByRole, userEvent } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); - const { wrapper } = await createFixtures(config); + const identifierField: HTMLInputElement = screen.getByTestId('hidden-identifier'); + expect(identifierField.value).toBe('email@test.com'); + }); - render(, { wrapper }); + it('updates passwords and leave other sessions intact', async () => { + const { wrapper, fixtures } = await createFixtures(initConfig); - expect(screen.getByLabelText(/new password/i)).toBeDisabled(); - expect(screen.getByLabelText(/confirm password/i)).toBeDisabled(); - expect(screen.getByRole('checkbox', { name: /sign out of all other devices/i })).toBeDisabled(); + const { userEvent, getByRole, getByLabelText } = render(, { wrapper }); - expect( - screen.getByText( - 'Your password can currently not be edited because you can sign in only via the enterprise connection.', - ), - ).toBeInTheDocument(); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); + + await userEvent.type(getByLabelText(/new password/i), 'testtest'); + await userEvent.type(getByLabelText(/confirm password/i), 'testtest'); + await userEvent.click(getByRole('checkbox', { name: /sign out of all other devices/i })); + await userEvent.click(getByRole('button', { name: /save$/i })); + expect(fixtures.clerk.user?.updatePassword).toHaveBeenCalledWith({ + newPassword: 'testtest', + signOutOfOtherSessions: false, + }); }); - it('does not prevent adding a password if user has no active enterprise connections', async () => { - const emailAddress = 'george@jungle.com'; - - const config = createFixtures.config(f => { - f.withEmailAddress(); - f.withSaml(); - f.withUser({ - email_addresses: [emailAddress], - saml_accounts: [ - { - id: 'samlacc_foo', - provider: 'saml_okta', - active: false, - email_address: emailAddress, - }, - ], + describe('with SAML', () => { + it('prevents setting a password if user has active enterprise connections', async () => { + const emailAddress = 'george@jungle.com'; + + const config = createFixtures.config(f => { + f.withEmailAddress(); + f.withSaml(); + f.withUser({ + email_addresses: [emailAddress], + saml_accounts: [ + { + id: 'samlacc_foo', + provider: 'saml_okta', + active: true, + email_address: emailAddress, + }, + ], + }); }); - }); - const { wrapper } = await createFixtures(config); + const { wrapper } = await createFixtures(config); - render(, { wrapper }); + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); - expect(screen.getByLabelText(/new password/i)).not.toBeDisabled(); - expect(screen.getByLabelText(/confirm password/i)).not.toBeDisabled(); - expect(screen.getByRole('checkbox', { name: /sign out of all other devices/i })).not.toBeDisabled(); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); - expect( - screen.queryByText( - 'Your password can currently not be edited because you can sign in only via the enterprise connection.', - ), - ).not.toBeInTheDocument(); - }); + expect(getByLabelText(/new password/i)).toBeDisabled(); + expect(getByLabelText(/confirm password/i)).toBeDisabled(); + expect(getByRole('checkbox', { name: /sign out of all other devices/i })).toBeDisabled(); - it('prevents changing a password if user has active enterprise connections', async () => { - const emailAddress = 'george@jungle.com'; - - const config = createFixtures.config(f => { - f.withEmailAddress(); - f.withSaml(); - f.withUser({ - password_enabled: true, - email_addresses: [emailAddress], - saml_accounts: [ - { - id: 'samlacc_foo', - provider: 'saml_okta', - active: true, - email_address: emailAddress, - }, - ], - }); + expect( + screen.getByText( + 'Your password can currently not be edited because you can sign in only via the enterprise connection.', + ), + ).toBeInTheDocument(); }); - const { wrapper } = await createFixtures(config); + it('does not prevent adding a password if user has no active enterprise connections', async () => { + const emailAddress = 'george@jungle.com'; + + const config = createFixtures.config(f => { + f.withEmailAddress(); + f.withSaml(); + f.withUser({ + email_addresses: [emailAddress], + saml_accounts: [ + { + id: 'samlacc_foo', + provider: 'saml_okta', + active: false, + email_address: emailAddress, + }, + ], + }); + }); - render(, { wrapper }); + const { wrapper } = await createFixtures(config); - expect(screen.getByLabelText(/current password/i)).toBeDisabled(); - expect(screen.getByLabelText(/new password/i)).toBeDisabled(); - expect(screen.getByLabelText(/confirm password/i)).toBeDisabled(); - expect(screen.getByRole('checkbox', { name: /sign out of all other devices/i })).toBeDisabled(); + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); - expect( - screen.getByText( - 'Your password can currently not be edited because you can sign in only via the enterprise connection.', - ), - ).toBeInTheDocument(); - }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); - it('does not prevent changing a password if user has no active enterprise connections', async () => { - const emailAddress = 'george@jungle.com'; - - const config = createFixtures.config(f => { - f.withEmailAddress(); - f.withSaml(); - f.withUser({ - password_enabled: true, - email_addresses: [emailAddress], - saml_accounts: [ - { - id: 'samlacc_foo', - provider: 'saml_okta', - active: false, - email_address: emailAddress, - }, - ], - }); + expect(getByLabelText(/new password/i)).not.toBeDisabled(); + expect(getByLabelText(/confirm password/i)).not.toBeDisabled(); + expect(getByRole('checkbox', { name: /sign out of all other devices/i })).not.toBeDisabled(); + + expect( + screen.queryByText( + 'Your password can currently not be edited because you can sign in only via the enterprise connection.', + ), + ).not.toBeInTheDocument(); }); + }); - const { wrapper } = await createFixtures(config); + describe('Form buttons', () => { + it('save button is disabled by default', async () => { + const { wrapper } = await createFixtures(initConfig); + const { getByRole, userEvent } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); - render(, { wrapper }); + expect(getByRole('button', { name: /save$/i })).toBeDisabled(); + }); + it('hides screen when when pressing cancel', async () => { + const { wrapper } = await createFixtures(initConfig); - expect(screen.getByLabelText(/current password/i)).not.toBeDisabled(); - expect(screen.getByLabelText(/new password/i)).not.toBeDisabled(); - expect(screen.getByLabelText(/confirm password/i)).not.toBeDisabled(); - expect(screen.getByRole('checkbox', { name: /sign out of all other devices/i })).not.toBeDisabled(); + const { userEvent, getByRole, queryByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); + expect(queryByRole('button', { name: /set password/i })).not.toBeInTheDocument(); - expect( - screen.queryByText( - 'Your password can currently not be edited because you can sign in only via the enterprise connection.', - ), - ).not.toBeInTheDocument(); + await userEvent.click(getByRole('button', { name: /cancel$/i })); + await waitFor(() => getByRole('button', { name: /set password/i })); + expect(queryByRole('heading', { name: /set password/i })).not.toBeInTheDocument(); + }); }); }); - describe('Actions', () => { - it('calls the appropriate function upon pressing continue and finish', async () => { - const { wrapper, fixtures } = await createFixtures(initConfig); + describe('Change password', () => { + it('renders the set password screen', async () => { + const { wrapper } = await createFixtures(changePasswordConfig); + + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); - fixtures.clerk.user?.update.mockResolvedValue({} as UserResource); - const { userEvent } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /change password/i })); + await waitFor(() => getByRole('heading', { name: /change password/i })); - await userEvent.type(screen.getByLabelText(/new password/i), 'testtest'); - await userEvent.type(screen.getByLabelText(/confirm password/i), 'testtest'); - await userEvent.click(screen.getByRole('button', { name: /continue/i })); + getByLabelText(/current password/i); + getByLabelText(/new password/i); + getByLabelText(/confirm password/i); + getByLabelText(/Sign out of all other devices/i); + getByLabelText(/It is advised to logout of all other devices that may user an old password/i); + }); + + it('changes a new password and calls the appropriate function and closes', async () => { + const { wrapper, fixtures } = await createFixtures(changePasswordConfig); + + const { getByRole, userEvent, getByLabelText, queryByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /change password/i })); + await waitFor(() => getByRole('heading', { name: /change password/i })); + + await userEvent.type(getByLabelText(/current password/i), 'testtest1234'); + await userEvent.type(getByLabelText(/new password/i), 'testtest'); + await userEvent.type(getByLabelText(/confirm password/i), 'testtest'); + await userEvent.click(getByRole('button', { name: /save$/i })); expect(fixtures.clerk.user?.updatePassword).toHaveBeenCalledWith({ + currentPassword: 'testtest1234', newPassword: 'testtest', signOutOfOtherSessions: true, }); + await waitFor(() => getByRole('button', { name: /change password/i })); + expect(queryByRole('heading', { name: /change password/i })).not.toBeInTheDocument(); + }); - expect(await screen.findByText(/has been set/i)); - expect(await screen.findByText(/signed out/i)); - await userEvent.click(screen.getByRole('button', { name: /finish/i })); - expect(fixtures.router.navigate).toHaveBeenCalledWith('/'); + describe('with SAML', () => { + it('prevents changing a password if user has active enterprise connections', async () => { + const emailAddress = 'george@jungle.com'; + + const config = createFixtures.config(f => { + f.withEmailAddress(); + f.withSaml(); + f.withUser({ + password_enabled: true, + email_addresses: [emailAddress], + saml_accounts: [ + { + id: 'samlacc_foo', + provider: 'saml_okta', + active: true, + email_address: emailAddress, + }, + ], + }); + }); + + const { wrapper } = await createFixtures(config); + + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /change password/i })); + await waitFor(() => getByRole('heading', { name: /change password/i })); + + expect(getByLabelText(/current password/i)).toBeDisabled(); + expect(getByLabelText(/new password/i)).toBeDisabled(); + expect(getByLabelText(/confirm password/i)).toBeDisabled(); + expect(getByRole('checkbox', { name: /sign out of all other devices/i })).toBeDisabled(); + + expect( + screen.getByText( + 'Your password can currently not be edited because you can sign in only via the enterprise connection.', + ), + ).toBeInTheDocument(); + }); + + it('does not prevent changing a password if user has no active enterprise connections', async () => { + const emailAddress = 'george@jungle.com'; + + const config = createFixtures.config(f => { + f.withEmailAddress(); + f.withSaml(); + f.withUser({ + password_enabled: true, + email_addresses: [emailAddress], + saml_accounts: [ + { + id: 'samlacc_foo', + provider: 'saml_okta', + active: false, + email_address: emailAddress, + }, + ], + }); + }); + + const { wrapper } = await createFixtures(config); + + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /change password/i })); + await waitFor(() => getByRole('heading', { name: /change password/i })); + + expect(getByLabelText(/current password/i)).not.toBeDisabled(); + expect(getByLabelText(/new password/i)).not.toBeDisabled(); + expect(getByLabelText(/confirm password/i)).not.toBeDisabled(); + expect(getByRole('checkbox', { name: /sign out of all other devices/i })).not.toBeDisabled(); + + expect( + screen.queryByText( + 'Your password can currently not be edited because you can sign in only via the enterprise connection.', + ), + ).not.toBeInTheDocument(); + }); }); - it('updates passwords and leave other sessions intact', async () => { - const { wrapper, fixtures } = await createFixtures(initConfig); + describe('Form buttons', () => { + it('save button is disabled until current password is set', async () => { + const { wrapper } = await createFixtures(changePasswordConfig); + const { getByRole, userEvent, getByLabelText } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /change password/i })); + await waitFor(() => getByRole('heading', { name: /change password/i })); - fixtures.clerk.user?.update.mockResolvedValue({} as UserResource); - const { userEvent } = render(, { wrapper }); + await userEvent.type(getByLabelText(/new password/i), 'testtest'); + await userEvent.type(getByLabelText(/confirm password/i), 'testtest'); - await userEvent.type(screen.getByLabelText(/new password/i), 'testtest'); - await userEvent.type(screen.getByLabelText(/confirm password/i), 'testtest'); - await userEvent.click(screen.getByRole('checkbox', { name: /sign out of all other devices/i })); - await userEvent.click(screen.getByRole('button', { name: /continue/i })); - expect(fixtures.clerk.user?.updatePassword).toHaveBeenCalledWith({ - newPassword: 'testtest', - signOutOfOtherSessions: false, + expect(getByRole('button', { name: /save$/i })).toBeDisabled(); + }); + }); + }); + + describe('UI errors', () => { + it('results in error if the password is too small', async () => { + const { wrapper } = await createFixtures(initConfig); + + await runFakeTimers(async () => { + const { userEvent, getByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); + + await userEvent.type(screen.getByLabelText(/new password/i), 'test'); + const confirmField = screen.getByLabelText(/confirm password/i); + await userEvent.type(confirmField, 'test'); + fireEvent.blur(confirmField); + await waitFor(() => { + screen.getByText(/or more/i); + }); }); }); @@ -236,7 +356,9 @@ describe.skip('PasswordSection', () => { const { wrapper } = await createFixtures(initConfig); await runFakeTimers(async () => { - const { userEvent } = render(, { wrapper }); + const { userEvent, getByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); await userEvent.type(screen.getByLabelText(/new password/i), 'test'); const confirmField = screen.getByLabelText(/confirm password/i); @@ -252,7 +374,9 @@ describe.skip('PasswordSection', () => { const { wrapper } = await createFixtures(initConfig); await runFakeTimers(async () => { - const { userEvent } = render(, { wrapper }); + const { userEvent, getByRole } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); await userEvent.type(screen.getByLabelText(/new password/i), 'testewrewr'); const confirmField = screen.getByLabelText(/confirm password/i); @@ -273,23 +397,25 @@ describe.skip('PasswordSection', () => { const { wrapper } = await createFixtures(initConfig); await runFakeTimers(async () => { - const { userEvent } = render(, { wrapper }); - const passwordField = screen.getByLabelText(/new password/i); + const { userEvent, getByRole, getByLabelText, queryByText } = render(, { wrapper }); + await userEvent.click(getByRole('button', { name: /set password/i })); + await waitFor(() => getByRole('heading', { name: /set password/i })); + const passwordField = getByLabelText(/new password/i); await userEvent.type(passwordField, 'testewrewr'); - const confirmField = screen.getByLabelText(/confirm password/i); + const confirmField = getByLabelText(/confirm password/i); await waitFor(() => { - expect(screen.queryByText(`Passwords match.`)).not.toBeInTheDocument(); + expect(queryByText(`Passwords match.`)).not.toBeInTheDocument(); }); await userEvent.type(confirmField, 'testewrewr'); await waitFor(() => { - expect(screen.getByText(`Passwords match.`)).toBeInTheDocument(); + expect(queryByText(`Passwords match.`)).toBeInTheDocument(); }); await userEvent.type(confirmField, 'testrwerrwqrwe'); await waitFor(() => { - expect(screen.queryByText(`Passwords match.`)).not.toBeVisible(); + expect(queryByText(`Passwords match.`)).not.toBeVisible(); }); await userEvent.type(passwordField, 'testrwerrwqrwe'); @@ -299,14 +425,5 @@ describe.skip('PasswordSection', () => { }); }); }, 10000); - - it('navigates to the root page upon pressing cancel', async () => { - const { wrapper, fixtures } = await createFixtures(initConfig); - - const { userEvent } = render(, { wrapper }); - - await userEvent.click(screen.getByRole('button', { name: /cancel/i })); - expect(fixtures.router.navigate).toHaveBeenCalledWith('/'); - }); }); }); diff --git a/packages/clerk-js/src/ui/components/UserProfile/__tests__/SecurityPage.test.tsx b/packages/clerk-js/src/ui/components/UserProfile/__tests__/SecurityPage.test.tsx index a5829eb303..a740574cc3 100644 --- a/packages/clerk-js/src/ui/components/UserProfile/__tests__/SecurityPage.test.tsx +++ b/packages/clerk-js/src/ui/components/UserProfile/__tests__/SecurityPage.test.tsx @@ -1,6 +1,5 @@ import type { SessionWithActivitiesResource } from '@clerk/types'; import { describe, it } from '@jest/globals'; -import { expect } from '@playwright/test'; import { within } from '@testing-library/dom'; import { render, screen, waitFor } from '../../../../testUtils'; @@ -16,8 +15,22 @@ describe('SecurityPage', () => { }); fixtures.clerk.user?.getSessions.mockReturnValue(Promise.resolve([])); - render(, { wrapper }); + const { queryByText } = render(, { wrapper }); await waitFor(() => expect(fixtures.clerk.user?.getSessions).toHaveBeenCalled()); + expect(queryByText(/^password/i)).not.toBeInTheDocument(); + }); + + it('renders the Password section if instance is password based', async () => { + const { wrapper, fixtures } = await createFixtures(f => { + f.withPassword({ + required: true, + }); + f.withUser({ email_addresses: ['test@clerk.com'] }); + }); + fixtures.clerk.user?.getSessions.mockReturnValue(Promise.resolve([])); + + const { getByText } = render(, { wrapper }); + await waitFor(() => getByText(/^password/i)); }); it('shows the active devices of the user and has appropriate buttons', async () => {