UNPKG

specgen

Version:

Angular - Jasmine Unit Test Spec file Generator

150 lines (142 loc) 6.5 kB
const path = require('path'); const {getImportLib, reIndent} = require('./lib/util.js'); const windowObjects = require('./lib/window-objects.js'); module.exports = function getDirectiveData(tsParsed, filePath, angularType) { let result = { className: tsParsed.name, imports: { '@angular/core': ['Component', 'Directive'], [`./${path.basename(filePath)}`.replace(/.ts$/, '')]: [tsParsed.name] // the directive itself }, inputs: {attributes: [], properties: []}, outputs: {attributes: [], properties: []}, providers: {}, mocks: {}, functionTests: {} }; // // Iterate properties // . if @Input, build input attributes and input properties // . if @Outpu, build output attributes and output properties // for (var key in tsParsed.properties) { const prop = tsParsed.properties[key]; if (prop.body.match(/@Input\(/)) { const attrName = (prop.body.match(/@Input\(['"](.*?)['"]\)/) || [])[1]; result.inputs.attributes.push(`[${attrName || key}]="${key}"`); result.inputs.properties.push(`${key}: ${prop.type};`); } else if (prop.body.match(/@Output\(/)) { const attrName = (prop.body.match(/@Output\(['"](.*?)['"]\)/) || [])[1]; const funcName = `on${key.replace(/^[a-z]/, x => x.toUpperCase())}`; result.outputs.attributes.push(`(${attrName || key})="${funcName}($event)"`); result.outputs.properties.push(`${funcName}(event): void { /* */ }`); } } // // Iterate constructor parameters // . if this pattern, `@Inject(PLATFORM_ID)`, // . add Inject, PLATFORM_ID to result.imports // . create provider with value // . if type is found at tsParsed.imports, // . add the type to result.imports // . if type is ElementRef, // . create a mock class // . add to result.providers with mock // . if source starts from './', which is a user-defined injectable // . create a mock class // . add te result.providers with mock // . otherwise, add to result.providers // (tsParsed.constructor.parameters || []).forEach(param => { // name, type, body // handle @Inject(XXXXXXXXX) const importLib = getImportLib(tsParsed.imports, param.type); const matches = param.body.match(/@Inject\(([A-Z0-9_]+)\)/); if (matches) { let className = matches[1] let lib1 = getImportLib(tsParsed.imports, 'Inject'); let lib2 = getImportLib(tsParsed.imports, className); result.imports[lib1] = result.imports[lib1] || []; result.imports[lib2] = result.imports[lib2] || []; result.imports[lib1].push('Inject'); result.imports[lib2].push(className); result.providers[matches[1]] = `{provide: ${className},useValue: 'browser'}`; } else if (param.type == 'ElementRef') { result.imports[importLib] = result.imports[importLib] || []; result.imports[importLib].push(param.type); result.mocks[param.type] = reIndent(` export class Mock${param.type} extends ElementRef { // constructor() { super(undefined); } nativeElement: any = {}; constructor(nativeElementValue) { super(null); this.nativeElement = nativeElementValue; } }`); result.providers[param.type] = `{provide: ${param.type}, useValue: Mock${param.type}}`; } else if (param.type === 'Router') { result.imports[importLib] = result.imports[importLib] || []; result.imports[importLib].push(param.type); result.mocks[param.type] = reIndent(` const Mock${param.type} = jasmine.createSpyObj('Router', ['navigateByUrl']); `); result.providers[param.type] = `{provide: ${param.type}, useValue: Mock${param.type}}`; } else if (param.type === 'ConfirmDialogService') { result.imports[importLib] = result.imports[importLib] || []; result.imports[importLib].push(param.type); result.mocks[param.type] = reIndent(` export class Mock${param.type} { confirm(message, key, ok, cancel) { return of(true); } } `); result.providers[param.type] = `{provide: ${param.type}, useClass: Mock${param.type}}`; } else if (importLib.match(/^[\.]+/)) { // starts from . or .., which is a user-defined provider result.imports[importLib] = result.imports[importLib] || []; result.imports[importLib].push(param.type); result.mocks[param.type] = reIndent(` export class Mock${param.type} { } `); result.providers[param.type] = `{provide: ${param.type}, useClass: Mock${param.type}}`; } else { result.imports[importLib] = result.imports[importLib] || []; result.imports[importLib].push(param.type); result.providers[param.type] = `${param.type}`; } }); // // Iterate properties // . if property type is a windows type // then create mock with (windows<any>) with the value of `jest.fn()`` // for (var key in tsParsed.properties) { let prop = tsParsed.properties[key]; let basicTypes = ['Object', 'boolean', 'number', 'string', 'Array', 'any', 'void', 'null', 'undefined', 'never']; let importLib = getImportLib(tsParsed.imports, prop.type); if (importLib || basicTypes.includes(prop.type)) { continue; } else if (windowObjects.includes(prop.type)) { result.mocks[prop.type] = reIndent(` (<any>window).${prop.type} = jest.fn(); `); } } // // Iterate methods // . Javascript to call the function with parameter; // for (var key in tsParsed.methods) { let method = tsParsed.methods[key]; let parameters = method.parameters.map(el => el.name).join(', '); let js = `${angularType.toLowerCase()}.${key}(${parameters})`; (method.type !== 'void') && (js = `const result = ${js}`); const testName = `should run #${key}()`; result.functionTests[testName] = reIndent(` it('${testName}', async () => { // ${js}; }); `, ' '); } return result; }