diff --git a/src/components/admin/ClassificationAdmin.vue b/src/components/admin/ClassificationAdmin.vue index ab9d9573f..ff95b3b3d 100644 --- a/src/components/admin/ClassificationAdmin.vue +++ b/src/components/admin/ClassificationAdmin.vue @@ -37,6 +37,7 @@
{
{
- +
{ /> {
{
- +
{ /> { } const getTags = debounce(async function () { - isLoading.value = refreshTokenGrantRequest + isLoading.value = true try { //await new Promise((resolve) => setTimeout(resolve, 300 * 1000)) const axiosReq = await getOrgClassificationTags( @@ -219,7 +218,7 @@ watch(() => [props.classification.value, search.value], getTags, { immediate: tr - + {{ tagTexts.title(tag) }} @@ -230,12 +229,14 @@ watch(() => [props.classification.value, search.value], getTags, { immediate: tr @click="editTag(tag)" class="small" action-icon="Pen" + data-test="edit-tag-button" /> @@ -243,6 +244,7 @@ watch(() => [props.classification.value, search.value], getTags, { immediate: tr
@@ -254,6 +256,7 @@ watch(() => [props.classification.value, search.value], getTags, { immediate: tr />
[props.classification.value, search.value], getTags, { immediate: tr /> ({ + getOrgClassificationTags: vi + .fn() + .mockResolvedValue({ data: { count: 3, results: [{ id: 1 }, { id: 2 }, { id: 3 }] } }), + getAllOrgClassifications: vi.fn().mockResolvedValue({ + count: 3, + results: [ + { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, + }, + { + id: 456, + slug: 'for-skill', + type: 'Custom', + is_enabled_for_projects: false, + is_enabled_for_skills: true, + }, + { + id: 789, + slug: 'for-skill-and-project', + type: 'Wikipedia', + is_enabled_for_projects: true, + is_enabled_for_skills: true, + }, + ], + }), +})) + +const i18n = { + locale: 'en', + fallbackLocale: 'en', + messages: { + en: english, + }, +} + +describe('ClassificationAdmin', () => { + let wrapper + let defaultParams + let organizationsStore + + beforeEach(() => { + organizationsStore = useOrganizationsStore(pinia) + organizationsStore.updateCurrentOrganization = vi.fn() + organizationsStore.current = { + code: 'test', + tags: [], + enabled_projects_tag_classifications: [ + { id: 123, slug: 'for-project', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + enabled_skills_tag_classifications: [ + { id: 456, slug: 'for-skill', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + default_projects_tags: [{ id: 11 }, { id: 12 }, { id: 13 }], + default_skills_tags: [{ id: 21 }, { id: 22 }, { id: 23 }], + } as unknown as OrganizationOutput + defaultParams = { + props: {}, + i18n, + } + }) + + it('should render ClassificationAdmin component', () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'projects' } }) + + expect(wrapper.exists()).toBeTruthy() + }) + + it('should display activate state for project', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'projects' } }) + + const vm: any = wrapper.vm + await flushPromises() + const switchComp = wrapper.findAllComponents( + '[data-test="classification-switch-for-projects"]' + ) + + expect(switchComp.length).toBe(3) + + expect(switchComp[0].vm.modelValue).toBe(true) + expect(switchComp[1].vm.modelValue).toBe(false) + expect(switchComp[2].vm.modelValue).toBe(true) + + const otherSwitchComp = wrapper.findAllComponents( + '[data-test="classification-switch-for-skills"]' + ) + expect(otherSwitchComp.length).toBe(0) + }) + + it('should display activate state for skills', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'skills' } }) + + const vm: any = wrapper.vm + await flushPromises() + const switchComp = wrapper.findAllComponents( + '[data-test="classification-switch-for-skills"]' + ) + + expect(switchComp.length).toBe(3) + + expect(switchComp[0].vm.modelValue).toBe(false) + expect(switchComp[1].vm.modelValue).toBe(true) + expect(switchComp[2].vm.modelValue).toBe(true) + + const otherSwitchComp = wrapper.findAllComponents( + '[data-test="classification-switch-for-projects"]' + ) + expect(otherSwitchComp.length).toBe(0) + }) + + it('should allow to activate and deactivate enabled state', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'skills' } }) + + const vm: any = wrapper.vm + await flushPromises() + let switchComp = wrapper.findComponent( + '[data-test="classification-switch-for-skills"]:nth(1)' + ) + + expect(switchComp.vm.modelValue).toBe(false) + + await switchComp.vm.$emit('update:modelValue', true) + await switchComp.vm.$nextTick() + + expect(switchComp.emitted()['update:modelValue'][0]).toStrictEqual([true]) + + await vm.$nextTick() + await flushPromises() + await new Promise((resolve) => setTimeout(resolve, 1000)) + expect(organizationsStore.updateCurrentOrganization).toHaveBeenLastCalledWith({ + enabled_skills_tag_classifications: [456, 789, 123], + }) + + await switchComp.vm.$emit('update:modelValue', false) + await switchComp.vm.$nextTick() + + expect(switchComp.emitted()['update:modelValue'][0]).toStrictEqual([true]) + + await vm.$nextTick() + await flushPromises() + await new Promise((resolve) => setTimeout(resolve, 1000)) + expect(organizationsStore.updateCurrentOrganization).toHaveBeenLastCalledWith({ + enabled_skills_tag_classifications: [456, 789], + }) + }) + + it('should ask confirmation for deleting classification', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'skills' } }) + + const vm: any = wrapper.vm + await flushPromises() + const deleteButtons = wrapper.findAllComponents( + '[data-test="delete-classification-button"]' + ) + let confirmModal = wrapper.findComponent( + '[data-test="confirm-delete-classification-modal"]' + ) + + expect(deleteButtons.length).toBe(3) + expect(confirmModal.exists()).toBeFalsy() + + await deleteButtons[0].trigger('click') + + await vm.$nextTick() + + confirmModal = wrapper.findComponent('[data-test="confirm-delete-classification-modal"]') + expect(confirmModal.exists()).toBeTruthy() + }) + + it('should allow to edit custom classification', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'skills' } }) + + const vm: any = wrapper.vm + await flushPromises() + const editButtons = wrapper.findAllComponents('[data-test="edit-classification-button"]') + let editDrawer = wrapper.findComponent('[data-test="edit-classification-drawer"]') + + expect(editButtons.length).toBe(3) + expect(editDrawer.vm.isOpen).toBeFalsy() + + await editButtons[0].trigger('click') + + await vm.$nextTick() + + expect(editDrawer.vm.isOpen).toBeTruthy() + }) + + it('should not allow to edit or delete non-custom classification', async () => { + wrapper = lpiMount(ClassificationAdmin, { ...defaultParams, props: { type: 'skills' } }) + + const vm: any = wrapper.vm + await flushPromises() + const editButtons = wrapper.findAllComponents('[data-test="edit-classification-button"]') + let editDrawer = wrapper.findComponent('[data-test="edit-classification-drawer"]') + + expect(editButtons.length).toBe(3) + expect(editDrawer.vm.isOpen).toBeFalsy() + + await editButtons[2].trigger('click') + + await vm.$nextTick() + + expect(editDrawer.vm.isOpen).toBeFalsy() + + const deleteButtons = wrapper.findAllComponents( + '[data-test="delete-classification-button"]' + ) + + let confirmModal = wrapper.findComponent( + '[data-test="confirm-delete-classification-modal"]' + ) + + expect(deleteButtons.length).toBe(3) + expect(confirmModal.exists()).toBeFalsy() + + await deleteButtons[2].trigger('click') + + await vm.$nextTick() + + confirmModal = wrapper.findComponent('[data-test="confirm-delete-classification-modal"]') + expect(confirmModal.exists()).toBeFalsy() + }) +}) diff --git a/tests/unit/components/admin/DefaultSkillsAdmin.spec.ts b/tests/unit/components/admin/DefaultSkillsAdmin.spec.ts new file mode 100644 index 000000000..7d363ac60 --- /dev/null +++ b/tests/unit/components/admin/DefaultSkillsAdmin.spec.ts @@ -0,0 +1,174 @@ +import { lpiMount } from '../../../helpers/LpiMount' +import english from '@/locales/en.json' +import waitForExpect from 'wait-for-expect' +import DefaultSkillsAdmin from '@/components/admin/DefaultSkillsAdmin.vue' + +import pinia from '@/stores' +import useOrganizationsStore from '@/stores/useOrganizations' + +import { OrganizationOutput, OrganizationPatchInput } from '@/models/organization.model' + +import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest' +import flushPromises from 'flush-promises' + +import { + getAllOrgClassifications, + getOrgClassificationTags, +} from '@/api/tag-classification.service' + +import debounce from 'lodash.debounce' + +vi.mock('lodash.debounce', () => ({ default: vi.fn((fn) => fn) })) + +vi.mock('@/api/tag-classification.service', () => ({ + getOrgClassificationTags: vi.fn().mockResolvedValue({ + data: { + count: 3, + current_page: 1, + total_page: 1, + previous: null, + next: null, + first: null, + last: null, + results: [{ id: 1 }, { id: 2 }, { id: 3 }], + }, + config: {}, + }), + getAllOrgClassifications: vi.fn().mockResolvedValue({ + count: 3, + results: [ + { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, + }, + { + id: 456, + slug: 'for-skill', + type: 'Custom', + is_enabled_for_projects: false, + is_enabled_for_skills: true, + }, + { + id: 789, + slug: 'for-skill-and-project', + type: 'Wikipedia', + is_enabled_for_projects: true, + is_enabled_for_skills: true, + }, + ], + }), +})) + +const classification = { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, +} + +const i18n = { + locale: 'en', + fallbackLocale: 'en', + messages: { + en: english, + }, +} + +describe('DefaultSkillsAdmin', () => { + let wrapper + let defaultParams + let organizationsStore + + beforeEach(() => { + organizationsStore = useOrganizationsStore(pinia) + organizationsStore.updateCurrentOrganization = vi.fn() + organizationsStore.current = { + code: 'test', + tags: [], + enabled_projects_tag_classifications: [ + { id: 123, slug: 'for-project', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + enabled_skills_tag_classifications: [ + { id: 456, slug: 'for-skill', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + default_projects_tags: [{ id: 11 }, { id: 12 }, { id: 13 }], + default_skills_tags: [{ id: 21 }, { id: 22 }, { id: 23 }], + } as unknown as OrganizationOutput + defaultParams = { + props: {}, + i18n, + } + }) + + it('should render DefaultSkillsAdmin component', () => { + wrapper = lpiMount(DefaultSkillsAdmin, { + ...defaultParams, + props: {}, + }) + + expect(wrapper.exists()).toBeTruthy() + }) + + it('should display default skills entry', async () => { + wrapper = lpiMount(DefaultSkillsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + await vm.$nextTick() + expect(vm.organizationTags.length).toBe(3) + const tagEntries = wrapper.findAll('[data-test="default-skill"]') + expect(tagEntries.length).toBe(3) + }) + + it('should ask confirmation for deleting tag', async () => { + wrapper = lpiMount(DefaultSkillsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + const deleteButtons = wrapper.findAllComponents('[data-test="default-skill"]') + let confirmModal = wrapper.findComponent('[data-test="confirm-delete-default-skill"]') + + expect(deleteButtons.length).toBe(3) + expect(confirmModal.exists()).toBeFalsy() + + await deleteButtons[0].trigger('click') + + await vm.$nextTick() + + confirmModal = wrapper.findComponent('[data-test="confirm-delete-default-skill"]') + expect(confirmModal.exists()).toBeTruthy() + }) + + it('should allow to add skills', async () => { + wrapper = lpiMount(DefaultSkillsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + const editButtons = wrapper.findAllComponents('[data-test="add-default-skills"]') + let addDrawer = wrapper.findComponent('[data-test="add-default-skills-drawer"]') + + expect(editButtons.length).toBe(1) + expect(addDrawer.vm.isOpened).toBeFalsy() + + await editButtons[0].trigger('click') + + await vm.$nextTick() + addDrawer = wrapper.findComponent('[data-test="add-default-skills-drawer"]') + expect(addDrawer.vm.isOpened).toBeTruthy() + }) +}) diff --git a/tests/unit/components/admin/DefaultTagsAdmin.spec.ts b/tests/unit/components/admin/DefaultTagsAdmin.spec.ts new file mode 100644 index 000000000..8060f2eca --- /dev/null +++ b/tests/unit/components/admin/DefaultTagsAdmin.spec.ts @@ -0,0 +1,174 @@ +import { lpiMount } from '../../../helpers/LpiMount' +import english from '@/locales/en.json' +import waitForExpect from 'wait-for-expect' +import DefaultTagsAdmin from '@/components/admin/DefaultTagsAdmin.vue' + +import pinia from '@/stores' +import useOrganizationsStore from '@/stores/useOrganizations' + +import { OrganizationOutput, OrganizationPatchInput } from '@/models/organization.model' + +import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest' +import flushPromises from 'flush-promises' + +import { + getAllOrgClassifications, + getOrgClassificationTags, +} from '@/api/tag-classification.service' + +import debounce from 'lodash.debounce' + +vi.mock('lodash.debounce', () => ({ default: vi.fn((fn) => fn) })) + +vi.mock('@/api/tag-classification.service', () => ({ + getOrgClassificationTags: vi.fn().mockResolvedValue({ + data: { + count: 3, + current_page: 1, + total_page: 1, + previous: null, + next: null, + first: null, + last: null, + results: [{ id: 1 }, { id: 2 }, { id: 3 }], + }, + config: {}, + }), + getAllOrgClassifications: vi.fn().mockResolvedValue({ + count: 3, + results: [ + { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, + }, + { + id: 456, + slug: 'for-skill', + type: 'Custom', + is_enabled_for_projects: false, + is_enabled_for_skills: true, + }, + { + id: 789, + slug: 'for-skill-and-project', + type: 'Wikipedia', + is_enabled_for_projects: true, + is_enabled_for_skills: true, + }, + ], + }), +})) + +const classification = { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, +} + +const i18n = { + locale: 'en', + fallbackLocale: 'en', + messages: { + en: english, + }, +} + +describe('DefaultTagsAdmin', () => { + let wrapper + let defaultParams + let organizationsStore + + beforeEach(() => { + organizationsStore = useOrganizationsStore(pinia) + organizationsStore.updateCurrentOrganization = vi.fn() + organizationsStore.current = { + code: 'test', + tags: [], + enabled_projects_tag_classifications: [ + { id: 123, slug: 'for-project', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + enabled_skills_tag_classifications: [ + { id: 456, slug: 'for-skill', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + default_projects_tags: [{ id: 11 }, { id: 12 }, { id: 13 }], + default_skills_tags: [{ id: 21 }, { id: 22 }, { id: 23 }], + } as unknown as OrganizationOutput + defaultParams = { + props: {}, + i18n, + } + }) + + it('should render DefaultTagsAdmin component', () => { + wrapper = lpiMount(DefaultTagsAdmin, { + ...defaultParams, + props: {}, + }) + + expect(wrapper.exists()).toBeTruthy() + }) + + it('should display default skills entry', async () => { + wrapper = lpiMount(DefaultTagsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + await vm.$nextTick() + expect(vm.organizationTags.length).toBe(3) + const tagEntries = wrapper.findAll('[data-test="default-tag"]') + expect(tagEntries.length).toBe(3) + }) + + it('should ask confirmation for deleting tag', async () => { + wrapper = lpiMount(DefaultTagsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + const deleteButtons = wrapper.findAllComponents('[data-test="default-tag"]') + let confirmModal = wrapper.findComponent('[data-test="confirm-delete-default-tag"]') + + expect(deleteButtons.length).toBe(3) + expect(confirmModal.exists()).toBeFalsy() + + await deleteButtons[0].trigger('click') + + await vm.$nextTick() + + confirmModal = wrapper.findComponent('[data-test="confirm-delete-default-tag"]') + expect(confirmModal.exists()).toBeTruthy() + }) + + it('should allow to add skills', async () => { + wrapper = lpiMount(DefaultTagsAdmin, { + ...defaultParams, + props: {}, + }) + + const vm: any = wrapper.vm + await flushPromises() + const editButtons = wrapper.findAllComponents('[data-test="add-default-tags"]') + let addDrawer = wrapper.findComponent('[data-test="add-default-tags-drawer"]') + + expect(editButtons.length).toBe(1) + expect(addDrawer.vm.isOpened).toBeFalsy() + + await editButtons[0].trigger('click') + + await vm.$nextTick() + addDrawer = wrapper.findComponent('[data-test="add-default-tags-drawer"]') + expect(addDrawer.vm.isOpened).toBeTruthy() + }) +}) diff --git a/tests/unit/components/admin/TagClassificationAdmin.spec.ts b/tests/unit/components/admin/TagClassificationAdmin.spec.ts new file mode 100644 index 000000000..9b0af9752 --- /dev/null +++ b/tests/unit/components/admin/TagClassificationAdmin.spec.ts @@ -0,0 +1,178 @@ +import { lpiMount } from '../../../helpers/LpiMount' +import english from '@/locales/en.json' +import waitForExpect from 'wait-for-expect' +import TagClassificationAdmin from '@/components/admin/TagClassificationAdmin.vue' + +import pinia from '@/stores' +import useOrganizationsStore from '@/stores/useOrganizations' + +import { OrganizationOutput, OrganizationPatchInput } from '@/models/organization.model' + +import { afterEach, beforeEach, describe, expect, it, vi, Mock } from 'vitest' +import flushPromises from 'flush-promises' + +import { + getAllOrgClassifications, + getOrgClassificationTags, +} from '@/api/tag-classification.service' + +import debounce from 'lodash.debounce' + +vi.mock('lodash.debounce', () => ({ default: vi.fn((fn) => fn) })) + +vi.mock('@/api/tag-classification.service', () => ({ + getOrgClassificationTags: vi.fn().mockResolvedValue({ + data: { + count: 3, + current_page: 1, + total_page: 1, + previous: null, + next: null, + first: null, + last: null, + results: [{ id: 1 }, { id: 2 }, { id: 3 }], + }, + config: {}, + }), + getAllOrgClassifications: vi.fn().mockResolvedValue({ + count: 3, + results: [ + { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, + }, + { + id: 456, + slug: 'for-skill', + type: 'Custom', + is_enabled_for_projects: false, + is_enabled_for_skills: true, + }, + { + id: 789, + slug: 'for-skill-and-project', + type: 'Wikipedia', + is_enabled_for_projects: true, + is_enabled_for_skills: true, + }, + ], + }), +})) + +const classification = { + id: 123, + slug: 'for-project', + type: 'Custom', + is_enabled_for_projects: true, + is_enabled_for_skills: false, +} + +const i18n = { + locale: 'en', + fallbackLocale: 'en', + messages: { + en: english, + }, +} + +describe('TagClassificationAdmin', () => { + let wrapper + let defaultParams + let organizationsStore + + beforeEach(() => { + organizationsStore = useOrganizationsStore(pinia) + organizationsStore.updateCurrentOrganization = vi.fn() + organizationsStore.current = { + code: 'test', + tags: [], + enabled_projects_tag_classifications: [ + { id: 123, slug: 'for-project', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + enabled_skills_tag_classifications: [ + { id: 456, slug: 'for-skill', type: 'Custom' }, + { id: 789, slug: 'for-skill-and-project', type: 'Custom' }, + ], + default_projects_tags: [{ id: 11 }, { id: 12 }, { id: 13 }], + default_skills_tags: [{ id: 21 }, { id: 22 }, { id: 23 }], + } as unknown as OrganizationOutput + defaultParams = { + props: {}, + i18n, + } + }) + + it('should render TagClassificationAdmin component', () => { + wrapper = lpiMount(TagClassificationAdmin, { + ...defaultParams, + props: { classification: classification }, + }) + + expect(wrapper.exists()).toBeTruthy() + }) + + it('should display tags entry', async () => { + wrapper = lpiMount(TagClassificationAdmin, { + ...defaultParams, + props: { classification: classification }, + }) + + const vm: any = wrapper.vm + await flushPromises() + await vm.$nextTick() + expect(getOrgClassificationTags).toHaveBeenCalled() + expect(vm.isLoading).toBeFalsy() + expect(vm.tagResults.length).toBe(3) + const tagEntries = wrapper.findAll('[data-test="tag-entry"]') + await waitForExpect(() => { + expect(tagEntries.length).toBe(3) + }) + }) + + it('should ask confirmation for deleting tag', async () => { + wrapper = lpiMount(TagClassificationAdmin, { + ...defaultParams, + props: { classification: classification }, + }) + + const vm: any = wrapper.vm + await flushPromises() + const deleteButtons = wrapper.findAllComponents('[data-test="delete-tag-button"]') + let confirmModal = wrapper.findComponent('[data-test="confirm-tag-delete-modal"]') + + expect(deleteButtons.length).toBe(3) + expect(confirmModal.exists()).toBeFalsy() + + await deleteButtons[0].trigger('click') + + await vm.$nextTick() + + confirmModal = wrapper.findComponent('[data-test="confirm-tag-delete-modal"]') + expect(confirmModal.exists()).toBeTruthy() + }) + + it('should allow to edit tag', async () => { + wrapper = lpiMount(TagClassificationAdmin, { + ...defaultParams, + props: { classification: classification }, + }) + + const vm: any = wrapper.vm + await flushPromises() + const editButtons = wrapper.findAllComponents('[data-test="edit-tag-button"]') + let editModal = wrapper.findComponent('[data-test="edit-tag-modal"]') + + expect(editButtons.length).toBe(3) + expect(editModal.exists()).toBeFalsy() + + await editButtons[0].trigger('click') + + await vm.$nextTick() + editModal = wrapper.findComponent('[data-test="edit-tag-modal"]') + expect(editModal.exists()).toBeTruthy() + }) +})