-
-
+
+
+
+
+
@@ -70,6 +73,10 @@ defineProps({
element: {
type: Object as PropType
,
},
+ isUnavailable: {
+ type: Boolean,
+ default: false,
+ },
});
const card = ref(null);
diff --git a/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.unit.ts b/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.unit.ts
new file mode 100644
index 0000000000..24abee6797
--- /dev/null
+++ b/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.unit.ts
@@ -0,0 +1,104 @@
+import {
+ createTestingI18n,
+ createTestingVuetify,
+} from "@@/tests/test-utils/setup";
+import { deletedElementResponseFactory } from "@@/tests/test-utils";
+import { mount } from "@vue/test-utils";
+import { BoardMenuActionDelete } from "@ui-board";
+import { nextTick } from "vue";
+import { ComponentProps } from "vue-component-type-helpers";
+import { VBtn } from "vuetify/lib/components/index.mjs";
+import MediaBoardExternalToolElementMenu from "./MediaBoardExternalToolElementMenu.vue";
+import MediaBoardDeletedElement from "./MediaBoardExternalToolDeletedElement.vue";
+
+describe("MediaBoardDeletedElement", () => {
+ const getWrapper = (
+ props: ComponentProps,
+ stubThreeDotMenu = true
+ ) => {
+ const wrapper = mount(MediaBoardDeletedElement, {
+ global: {
+ plugins: [createTestingVuetify(), createTestingI18n()],
+ },
+ props,
+ stubs: {
+ MediaBoardExternalToolElementMenu: stubThreeDotMenu,
+ },
+ });
+
+ return {
+ wrapper,
+ };
+ };
+
+ describe("three dot menu", () => {
+ describe("when clicking on the the three dot menu", () => {
+ const setupOverlayDiv = () => {
+ const overlayDiv = document.createElement("div");
+ overlayDiv.className = "v-overlay-container";
+ document.body.append();
+ };
+
+ const setup = () => {
+ const deletedElement = deletedElementResponseFactory.build();
+
+ const { wrapper } = getWrapper(
+ {
+ element: deletedElement,
+ },
+ false
+ );
+
+ setupOverlayDiv();
+
+ return {
+ wrapper,
+ };
+ };
+
+ afterEach(() => {
+ document.body.innerHTML = "";
+ });
+
+ it("should show the delete action", async () => {
+ const { wrapper } = setup();
+
+ const menuBtn = wrapper
+ .getComponent(MediaBoardExternalToolElementMenu)
+ .getComponent(VBtn);
+ await menuBtn.trigger("click");
+
+ const deleteAction = wrapper.findComponent(BoardMenuActionDelete);
+
+ expect(deleteAction.exists()).toEqual(true);
+ });
+ });
+
+ describe("when deleting the element from the menu", () => {
+ const setup = () => {
+ const deletedElement = deletedElementResponseFactory.build();
+
+ const { wrapper } = getWrapper({
+ element: deletedElement,
+ });
+
+ return {
+ wrapper,
+ deletedElement,
+ };
+ };
+
+ it("should emit a delete event", async () => {
+ const { wrapper, deletedElement } = setup();
+
+ const menu = wrapper.getComponent(MediaBoardExternalToolElementMenu);
+ menu.vm.$emit("delete:element");
+ await nextTick();
+
+ expect(wrapper.emitted("delete:element")).toEqual([
+ [deletedElement.id],
+ ]);
+ });
+ });
+ });
+});
diff --git a/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.vue b/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.vue
new file mode 100644
index 0000000000..a89fdc3cff
--- /dev/null
+++ b/src/modules/feature/media-shelf/MediaBoardExternalToolDeletedElement.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+ {{ $t("common.medium.chip.noLongerAvailable") }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/feature/media-shelf/MediaBoardLine.unit.ts b/src/modules/feature/media-shelf/MediaBoardLine.unit.ts
index ac7daacce9..a30a07362a 100644
--- a/src/modules/feature/media-shelf/MediaBoardLine.unit.ts
+++ b/src/modules/feature/media-shelf/MediaBoardLine.unit.ts
@@ -1,5 +1,9 @@
import { MediaBoardLayoutType } from "@/serverApi/v3";
-import { mediaLineResponseFactory } from "@@/tests/test-utils";
+import {
+ deletedElementResponseFactory,
+ mediaExternalToolElementResponseFactory,
+ mediaLineResponseFactory,
+} from "@@/tests/test-utils";
import {
createTestingI18n,
createTestingVuetify,
@@ -18,6 +22,7 @@ import MediaBoardExternalToolElement from "./MediaBoardExternalToolElement.vue";
import MediaBoardLine from "./MediaBoardLine.vue";
import MediaBoardLineHeader from "./MediaBoardLineHeader.vue";
import MediaBoardLineMenu from "./MediaBoardLineMenu.vue";
+import MediaBoardExternalToolDeletedElement from "./MediaBoardExternalToolDeletedElement.vue";
jest.mock("@vueuse/core", () => {
return {
@@ -519,4 +524,58 @@ describe("MediaBoardLine", () => {
expect(wrapper.emitted("delete:element")).toEqual([["elementId"]]);
});
});
+
+ describe("when rendering an element", () => {
+ describe("when the element response is a DeletedElementResponse", () => {
+ const setup = () => {
+ const { wrapper } = getWrapper({
+ line: mediaLineResponseFactory.build({
+ elements: deletedElementResponseFactory.buildList(1),
+ }),
+ layout: MediaBoardLayoutType.List,
+ index: 0,
+ });
+
+ return {
+ wrapper,
+ };
+ };
+
+ it("should render the element as MediaBoardExternalToolDeletedElement", () => {
+ const { wrapper } = setup();
+
+ const deletedElement = wrapper.findComponent(
+ MediaBoardExternalToolDeletedElement
+ );
+
+ expect(deletedElement.exists()).toEqual(true);
+ });
+ });
+
+ describe("when the element response is a MediaExternalToolElementResponse", () => {
+ const setup = () => {
+ const { wrapper } = getWrapper({
+ line: mediaLineResponseFactory.build({
+ elements: mediaExternalToolElementResponseFactory.buildList(1),
+ }),
+ layout: MediaBoardLayoutType.List,
+ index: 0,
+ });
+
+ return {
+ wrapper,
+ };
+ };
+
+ it("should render the element as MediaBoardExternalToolElement", () => {
+ const { wrapper } = setup();
+
+ const externalToolElement = wrapper.findComponent(
+ MediaBoardExternalToolElement
+ );
+
+ expect(externalToolElement.exists()).toEqual(true);
+ });
+ });
+ });
});
diff --git a/src/modules/feature/media-shelf/MediaBoardLine.vue b/src/modules/feature/media-shelf/MediaBoardLine.vue
index 32bbe7526e..ba3165ee9a 100644
--- a/src/modules/feature/media-shelf/MediaBoardLine.vue
+++ b/src/modules/feature/media-shelf/MediaBoardLine.vue
@@ -53,9 +53,15 @@
@end="onElementDragEnd"
>
+
@@ -69,8 +75,11 @@
diff --git a/src/modules/feature/media-shelf/data/mediaBoardState.composable.ts b/src/modules/feature/media-shelf/data/mediaBoardState.composable.ts
index 10070d3fb8..aac73660d9 100644
--- a/src/modules/feature/media-shelf/data/mediaBoardState.composable.ts
+++ b/src/modules/feature/media-shelf/data/mediaBoardState.composable.ts
@@ -4,6 +4,7 @@ import {
useErrorHandler,
} from "@/components/error-handling/ErrorHandler.composable";
import {
+ DeletedElementResponse,
MediaAvailableLineResponse,
MediaBoardColors,
MediaBoardLayoutType,
@@ -44,8 +45,10 @@ const useMediaBoardState = () => {
}
const lineIndex: number = mediaBoard.value.lines.findIndex((line) => {
- const element: MediaExternalToolElementResponse | undefined =
- line.elements.find((element) => element.id === elementId);
+ const element:
+ | MediaExternalToolElementResponse
+ | DeletedElementResponse
+ | undefined = line.elements.find((element) => element.id === elementId);
return element !== undefined;
});
@@ -456,10 +459,8 @@ const useMediaBoardState = () => {
const tempFromLine = Array.from(
mediaBoard.value.lines[fromLineIndex].elements
);
- const element: MediaExternalToolElementResponse = tempFromLine.splice(
- oldElementIndex,
- 1
- )[0];
+ const element: MediaExternalToolElementResponse | DeletedElementResponse =
+ tempFromLine.splice(oldElementIndex, 1)[0];
mediaBoard.value.lines[fromLineIndex].elements = tempFromLine;
const tempToLine = Array.from(
diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts
index 8d001c13d3..d108bf6e67 100644
--- a/src/serverApi/v3/api.ts
+++ b/src/serverApi/v3/api.ts
@@ -2542,6 +2542,12 @@ export interface DeletedElementContent {
* @memberof DeletedElementContent
*/
deletedElementType: ContentElementType;
+ /**
+ *
+ * @type {string}
+ * @memberof DeletedElementContent
+ */
+ description: string;
}
/**
*
@@ -4540,10 +4546,10 @@ export interface MediaLineResponse {
title: string;
/**
* The elements of the media line
- * @type {Array}
+ * @type {Array}
* @memberof MediaLineResponse
*/
- elements: Array;
+ elements: Array;
/**
* The timestamps of the media line
* @type {TimestampsResponse}
diff --git a/tests/test-utils/factory/deletedElementContentFactory.ts b/tests/test-utils/factory/deletedElementContentFactory.ts
new file mode 100644
index 0000000000..0811e9fc74
--- /dev/null
+++ b/tests/test-utils/factory/deletedElementContentFactory.ts
@@ -0,0 +1,9 @@
+import { ContentElementType, DeletedElementContent } from "@/serverApi/v3";
+import { Factory } from "fishery";
+
+export const deletedElementContentFactory =
+ Factory.define(({ sequence }) => ({
+ title: `deleted-element-${sequence}`,
+ deletedElementType: ContentElementType.ExternalTool,
+ description: "test-description",
+ }));
diff --git a/tests/test-utils/factory/deletedElementResponseFactory.ts b/tests/test-utils/factory/deletedElementResponseFactory.ts
new file mode 100644
index 0000000000..e6b3a59813
--- /dev/null
+++ b/tests/test-utils/factory/deletedElementResponseFactory.ts
@@ -0,0 +1,13 @@
+import { ContentElementType, DeletedElementResponse } from "@/serverApi/v3";
+import { Factory } from "fishery";
+import { timestampsResponseFactory } from "./timestampsResponseFactory";
+import { deletedElementContentFactory } from "./deletedElementContentFactory";
+
+export const deletedElementResponseFactory =
+ Factory.define(({ sequence }) => ({
+ id: `deleted-element-response-${sequence}`,
+ type: ContentElementType.Deleted,
+ content: deletedElementContentFactory.build(),
+ timestamps: timestampsResponseFactory.build(),
+ description: "test-description",
+ }));
diff --git a/tests/test-utils/factory/index.ts b/tests/test-utils/factory/index.ts
index a7b92036ee..80cfb0efd4 100644
--- a/tests/test-utils/factory/index.ts
+++ b/tests/test-utils/factory/index.ts
@@ -64,3 +64,4 @@ export * from "./envsFactory";
export * from "./media-board";
export * from "./contextExternalToolResponseFactory";
export * from "./courseInfoDataResponseFactory";
+export * from "./deletedElementResponseFactory";
From de542865801bd233743bb7dd30218dff4e6b07fd Mon Sep 17 00:00:00 2001
From: Uwe Ilgenstein
Date: Wed, 18 Sep 2024 09:55:33 +0200
Subject: [PATCH 3/4] BC-7985 - Adapt sidebar active selection to rooms changes
(#3390)
* implement selective sidebar selection for /rooms/:id
* fix sidebar selection for board
* move sidebar selection to composable
* add/fix tests
---
src/layouts/LoggedIn.unit.ts | 12 +-
src/modules/data/board/BoardApi.composable.ts | 4 +-
.../board/BoardPageInformation.composable.ts | 4 +
.../BoardPageInformation.composable.unit.ts | 31 +-
src/modules/data/room/RoomDetails.state.ts | 25 --
src/modules/data/room/RoomDetails.store.ts | 44 +++
src/modules/data/room/index.ts | 2 +-
src/modules/feature/board/board/Board.unit.ts | 1 +
src/modules/page/room/RoomDetails.page.vue | 18 +-
src/modules/ui/layout/sidebar/Sidebar.unit.ts | 8 +-
.../sidebar/SidebarCategoryItem.unit.ts | 7 +
.../ui/layout/sidebar/SidebarItem.unit.ts | 20 +-
src/modules/ui/layout/sidebar/SidebarItem.vue | 27 +-
.../sidebar/SidebarSelection.composable.ts | 74 +++++
.../SidebarSelection.composable.unit.ts | 302 ++++++++++++++++++
src/pages/Home.page.vue | 1 +
src/router/routes.ts | 5 +
src/types/board/BoardContext.ts | 3 +
18 files changed, 513 insertions(+), 75 deletions(-)
delete mode 100644 src/modules/data/room/RoomDetails.state.ts
create mode 100644 src/modules/data/room/RoomDetails.store.ts
create mode 100644 src/modules/ui/layout/sidebar/SidebarSelection.composable.ts
create mode 100644 src/modules/ui/layout/sidebar/SidebarSelection.composable.unit.ts
create mode 100644 src/pages/Home.page.vue
create mode 100644 src/types/board/BoardContext.ts
diff --git a/src/layouts/LoggedIn.unit.ts b/src/layouts/LoggedIn.unit.ts
index 3b7e538584..d1168afeb6 100644
--- a/src/layouts/LoggedIn.unit.ts
+++ b/src/layouts/LoggedIn.unit.ts
@@ -19,6 +19,8 @@ import { h, nextTick } from "vue";
import { VApp } from "vuetify/lib/components/index.mjs";
import LoggedInLayout from "./LoggedIn.layout.vue";
import { Topbar } from "@ui-layout";
+import { createTestingPinia } from "@pinia/testing";
+import setupStores from "@@/tests/test-utils/setupStores";
jest.mock("vue-router", () => ({
useRoute: () => ({ path: "rooms/courses-list" }),
@@ -43,12 +45,20 @@ const setup = () => {
},
});
+ setupStores({
+ envConfigModule: EnvConfigModule,
+ });
+
const wrapper = mount(VApp, {
slots: {
default: h(LoggedInLayout),
},
global: {
- plugins: [createTestingVuetify(), createTestingI18n()],
+ plugins: [
+ createTestingVuetify(),
+ createTestingI18n(),
+ createTestingPinia(),
+ ],
provide: {
[AUTH_MODULE_KEY.valueOf()]: authModule,
[ENV_CONFIG_MODULE_KEY.valueOf()]: envConfigModule,
diff --git a/src/modules/data/board/BoardApi.composable.ts b/src/modules/data/board/BoardApi.composable.ts
index e05522f8db..1f8493c72a 100644
--- a/src/modules/data/board/BoardApi.composable.ts
+++ b/src/modules/data/board/BoardApi.composable.ts
@@ -17,6 +17,7 @@ import {
CourseRoomsApiFactory,
SubmissionContainerElementContentBody,
} from "@/serverApi/v3";
+import { BoardContextType } from "@/types/board/BoardContext";
import { AnyContentElement } from "@/types/board/ContentElement";
import { $axios, mapAxiosErrorToResponseError } from "@/utils/api";
import { createApplicationError } from "@/utils/create-application-error.factory";
@@ -185,7 +186,7 @@ export const useBoardApi = () => {
});
};
- type ContextInfo = { id: string; name: string };
+ type ContextInfo = { id: string; type: BoardContextType; name: string };
const getContextInfo = async (
boardId: string
@@ -205,6 +206,7 @@ export const useBoardApi = () => {
}
return {
id: roomResponse.data.roomId,
+ type: context.type,
name: roomResponse.data.title,
};
};
diff --git a/src/modules/data/board/BoardPageInformation.composable.ts b/src/modules/data/board/BoardPageInformation.composable.ts
index 5520dd25b0..4612de5f09 100644
--- a/src/modules/data/board/BoardPageInformation.composable.ts
+++ b/src/modules/data/board/BoardPageInformation.composable.ts
@@ -4,6 +4,7 @@ import { createSharedComposable } from "@vueuse/core";
import { ref, Ref } from "vue";
import { useI18n } from "vue-i18n";
import { useBoardApi } from "./BoardApi.composable";
+import { BoardContextType } from "@/types/board/BoardContext";
const useBoardPageInformation = () => {
const { t } = useI18n();
@@ -20,6 +21,7 @@ const useBoardPageInformation = () => {
const pageTitle: Ref = ref(getPageTitle());
const roomId: Ref = ref(undefined);
const breadcrumbs: Ref = ref([]);
+ const contextType: Ref = ref();
function getBreadcrumbs(
contextInfo: { id: string; name: string } | undefined
@@ -44,12 +46,14 @@ const useBoardPageInformation = () => {
const contextInfo = await getContextInfo(id);
pageTitle.value = getPageTitle(contextInfo?.name);
breadcrumbs.value = getBreadcrumbs(contextInfo);
+ contextType.value = contextInfo?.type;
roomId.value = contextInfo?.id;
};
return {
createPageInformation,
breadcrumbs,
+ contextType,
pageTitle,
roomId,
};
diff --git a/src/modules/data/board/BoardPageInformation.composable.unit.ts b/src/modules/data/board/BoardPageInformation.composable.unit.ts
index fd85ba2585..fdfe1001d7 100644
--- a/src/modules/data/board/BoardPageInformation.composable.unit.ts
+++ b/src/modules/data/board/BoardPageInformation.composable.unit.ts
@@ -2,6 +2,7 @@ import { mountComposable } from "@@/tests/test-utils/mountComposable";
import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { useBoardApi } from "./BoardApi.composable";
import { useSharedBoardPageInformation } from "./BoardPageInformation.composable";
+import { BoardContextType } from "@/types/board/BoardContext";
jest.mock("./BoardApi.composable");
const mockedUseBoardApi = jest.mocked(useBoardApi);
@@ -36,13 +37,25 @@ describe("BoardPageInformation.composable", () => {
const setup = () => {
mockedBoardApiCalls.getContextInfo.mockResolvedValue({
id: "courseId",
+ type: BoardContextType.Course,
name: "Course #1",
});
- const { createPageInformation, breadcrumbs, pageTitle, roomId } =
- mountComposable(() => useSharedBoardPageInformation());
-
- return { createPageInformation, breadcrumbs, pageTitle, roomId };
+ const {
+ createPageInformation,
+ breadcrumbs,
+ contextType,
+ pageTitle,
+ roomId,
+ } = mountComposable(() => useSharedBoardPageInformation());
+
+ return {
+ createPageInformation,
+ breadcrumbs,
+ contextType,
+ pageTitle,
+ roomId,
+ };
};
it("should return two breadcrumbs: 1. course page and and 2. course-overview page", async () => {
@@ -74,6 +87,16 @@ describe("BoardPageInformation.composable", () => {
expect(roomId.value).toEqual("courseId");
});
+
+ it("should set context type", async () => {
+ const { createPageInformation, contextType } = setup();
+
+ const fakeId = "abc123-2";
+
+ await createPageInformation(fakeId);
+
+ expect(contextType.value).toEqual(BoardContextType.Course);
+ });
});
describe("when board context does not exist", () => {
diff --git a/src/modules/data/room/RoomDetails.state.ts b/src/modules/data/room/RoomDetails.state.ts
deleted file mode 100644
index 58ef05ca6c..0000000000
--- a/src/modules/data/room/RoomDetails.state.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Room } from "@/types/room/Room";
-import { delay } from "@/utils/helpers";
-import { ref } from "vue";
-import { roomsData } from "./rooms-mock-data";
-
-export const useRoomDetailsState = () => {
- const room = ref();
- const isLoading = ref(true);
- const isRoom = ref(false);
-
- const fetchRoom = async (id: string) => {
- await delay(100);
- // TODO call API
- room.value = roomsData.find((r) => r.id === id);
- isRoom.value = room.value != null;
- isLoading.value = false;
- };
-
- return {
- fetchRoom,
- isLoading,
- isRoom,
- room,
- };
-};
diff --git a/src/modules/data/room/RoomDetails.store.ts b/src/modules/data/room/RoomDetails.store.ts
new file mode 100644
index 0000000000..a0dd51c2ac
--- /dev/null
+++ b/src/modules/data/room/RoomDetails.store.ts
@@ -0,0 +1,44 @@
+import { Room } from "@/types/room/Room";
+import { delay } from "@/utils/helpers";
+import { ref } from "vue";
+import { roomsData } from "./rooms-mock-data";
+import { defineStore } from "pinia";
+
+export enum RoomVariant {
+ ROOM = "room",
+ COURSE_ROOM = "courseRoom",
+}
+
+export const useRoomDetailsStore = defineStore("roomDetailsStore", () => {
+ const isLoading = ref(true);
+ const room = ref();
+ const roomVariant = ref();
+
+ const fetchRoom = async (id: string) => {
+ await delay(100);
+ // TODO call API
+ room.value = roomsData.find((r) => r.id === id);
+ roomVariant.value =
+ room.value != null ? RoomVariant.ROOM : RoomVariant.COURSE_ROOM;
+ isLoading.value = false;
+ };
+
+ const resetState = () => {
+ isLoading.value = true;
+ room.value = undefined;
+ };
+
+ const deactivateRoom = () => {
+ resetState();
+ isLoading.value = false;
+ };
+
+ return {
+ deactivateRoom,
+ fetchRoom,
+ isLoading,
+ resetState,
+ room,
+ roomVariant,
+ };
+});
diff --git a/src/modules/data/room/index.ts b/src/modules/data/room/index.ts
index e86232bd40..c730814c25 100644
--- a/src/modules/data/room/index.ts
+++ b/src/modules/data/room/index.ts
@@ -1,5 +1,5 @@
export { useCourseApi } from "./courseApi.composable";
export { useRoomsState } from "./Rooms.state";
-export { useRoomDetailsState } from "./RoomDetails.state";
+export { useRoomDetailsStore, RoomVariant } from "./RoomDetails.store";
export { useCourseInfoApi } from "./courseInfoApi.composable";
export { useCourseList } from "./courseList.composable";
diff --git a/src/modules/feature/board/board/Board.unit.ts b/src/modules/feature/board/board/Board.unit.ts
index 05ee7cd409..8a93c14a6c 100644
--- a/src/modules/feature/board/board/Board.unit.ts
+++ b/src/modules/feature/board/board/Board.unit.ts
@@ -129,6 +129,7 @@ describe("Board", () => {
mockedUseSharedBoardPageInformation.mockReturnValue({
createPageInformation: jest.fn(),
breadcrumbs: ref([]),
+ contextType: ref(),
pageTitle: ref("page-title"),
roomId: ref("room-id"),
});
diff --git a/src/modules/page/room/RoomDetails.page.vue b/src/modules/page/room/RoomDetails.page.vue
index b3e0ef13e8..da5e5abc25 100644
--- a/src/modules/page/room/RoomDetails.page.vue
+++ b/src/modules/page/room/RoomDetails.page.vue
@@ -13,15 +13,18 @@
diff --git a/src/modules/ui/layout/sidebar/Sidebar.unit.ts b/src/modules/ui/layout/sidebar/Sidebar.unit.ts
index a2491bfde1..20d5533fd7 100644
--- a/src/modules/ui/layout/sidebar/Sidebar.unit.ts
+++ b/src/modules/ui/layout/sidebar/Sidebar.unit.ts
@@ -1,5 +1,5 @@
import { mount } from "@vue/test-utils";
-import { h, nextTick } from "vue";
+import { h, nextTick, ref } from "vue";
import { VApp } from "vuetify/lib/components/index.mjs";
import {
createTestingI18n,
@@ -18,11 +18,15 @@ import FilePathsModule from "@/store/filePaths";
import { createModuleMocks } from "@/utils/mock-store-module";
import { SchulcloudTheme } from "@/serverApi/v3";
import { envsFactory } from "@@/tests/test-utils";
+import { useSidebarSelection } from "./SidebarSelection.composable";
jest.mock("vue-router", () => ({
useRoute: () => ({ path: "rooms/courses-list" }),
}));
+jest.mock("./SidebarSelection.composable");
+const mockedUseSidebarSelection = jest.mocked(useSidebarSelection);
+
const setup = (permissions?: string[]) => {
const authModule = createModuleMocks(AuthModule, {
getUserPermissions: permissions,
@@ -43,6 +47,8 @@ const setup = (permissions?: string[]) => {
},
});
+ mockedUseSidebarSelection.mockReturnValue({ isActive: ref(false) });
+
const wrapper = mount(VApp, {
global: {
plugins: [createTestingVuetify(), createTestingI18n()],
diff --git a/src/modules/ui/layout/sidebar/SidebarCategoryItem.unit.ts b/src/modules/ui/layout/sidebar/SidebarCategoryItem.unit.ts
index 2527086313..4b1a036fc7 100644
--- a/src/modules/ui/layout/sidebar/SidebarCategoryItem.unit.ts
+++ b/src/modules/ui/layout/sidebar/SidebarCategoryItem.unit.ts
@@ -5,6 +5,8 @@ import {
} from "@@/tests/test-utils/setup";
import SidebarCategoryItem from "./SidebarCategoryItem.vue";
import { SidebarGroupItem } from "../types";
+import { useSidebarSelection } from "./SidebarSelection.composable";
+import { ref } from "vue";
const groupItem: SidebarGroupItem = {
icon: "mdiOpen",
@@ -33,7 +35,12 @@ jest.mock("vue-router", () => ({
useRoute: () => ({ path: "rooms/courses-list" }),
}));
+jest.mock("./SidebarSelection.composable");
+const mockedUseSidebarSelection = jest.mocked(useSidebarSelection);
+
describe("@ui-layout/SidebarCategoryItem", () => {
+ mockedUseSidebarSelection.mockReturnValue({ isActive: ref(false) });
+
const setup = (sidebarItem: SidebarGroupItem) => {
const wrapper = mount(SidebarCategoryItem, {
global: {
diff --git a/src/modules/ui/layout/sidebar/SidebarItem.unit.ts b/src/modules/ui/layout/sidebar/SidebarItem.unit.ts
index 214735df5d..1424ecb846 100644
--- a/src/modules/ui/layout/sidebar/SidebarItem.unit.ts
+++ b/src/modules/ui/layout/sidebar/SidebarItem.unit.ts
@@ -5,6 +5,8 @@ import {
} from "@@/tests/test-utils/setup";
import SidebarItem from "./SidebarItem.vue";
import { SidebarSingleItem } from "../types";
+import { ref } from "vue";
+import { useSidebarSelection } from "./SidebarSelection.composable";
const iconItem: SidebarSingleItem = {
icon: "mdiOpen",
@@ -23,8 +25,13 @@ jest.mock("vue-router", () => ({
useRoute: () => ({ path: "rooms/courses-list" }),
}));
+jest.mock("./SidebarSelection.composable");
+const mockedUseSidebarSelection = jest.mocked(useSidebarSelection);
+
describe("@ui-layout/SidebarItem", () => {
const setup = (sidebarItem: SidebarSingleItem) => {
+ mockedUseSidebarSelection.mockReturnValue({ isActive: ref(true) });
+
const wrapper = mount(SidebarItem, {
global: {
plugins: [createTestingVuetify(), createTestingI18n()],
@@ -51,7 +58,7 @@ describe("@ui-layout/SidebarItem", () => {
expect(wrapper.findComponent(".v-icon").exists()).toBe(false);
});
- it("should highlight correct sidebar item", () => {
+ it("should highlight item when selection is active", () => {
const { wrapper } = setup({
icon: "mdiOpen",
title: "title",
@@ -61,15 +68,4 @@ describe("@ui-layout/SidebarItem", () => {
expect(wrapper.classes()).toContain("v-list-item--active");
});
-
- it("should not highlight wrong sidebar item", () => {
- const { wrapper } = setup({
- icon: "mdiOpen",
- title: "title",
- testId: "testId",
- to: "/administration/rooms/new",
- });
-
- expect(wrapper.classes()).not.toContain("v-list-item--active");
- });
});
diff --git a/src/modules/ui/layout/sidebar/SidebarItem.vue b/src/modules/ui/layout/sidebar/SidebarItem.vue
index 6ac94950bb..b18df650c8 100644
--- a/src/modules/ui/layout/sidebar/SidebarItem.vue
+++ b/src/modules/ui/layout/sidebar/SidebarItem.vue
@@ -22,7 +22,7 @@
diff --git a/tests/test-utils/factory/externalToolElementResponseFactory.ts b/tests/test-utils/factory/externalToolElementResponseFactory.ts
new file mode 100644
index 0000000000..1045bf9ad1
--- /dev/null
+++ b/tests/test-utils/factory/externalToolElementResponseFactory.ts
@@ -0,0 +1,16 @@
+import {
+ ContentElementType,
+ ExternalToolElementResponse,
+} from "@/serverApi/v3";
+import { Factory } from "fishery";
+import { timestampsResponseFactory } from "./timestampsResponseFactory";
+
+export const externalToolElementResponseFactory =
+ Factory.define(({ sequence }) => ({
+ id: `external-tool-element-response-${sequence}`,
+ type: ContentElementType.ExternalTool,
+ content: {
+ contextExternalToolId: null,
+ },
+ timestamps: timestampsResponseFactory.build(),
+ }));
diff --git a/tests/test-utils/factory/index.ts b/tests/test-utils/factory/index.ts
index 80cfb0efd4..b38763660a 100644
--- a/tests/test-utils/factory/index.ts
+++ b/tests/test-utils/factory/index.ts
@@ -25,6 +25,7 @@ export * from "./customParameterResponseFactory";
export * from "./drawingElementResponseFactory";
export * from "./envsFactory";
export * from "./externalToolDisplayDataFactory";
+export * from "./externalToolElementResponseFactory";
export * from "./fileElementContentFactory";
export * from "./fileElementResponseFactory";
export * from "./filerecordResponse.factory";