-
Notifications
You must be signed in to change notification settings - Fork 467
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(edit-content) clean up, add more test
- Loading branch information
Showing
13 changed files
with
501 additions
and
388 deletions.
There are no files selected for viewing
273 changes: 24 additions & 249 deletions
273
core-web/libs/edit-content/src/lib/feature/edit-content/store/edit-content.store.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,285 +1,60 @@ | ||
import { | ||
createServiceFactory, | ||
mockProvider, | ||
SpectatorService, | ||
SpyObject | ||
} from '@ngneat/spectator/jest'; | ||
import { of, throwError } from 'rxjs'; | ||
|
||
import { HttpErrorResponse } from '@angular/common/http'; | ||
import { fakeAsync, tick } from '@angular/core/testing'; | ||
import { ActivatedRoute, Router } from '@angular/router'; | ||
|
||
import { MessageService } from 'primeng/api'; | ||
|
||
import { ActivatedRoute } from '@angular/router'; | ||
import { | ||
DotContentTypeService, | ||
DotFireActionOptions, | ||
DotHttpErrorManagerService, | ||
DotMessageService, | ||
DotRenderMode, | ||
DotWorkflowActionsFireService, | ||
DotWorkflowsActionsService, | ||
DotWorkflowService | ||
} from '@dotcms/data-access'; | ||
import { | ||
ComponentStatus, | ||
DotCMSContentlet, | ||
DotCMSContentType, | ||
DotCMSWorkflowAction | ||
} from '@dotcms/dotcms-models'; | ||
import { MOCK_SINGLE_WORKFLOW_ACTIONS, MockDotMessageService } from '@dotcms/utils-testing'; | ||
|
||
import { DotEditContentStore } from './edit-content.store'; | ||
|
||
import { ComponentStatus } from '@dotcms/dotcms-models'; | ||
import { createServiceFactory, mockProvider, SpectatorService } from '@ngneat/spectator/jest'; | ||
import { MessageService } from 'primeng/api'; | ||
import { DotEditContentService } from '../../../services/dot-edit-content.service'; | ||
import { CONTENT_TYPE_MOCK } from '../../../utils/mocks'; | ||
|
||
const messageServiceMock = new MockDotMessageService({ | ||
'edit.content.success.workflow.message': 'Your changes have being applied.', | ||
success: 'Success' | ||
}); | ||
import { DotEditContentStore } from './edit-content.store'; | ||
|
||
describe('DotEditContentStore', () => { | ||
let spectator: SpectatorService<InstanceType<typeof DotEditContentStore>>; | ||
let store: InstanceType<typeof DotEditContentStore>; | ||
|
||
let contentTypeService: SpyObject<DotContentTypeService>; | ||
|
||
let dotHttpErrorManagerService: SpyObject<DotHttpErrorManagerService>; | ||
let dotEditContentService: SpyObject<DotEditContentService>; | ||
|
||
let mockActivatedRouteParams: { [key: string]: unknown }; | ||
let router: SpyObject<Router>; | ||
|
||
let workflowActionsService: SpyObject<DotWorkflowsActionsService>; | ||
let workflowActionsFireService: SpyObject<DotWorkflowActionsFireService>; | ||
let messageService: SpyObject<MessageService>; | ||
|
||
const createService = createServiceFactory({ | ||
service: DotEditContentStore, | ||
mocks: [ | ||
DotWorkflowActionsFireService, | ||
DotContentTypeService, | ||
DotEditContentService, | ||
DotHttpErrorManagerService, | ||
DotWorkflowsActionsService, | ||
DotWorkflowService, | ||
MessageService | ||
], | ||
providers: [ | ||
{ | ||
provide: ActivatedRoute, | ||
useValue: { | ||
get snapshot() { | ||
return { params: mockActivatedRouteParams }; | ||
return { params: {} }; | ||
} | ||
} | ||
}, | ||
|
||
mockProvider(Router, { | ||
navigate: jest.fn().mockReturnValue(Promise.resolve(true)) | ||
}), | ||
{ | ||
provide: DotMessageService, | ||
useValue: messageServiceMock | ||
} | ||
mockProvider(DotHttpErrorManagerService), | ||
mockProvider(DotEditContentService), | ||
mockProvider(DotContentTypeService), | ||
mockProvider(DotWorkflowsActionsService), | ||
mockProvider(DotWorkflowService), | ||
mockProvider(DotWorkflowActionsFireService), | ||
mockProvider(MessageService), | ||
mockProvider(DotMessageService) | ||
] | ||
}); | ||
|
||
beforeEach(() => { | ||
mockActivatedRouteParams = {}; | ||
|
||
spectator = createService(); | ||
|
||
store = spectator.service; | ||
contentTypeService = spectator.inject(DotContentTypeService); | ||
dotHttpErrorManagerService = spectator.inject(DotHttpErrorManagerService); | ||
workflowActionsService = spectator.inject(DotWorkflowsActionsService); | ||
workflowActionsFireService = spectator.inject(DotWorkflowActionsFireService); | ||
dotEditContentService = spectator.inject(DotEditContentService); | ||
messageService = spectator.inject(MessageService); | ||
|
||
router = spectator.inject(Router); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
it('should create the store', () => { | ||
expect(spectator.service).toBeDefined(); | ||
}); | ||
|
||
describe('initializeNewContent', () => { | ||
it('should initialize new content successfully', () => { | ||
const testContentType = 'testContentType'; | ||
|
||
contentTypeService.getContentType.mockReturnValue(of(CONTENT_TYPE_MOCK)); | ||
workflowActionsService.getDefaultActions.mockReturnValue( | ||
of(MOCK_SINGLE_WORKFLOW_ACTIONS) | ||
); | ||
workflowActionsService.getWorkFlowActions.mockReturnValue( | ||
of(MOCK_SINGLE_WORKFLOW_ACTIONS) | ||
); | ||
|
||
store.initializeNewContent(testContentType); | ||
|
||
// use the proper contentType for get the data | ||
expect(contentTypeService.getContentType).toHaveBeenCalledWith(testContentType); | ||
expect(workflowActionsService.getDefaultActions).toHaveBeenCalledWith(testContentType); | ||
|
||
expect(store.contentType()).toEqual(CONTENT_TYPE_MOCK); | ||
|
||
expect(store.state()).toBe(ComponentStatus.LOADED); | ||
expect(store.error()).toBeNull(); | ||
}); | ||
|
||
it('should handle error when initializing new content', fakeAsync(() => { | ||
const mockError = new HttpErrorResponse({ status: 404, statusText: 'Not Found' }); | ||
|
||
contentTypeService.getContentType.mockReturnValue(throwError(() => mockError)); | ||
workflowActionsService.getDefaultActions.mockReturnValue( | ||
of(MOCK_SINGLE_WORKFLOW_ACTIONS) | ||
); | ||
|
||
store.initializeNewContent('testContentType'); | ||
|
||
expect(store.error()).toBe('Error initializing content'); | ||
expect(store.state()).toBe(ComponentStatus.ERROR); | ||
expect(dotHttpErrorManagerService.handle).toHaveBeenCalled(); | ||
})); | ||
}); | ||
|
||
describe('initializeExistingContent', () => { | ||
const testInode = '123-test-inode'; | ||
it('should initialize existing content successfully', () => { | ||
const mockContentlet = { | ||
inode: testInode, | ||
contentType: 'testContentType' | ||
} as DotCMSContentlet; | ||
|
||
const mockContentType = { | ||
id: '1', | ||
name: 'Test Content Type' | ||
} as DotCMSContentType; | ||
|
||
const mockActions = [{ id: '1', name: 'Test Action' }] as DotCMSWorkflowAction[]; | ||
|
||
dotEditContentService.getContentById.mockReturnValue(of(mockContentlet)); | ||
contentTypeService.getContentType.mockReturnValue(of(mockContentType)); | ||
workflowActionsService.getByInode.mockReturnValue(of(mockActions)); | ||
workflowActionsService.getWorkFlowActions.mockReturnValue( | ||
of(MOCK_SINGLE_WORKFLOW_ACTIONS) | ||
); | ||
|
||
store.initializeExistingContent(testInode); | ||
|
||
expect(dotEditContentService.getContentById).toHaveBeenCalledWith(testInode); | ||
expect(contentTypeService.getContentType).toHaveBeenCalledWith( | ||
mockContentlet.contentType | ||
); | ||
expect(workflowActionsService.getByInode).toHaveBeenCalledWith( | ||
testInode, | ||
expect.anything() | ||
); | ||
|
||
expect(store.contentlet()).toEqual(mockContentlet); | ||
expect(store.contentType()).toEqual(mockContentType); | ||
|
||
expect(store.state()).toBe(ComponentStatus.LOADED); | ||
expect(store.error()).toBe(null); | ||
}); | ||
|
||
it('should handle error when initializing existing content', fakeAsync(() => { | ||
const mockError = new HttpErrorResponse({ status: 404, statusText: 'Not Found' }); | ||
|
||
dotEditContentService.getContentById.mockReturnValue(throwError(() => mockError)); | ||
|
||
store.initializeExistingContent(testInode); | ||
tick(); | ||
|
||
expect(dotEditContentService.getContentById).toHaveBeenCalledWith(testInode); | ||
expect(dotHttpErrorManagerService.handle).toHaveBeenCalled(); | ||
expect(router.navigate).toHaveBeenCalledWith(['/c/content']); | ||
|
||
expect(store.state()).toBe(ComponentStatus.ERROR); | ||
})); | ||
}); | ||
|
||
describe('fireWorkflowAction', () => { | ||
const mockOptions: DotFireActionOptions<{ [key: string]: string | object }> = { | ||
inode: '123', | ||
actionId: 'publish' | ||
}; | ||
|
||
it('should fire workflow action successfully', fakeAsync(() => { | ||
const mockContentlet = { inode: '456', contentType: 'testType' } as DotCMSContentlet; | ||
const mockActions = [{ id: '1', name: 'Test Action' }] as DotCMSWorkflowAction[]; | ||
|
||
workflowActionsFireService.fireTo.mockReturnValue(of(mockContentlet)); | ||
workflowActionsService.getByInode.mockReturnValue(of(mockActions)); | ||
|
||
store.fireWorkflowAction(mockOptions); | ||
tick(); | ||
|
||
expect(store.state()).toBe(ComponentStatus.LOADED); | ||
expect(store.contentlet()).toEqual(mockContentlet); | ||
|
||
expect(store.error()).toBeNull(); | ||
|
||
expect(workflowActionsFireService.fireTo).toHaveBeenCalledWith(mockOptions); | ||
expect(workflowActionsService.getByInode).toHaveBeenCalledWith( | ||
mockContentlet.inode, | ||
DotRenderMode.EDITING | ||
); | ||
expect(router.navigate).toHaveBeenCalledWith(['/content', mockContentlet.inode], { | ||
replaceUrl: true, | ||
queryParamsHandling: 'preserve' | ||
}); | ||
|
||
expect(messageService.add).toHaveBeenCalledWith({ | ||
severity: 'success', | ||
summary: 'Success', | ||
detail: 'Your changes have being applied.' | ||
}); | ||
})); | ||
|
||
it('should handle error when firing workflow action', fakeAsync(() => { | ||
const mockError = new HttpErrorResponse({ | ||
status: 500, | ||
statusText: 'Internal Server Error' | ||
}); | ||
|
||
workflowActionsFireService.fireTo.mockReturnValue(throwError(() => mockError)); | ||
|
||
store.fireWorkflowAction(mockOptions); | ||
tick(); | ||
|
||
expect(store.state()).toBe(ComponentStatus.LOADED); | ||
expect(store.error()).toBe('Error firing workflow action'); | ||
expect(dotHttpErrorManagerService.handle).toHaveBeenCalled(); | ||
})); | ||
|
||
it('should navigate to content list if contentlet has no inode', fakeAsync(() => { | ||
const mockContentletWithoutInode = { contentType: 'testType' } as DotCMSContentlet; | ||
|
||
workflowActionsFireService.fireTo.mockReturnValue(of(mockContentletWithoutInode)); | ||
|
||
store.fireWorkflowAction(mockOptions); | ||
tick(); | ||
|
||
expect(router.navigate).toHaveBeenCalledWith(['/c/content']); | ||
})); | ||
it('should create store with initial state', () => { | ||
expect(store.state()).toBe(ComponentStatus.INIT); | ||
expect(store.error()).toBeNull(); | ||
}); | ||
|
||
describe('toggleSidebar', () => { | ||
it('should toggle sidebar state', () => { | ||
expect(store.showSidebar()).toBe(true); | ||
store.toggleSidebar(); | ||
expect(store.showSidebar()).toBe(false); | ||
store.toggleSidebar(); | ||
expect(store.showSidebar()).toBe(true); | ||
}); | ||
it('should compose with all required features', () => { | ||
// Verify features are composed into the store | ||
expect(store.contentType).toBeDefined(); | ||
expect(store.contentlet).toBeDefined(); | ||
expect(store.showSidebar).toBeDefined(); | ||
expect(store.showWorkflowActions).toBeDefined(); | ||
expect(store.information).toBeDefined(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.