Skip to content

Commit

Permalink
refactored index.js to return string
Browse files Browse the repository at this point in the history
  • Loading branch information
Kim, Allen committed Aug 27, 2023
1 parent 20744f9 commit 0082a4a
Show file tree
Hide file tree
Showing 14 changed files with 116 additions and 147 deletions.
15 changes: 1 addition & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,6 @@ You can override configuration by creating a file named as `ngentest.config.js`
}
```
* **includeMatch**: When ngentest runs with a directory, include only these files. e.g.,
```javascript
includeMatch: [/(component|directive|pipe|service).ts/],
````
* **excludeMatch**: When ngentest runs with a directory, exclude these files. e.g.,
```javascript
excludeMatch: [/.*module.ts$/]
```
### Full Example (https://github.com/allenhwkim/ngentest/blob/master/ngentest.config.js)
```javascript
module.exports = {
Expand Down Expand Up @@ -109,11 +100,7 @@ You can override configuration by creating a file named as `ngentest.config.js`
HttpClient: ['post() {};'],
TranslateService: ['translate() {};'],
EncryptionService: [],
},
// when ngentest runs with a directory, include only these files
includeMatch: [/(component|directive|pipe|service).ts/],
// when ngentest runs with a directory, exclude these files
excludeMatch: []
}
}
```
Expand Down
34 changes: 25 additions & 9 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,34 @@ if (argv.config) {
}

Util.DEBUG = argv.verbose;
Util.DEBUG && console.log(' *** config ***', config);
Util.DEBUG && console.debug(' *** config ***', config);
Util.FRAMEWORK = config.framework || argv.framework;

const tsFile = argv._[0]?.replace(/\.spec\.ts$/, '.ts');
if (!(tsFile && fs.existsSync(tsFile))) {
const tsFilePath = argv._[0]?.replace(/\.spec\.ts$/, '.ts');
if (!tsFilePath || !(tsFilePath && fs.existsSync(tsFilePath))) {
console.error('Error. invalid typescript file. e.g., Usage $0 <tsFile> [options]');
process.exit(1);
}

const options = Object.assign({}, config, {
spec: argv.spec,
force: argv.force,
verbose: config.verbose || argv.verbose,
});
ngentest(tsFile, options);
const options = Object.assign({}, config, {tsPath: tsFilePath});
const typescript = fs.readFileSync(path.resolve(tsFilePath), 'utf8');
const generated = ngentest(typescript, options).replace(/\r\n/g, '\n');

if (argv.spec) {
const specPath = path.resolve(tsFilePath.replace(/\.ts$/, '.spec.ts'));
const specFileExists = fs.existsSync(specPath);
if (specFileExists) {
if (argv.force) {
backupExistingFile(specPath, generated);
writeToSpecFile(specPath, generated);
} else {
console.error('\x1b[33m%s\x1b[0m', `ERROR!, ${specPath} already exists.`);
process.stdout.write(generated);
}
} else {
backupExistingFile(specPath, generated);
writeToSpecFile(specPath, generated);
}
} else {
process.stdout.write(generated);
}
10 changes: 5 additions & 5 deletions examples/example6.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Component63 } from '../comp63.component'
import { serviceThreeOptions, ServiceThree, Component64, Component65 } from './my-components';
import { Component66, Component67 } from './my-components';
import { ServiceFour } from './four.service';
import { serviceOne } from '../one.service';
import { serviceOne } from '../one.service';
import { Service61 } from '../sixty-one.service';
import { Service62 } from './sixty-two.service';
import { ServiceEleven } from '../../evleven.service';
Expand Down Expand Up @@ -51,7 +51,7 @@ export class Example6Component implements OnInit {
private sanitize: DomSanitizer,
private serviceFour: ServiceFour,
private service64: Service61,
private serviceOne:  serviceOne,
private serviceOne: serviceOne,
private service8: ServiceEight,
private router: Router,
private route: ActivatedRoute,
Expand Down Expand Up @@ -212,8 +212,8 @@ export class Example6Component implements OnInit {
);

this.serviceOne.getHhhPppp().subscribe(
      resp => this.hhhPppp =  resp,
      error => console.log('error: ',  error)
resp => this.hhhPppp = resp,
 error => console.error('error: ', error)
);

this.serviceFour.getmyConfig().subscribe(
Expand Down Expand Up @@ -353,7 +353,7 @@ export class Example6Component implements OnInit {
}
}, 500);
} else {
console.log('Error accessing iframe');
console.error('Error accessing iframe');
}
}

Expand Down
77 changes: 49 additions & 28 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,59 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path'); // eslint-disable-line
const ts = require('typescript');
const glob = require('glob');

const Util = require('./src/util.js');
const FuncTestGen = require('./src/func-test-gen.js');

const ComponentTestGen = require('./src/component/component-test-gen.js');
const DirectiveTestGen = require('./src/directive/directive-test-gen.js');
const InjectableTestGen = require('./src/injectable/injectable-test-gen.js');
const PipeTestGen = require('./src/pipe/pipe-test-gen.js');
const ClassTestGen = require('./src/class/class-test-gen.js');

module.exports = function(tsFile, config) {
/**
* Returns generated unit test contents from the given typescript
*
* @param {String} typescript
* @param {Object} config
* framework: 'jest' | 'karma',
* tsPath: string, // e.g. './my-component.component.ts'
* templates: {
* klass: string,
* component: string,
* directive: string,
* injectable: string,
* pipe: string
* },
* directives: [ // necessary directives used for a component test
* 'my-custom-directive'
* ],
* pipes: [ // necessary pipes used for a component test
* 'translate', 'phoneNumber', 'safeHtml'
* ],
* replacements: [ // when convert to JS, some codes need to be replaced to work
* { from: '^\\S+\\.define\\(.*\\);', to: ''} // some commands causes error
* ],
* // when constructor typs is as following, create a mock class with this properties
* // e.g. @Injectable() MockElementRef { nativeElement = {}; }
* providerMocks: {
* ElementRef: ['nativeElement = {};'],
* Router: ['navigate() {};'],
* Document: ['querySelector() {};'],
* HttpClient: ['post() {};'],
* TranslateService: ['translate() {};'],
* EncryptionService: [],
* }
* }
*/
module.exports = function(typescript, config) {
try {
const testGenerator = getTestGenerator(tsFile, config);
const typescript = fs.readFileSync(path.resolve(tsFile), 'utf8');
const angularType = Util.getAngularType(typescript).toLowerCase();
config.tsPath ||= `./my-${angularType}.${angularType}.ts`;
const testGenerator =
angularType === 'component' ? new ComponentTestGen(typescript, config) :
angularType === 'directive' ? new DirectiveTestGen(typescript, config) :
angularType === 'service' ? new InjectableTestGen(typescript, config) :
angularType === 'pipe' ? new PipeTestGen(typescript, config) :
new ClassTestGen(typescript, config);

const {ejsData} = testGenerator.getData();

ejsData.config = config;
Expand Down Expand Up @@ -64,12 +100,10 @@ module.exports = function(tsFile, config) {
}
});

const generated = testGenerator.getGenerated(ejsData);
if (generated) {
testGenerator.writeGenerated(generated, config);
}
const generated =
testGenerator.getGenerated(ejsData) + errors.join('\n');

errors.forEach( e => console.error(e) );
return generated;
} catch (e) {
console.error(e);
process.exit(1);
Expand Down Expand Up @@ -117,28 +151,15 @@ function getFuncMockData (Klass, funcName, funcType) {
};
funcTestGen.getExpressionStatements().forEach((expr, ndx) => {
const code = funcTestGen.classCode.substring(expr.start, expr.end);
Util.DEBUG && console.log(' *** EXPRESSION ***', ndx, code.replace(/\n+/g, '').replace(/\s+/g, ' '));
Util.DEBUG && console.debug(' *** EXPRESSION ***', ndx, code.replace(/\n+/g, '').replace(/\s+/g, ' '));
funcTestGen.setMockData(expr, funcMockData);
});

return funcMockData;
}

function getTestGenerator (tsPath, config) {
const typescript = fs.readFileSync(path.resolve(tsPath), 'utf8');
const angularType = Util.getAngularType(typescript).toLowerCase();
const testGenerator = /* eslint-disable */
angularType === 'component' ? new ComponentTestGen(tsPath, config) :
angularType === 'directive' ? new DirectiveTestGen(tsPath, config) :
angularType === 'service' ? new InjectableTestGen(tsPath, config) :
angularType === 'pipe' ? new PipeTestGen(tsPath, config) :
new ClassTestGen(tsPath, config); /* eslint-enable */
return testGenerator;
}

function getFuncTest(Klass, funcName, funcType, angularType) {
Util.DEBUG &&
console.log('\x1b[36m%s\x1b[0m', `\nPROCESSING #${funcName}`);
Util.DEBUG && console.debug('\x1b[36m%s\x1b[0m', `\nPROCESSING #${funcName}`);

const funcMockData = getFuncMockData(Klass, funcName, funcType);
const [allFuncMockJS, asserts] = Util.getFuncMockJS(funcMockData, angularType);
Expand Down
6 changes: 1 addition & 5 deletions ngentest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,5 @@ module.exports = {
HttpClient: ['post() {};'],
TranslateService: ['translate() {};'],
EncryptionService: [],
},
// when ngentest runs with a directory, include only these files
includeMatch: [/(component|directive|pipe|service).ts/],
// when ngentest runs with a directory, exclude these files
excludeMatch: []
}
}
9 changes: 9 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
// TODO: ongoing work to run this as an API
// POST /api/gentest
// Payload {
// typescript: 'xxxxxxxxxxxxxxxxxx',
// options: e.g. {framework: 'jest', templates: {......}, directives: {.....}}
// }
// Response: {
// output: string // e.g. '// @ts-nocheck\n import { async, ComponentFixture, TestBed } ...'
// }
const app = require('express')();
const { v4 } = require('uuid');

Expand Down
15 changes: 4 additions & 11 deletions src/class/class-test-gen.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ const fs = require('fs');
const CommonTestGen = require('../common-test-gen.js');

class ClassTestGen {
constructor (tsPath, config) {
if (tsPath && fs.existsSync(tsPath)) {
this.tsPath = tsPath;
this.config = config;
} else {
throw new Error(`Error. invalid typescript file. e.g., Usage $0 ${tsPath} [options]`);
}

this.tsPath = tsPath;
this.typescript = fs.readFileSync(path.resolve(tsPath), 'utf8');
constructor (typescript, config) {
this.config = config;
this.tsPath = config.tsPath;
this.typescript = typescript;
this.template = config.templates.klass;

this.klass = CommonTestGen.getKlass.bind(this)();
Expand All @@ -26,7 +20,6 @@ class ClassTestGen {

this.getProviderMocks = CommonTestGen.getProviderMocks.bind(this);
this.getGenerated = CommonTestGen.getGenerated.bind(this);
this.writeGenerated = CommonTestGen.writeGenerated.bind(this);
}

getData () {
Expand Down
31 changes: 3 additions & 28 deletions src/common-test-gen.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ function getGenerated (ejsData) {

function writeToSpecFile (specPath, generated) {
fs.writeFileSync(specPath, generated);
console.log('Generated unit test to', specPath);
console.info('Generated unit test to', specPath);
}

function backupExistingFile (specPath, generated) {
Expand All @@ -304,35 +304,11 @@ function backupExistingFile (specPath, generated) {
const backupContents = fs.readFileSync(specPath, 'utf8');
if (backupContents !== generated) {
fs.writeFileSync(`${specPath}.${backupTime}`, backupContents, 'utf8'); // write backup
console.log('Backup the exisiting file to', `${specPath}.${backupTime}`);
console.info('Backup the exisiting file to', `${specPath}.${backupTime}`);
}
}
};

function writeGenerated (generated, options) {
const specPath = path.resolve(this.tsPath.replace(/\.ts$/, '.spec.ts'));
generated = generated.replace(/\r\n/g, '\n');

const specFileExists = fs.existsSync(specPath);

if (options.spec) {
if (specFileExists) {
if (options.force) {
backupExistingFile(specPath, generated);
writeToSpecFile(specPath, generated);
} else {
console.error('\x1b[33m%s\x1b[0m', `ERROR!, ${specPath} already exists.`);
process.stdout.write(generated);
}
} else {
backupExistingFile(specPath, generated);
writeToSpecFile(specPath, generated);
}
} else {
process.stdout.write(generated);
}
}

const CommonGenFunctions = {
getKlass,
getImports,
Expand All @@ -349,8 +325,7 @@ const CommonGenFunctions = {
getComponentProviderMocks,
getDirectiveSelector,

getGenerated,
writeGenerated
getGenerated
};

module.exports = CommonGenFunctions;
15 changes: 4 additions & 11 deletions src/component/component-test-gen.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ const fs = require('fs');
const CommonTestGen = require('../common-test-gen.js');

class ComponentTestGen {
constructor (tsPath, config) {
if (tsPath && fs.existsSync(tsPath)) {
this.tsPath = tsPath;
this.config = config;
} else {
throw new Error(`Error. invalid typescript file. e.g., Usage $0 ${tsPath} [options]`);
}

this.tsPath = tsPath;
this.typescript = fs.readFileSync(path.resolve(tsPath), 'utf8');
constructor (typescript, config) {
this.config = config;
this.typescript = typescript;
this.tsPath = config.tsPath;
this.template = config.templates.component;

this.klass = CommonTestGen.getKlass.bind(this)();
Expand All @@ -26,7 +20,6 @@ class ComponentTestGen {

this.getProviderMocks = CommonTestGen.getProviderMocks.bind(this);
this.getGenerated = CommonTestGen.getGenerated.bind(this);
this.writeGenerated = CommonTestGen.writeGenerated.bind(this);
}

getData () {
Expand Down
15 changes: 4 additions & 11 deletions src/directive/directive-test-gen.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ const fs = require('fs');
const CommonTestGen = require('../common-test-gen.js');

class DirectiveTestGen {
constructor (tsPath, config) {
if (tsPath && fs.existsSync(tsPath)) {
this.tsPath = tsPath;
this.config = config;
} else {
throw new Error(`Error. invalid typescript file. e.g., Usage $0 ${tsPath} [options]`);
}

this.tsPath = tsPath;
this.typescript = fs.readFileSync(path.resolve(tsPath), 'utf8');
constructor (typescript, config) {
this.config = config;
this.typescript = typescript;
this.tsPath = config.tsPath;
this.template = config.templates.directive;

this.klass = CommonTestGen.getKlass.bind(this)();
Expand All @@ -26,7 +20,6 @@ class DirectiveTestGen {

this.getProviderMocks = CommonTestGen.getProviderMocks.bind(this);
this.getGenerated = CommonTestGen.getGenerated.bind(this);
this.writeGenerated = CommonTestGen.writeGenerated.bind(this);
}

getData () {
Expand Down
Loading

0 comments on commit 0082a4a

Please sign in to comment.