Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature: Desktop view - Implement personal setting section to change …
…the password. Co-authored-by: Florian Liebe <fl@zammad.com>
- Loading branch information
Showing
17 changed files
with
728 additions
and
22 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
20 changes: 20 additions & 0 deletions
20
...tend/apps/desktop/pages/personal-setting/__tests__/personal-setting-password-a11y.spec.ts
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,20 @@ | ||
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ | ||
|
||
import { axe } from 'vitest-axe' | ||
|
||
import { visitView } from '#tests/support/components/visitView.ts' | ||
import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts' | ||
|
||
describe('testing locale a11y view', async () => { | ||
beforeEach(() => { | ||
mockApplicationConfig({ | ||
user_show_password_login: true, | ||
}) | ||
}) | ||
|
||
it('has no accessibility violations', async () => { | ||
const view = await visitView('/personal-setting/password') | ||
const results = await axe(view.html()) | ||
expect(results).toHaveNoViolations() | ||
}) | ||
}) |
119 changes: 119 additions & 0 deletions
119
app/frontend/apps/desktop/pages/personal-setting/__tests__/personal-setting-password.spec.ts
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,119 @@ | ||
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ | ||
|
||
import type { ExtendedRenderResult } from '#tests/support/components/renderComponent.ts' | ||
import { visitView } from '#tests/support/components/visitView.ts' | ||
import { mockAccount } from '#tests/support/mock-account.ts' | ||
import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts' | ||
|
||
import { mockAccountChangePasswordMutation } from '../graphql/mutations/accountChangePassword.mocks.ts' | ||
|
||
const changePassword = async ( | ||
view: ExtendedRenderResult, | ||
currentPassword: string, | ||
newPassword: string, | ||
newPasswordConfirm?: string, | ||
) => { | ||
await view.events.type( | ||
await view.findByLabelText('Current password'), | ||
currentPassword, | ||
) | ||
await view.events.type( | ||
await view.findByLabelText('New password'), | ||
newPassword, | ||
) | ||
await view.events.type( | ||
await view.findByLabelText('Confirm new password'), | ||
newPasswordConfirm || newPassword, | ||
) | ||
await view.events.click(view.getByRole('button', { name: 'Change Password' })) | ||
} | ||
|
||
describe('password personal settings', () => { | ||
beforeEach(() => { | ||
mockAccount({ | ||
firstname: 'John', | ||
lastname: 'Doe', | ||
}) | ||
|
||
mockApplicationConfig({ | ||
user_show_password_login: true, | ||
}) | ||
}) | ||
|
||
it('redirects to the error page when password login is disabled', async () => { | ||
mockApplicationConfig({ | ||
user_show_password_login: false, | ||
}) | ||
|
||
const view = await visitView('/personal-setting/password') | ||
|
||
await vi.waitFor(() => { | ||
expect(view, 'correctly redirects to error page').toHaveCurrentUrl( | ||
'/error', | ||
) | ||
}) | ||
}) | ||
|
||
it('shows the form to change the password', async () => { | ||
const view = await visitView('/personal-setting/password') | ||
|
||
expect(view.getByText('Current password')).toBeInTheDocument() | ||
expect(view.getByText('New password')).toBeInTheDocument() | ||
expect(view.getByText('Confirm new password')).toBeInTheDocument() | ||
|
||
expect( | ||
view.getByRole('button', { name: 'Change Password' }), | ||
).toBeInTheDocument() | ||
}) | ||
|
||
it('shows an error message when e.g. current password is incorrect', async () => { | ||
mockAccountChangePasswordMutation({ | ||
accountChangePassword: { | ||
success: false, | ||
errors: [ | ||
{ | ||
message: 'The current password you provided is incorrect.', | ||
field: 'current_password', | ||
}, | ||
], | ||
}, | ||
}) | ||
|
||
const view = await visitView('/personal-setting/password') | ||
|
||
await changePassword(view, 'wrong-password', 'new-password') | ||
|
||
expect( | ||
await view.findByText('The current password you provided is incorrect.'), | ||
).toBeInTheDocument() | ||
}) | ||
|
||
it('shows an error message when new password and confirmation do not match', async () => { | ||
const view = await visitView('/personal-setting/password') | ||
|
||
await changePassword(view, 'old-password', 'new-password', 'wrong-password') | ||
|
||
expect( | ||
await view.findByText( | ||
"This field doesn't correspond to the expected value.", | ||
), | ||
).toBeInTheDocument() | ||
}) | ||
|
||
it('shows a success message when password was changed successfully', async () => { | ||
mockAccountChangePasswordMutation({ | ||
accountChangePassword: { | ||
success: true, | ||
errors: null, | ||
}, | ||
}) | ||
|
||
const view = await visitView('/personal-setting/password') | ||
|
||
await changePassword(view, 'old-password', 'new-password') | ||
|
||
expect( | ||
await view.findByText('Password changed successfully.'), | ||
).toBeInTheDocument() | ||
}) | ||
}) |
25 changes: 25 additions & 0 deletions
25
...ontend/apps/desktop/pages/personal-setting/graphql/mutations/accountChangePassword.api.ts
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,25 @@ | ||
import * as Types from '#shared/graphql/types.ts'; | ||
|
||
import gql from 'graphql-tag'; | ||
import { ErrorsFragmentDoc } from '../../../../../../shared/graphql/fragments/errors.api'; | ||
import * as VueApolloComposable from '@vue/apollo-composable'; | ||
import * as VueCompositionApi from 'vue'; | ||
export type ReactiveFunction<TParam> = () => TParam; | ||
|
||
export const AccountChangePasswordDocument = gql` | ||
mutation accountChangePassword($currentPassword: String!, $newPassword: String!) { | ||
accountChangePassword( | ||
currentPassword: $currentPassword | ||
newPassword: $newPassword | ||
) { | ||
success | ||
errors { | ||
...errors | ||
} | ||
} | ||
} | ||
${ErrorsFragmentDoc}`; | ||
export function useAccountChangePasswordMutation(options: VueApolloComposable.UseMutationOptions<Types.AccountChangePasswordMutation, Types.AccountChangePasswordMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<Types.AccountChangePasswordMutation, Types.AccountChangePasswordMutationVariables>> = {}) { | ||
return VueApolloComposable.useMutation<Types.AccountChangePasswordMutation, Types.AccountChangePasswordMutationVariables>(AccountChangePasswordDocument, options); | ||
} | ||
export type AccountChangePasswordMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<Types.AccountChangePasswordMutation, Types.AccountChangePasswordMutationVariables>; |
8 changes: 8 additions & 0 deletions
8
...ntend/apps/desktop/pages/personal-setting/graphql/mutations/accountChangePassword.graphql
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,8 @@ | ||
mutation accountChangePassword($currentPassword: String!, $newPassword: String!) { | ||
accountChangePassword(currentPassword: $currentPassword, newPassword: $newPassword) { | ||
success | ||
errors { | ||
...errors | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
...tend/apps/desktop/pages/personal-setting/graphql/mutations/accountChangePassword.mocks.ts
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,12 @@ | ||
import * as Types from '#shared/graphql/types.ts'; | ||
|
||
import * as Mocks from '#tests/graphql/builders/mocks.ts' | ||
import * as Operations from './accountChangePassword.api.ts' | ||
|
||
export function mockAccountChangePasswordMutation(defaults: Mocks.MockDefaultsValue<Types.AccountChangePasswordMutation, Types.AccountChangePasswordMutationVariables>) { | ||
return Mocks.mockGraphQLResult(Operations.AccountChangePasswordDocument, defaults) | ||
} | ||
|
||
export function waitForAccountChangePasswordMutationCalls() { | ||
return Mocks.waitForGraphQLMockCalls<Types.AccountChangePasswordMutation>(Operations.AccountChangePasswordDocument) | ||
} |
9 changes: 9 additions & 0 deletions
9
app/frontend/apps/desktop/pages/personal-setting/types/change-password.ts
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,9 @@ | ||
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ | ||
|
||
import type { FormValues } from '#shared/components/Form/types.ts' | ||
|
||
export interface ChangePasswordFormData extends FormValues { | ||
currentPassword: string | ||
newPassword: string | ||
newPasswordConfirmation: string | ||
} |
35 changes: 35 additions & 0 deletions
35
app/frontend/apps/desktop/pages/personal-setting/views/PersonalSetting/plugins/password.ts
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,35 @@ | ||
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ | ||
|
||
import { useApplicationStore } from '#shared/stores/application.ts' | ||
|
||
import type { PersonalSettingPlugin } from './types.ts' | ||
|
||
export default <PersonalSettingPlugin>{ | ||
label: __('Password'), | ||
category: { | ||
label: __('Security'), | ||
id: 'category-security', | ||
order: 9000, | ||
}, | ||
route: { | ||
path: 'password', | ||
name: 'PersonalSettingPassword', | ||
component: () => import('../../PersonalSettingPassword.vue'), | ||
level: 2, | ||
meta: { | ||
title: __('Password'), | ||
requiresAuth: true, | ||
requiredPermission: 'user_preferences.password', | ||
}, | ||
}, | ||
order: 1000, | ||
keywords: __( | ||
'current,new,confirm,change,current password,new password,confirm password,change password', | ||
), | ||
show: () => { | ||
const { config } = useApplicationStore() | ||
|
||
if (!config.user_show_password_login) return false | ||
return true | ||
}, | ||
} |
Oops, something went wrong.