Skip to content
Merged
302 changes: 168 additions & 134 deletions src/modules/feature/room/roomMembers/dialogs/AddMembersDialog.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ describe("AddMembersDialog", () => {

const setup = (options?: {
customRoomAuthorization?: RoomAuthorizationRefs;
schoolRole?: RoleName.Teacher | RoleName.Student;
schoolRole?: RoleName.Teacher | RoleName.Student | RoleName.Administrator;
isOpen?: boolean;
isAdminMode?: boolean;
}) => {
const configDefaults = {
canAddRoomMembers: true,
Expand Down Expand Up @@ -96,6 +97,7 @@ describe("AddMembersDialog", () => {
wrapper = mount(AddMembersDialog, {
props: {
modelValue: options?.isOpen ?? true,
isAdminMode: options?.isAdminMode ?? false,
},
attachTo: document.body,
global: {
Expand Down Expand Up @@ -206,139 +208,6 @@ describe("AddMembersDialog", () => {
});
});

describe("when school is changed", () => {
it("should call resetPotentialMembers", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedSchool = roomMembersSchools[1].id;
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});

await schoolComponent.setValue(selectedSchool);

expect(roomMembersStore.resetPotentialMembers).toHaveBeenCalledTimes(1);
});

it("should reset selectedUsers", async () => {
const { wrapper } = setup();
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});

const userComponent = wrapper.getComponent({
ref: "autoCompleteUsers",
});

await schoolComponent.setValue("schoolId");

expect(userComponent.props("modelValue")).toEqual([]);
});

it("should call getPotentialMembers for set role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedSchool = roomMembersSchools[1].id;
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});
const selectedRole = roleComponent.props("modelValue");

await schoolComponent.setValue(selectedSchool);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, selectedSchool);
});
});

describe("when userRole is changed", () => {
it("should call resetPotentialMembers", async () => {
const { wrapper, roomMembersStore } = setup();
const selectedRole = RoleName.Student;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.resetPotentialMembers).toHaveBeenCalledTimes(1);
});

it("should reset selectedUsers", async () => {
const { wrapper } = setup();
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

const userComponent = wrapper.getComponent({
ref: "autoCompleteUsers",
});

await roleComponent.setValue(RoleName.Roomeditor);

expect(userComponent.props("modelValue")).toEqual([]);
});

describe("and the role is set to student", () => {
it("should call getPotentialMembers for student role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedRole = RoleName.Student;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, roomMembersSchools[0].id);
});

it("should render an icon with text for student role", async () => {
const { wrapper } = setup();

const roleComponent = wrapper.getComponent({
ref: "selectRole",
});
await roleComponent.setValue(RoleName.Student);

const roleIcon = roleComponent.findComponent(VIcon);

expect(roleIcon.props("icon")).toBe(mdiAccountOutline);
expect(roleComponent.text()).toContain("common.labels.student.neutral");
});
});

describe("and the role is set to teacher", () => {
it("should call getPotentialMembers for teacher role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedRole = RoleName.Teacher;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, roomMembersSchools[0].id);
});

it("should render an icon with text for teacher role", async () => {
const { wrapper } = setup();

const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(RoleName.Teacher);
const roleIcon = roleComponent.findComponent(VIcon);

expect(roleIcon.props("icon")).toBe(mdiAccountSchoolOutline);
expect(roleComponent.text()).toContain("common.labels.teacher.neutral");
});
});
});

describe("when user(s) selected", () => {
it("should add user to selectedUsers", async () => {
const { wrapper, potentialRoomMembers } = setup();
Expand Down Expand Up @@ -619,6 +488,171 @@ describe("AddMembersDialog", () => {
});
});

describe("when it is used by an administrator in the room administration", () => {
it("should not allow the school role to be changed", () => {
const { wrapper } = setup({ schoolRole: RoleName.Administrator, isOpen: true, isAdminMode: true });
const roleSelect = wrapper.getComponent({
ref: "selectRole",
});

expect(roleSelect.props("readonly")).toBe(true);
expect(roleSelect.props("menuIcon")).toBe("");
});
it("the school role should be set to teacher", () => {
const { wrapper } = setup({ schoolRole: RoleName.Administrator, isOpen: true, isAdminMode: true });
const roleSelect = wrapper.getComponent({
ref: "selectRole",
});

expect(roleSelect.props("modelValue")).toBe(RoleName.Teacher);
});
});

describe("when it is used by a teacher in the room management", () => {
it("should allow the school role to be changed", () => {
const { wrapper } = setup({ schoolRole: RoleName.Teacher, isOpen: true, isAdminMode: false });
const roleSelect = wrapper.getComponent({
ref: "selectRole",
});

expect(roleSelect.props("readonly")).toBe(false);
expect(roleSelect.props("menuIcon")).not.toBe("");
});

describe("when school is changed", () => {
it("should call resetPotentialMembers", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedSchool = roomMembersSchools[1].id;
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});

await schoolComponent.setValue(selectedSchool);

expect(roomMembersStore.resetPotentialMembers).toHaveBeenCalledTimes(1);
});

it("should reset selectedUsers", async () => {
const { wrapper } = setup();
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});

const userComponent = wrapper.getComponent({
ref: "autoCompleteUsers",
});

await schoolComponent.setValue("schoolId");

expect(userComponent.props("modelValue")).toEqual([]);
});

it("should call getPotentialMembers for set role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedSchool = roomMembersSchools[1].id;
const schoolComponent = wrapper.getComponent({
ref: "autoCompleteSchool",
});
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});
const selectedRole = roleComponent.props("modelValue");

await schoolComponent.setValue(selectedSchool);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, selectedSchool);
});
});

describe("when userRole is changed", () => {
it("should call resetPotentialMembers", async () => {
const { wrapper, roomMembersStore } = setup();
const selectedRole = RoleName.Student;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.resetPotentialMembers).toHaveBeenCalledTimes(1);
});

it("should reset selectedUsers", async () => {
const { wrapper } = setup();
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

const userComponent = wrapper.getComponent({
ref: "autoCompleteUsers",
});

await roleComponent.setValue(RoleName.Roomeditor);

expect(userComponent.props("modelValue")).toEqual([]);
});

describe("and the role is set to student", () => {
it("should call getPotentialMembers for student role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedRole = RoleName.Student;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, roomMembersSchools[0].id);
});

it("should render an icon with text for student role", async () => {
const { wrapper } = setup();

const roleComponent = wrapper.getComponent({
ref: "selectRole",
});
await roleComponent.setValue(RoleName.Student);

const roleIcon = roleComponent.findComponent(VIcon);

expect(roleIcon.props("icon")).toBe(mdiAccountOutline);
expect(roleComponent.text()).toContain("common.labels.student.neutral");
});
});

describe("and the role is set to teacher", () => {
it("should call getPotentialMembers for teacher role", async () => {
const { wrapper, roomMembersSchools, roomMembersStore } = setup();
const selectedRole = RoleName.Teacher;
const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(selectedRole);

expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledTimes(1);
expect(roomMembersStore.getPotentialMembers).toHaveBeenCalledWith(selectedRole, roomMembersSchools[0].id);
});

it("should render an icon with text for teacher role", async () => {
const { wrapper } = setup();

const roleComponent = wrapper.getComponent({
ref: "selectRole",
});

await roleComponent.setValue(RoleName.Teacher);
const roleIcon = roleComponent.findComponent(VIcon);

expect(roleIcon.props("icon")).toBe(mdiAccountSchoolOutline);
expect(roleComponent.text()).toContain("common.labels.teacher.neutral");
});
});
});
});

describe("when current user is a student admin", () => {
it("should disable the school selection with current users school selected", () => {
const { mockedMe, wrapper } = setup({ schoolRole: RoleName.Student });
Expand Down
31 changes: 17 additions & 14 deletions src/modules/feature/room/roomMembers/dialogs/AddMembersDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
:label="t('pages.rooms.members.tableHeader.schoolRole')"
:disabled="isItemListDisabled"
:aria-disabled="isItemListDisabled"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not added by this PR, but I think we can remove the aria-disabled because we already have disabled 💭

:readonly="schoolRoles.length === 1"
:data-testid="`role-item-${selectedSchoolRole}`"
v-bind="isAdminMode ? { menuIcon: '', readonly: true } : undefined"
@update:model-value="onValueChange"
@update:menu="onItemListToggle"
>
Expand Down Expand Up @@ -128,7 +130,7 @@ import { storeToRefs } from "pinia";
import { computed, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import { useDisplay } from "vuetify";
import type { VAutocomplete, VCard, VSelect } from "vuetify/components";
import { type VAutocomplete, type VCard, type VSelect } from "vuetify/components";
interface SchoolRoleItem {
id: RoleName;
name: string;
Expand Down Expand Up @@ -176,25 +178,26 @@ const { canAddAllStudents } = useRoomAuthorization();

const selectedSchool = ref(schools.value[0].id);

const schoolRoles: SchoolRoleItem[] = [
{
id: RoleName.Student,
name: t("common.labels.student.neutral"),
icon: mdiAccountOutline,
},
{
id: RoleName.Teacher,
name: t("common.labels.teacher.neutral"),
icon: mdiAccountSchoolOutline,
},
];
const schoolRoleStudent: SchoolRoleItem = {
id: RoleName.Student,
name: t("common.labels.student.neutral"),
icon: mdiAccountOutline,
};

const schoolRoleTeacher: SchoolRoleItem = {
id: RoleName.Teacher,
name: t("common.labels.teacher.neutral"),
icon: mdiAccountSchoolOutline,
};

const schoolRoles = computed(() => (props.isAdminMode ? [schoolRoleTeacher] : [schoolRoleStudent, schoolRoleTeacher]));

const schoolRoleListItemProps = (item: SchoolRoleItem) => ({
title: item.name,
prependIcon: item.icon,
});

const selectedSchoolRole = ref<RoleName>(schoolRoles[0].id);
const selectedSchoolRole = ref<RoleName>(schoolRoles.value[0].id);
const selectedUsers = ref<string[]>([]);

const addMembersContent = ref<VCard>();
Expand Down
Loading