Browse Source

add: service tests

pull/24234/head
sumeyye 4 months ago
parent
commit
ab2a1f77b7
  1. 8
      npm/ng-packs/guides/CMS_KIT_ANGULAR_STRUCTURE.md
  2. 1
      npm/ng-packs/packages/cms-kit/admin/src/services/blog-post-form.service.ts
  3. 141
      npm/ng-packs/packages/cms-kit/admin/src/tests/blog-post-form.service.spec.ts
  4. 64
      npm/ng-packs/packages/cms-kit/admin/src/tests/cms-kit-admin.routes.spec.ts
  5. 102
      npm/ng-packs/packages/cms-kit/admin/src/tests/comment-entity.service.spec.ts
  6. 156
      npm/ng-packs/packages/cms-kit/admin/src/tests/page-form.service.spec.ts
  7. 16
      npm/ng-packs/packages/cms-kit/src/test-setup.ts

8
npm/ng-packs/guides/CMS_KIT_ANGULAR_STRUCTURE.md

@ -1221,9 +1221,9 @@ export enum eCmsKitAdminRouteNames {
### Phase 8: Admin - Global Resources Feature
- [ ] Create GlobalResourceListComponent
- [ ] Create default extension points
- [ ] Add routes and providers
- [x] Create GlobalResourceListComponent
- [x] Create default extension points
- [x] Add routes and providers
### Phase 9: Public - Pages Feature
@ -1254,8 +1254,6 @@ export enum eCmsKitAdminRouteNames {
- [ ] Write unit tests for services
- [ ] Write unit tests for components
- [ ] Write integration tests
- [ ] Update README documentation
- [ ] Create usage examples
## Best Practices

1
npm/ng-packs/packages/cms-kit/admin/src/services/blog-post-form.service.ts

@ -9,7 +9,6 @@ import {
CreateBlogPostDto,
UpdateBlogPostDto,
BlogPostDto,
BlogPostStatus,
} from '@abp/ng.cms-kit/proxy';
@Injectable({

141
npm/ng-packs/packages/cms-kit/admin/src/tests/blog-post-form.service.spec.ts

@ -0,0 +1,141 @@
/* eslint-disable */
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
import { FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
// @ts-ignore - test types are resolved only in the library build context
import { ToasterService } from '@abp/ng.theme.shared';
// @ts-ignore - test types are resolved only in the library build context
import { BlogPostAdminService } from '@abp/ng.cms-kit/proxy';
import { BlogPostFormService } from '../services';
describe('BlogPostFormService', () => {
let service: BlogPostFormService;
let blogPostAdminService: any;
let toasterService: any;
let router: any;
beforeEach(() => {
blogPostAdminService = {
create: jest.fn().mockReturnValue(of({})),
createAndPublish: jest.fn().mockReturnValue(of({})),
createAndSendToReview: jest.fn().mockReturnValue(of({})),
update: jest.fn().mockReturnValue(of({})),
};
toasterService = {
success: jest.fn(),
};
router = {
navigate: jest.fn(),
};
TestBed.configureTestingModule({
providers: [
BlogPostFormService,
{ provide: BlogPostAdminService, useValue: blogPostAdminService },
{ provide: ToasterService, useValue: toasterService },
{ provide: Router, useValue: router },
],
});
service = TestBed.inject(BlogPostFormService);
});
function createValidForm(): FormGroup {
// We don't rely on any specific controls, only on form.value and validity.
return new FormGroup({});
}
function createInvalidForm(): FormGroup {
const form = new FormGroup({});
form.setErrors({ invalid: true });
return form;
}
it('should throw when creating with invalid form', () => {
const form = createInvalidForm();
expect(() => service.create(form)).toThrowError('Form is invalid');
});
it('should call BlogPostAdminService.create and navigate on create', done => {
const form = createValidForm();
service.create(form).subscribe({
next: () => {
expect(blogPostAdminService.create).toHaveBeenCalledWith(form.value);
expect(toasterService.success).toHaveBeenCalledWith('AbpUi::SavedSuccessfully');
expect(router.navigate).toHaveBeenCalledWith(['/cms/blog-posts']);
done();
},
error: err => done(err as any),
});
});
it('should call BlogPostAdminService.create on createAsDraft', done => {
const form = createValidForm();
service.createAsDraft(form).subscribe({
next: () => {
expect(blogPostAdminService.create).toHaveBeenCalledWith(form.value);
done();
},
error: err => done(err as any),
});
});
it('should call BlogPostAdminService.createAndPublish on createAndPublish', done => {
const form = createValidForm();
service.createAndPublish(form).subscribe({
next: () => {
expect(blogPostAdminService.createAndPublish).toHaveBeenCalledWith(form.value);
done();
},
error: err => done(err as any),
});
});
it('should call BlogPostAdminService.createAndSendToReview on createAndSendToReview', done => {
const form = createValidForm();
service.createAndSendToReview(form).subscribe({
next: () => {
expect(blogPostAdminService.createAndSendToReview).toHaveBeenCalledWith(form.value);
done();
},
error: err => done(err as any),
});
});
it('should throw when updating with invalid form or missing blog post', () => {
const form = createInvalidForm();
expect(() => service.update('id', form, {} as any)).toThrowError(
'Form is invalid or blog post is missing',
);
const validForm = createValidForm();
expect(() => service.update('id', validForm, null as any)).toThrowError(
'Form is invalid or blog post is missing',
);
});
it('should call BlogPostAdminService.update and navigate on update', done => {
const form = createValidForm();
const blogPost = { id: '1', title: 't' };
service.update('1', form, blogPost).subscribe({
next: () => {
expect(blogPostAdminService.update).toHaveBeenCalled();
expect(toasterService.success).toHaveBeenCalledWith('AbpUi::SavedSuccessfully');
expect(router.navigate).toHaveBeenCalledWith(['/cms/blog-posts']);
done();
},
error: err => done(err as any),
});
});
});

64
npm/ng-packs/packages/cms-kit/admin/src/tests/cms-kit-admin.routes.spec.ts

@ -0,0 +1,64 @@
/* eslint-disable */
import { describe, it, expect } from '@jest/globals';
import { Routes } from '@angular/router';
import { createRoutes } from '../cms-kit-admin.routes';
import { CmsKitAdminConfigOptions } from '../models';
describe('cms-kit-admin routes', () => {
function findRoute(routes: Routes, path: string): any {
for (const route of routes) {
if (route.path === path) {
return route;
}
if (route.children) {
const found = findRoute(route.children, path);
if (found) {
return found;
}
}
}
return null;
}
it('should create base route with children', () => {
const routes = createRoutes();
expect(Array.isArray(routes)).toBe(true);
const root = routes[0];
expect(root.path).toBe('');
expect(root.children?.length).toBeGreaterThan(0);
});
it('should contain expected admin routes with required policies', () => {
const routes = createRoutes();
const comments = findRoute(routes, 'comments');
const pages = findRoute(routes, 'pages');
const blogs = findRoute(routes, 'blogs');
const blogPosts = findRoute(routes, 'blog-posts');
const menus = findRoute(routes, 'menus');
const globalResources = findRoute(routes, 'global-resources');
expect(comments?.data?.requiredPolicy).toBe('CmsKit.Comments');
expect(pages?.data?.requiredPolicy).toBe('CmsKit.Pages');
expect(blogs?.data?.requiredPolicy).toBe('CmsKit.Blogs');
expect(blogPosts?.data?.requiredPolicy).toBe('CmsKit.BlogPosts');
expect(menus?.data?.requiredPolicy).toBe('CmsKit.Menus');
expect(globalResources?.data?.requiredPolicy).toBe('CmsKit.GlobalResources');
});
it('should propagate contributors from config options', () => {
const options: CmsKitAdminConfigOptions = {
entityActionContributors: {},
entityPropContributors: {},
toolbarActionContributors: {},
createFormPropContributors: {},
editFormPropContributors: {},
};
const routes = createRoutes(options);
const root = routes[0];
expect(root.providers).toBeDefined();
});
});

102
npm/ng-packs/packages/cms-kit/admin/src/tests/comment-entity.service.spec.ts

@ -0,0 +1,102 @@
/* eslint-disable */
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
import { Router } from '@angular/router';
import { TestBed } from '@angular/core/testing';
import { of, Subject } from 'rxjs';
// @ts-ignore - test types are resolved only in the library build context
import { ConfigStateService, ListService } from '@abp/ng.core';
// @ts-ignore - test types are resolved only in the library build context
import { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';
// @ts-ignore - proxy module types are resolved only in the library build context
import { CommentAdminService, CommentGetListInput } from '@abp/ng.cms-kit/proxy';
import { CommentEntityService } from '../services';
describe('CommentEntityService', () => {
let service: CommentEntityService;
let commentAdminService: any;
let toasterService: any;
let confirmationService: any;
let configStateService: any;
let router: any;
beforeEach(() => {
commentAdminService = {
updateApprovalStatus: jest.fn().mockReturnValue(of(void 0)),
delete: jest.fn().mockReturnValue(of(void 0)),
};
toasterService = {
success: jest.fn(),
};
confirmationService = {
warn: jest.fn(),
};
configStateService = {
getSetting: jest.fn(),
};
router = {
url: '/cms/comments/123',
};
TestBed.configureTestingModule({
providers: [
CommentEntityService,
{ provide: CommentAdminService, useValue: commentAdminService },
{ provide: ToasterService, useValue: toasterService },
{ provide: ConfirmationService, useValue: confirmationService },
{ provide: ConfigStateService, useValue: configStateService },
{ provide: Router, useValue: router },
],
});
service = TestBed.inject(CommentEntityService);
});
it('should return requireApprovement based on setting', () => {
configStateService.getSetting.mockReturnValue('true');
expect(service.requireApprovement).toBe(true);
configStateService.getSetting.mockReturnValue('false');
expect(service.requireApprovement).toBe(false);
});
it('should detect comment reply from router url', () => {
expect(service.isCommentReply('123')).toBe(true);
expect(service.isCommentReply('456')).toBe(false);
expect(service.isCommentReply(undefined)).toBe(false);
});
it('should update approval status and refresh list', () => {
const list = {
get: jest.fn(),
} as unknown as ListService<any>;
service.updateApprovalStatus('1', true, list);
expect(commentAdminService.updateApprovalStatus).toHaveBeenCalledWith('1', {
isApproved: true,
});
expect(list.get).toHaveBeenCalled();
expect(toasterService.success).toHaveBeenCalledWith('CmsKit::ApprovedSuccessfully');
});
it('should show confirmation and delete comment when confirmed', () => {
const subject = new Subject<Confirmation.Status>();
(confirmationService.warn as jest.Mock).mockReturnValue(subject.asObservable());
const list = {
get: jest.fn(),
} as unknown as ListService<CommentGetListInput>;
service.delete('1', list);
subject.next(Confirmation.Status.confirm);
subject.complete();
expect(commentAdminService.delete).toHaveBeenCalledWith('1');
expect(list.get).toHaveBeenCalled();
});
});

156
npm/ng-packs/packages/cms-kit/admin/src/tests/page-form.service.spec.ts

@ -0,0 +1,156 @@
/* eslint-disable */
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
import { FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
// @ts-ignore - test types are resolved only in the library build context
import { ToasterService } from '@abp/ng.theme.shared';
// @ts-ignore - proxy module types are resolved only in the library build context
import { PageAdminService, PageDto } from '@abp/ng.cms-kit/proxy';
import { PageFormService } from '../services';
describe('PageFormService', () => {
let service: PageFormService;
let pageAdminService: any;
let toasterService: any;
let router: any;
beforeEach(() => {
pageAdminService = {
create: jest.fn().mockReturnValue(of({})),
update: jest.fn().mockReturnValue(of({})),
setAsHomePage: jest.fn(),
delete: jest.fn(),
get: jest.fn(),
getList: jest.fn(),
};
toasterService = {
success: jest.fn(),
};
router = {
navigate: jest.fn(),
};
TestBed.configureTestingModule({
providers: [
PageFormService,
{ provide: PageAdminService, useValue: pageAdminService },
{ provide: ToasterService, useValue: toasterService },
{ provide: Router, useValue: router },
],
});
service = TestBed.inject(PageFormService);
});
function createValidForm(): FormGroup {
return new FormGroup({});
}
function createInvalidForm(): FormGroup {
const form = new FormGroup({});
form.setErrors({ invalid: true });
return form;
}
it('should throw when creating with invalid form', () => {
const form = createInvalidForm();
expect(() => service.create(form)).toThrowError('Form is invalid');
});
it('should call PageAdminService.create and navigate on create', done => {
const form = createValidForm();
service.create(form).subscribe({
next: () => {
expect(pageAdminService.create).toHaveBeenCalledWith(form.value);
expect(toasterService.success).toHaveBeenCalledWith('AbpUi::SavedSuccessfully');
expect(router.navigate).toHaveBeenCalledWith(['/cms/pages']);
done();
},
error: err => done(err as any),
});
});
it('should call PageAdminService.create on createAsDraft', done => {
const form = createValidForm();
service.createAsDraft(form).subscribe({
next: () => {
expect(pageAdminService.create).toHaveBeenCalled();
done();
},
error: err => done(err as any),
});
});
it('should call PageAdminService.create on publish', done => {
const form = createValidForm();
service.publish(form).subscribe({
next: () => {
expect(pageAdminService.create).toHaveBeenCalled();
done();
},
error: err => done(err as any),
});
});
it('should throw when updating with invalid form or missing page', () => {
const form = createInvalidForm();
expect(() => service.update('id', form, {} as any)).toThrowError(
'Form is invalid or page is missing',
);
const validForm = createValidForm();
expect(() => service.update('id', validForm, null as any)).toThrowError(
'Form is invalid or page is missing',
);
});
it('should call PageAdminService.update on update', done => {
const form = createValidForm();
const page = { id: '1', name: 'test', isHomePage: false };
service.update('1', form, page).subscribe({
next: () => {
expect(pageAdminService.update).toHaveBeenCalledWith('1', expect.objectContaining(page));
done();
},
error: err => done(err as any),
});
});
it('should set status Draft on updateAsDraft', done => {
const form = createValidForm();
const page = { id: '1', name: 'test', isHomePage: false };
service.updateAsDraft('1', form, page).subscribe({
next: () => {
const arg = pageAdminService.update.mock.calls[0][1];
expect(arg).toMatchObject(page);
done();
},
error: err => done(err as any),
});
});
it('should set status Publish on updateAndPublish', done => {
const form = createValidForm();
const page = { id: '1', name: 'test', isHomePage: false };
service.updateAndPublish('1', form, page).subscribe({
next: () => {
const arg = pageAdminService.update.mock.calls[0][1];
expect(arg).toMatchObject(page);
done();
},
error: err => done(err as any),
});
});
});

16
npm/ng-packs/packages/cms-kit/src/test-setup.ts

@ -1 +1,15 @@
import 'jest-preset-angular/setup-jest';
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
// Optional: align with core package behavior and provide a stable window.location
Object.defineProperty(window, 'location', {
value: {
href: 'http://localhost:4200',
origin: 'http://localhost:4200',
pathname: '/',
search: '',
hash: '',
},
writable: true,
});

Loading…
Cancel
Save