Skip to content

Commit 97e8172

Browse files
[Remove Vuetify from Studio] Add / remove admin privileges dialogs
1 parent ad4d81e commit 97e8172

File tree

3 files changed

+204
-116
lines changed

3 files changed

+204
-116
lines changed

contentcuration/contentcuration/frontend/administration/pages/Users/UserActionsDropdown.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929
</KModal>
3030
<UserPrivilegeModal
3131
v-model="addAdminPrivilegeDialog"
32-
header="Add admin privileges"
32+
title="Add admin privileges"
3333
:text="`Are you sure you want to add admin privileges to user '${user.name}'?`"
3434
confirmText="Add privileges"
3535
:confirmAction="addAdminHandler"
3636
/>
3737
<UserPrivilegeModal
3838
v-model="removeAdminPrivilegeDialog"
39-
header="Remove admin privileges"
39+
title="Remove admin privileges"
4040
:text="`Are you sure you want to remove admin privileges from user '${user.name}'?`"
4141
confirmText="Remove privileges"
4242
:confirmAction="removeAdminHandler"

contentcuration/contentcuration/frontend/administration/pages/Users/UserPrivilegeModal.vue

Lines changed: 48 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,53 @@
11
<template>
22

3-
<MessageDialog
4-
v-model="dialog"
5-
:header="header"
6-
:text="text"
3+
<KModal
4+
v-if="dialog"
5+
:title="title"
6+
:submitText="confirmText"
7+
cancelText="Cancel"
8+
@submit="submit"
9+
@cancel="close"
710
>
8-
<VForm
9-
ref="form"
10-
lazy-validation
11-
@submit.prevent="confirm"
12-
>
13-
<p>Enter your email address to continue</p>
14-
<VTextField
15-
v-model="emailConfirm"
16-
box
17-
maxlength="100"
18-
counter
19-
required
20-
:rules="emailRules"
21-
label="Email address"
22-
@input="resetValidation"
23-
/>
24-
</VForm>
25-
<template #buttons>
26-
<VBtn
27-
flat
28-
data-test="cancel"
29-
@click="close"
30-
>
31-
Cancel
32-
</VBtn>
33-
<VBtn
34-
color="primary"
35-
@click="confirm"
36-
>
37-
{{ confirmText }}
38-
</VBtn>
39-
</template>
40-
</MessageDialog>
11+
<p>{{ text }}</p>
12+
13+
<p>Enter your email address to continue</p>
14+
15+
<KTextbox
16+
v-model="emailConfirm"
17+
:maxlength="100"
18+
label="Email address"
19+
:invalid="errors.emailConfirm"
20+
invalidText="Email does not match your account email"
21+
:showInvalidText="true"
22+
/>
23+
</KModal>
4124

4225
</template>
4326

4427

4528
<script>
4629
4730
import { mapState } from 'vuex';
48-
import MessageDialog from 'shared/views/MessageDialog';
31+
import { generateFormMixin } from 'shared/mixins';
32+
33+
const formMixin = generateFormMixin({
34+
emailConfirm: {
35+
required: true,
36+
validator: (value, vm) => {
37+
return value === vm.currentEmail;
38+
},
39+
},
40+
});
4941
5042
export default {
5143
name: 'UserPrivilegeModal',
52-
components: {
53-
MessageDialog,
54-
},
44+
mixins: [formMixin],
5545
props: {
5646
value: {
5747
type: Boolean,
5848
default: false,
5949
},
60-
header: {
50+
title: {
6151
type: String,
6252
required: true,
6353
},
@@ -74,13 +64,9 @@
7464
required: true,
7565
},
7666
},
77-
data() {
78-
return {
79-
emailConfirm: '',
80-
};
81-
},
8267
computed: {
8368
...mapState({
69+
// eslint-disable-next-line kolibri/vue-no-unused-vuex-properties, vue/no-unused-properties
8470
currentEmail: state => state.session.currentUser.email,
8571
}),
8672
dialog: {
@@ -91,28 +77,26 @@
9177
this.$emit('input', value);
9278
},
9379
},
94-
emailRules() {
95-
return [
96-
v => Boolean(v) || 'Field is required',
97-
v => v === this.currentEmail || 'Email does not match your account email',
98-
];
80+
},
81+
watch: {
82+
value(val) {
83+
if (val) {
84+
this.reset();
85+
}
9986
},
10087
},
10188
methods: {
10289
close() {
103-
this.emailConfirm = '';
104-
this.resetValidation();
105-
this.dialog = false;
90+
this.$emit('input', false);
10691
},
107-
resetValidation() {
108-
this.$refs.form.resetValidation();
109-
},
110-
confirm() {
111-
if (this.$refs.form.validate()) {
112-
return this.confirmAction();
113-
} else {
114-
return Promise.resolve();
115-
}
92+
93+
// This is called from formMixin
94+
// eslint-disable-next-line kolibri/vue-no-unused-methods, vue/no-unused-properties
95+
onSubmit() {
96+
return Promise.resolve(this.confirmAction()).then(result => {
97+
this.dialog = false;
98+
return result;
99+
});
116100
},
117101
},
118102
};
Lines changed: 154 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,174 @@
1-
import { mount } from '@vue/test-utils';
1+
import { render, screen } from '@testing-library/vue';
2+
import userEvent from '@testing-library/user-event';
3+
import { createLocalVue } from '@vue/test-utils';
4+
import Vuex, { Store } from 'vuex';
5+
import VueRouter from 'vue-router';
26
import UserPrivilegeModal from '../UserPrivilegeModal';
37

4-
const userId = 'test-user-id';
5-
const currentEmail = '[email protected]';
8+
const localVue = createLocalVue();
9+
localVue.use(Vuex);
10+
localVue.use(VueRouter);
611

7-
function makeWrapper(props = {}) {
8-
return mount(UserPrivilegeModal, {
9-
propsData: {
10-
userId,
11-
value: true,
12-
...props,
13-
},
14-
computed: {
15-
user() {
16-
return {
17-
id: userId,
18-
};
19-
},
20-
currentEmail() {
21-
return currentEmail;
12+
const currentEmail = '[email protected]';
13+
14+
const createMockStore = () => {
15+
return new Store({
16+
state: {
17+
session: {
18+
currentUser: {
19+
email: currentEmail,
20+
},
2221
},
2322
},
2423
});
25-
}
24+
};
25+
26+
const renderComponent = (props = {}) => {
27+
const confirmAction = jest.fn(() => Promise.resolve());
28+
const store = createMockStore();
29+
30+
const defaultProps = {
31+
value: true,
32+
title: 'Add admin privileges',
33+
text: 'Are you sure you want to add admin privileges to user ...?',
34+
confirmText: 'Add privileges',
35+
confirmAction,
36+
...props,
37+
};
38+
39+
return {
40+
...render(UserPrivilegeModal, {
41+
localVue,
42+
store,
43+
routes: new VueRouter(),
44+
props: defaultProps,
45+
}),
46+
confirmAction,
47+
};
48+
};
2649

2750
describe('userPrivilegeModal', () => {
28-
let wrapper;
29-
let confirmAction;
51+
it('should render modal with correct title, text, and confirm button label', () => {
52+
renderComponent();
3053

31-
beforeEach(() => {
32-
confirmAction = jest.fn();
33-
wrapper = makeWrapper({ confirmAction });
54+
expect(screen.getByText('Add admin privileges')).toBeInTheDocument();
55+
expect(
56+
screen.getByText('Are you sure you want to add admin privileges to user ...?'),
57+
).toBeInTheDocument();
58+
expect(screen.getByText('Add privileges')).toBeInTheDocument();
3459
});
3560

36-
it('clicking cancel should reset the values', async () => {
37-
wrapper = makeWrapper({ emailConfirm: 'testing' });
38-
wrapper.findComponent('[data-test="cancel"]').trigger('click');
39-
await wrapper.vm.$nextTick();
40-
expect(wrapper.vm.emailConfirm).toBe('');
41-
});
61+
describe('clicking cancel', () => {
62+
let user;
63+
let confirmAction;
64+
let emitted;
4265

43-
it('submitting form should call confirm', async () => {
44-
const confirm = jest.spyOn(wrapper.vm, 'confirm');
45-
confirm.mockImplementation(() => {});
46-
wrapper.findComponent({ ref: 'form' }).trigger('submit');
47-
await wrapper.vm.$nextTick();
48-
expect(confirm).toHaveBeenCalled();
66+
beforeEach(async () => {
67+
user = userEvent.setup();
68+
const result = renderComponent();
69+
confirmAction = result.confirmAction;
70+
emitted = result.emitted;
71+
72+
const cancelButton = screen.getByRole('button', { name: /cancel/i });
73+
await user.click(cancelButton);
74+
});
75+
76+
it('should not call confirmAction', () => {
77+
expect(confirmAction).not.toHaveBeenCalled();
78+
});
79+
80+
it('should emit input event with false', () => {
81+
expect(emitted().input[0]).toEqual([false]);
82+
});
4983
});
5084

51-
it('confirm should not call confirmAction if emailConfirm is blank', async () => {
52-
wrapper.vm.confirm();
53-
await wrapper.vm.$nextTick();
54-
expect(confirmAction).not.toHaveBeenCalled();
85+
describe('submitting the form with empty e-mail', () => {
86+
let user;
87+
let confirmAction;
88+
let emitted;
89+
90+
beforeEach(async () => {
91+
user = userEvent.setup();
92+
const result = renderComponent();
93+
confirmAction = result.confirmAction;
94+
emitted = result.emitted;
95+
96+
const submitButton = screen.getByRole('button', { name: /add privileges/i });
97+
await user.click(submitButton);
98+
});
99+
100+
it('should show validation error', () => {
101+
expect(screen.getByText('Email does not match your account email')).toBeInTheDocument();
102+
});
103+
104+
it('should not call confirmAction', () => {
105+
expect(confirmAction).not.toHaveBeenCalled();
106+
});
107+
108+
it('should not emit input event', () => {
109+
expect(emitted().input).toBeUndefined();
110+
});
55111
});
56112

57-
it('confirm should not call confirmAction if emailConfirm is not correct', async () => {
58-
await wrapper.setData({ emailConfirm: '[email protected]' });
59-
wrapper.vm.confirm();
60-
await wrapper.vm.$nextTick();
61-
expect(confirmAction).not.toHaveBeenCalled();
113+
describe('submitting the form with an e-mail different from the current e-mail', () => {
114+
let user;
115+
let confirmAction;
116+
let emitted;
117+
118+
beforeEach(async () => {
119+
user = userEvent.setup();
120+
const result = renderComponent();
121+
confirmAction = result.confirmAction;
122+
emitted = result.emitted;
123+
124+
const emailInput = screen.getByLabelText(/email address/i);
125+
await user.type(emailInput, '[email protected]');
126+
127+
const submitButton = screen.getByRole('button', { name: /add privileges/i });
128+
await user.click(submitButton);
129+
});
130+
131+
it('should show validation error', () => {
132+
expect(screen.getByText('Email does not match your account email')).toBeInTheDocument();
133+
});
134+
135+
it('should not call confirmAction', () => {
136+
expect(confirmAction).not.toHaveBeenCalled();
137+
});
138+
139+
it('should not emit input event', () => {
140+
expect(emitted().input).toBeUndefined();
141+
});
62142
});
63143

64-
it('confirm should call confirmAction if form is valid', async () => {
65-
await wrapper.setData({ emailConfirm: currentEmail });
66-
wrapper.vm.confirm();
67-
await wrapper.vm.$nextTick();
68-
expect(confirmAction).toHaveBeenCalled();
144+
describe('submitting the form with the current e-mail', () => {
145+
let user;
146+
let confirmAction;
147+
let emitted;
148+
149+
beforeEach(async () => {
150+
user = userEvent.setup();
151+
const result = renderComponent();
152+
confirmAction = result.confirmAction;
153+
emitted = result.emitted;
154+
155+
const emailInput = screen.getByLabelText(/email address/i);
156+
await user.type(emailInput, currentEmail);
157+
158+
const submitButton = screen.getByRole('button', { name: /add privileges/i });
159+
await user.click(submitButton);
160+
});
161+
162+
it('should not show validation error', () => {
163+
expect(screen.queryByText('Email does not match your account email')).not.toBeInTheDocument();
164+
});
165+
166+
it('should call confirmAction', () => {
167+
expect(confirmAction).toHaveBeenCalled();
168+
});
169+
170+
it('should emit input event with false', () => {
171+
expect(emitted().input[0]).toEqual([false]);
172+
});
69173
});
70174
});

0 commit comments

Comments
 (0)