diff --git a/tests/units/components/description/cytomine-description-modal.test.js b/tests/units/components/description/cytomine-description-modal.test.js
new file mode 100644
index 00000000..b7f08405
--- /dev/null
+++ b/tests/units/components/description/cytomine-description-modal.test.js
@@ -0,0 +1,43 @@
+import {createLocalVue, shallowMount} from '@vue/test-utils';
+import VueI18n from 'vue-i18n';
+
+import CytomineDescriptionModal from '@/components/description/CytomineDescriptionModal';
+import CytomineModalCard from '@/components/utils/CytomineModalCard';
+
+jest.mock('@/components/utils/CytomineModalCard', () => ({
+ name: 'cytomine-modal-card',
+ template: '
'
+}));
+
+jest.mock('@/components/form/CytomineQuillEditor', () => ({
+ name: 'cytomine-quill-editor',
+ template: '
',
+ props: ['value', 'placeholder']
+}));
+
+describe('CytomineDescriptionModal', () => {
+ const localVue = createLocalVue();
+ localVue.use(VueI18n);
+
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = shallowMount(CytomineDescriptionModal, {
+ localVue,
+ mocks: {
+ $t: (message) => message,
+ $notify: jest.fn()
+ },
+ propsData: {
+ description: {data: 'Test description'},
+ edit: false
+ }
+ });
+ });
+
+ it('should render the component correctly', () => {
+ expect(wrapper.findComponent(CytomineModalCard).exists()).toBe(true);
+ expect(wrapper.find('.ql-editor.preview').exists()).toBe(true);
+ expect(wrapper.text()).toContain('description');
+ });
+});
diff --git a/tests/units/components/description/cytomine-description.test.js b/tests/units/components/description/cytomine-description.test.js
new file mode 100644
index 00000000..a418d840
--- /dev/null
+++ b/tests/units/components/description/cytomine-description.test.js
@@ -0,0 +1,96 @@
+import {createLocalVue, shallowMount} from '@vue/test-utils';
+import Buefy from 'buefy';
+import Vuex from 'vuex';
+
+import CytomineDescription from '@/components/description/CytomineDescription';
+
+jest.mock('cytomine-client', () => ({
+ Description: {
+ fetch: jest.fn()
+ }
+}));
+
+jest.mock('@/utils/constants.js', () => ({
+ STOP_PREVIEW_KEYWORD: 'STOP_PREVIEW'
+}));
+
+describe('CytomineDescription.vue', () => {
+ const localVue = createLocalVue();
+ localVue.use(Buefy);
+ localVue.use(Vuex);
+
+ let actions;
+ let store;
+ let wrapper;
+
+ beforeEach(() => {
+ actions = {
+ fetchDescription: jest.fn()
+ };
+ store = new Vuex.Store({
+ actions
+ });
+
+ wrapper = shallowMount(CytomineDescription, {
+ localVue,
+ store,
+ mocks: {
+ $t: (message) => message
+ },
+ propsData: {
+ object: {id: 1},
+ canEdit: true,
+ maxPreviewLength: 100
+ }
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render the component correctly', () => {
+ expect(wrapper.exists()).toBe(true);
+ });
+
+ it('should render a loading spinner when loading is true', () => {
+ wrapper.setData({loading: true});
+
+ expect(wrapper.findComponent({name: 'b-loading'}).exists()).toBe(true);
+ });
+
+ it('should display description content when available', async () => {
+ wrapper.setData({
+ loading: false,
+ description: {data: 'This is a sample description text.'}
+ });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find('.ql-editor').exists()).toBe(true);
+ expect(wrapper.find('.ql-editor').html()).toContain('This is a sample description text.');
+ });
+
+ it('should display "no-description" message when description is not available', () => {
+ wrapper.setData({loading: false, description: null});
+
+ expect(wrapper.find('em').text()).toBe('no-description');
+ });
+
+ it('should display "add" button when description is not available and canEdit is true', () => {
+ wrapper.setData({loading: false, description: null});
+
+ expect(wrapper.find('.button.is-small.margin').exists()).toBe(true);
+ });
+
+ it('should compute previewDescription correctly', () => {
+ wrapper.setData({
+ description: {data: 'Short description text'}
+ });
+ expect(wrapper.vm.previewDescription).toBe('Short description text');
+
+ wrapper.setData({
+ description: {data: 'A very long description text that exceeds the preview length limit...'}
+ });
+ expect(wrapper.vm.previewDescription).toBe('A very long description text that exceeds the preview length limit...');
+ });
+});