diff --git a/src/components/administration/ExternalToolSection.vue b/src/components/administration/ExternalToolSection.vue index d62ac56c20..ec6ad50f13 100644 --- a/src/components/administration/ExternalToolSection.vue +++ b/src/components/administration/ExternalToolSection.vue @@ -41,6 +41,7 @@ class="mt-8 mb-4 button-save float-right" color="primary" depressed + data-testid="add-external-tool-button" :to="{ name: 'administration-tool-config-overview' }" > {{ t("components.administration.externalToolsSection.action.add") }} diff --git a/src/components/copy-result-modal/CopyResultModal.unit.ts b/src/components/copy-result-modal/CopyResultModal.unit.ts index b0eda2227e..ffb3afffe5 100644 --- a/src/components/copy-result-modal/CopyResultModal.unit.ts +++ b/src/components/copy-result-modal/CopyResultModal.unit.ts @@ -66,7 +66,7 @@ const getWrapper = (props?: any) => { }; describe("@/components/copy-result-modal/CopyResultModal", () => { - beforeEach(() => { + beforeAll(() => { // Avoids console warnings "[Vuetify] Unable to locate target [data-app]" document.body.setAttribute("data-app", "true"); setupStores({ @@ -74,6 +74,10 @@ describe("@/components/copy-result-modal/CopyResultModal", () => { }); }); + afterEach(() => { + jest.clearAllMocks(); + }); + describe("basic functions", () => { it("Should render component", () => { const wrapper = getWrapper(); @@ -152,6 +156,35 @@ describe("@/components/copy-result-modal/CopyResultModal", () => { ); }); + describe("when root item is a Course, has no failed file and CTL_TOOLS_COPY feature flag is enabled", () => { + const setup = () => { + const copyResultItems = mockResultItems([]); + const wrapper = getWrapper({ + isOpen: true, + copyResultItems, + copyResultRootItemType: CopyApiResponseTypeEnum.Course, + }); + + return { wrapper }; + }; + + it("should render ctl tools copy info ", () => { + envConfigModule.setEnvs({ + FEATURE_CTL_TOOLS_TAB_ENABLED: true, + FEATURE_CTL_TOOLS_COPY_ENABLED: true, + } as Envs); + const { wrapper } = setup(); + + expect( + wrapper.find('[data-testid="copy-result-notifications"]').text() + ).toContain( + wrapper.vm.$i18n.t( + "components.molecules.copyResult.ctlTools.withFeature.info" + ) + ); + }); + }); + it("should merge file error and coursefiles info if root item is a Course and has a failed file ", () => { const copyResultItems = mockResultItems([fileItem]); diff --git a/src/components/copy-result-modal/CopyResultModal.vue b/src/components/copy-result-modal/CopyResultModal.vue index f8917b41af..9a1b40bcf3 100644 --- a/src/components/copy-result-modal/CopyResultModal.vue +++ b/src/components/copy-result-modal/CopyResultModal.vue @@ -169,7 +169,9 @@ export default { : this.$t("components.molecules.copyResult.nexboardCopy.infoTldraw"); }, externalToolsInfoText() { - return this.$t("components.molecules.copyResult.ctlTools.info"); + return envConfigModule.getCtlToolsCopyEnabled + ? this.$t("components.molecules.copyResult.ctlTools.withFeature.info") + : this.$t("components.molecules.copyResult.ctlTools.info"); }, }, methods: { diff --git a/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.ts b/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.ts index bd4905d598..0f801660b3 100644 --- a/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.ts +++ b/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.ts @@ -25,7 +25,18 @@ export const useContextExternalToolConfigurationStatus = () => { } }; + const determineIncompleteTranslationKey = (): string => { + const userRoles = authModule.getUserRoles; + + if (userRoles.includes("teacher")) { + return "common.tool.information.incompleteOnContext.teacher"; + } else { + return "common.tool.information.incomplete.student"; + } + }; + return { determineOutdatedTranslationKey, + determineIncompleteTranslationKey, }; }; diff --git a/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.unit.ts b/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.unit.ts index 4fc39d890d..bd36f6b239 100644 --- a/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.unit.ts +++ b/src/components/data-external-tool/ContextExternalToolConfigurationStatus.composable.unit.ts @@ -152,7 +152,7 @@ describe("ToolConfigurationStatus.composable", () => { }; }; - it("should return translationkey for outdated on scope school and context", () => { + it("should return translationkey for outdated", () => { const { determineOutdatedTranslationKey, toolConfigurationStatus } = setup(); @@ -187,7 +187,7 @@ describe("ToolConfigurationStatus.composable", () => { }; }; - it("should return translationkey for outdated on scope school ", () => { + it("should return translationkey for outdated ", () => { const { determineOutdatedTranslationKey, toolConfigurationStatus } = setup(); @@ -222,7 +222,7 @@ describe("ToolConfigurationStatus.composable", () => { }; }; - it("should return translationkey for outdated on scope context ", () => { + it("should return translationkey for outdated", () => { const { determineOutdatedTranslationKey, toolConfigurationStatus } = setup(); @@ -232,4 +232,63 @@ describe("ToolConfigurationStatus.composable", () => { }); }); }); + + describe("determineIncompleteTranslationKey", () => { + describe("when user is teacher and tool is incomplete on scope context", () => { + const setup = () => { + const authModule = createModuleMocks(AuthModule, { + getUserRoles: ["teacher"], + }); + + const composable = mountComposable( + () => useContextExternalToolConfigurationStatus(), + { + [AUTH_MODULE_KEY.valueOf()]: authModule, + } + ); + + return { + ...composable, + authModule, + }; + }; + + it("should return translationkey for incomplete tool on scope context ", () => { + const { determineIncompleteTranslationKey } = setup(); + + const result = determineIncompleteTranslationKey(); + + expect(result).toEqual( + "common.tool.information.incompleteOnContext.teacher" + ); + }); + }); + + describe("when user is student and tool is incomplete on scope context", () => { + const setup = () => { + const authModule = createModuleMocks(AuthModule, { + getUserRoles: ["student"], + }); + + const composable = mountComposable( + () => useContextExternalToolConfigurationStatus(), + { + [AUTH_MODULE_KEY.valueOf()]: authModule, + } + ); + + return { + ...composable, + }; + }; + + it("should return translationkey for incomplete on scope context ", () => { + const { determineIncompleteTranslationKey } = setup(); + + const result = determineIncompleteTranslationKey(); + + expect(result).toEqual("common.tool.information.incomplete.student"); + }); + }); + }); }); diff --git a/src/components/external-tools/configuration/ExternalToolConfigSettings.vue b/src/components/external-tools/configuration/ExternalToolConfigSettings.vue index 61c023a6f0..54e03314ad 100644 --- a/src/components/external-tools/configuration/ExternalToolConfigSettings.vue +++ b/src/components/external-tools/configuration/ExternalToolConfigSettings.vue @@ -10,7 +10,7 @@