From feb9fbb1ea84e72bea491dcd525de587203e6fcc Mon Sep 17 00:00:00 2001 From: Nicolas Molina Date: Fri, 27 Sep 2024 17:32:31 -0400 Subject: [PATCH] feat(editor-content): add unit tests to file field store #30059 --- .../store/file-field.store.spec.ts | 250 ++++++++++++++++++ .../utils/messages.spec.ts | 23 ++ .../utils/messages.ts | 17 +- 3 files changed, 287 insertions(+), 3 deletions(-) create mode 100644 core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/store/file-field.store.spec.ts create mode 100644 core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.spec.ts diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/store/file-field.store.spec.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/store/file-field.store.spec.ts new file mode 100644 index 000000000000..4904da297ec6 --- /dev/null +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/store/file-field.store.spec.ts @@ -0,0 +1,250 @@ +import { SpyObject, mockProvider } from '@ngneat/spectator/jest'; +import { patchState } from '@ngrx/signals'; +import { of, throwError } from 'rxjs'; + +import { TestBed } from '@angular/core/testing'; + +import { FileFieldStore } from './file-field.store'; + +import { NEW_FILE_MOCK, TEMP_FILE_MOCK } from '../../../utils/mocks'; +import { UIMessage } from '../models'; +import { DotFileFieldUploadService } from '../services/upload-file/upload-file.service'; +import { getUiMessage } from '../utils/messages'; + +describe('FileFieldStore', () => { + let store: InstanceType; + let service: SpyObject; + + beforeEach(() => { + store = TestBed.overrideProvider( + DotFileFieldUploadService, + mockProvider(DotFileFieldUploadService) + ).runInInjectionContext(() => new FileFieldStore()); + + service = TestBed.inject(DotFileFieldUploadService) as SpyObject; + }); + + it('should be created', () => { + expect(store).toBeTruthy(); + }); + + describe('Method: initLoad', () => { + it('should init the state properly for File input', () => { + store.initLoad({ + inputType: 'File', + fieldVariable: 'myVar' + }); + + expect(store.inputType()).toEqual('File'); + expect(store.fieldVariable()).toEqual('myVar'); + expect(store.allowExistingFile()).toBe(true); + expect(store.allowURLImport()).toBe(true); + expect(store.allowCreateFile()).toBe(true); + expect(store.allowGenerateImg()).toBe(false); + expect(store.acceptedFiles().length).toBe(0); + expect(store.maxFileSize()).toBeNull(); + }); + + it('should init the state properly for Image input', () => { + store.initLoad({ + inputType: 'Image', + fieldVariable: 'myVar' + }); + + expect(store.inputType()).toEqual('Image'); + expect(store.fieldVariable()).toEqual('myVar'); + expect(store.allowExistingFile()).toBe(true); + expect(store.allowURLImport()).toBe(true); + expect(store.allowCreateFile()).toBe(false); + expect(store.allowGenerateImg()).toBe(true); + expect(store.acceptedFiles()).toContain('image/*'); + expect(store.maxFileSize()).toBeNull(); + }); + + it('should init the state properly for Binary input', () => { + store.initLoad({ + inputType: 'Binary', + fieldVariable: 'myVar' + }); + + expect(store.inputType()).toEqual('Binary'); + expect(store.fieldVariable()).toEqual('myVar'); + expect(store.allowExistingFile()).toBe(false); + expect(store.allowURLImport()).toBe(true); + expect(store.allowCreateFile()).toBe(true); + expect(store.allowGenerateImg()).toBe(true); + expect(store.acceptedFiles().length).toBe(0); + expect(store.maxFileSize()).toBeNull(); + }); + }); + + describe('Method: setUIMessage', () => { + it('should set uiMessage with valid UIMessage object', () => { + const uiMessage: UIMessage = { + message: 'test message', + severity: 'info', + icon: 'pi pi-upload' + }; + + store.setUIMessage(uiMessage); + + expect(store.uiMessage()).toEqual({ + message: 'test message', + severity: 'info', + icon: 'pi pi-upload', + args: [`${store.maxFileSize()}`, store.acceptedFiles().join(', ')] + }); + }); + }); + + describe('Method: removeFile', () => { + it('should set the state properly when removeFile is called', () => { + patchState(store, { + contentlet: NEW_FILE_MOCK.entity, + tempFile: TEMP_FILE_MOCK, + value: 'some value', + fileStatus: 'preview', + uiMessage: getUiMessage('SERVER_ERROR') + }); + store.removeFile(); + expect(store.contentlet()).toBeNull(); + expect(store.tempFile()).toBeNull(); + expect(store.value()).toBe(''); + expect(store.fileStatus()).toBe('init'); + expect(store.uiMessage()).toBe(getUiMessage('DEFAULT')); + }); + }); + + describe('Method: setDropZoneState', () => { + it('should set dropZoneActive to true', () => { + patchState(store, { + dropZoneActive: false + }); + store.setDropZoneState(true); + expect(store.dropZoneActive()).toBe(true); + }); + + it('should set dropZoneActive to false', () => { + patchState(store, { + dropZoneActive: true + }); + store.setDropZoneState(false); + expect(store.dropZoneActive()).toBe(false); + }); + }); + + describe('Method: handleUploadFile', () => { + it('should does not call uploadService with maxFileSize exceeded', () => { + patchState(store, { + maxFileSize: 10000 + }); + + const file = new File([''], 'filename', { type: 'text/plain' }); + Object.defineProperty(file, 'size', { value: 20000 }); + + store.handleUploadFile(file); + expect(service.uploadDotAsset).not.toHaveBeenCalled(); + }); + + it('should set state properly with maxFileSize exceeded', () => { + patchState(store, { + maxFileSize: 10000 + }); + + const file = new File([''], 'filename', { type: 'text/plain' }); + Object.defineProperty(file, 'size', { value: 20000 }); + + store.handleUploadFile(file); + expect(store.dropZoneActive()).toBe(true); + expect(store.fileStatus()).toBe('init'); + expect(store.uiMessage()).toEqual({ + ...getUiMessage('MAX_FILE_SIZE_EXCEEDED'), + args: ['10000'] + }); + }); + + it('should call uploadService with maxFileSize not exceeded', () => { + service.uploadDotAsset.mockReturnValue(of(NEW_FILE_MOCK.entity)); + + patchState(store, { + maxFileSize: 10000 + }); + + const file = new File([''], 'filename', { type: 'text/plain' }); + Object.defineProperty(file, 'size', { value: 5000 }); + + store.handleUploadFile(file); + expect(service.uploadDotAsset).toHaveBeenCalledWith(file); + }); + + it('should set state properly with maxFileSize not exceeded', () => { + const mockContentlet = NEW_FILE_MOCK.entity; + + service.uploadDotAsset.mockReturnValue(of(mockContentlet)); + + patchState(store, { + maxFileSize: 10000 + }); + + const file = new File([''], 'filename', { type: 'text/plain' }); + Object.defineProperty(file, 'size', { value: 5000 }); + + store.handleUploadFile(file); + expect(store.tempFile()).toBeNull(); + expect(store.value()).toBe(mockContentlet.identifier); + expect(store.contentlet()).toEqual(mockContentlet); + expect(store.fileStatus()).toBe('preview'); + expect(store.previewFile()).toEqual({ + source: 'contentlet', + file: mockContentlet + }); + }); + + it('should set state properly with an error calling uploadDotAsset', () => { + service.uploadDotAsset.mockReturnValue(throwError('error')); + + const file = new File([''], 'filename', { type: 'text/plain' }); + store.handleUploadFile(file); + + expect(service.uploadDotAsset).toHaveBeenCalledWith(file); + expect(store.fileStatus()).toBe('init'); + expect(store.uiMessage()).toEqual(getUiMessage('SERVER_ERROR')); + }); + }); + + describe('Method: getAssetData', () => { + it('should call getContentById', () => { + const mockContentlet = NEW_FILE_MOCK.entity; + service.getContentById.mockReturnValue(of(mockContentlet)); + + store.getAssetData(mockContentlet.identifier); + expect(service.getContentById).toHaveBeenCalledWith(mockContentlet.identifier); + }); + + it('should set state properly', () => { + const mockContentlet = NEW_FILE_MOCK.entity; + service.getContentById.mockReturnValue(of(mockContentlet)); + + store.getAssetData(mockContentlet.identifier); + + expect(store.tempFile()).toBeNull(); + expect(store.value()).toBe(mockContentlet.identifier); + expect(store.contentlet()).toEqual(mockContentlet); + expect(store.fileStatus()).toBe('preview'); + expect(store.previewFile()).toEqual({ + source: 'contentlet', + file: mockContentlet + }); + }); + + it('should set state properly with an error calling getAssetData', () => { + service.getContentById.mockReturnValue(throwError('error')); + + store.getAssetData('id'); + + expect(service.getContentById).toHaveBeenCalledWith('id'); + expect(store.fileStatus()).toBe('init'); + expect(store.uiMessage()).toEqual(getUiMessage('SERVER_ERROR')); + }); + }); +}); diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.spec.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.spec.ts new file mode 100644 index 000000000000..f4406a10887c --- /dev/null +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.spec.ts @@ -0,0 +1,23 @@ +import { getUiMessage, UiMessageMap } from './messages'; + +import { MESSAGES_TYPES } from '../models'; + +describe('getUiMessage function', () => { + it('should return the correct uiMessage for a valid key', () => { + const key: MESSAGES_TYPES = 'DEFAULT'; + const expectedUiMessage = UiMessageMap[key]; + expect(getUiMessage(key)).toEqual(expectedUiMessage); + }); + + it('should throw an error for an invalid key', () => { + const key = 'INVALID_KEY' as MESSAGES_TYPES; + expect(() => getUiMessage(key)).toThrowError(`Key ${key} not found in UiMessageMap`); + }); + + it('should throw an error for a null or undefined key', () => { + const key = null as unknown as MESSAGES_TYPES; + expect(() => getUiMessage(key)).toThrowError(`Key ${key} not found in UiMessageMap`); + const key2 = undefined as unknown as MESSAGES_TYPES; + expect(() => getUiMessage(key2)).toThrowError(`Key ${key2} not found in UiMessageMap`); + }); +}); diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.ts index 30f188a17dc4..b2f3d5fa491b 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.ts +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/utils/messages.ts @@ -1,4 +1,4 @@ -import { MESSAGES_TYPES, UIMessagesMap } from '../models'; +import { MESSAGES_TYPES, UIMessage, UIMessagesMap } from '../models'; export const UiMessageMap: UIMessagesMap = { DEFAULT: { @@ -28,6 +28,17 @@ export const UiMessageMap: UIMessagesMap = { } }; -export function getUiMessage(key: MESSAGES_TYPES) { - return UiMessageMap[key]; +/** + * Returns a uiMessage given its key + * @param key The key of the uiMessage + * @returns The uiMessage + */ +export function getUiMessage(key: MESSAGES_TYPES): UIMessage { + const uiMessage = UiMessageMap[key]; + + if (!uiMessage) { + throw new Error(`Key ${key} not found in UiMessageMap`); + } + + return uiMessage; }