Skip to content

Commit 2b9e620

Browse files
authored
Remove Vuetify from change password form in Settings
1 parent 5c06498 commit 2b9e620

File tree

2 files changed

+114
-56
lines changed

2 files changed

+114
-56
lines changed

contentcuration/contentcuration/frontend/settings/pages/Account/ChangePasswordForm.vue

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,27 @@
55
:title="$tr('changePasswordHeader')"
66
:submitText="$tr('saveChangesAction')"
77
:cancelText="$tr('cancelAction')"
8-
@submit="submitPassword"
8+
@submit="submit"
99
@cancel="dialog = false"
1010
>
11-
<!-- inline style here avoids scrollbar on validations -->
12-
<VForm
13-
ref="form"
14-
style="height: 196px"
15-
>
16-
<PasswordField
11+
<form ref="form">
12+
<KTextbox
1713
v-model="password"
18-
:additionalRules="passwordValidationRules"
14+
type="password"
1915
:label="$tr('newPasswordLabel')"
16+
:invalid="errors.password"
17+
:invalidText="$tr('passwordValidationMessage')"
18+
:showInvalidText="true"
2019
/>
21-
<PasswordField
20+
<KTextbox
2221
v-model="confirmation"
22+
type="password"
2323
:label="$tr('confirmNewPasswordLabel')"
24-
:additionalRules="passwordConfirmRules"
24+
:invalid="errors.confirmation"
25+
:invalidText="$tr('formInvalidText')"
26+
:showInvalidText="true"
2527
/>
26-
</VForm>
28+
</form>
2729
</KModal>
2830

2931
</template>
@@ -32,23 +34,33 @@
3234
<script>
3335
3436
import { mapActions } from 'vuex';
35-
import PasswordField from 'shared/views/form/PasswordField';
37+
import { generateFormMixin } from 'shared/mixins';
38+
39+
const formMixin = generateFormMixin({
40+
password: {
41+
required: true,
42+
// eslint-disable-next-line no-unused-vars
43+
validator: (value, _vm) => {
44+
return value.length >= 8;
45+
},
46+
},
47+
confirmation: {
48+
required: true,
49+
validator: (value, vm) => {
50+
return value === vm.password;
51+
},
52+
},
53+
});
3654
3755
export default {
3856
name: 'ChangePasswordForm',
39-
components: { PasswordField },
57+
mixins: [formMixin],
4058
props: {
4159
value: {
4260
type: Boolean,
4361
default: false,
4462
},
4563
},
46-
data() {
47-
return {
48-
password: '',
49-
confirmation: '',
50-
};
51-
},
5264
computed: {
5365
dialog: {
5466
get() {
@@ -58,36 +70,30 @@
5870
this.$emit('input', value);
5971
},
6072
},
61-
passwordValidationRules() {
62-
return [value => (value.length >= 8 ? true : this.$tr('passwordValidationMessage'))];
63-
},
64-
passwordConfirmRules() {
65-
return [value => (this.password === value ? true : this.$tr('formInvalidText'))];
66-
},
6773
},
6874
watch: {
6975
value(value) {
7076
// Reset values on open
7177
if (value) {
72-
this.password = '';
73-
this.confirmation = '';
78+
this.reset();
7479
}
7580
},
7681
},
7782
methods: {
7883
...mapActions(['showSnackbar']),
7984
...mapActions('settings', ['updateUserPassword']),
80-
submitPassword() {
81-
if (this.$refs.form.validate()) {
82-
return this.updateUserPassword(this.password)
83-
.then(() => {
84-
this.dialog = false;
85-
this.showSnackbar({ text: this.$tr('paswordChangeSuccess') });
86-
})
87-
.catch(() => {
88-
this.showSnackbar({ text: this.$tr('passwordChangeFailed') });
89-
});
90-
}
85+
86+
// This is called from formMixin
87+
// eslint-disable-next-line kolibri/vue-no-unused-methods, vue/no-unused-properties
88+
onSubmit() {
89+
return this.updateUserPassword(this.password)
90+
.then(() => {
91+
this.dialog = false;
92+
this.showSnackbar({ text: this.$tr('paswordChangeSuccess') });
93+
})
94+
.catch(() => {
95+
this.showSnackbar({ text: this.$tr('passwordChangeFailed') });
96+
});
9197
},
9298
},
9399
$trs: {

contentcuration/contentcuration/frontend/settings/pages/__tests__/changePasswordForm.spec.js

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,81 @@ function makeWrapper() {
1313
}
1414

1515
describe('changePasswordForm', () => {
16-
let wrapper;
17-
18-
beforeEach(() => {
19-
wrapper = makeWrapper();
16+
it('should render the form', () => {
17+
const wrapper = makeWrapper();
18+
expect(wrapper.html()).toContain('Change password');
19+
expect(wrapper.html()).toContain('New password');
20+
expect(wrapper.html()).toContain('Confirm new password');
21+
expect(wrapper.html()).toContain('Save changes');
22+
expect(wrapper.html()).toContain('Cancel');
2023
});
2124

22-
it('validation should fail if passwords do not match', async () => {
23-
await wrapper.setData({ password: 'test' });
24-
expect(typeof wrapper.vm.passwordConfirmRules[0]('data')).toBe('string');
25+
describe('if a password is too short', () => {
26+
let updateUserPassword;
27+
let wrapper;
28+
29+
beforeAll(async () => {
30+
wrapper = makeWrapper();
31+
updateUserPassword = jest.spyOn(wrapper.vm, 'updateUserPassword');
32+
const passwordInputs = wrapper.findAll('input[type="password"]');
33+
passwordInputs.at(0).setValue('pw');
34+
wrapper.findComponent({ name: 'KModal' }).vm.$emit('submit');
35+
await wrapper.vm.$nextTick();
36+
});
37+
38+
it('should show a correct error message', () => {
39+
expect(wrapper.html()).toContain('Password should be at least 8 characters long');
40+
});
41+
42+
it('should not call updateUserPassword', () => {
43+
expect(updateUserPassword).not.toHaveBeenCalled();
44+
});
2545
});
2646

27-
it('failed validation should not call updateUserPassword', async () => {
28-
const updateUserPassword = jest.spyOn(wrapper.vm, 'updateUserPassword');
29-
updateUserPassword.mockImplementation(() => Promise.resolve());
30-
await wrapper.vm.submitPassword();
31-
expect(updateUserPassword).not.toHaveBeenCalled();
47+
describe(`if passwords don't match`, () => {
48+
let updateUserPassword;
49+
let wrapper;
50+
51+
beforeAll(async () => {
52+
wrapper = makeWrapper();
53+
updateUserPassword = jest.spyOn(wrapper.vm, 'updateUserPassword');
54+
const passwordInputs = wrapper.findAll('input[type="password"]');
55+
passwordInputs.at(0).setValue('password1');
56+
passwordInputs.at(1).setValue('password2');
57+
wrapper.findComponent({ name: 'KModal' }).vm.$emit('submit');
58+
await wrapper.vm.$nextTick();
59+
});
60+
61+
it('should show a correct error message', () => {
62+
expect(wrapper.html()).toContain(`Passwords don't match`);
63+
});
64+
65+
it('should not call updateUserPassword', () => {
66+
expect(updateUserPassword).not.toHaveBeenCalled();
67+
});
3268
});
3369

34-
it('clicking submit should call updateUserPassword', async () => {
35-
const updateUserPassword = jest.spyOn(wrapper.vm, 'updateUserPassword');
36-
updateUserPassword.mockImplementation(() => Promise.resolve());
37-
await wrapper.setData({ password: 'tester123', confirmation: 'tester123' });
38-
await wrapper.vm.submitPassword();
39-
expect(updateUserPassword).toHaveBeenCalled();
70+
describe('if passwords match and are valid', () => {
71+
let updateUserPassword;
72+
let wrapper;
73+
74+
beforeAll(async () => {
75+
wrapper = makeWrapper();
76+
updateUserPassword = jest.spyOn(wrapper.vm, 'updateUserPassword');
77+
const passwordInputs = wrapper.findAll('input[type="password"]');
78+
passwordInputs.at(0).setValue('password123');
79+
passwordInputs.at(1).setValue('password123');
80+
wrapper.findComponent({ name: 'KModal' }).vm.$emit('submit');
81+
await wrapper.vm.$nextTick();
82+
});
83+
84+
it('should not show any error messages', () => {
85+
expect(wrapper.html()).not.toContain('Password should be at least 8 characters long');
86+
expect(wrapper.html()).not.toContain(`Passwords don't match`);
87+
});
88+
89+
it('should call updateUserPassword', () => {
90+
expect(updateUserPassword).toHaveBeenCalled();
91+
});
4092
});
4193
});

0 commit comments

Comments
 (0)