feat: add .spec.ts generation for models, mappers, repositories and use-cases
Add 4 new Mustache templates for generating unit test specs: - model-entity.spec.mustache: tests instantiation, property setting, mock builder - mapper.spec.mustache: tests per-property DTO→Entity mapping, instanceof, all fields - api.repository.impl.spec.mustache: tests HTTP method, response mapping, error propagation - api.use-cases.impl.spec.mustache: tests repository delegation, observable forwarding Generator changes: - Add uppercaseHttpMethod to TagOperation for spec HTTP assertions - Add testValue to TagOperationParam for auto-generated test arguments - Add resolveTestParamValue utility for primitive/complex type test literals - Add specs counter to GeneratedCount and GenerationReport - Wire 4 new renderTemplate calls in schema and tag loops - Update report generator to count .spec.ts files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
97
templates/api.repository.impl.spec.mustache
Normal file
97
templates/api.repository.impl.spec.mustache
Normal file
@@ -0,0 +1,97 @@
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { {{classname}}RepositoryImpl } from './{{classFilename}}.repository.impl';
|
||||
{{#returnImports}}
|
||||
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
||||
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
||||
{{/returnImports}}
|
||||
|
||||
describe('{{classname}}RepositoryImpl', () => {
|
||||
let repository: {{classname}}RepositoryImpl;
|
||||
let httpMock: HttpTestingController;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [HttpClientTestingModule],
|
||||
providers: [{{classname}}RepositoryImpl]
|
||||
});
|
||||
|
||||
repository = TestBed.inject({{classname}}RepositoryImpl);
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
httpMock.verify();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(repository).toBeTruthy();
|
||||
});
|
||||
|
||||
{{#operation}}
|
||||
describe('{{nickname}}', () => {
|
||||
it('should perform a {{uppercaseHttpMethod}} request', () => {
|
||||
repository.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe();
|
||||
|
||||
const req = httpMock.expectOne((r) => r.method === '{{uppercaseHttpMethod}}');
|
||||
expect(req.request.method).toBe('{{uppercaseHttpMethod}}');
|
||||
{{#isListContainer}}
|
||||
req.flush({ items: [mock{{returnBaseType}}Dto()] });
|
||||
{{/isListContainer}}
|
||||
{{^isListContainer}}
|
||||
{{#returnType}}
|
||||
req.flush(mock{{returnBaseType}}Dto());
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
req.flush(null);
|
||||
{{/returnType}}
|
||||
{{/isListContainer}}
|
||||
});
|
||||
|
||||
{{#returnType}}
|
||||
it('should map the response to the domain model', () => {
|
||||
const dto = mock{{returnBaseType}}Dto();
|
||||
const expectedModel = mock{{returnBaseType}}Model();
|
||||
|
||||
{{#isListContainer}}
|
||||
repository.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe((result) => {
|
||||
expect(result).toBeTruthy();
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
httpMock.expectOne((r) => r.method === '{{uppercaseHttpMethod}}').flush({ items: [dto] });
|
||||
{{/isListContainer}}
|
||||
{{^isListContainer}}
|
||||
repository.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe((result) => {
|
||||
expect(result).toEqual(expectedModel);
|
||||
});
|
||||
|
||||
httpMock.expectOne((r) => r.method === '{{uppercaseHttpMethod}}').flush(dto);
|
||||
{{/isListContainer}}
|
||||
});
|
||||
|
||||
{{/returnType}}
|
||||
it('should propagate HTTP errors', (done) => {
|
||||
repository.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe({
|
||||
error: (err) => {
|
||||
expect(err.status).toBe(500);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
httpMock
|
||||
.expectOne((r) => r.method === '{{uppercaseHttpMethod}}')
|
||||
.flush('Internal Server Error', { status: 500, statusText: 'Internal Server Error' });
|
||||
});
|
||||
});
|
||||
|
||||
{{/operation}}
|
||||
});
|
||||
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
91
templates/api.use-cases.impl.spec.mustache
Normal file
91
templates/api.use-cases.impl.spec.mustache
Normal file
@@ -0,0 +1,91 @@
|
||||
{{#apiInfo}}
|
||||
{{#apis}}
|
||||
{{#operations}}
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { {{classname}}UseCasesImpl } from './{{classFilename}}.use-cases.impl';
|
||||
|
||||
import { {{constantName}}_REPOSITORY, {{classname}}Repository } from '@/domain/repositories/{{classFilename}}.repository.contract';
|
||||
{{#returnImports}}
|
||||
import { mock{{classname}}Model } from '@/entities/models/{{classFilename}}.model.mock';
|
||||
{{/returnImports}}
|
||||
|
||||
describe('{{classname}}UseCasesImpl', () => {
|
||||
let useCase: {{classname}}UseCasesImpl;
|
||||
let mockRepository: jasmine.SpyObj<{{classname}}Repository>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRepository = jasmine.createSpyObj('{{classname}}Repository', [{{#operation}}'{{nickname}}', {{/operation}}]);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{{classname}}UseCasesImpl,
|
||||
{ provide: {{constantName}}_REPOSITORY, useValue: mockRepository }
|
||||
]
|
||||
});
|
||||
|
||||
useCase = TestBed.inject({{classname}}UseCasesImpl);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(useCase).toBeTruthy();
|
||||
});
|
||||
|
||||
{{#operation}}
|
||||
describe('{{nickname}}', () => {
|
||||
it('should delegate to the repository', () => {
|
||||
{{#isListContainer}}
|
||||
mockRepository.{{nickname}}.and.returnValue(of([mock{{returnBaseType}}Model()]));
|
||||
{{/isListContainer}}
|
||||
{{^isListContainer}}
|
||||
{{#returnBaseType}}
|
||||
mockRepository.{{nickname}}.and.returnValue(of(mock{{returnBaseType}}Model()));
|
||||
{{/returnBaseType}}
|
||||
{{^returnBaseType}}
|
||||
mockRepository.{{nickname}}.and.returnValue(of(undefined));
|
||||
{{/returnBaseType}}
|
||||
{{/isListContainer}}
|
||||
|
||||
useCase.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}});
|
||||
|
||||
expect(mockRepository.{{nickname}}).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return the observable from the repository', (done) => {
|
||||
{{#isListContainer}}
|
||||
const expected = [mock{{returnBaseType}}Model()];
|
||||
mockRepository.{{nickname}}.and.returnValue(of(expected));
|
||||
|
||||
useCase.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe((result) => {
|
||||
expect(result).toEqual(expected);
|
||||
done();
|
||||
});
|
||||
{{/isListContainer}}
|
||||
{{^isListContainer}}
|
||||
{{#returnBaseType}}
|
||||
const expected = mock{{returnBaseType}}Model();
|
||||
mockRepository.{{nickname}}.and.returnValue(of(expected));
|
||||
|
||||
useCase.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe((result) => {
|
||||
expect(result).toEqual(expected);
|
||||
done();
|
||||
});
|
||||
{{/returnBaseType}}
|
||||
{{^returnBaseType}}
|
||||
mockRepository.{{nickname}}.and.returnValue(of(undefined));
|
||||
|
||||
useCase.{{nickname}}({{#allParams}}{{{testValue}}}{{^-last}}, {{/-last}}{{/allParams}}).subscribe({
|
||||
complete: () => done()
|
||||
});
|
||||
{{/returnBaseType}}
|
||||
{{/isListContainer}}
|
||||
});
|
||||
});
|
||||
|
||||
{{/operation}}
|
||||
});
|
||||
|
||||
{{/operations}}
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
39
templates/mapper.spec.mustache
Normal file
39
templates/mapper.spec.mustache
Normal file
@@ -0,0 +1,39 @@
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
import { {{classVarName}}Mapper } from './{{classFilename}}.mapper';
|
||||
|
||||
import { mock{{classname}}Dto } from '@/dtos/{{classFilename}}.dto.mock';
|
||||
import { {{classname}} } from '@/entities/models/{{classFilename}}.model';
|
||||
|
||||
describe('{{classVarName}}Mapper', () => {
|
||||
{{#vars}}
|
||||
it('should map {{name}} from DTO to model', () => {
|
||||
const dto = mock{{classname}}Dto();
|
||||
|
||||
const result = {{classVarName}}Mapper(dto);
|
||||
|
||||
expect(result.{{name}}).toBe(dto.{{name}});
|
||||
});
|
||||
|
||||
{{/vars}}
|
||||
it('should return an instance of {{classname}}', () => {
|
||||
const dto = mock{{classname}}Dto();
|
||||
|
||||
const result = {{classVarName}}Mapper(dto);
|
||||
|
||||
expect(result).toBeInstanceOf({{classname}});
|
||||
});
|
||||
|
||||
it('should map all fields correctly from a complete DTO', () => {
|
||||
const dto = mock{{classname}}Dto();
|
||||
|
||||
const result = {{classVarName}}Mapper(dto);
|
||||
|
||||
{{#vars}}
|
||||
expect(result.{{name}}).toBe(dto.{{name}});
|
||||
{{/vars}}
|
||||
});
|
||||
});
|
||||
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
34
templates/model-entity.spec.mustache
Normal file
34
templates/model-entity.spec.mustache
Normal file
@@ -0,0 +1,34 @@
|
||||
{{#models}}
|
||||
{{#model}}
|
||||
import { {{classname}} } from './{{classFilename}}.model';
|
||||
import { mock{{classname}}Model } from './{{classFilename}}.model.mock';
|
||||
|
||||
describe('{{classname}}', () => {
|
||||
it('should create an instance', () => {
|
||||
const model = new {{classname}}();
|
||||
|
||||
expect(model).toBeInstanceOf({{classname}});
|
||||
});
|
||||
|
||||
{{#vars}}
|
||||
it('should allow setting {{name}}', () => {
|
||||
const model = new {{classname}}();
|
||||
const expected = mock{{classname}}Model();
|
||||
model.{{name}} = expected.{{name}};
|
||||
|
||||
expect(model.{{name}}).toBe(expected.{{name}});
|
||||
});
|
||||
|
||||
{{/vars}}
|
||||
it('should build a valid model from mock', () => {
|
||||
const model = mock{{classname}}Model();
|
||||
|
||||
expect(model).toBeInstanceOf({{classname}});
|
||||
{{#vars}}
|
||||
expect(model.{{name}}).toBeDefined();
|
||||
{{/vars}}
|
||||
});
|
||||
});
|
||||
|
||||
{{/model}}
|
||||
{{/models}}
|
||||
Reference in New Issue
Block a user