Skip to content

Commit 828ed07

Browse files
In generator-aspnetcore-spa, offer user the choice of whether to include tests
1 parent a734a31 commit 828ed07

File tree

1 file changed

+104
-22
lines changed
  • templates/package-builder/src/yeoman/app

1 file changed

+104
-22
lines changed

templates/package-builder/src/yeoman/app/index.ts

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import * as yeoman from 'yeoman-generator';
34
import * as uuid from 'node-uuid';
@@ -9,15 +10,35 @@ const yosay = require('yosay');
910
const toPascalCase = require('to-pascal-case');
1011
const isWindows = /^win/.test(process.platform);
1112

13+
// Paths matching these regexes will only be included if the user wants tests
14+
const testSpecificPaths = [
15+
/\.spec.ts$/, // Files ending '.spec.ts'
16+
/(^|\/|\\)test($|\/|\\)/ // Files under any directory called 'test'
17+
];
18+
19+
// These NPM dependencies will only be included if the user wants tests
20+
const testSpecificNpmPackages = [
21+
"@types/chai",
22+
"@types/jasmine",
23+
"chai",
24+
"jasmine-core",
25+
"karma",
26+
"karma-chai",
27+
"karma-chrome-launcher",
28+
"karma-cli",
29+
"karma-jasmine",
30+
"karma-webpack"
31+
];
32+
1233
type YeomanPrompt = (opt: yeoman.IPromptOptions | yeoman.IPromptOptions[], callback: (answers: any) => void) => void;
1334
const optionOrPrompt: YeomanPrompt = require('yeoman-option-or-prompt');
1435

1536
const templates = [
16-
{ value: 'angular-2', name: 'Angular 2' },
17-
{ value: 'aurelia', name: 'Aurelia' },
18-
{ value: 'knockout', name: 'Knockout' },
19-
{ value: 'react', name: 'React' },
20-
{ value: 'react-redux', name: 'React with Redux' }
37+
{ value: 'angular-2', name: 'Angular 2', tests: true },
38+
{ value: 'aurelia', name: 'Aurelia', tests: false },
39+
{ value: 'knockout', name: 'Knockout', tests: false },
40+
{ value: 'react', name: 'React', tests: false },
41+
{ value: 'react-redux', name: 'React with Redux', tests: false }
2142
];
2243

2344
class MyGenerator extends yeoman.Base {
@@ -35,24 +56,40 @@ class MyGenerator extends yeoman.Base {
3556
}
3657

3758
prompting() {
38-
const done = this.async();
39-
4059
this.option('projectguid');
60+
61+
const done = this.async();
4162
this._optionOrPrompt([{
4263
type: 'list',
4364
name: 'framework',
4465
message: 'Framework',
4566
choices: templates
46-
}, {
47-
type: 'input',
48-
name: 'name',
49-
message: 'Your project name',
50-
default: this.appname
51-
}], answers => {
52-
this._answers = answers;
53-
this._answers.namePascalCase = toPascalCase(answers.name);
54-
this._answers.projectGuid = this.options['projectguid'] || uuid.v4();
55-
done();
67+
}], frameworkAnswer => {
68+
const frameworkChoice = templates.filter(t => t.value === frameworkAnswer.framework)[0];
69+
const furtherQuestions = [{
70+
type: 'input',
71+
name: 'name',
72+
message: 'Your project name',
73+
default: this.appname
74+
}];
75+
76+
if (frameworkChoice.tests) {
77+
furtherQuestions.unshift({
78+
type: 'confirm',
79+
name: 'tests',
80+
message: 'Do you want to include unit tests?',
81+
default: true as any
82+
});
83+
}
84+
85+
this._optionOrPrompt(furtherQuestions, answers => {
86+
answers.framework = frameworkAnswer.framework;
87+
this._answers = answers;
88+
this._answers.framework = frameworkAnswer.framework;
89+
this._answers.namePascalCase = toPascalCase(answers.name);
90+
this._answers.projectGuid = this.options['projectguid'] || uuid.v4();
91+
done();
92+
});
5693
});
5794
}
5895

@@ -79,11 +116,27 @@ class MyGenerator extends yeoman.Base {
79116
outputFn = path.join(path.dirname(fn), 'node_modules', '_placeholder.txt');
80117
}
81118

82-
this.fs.copyTpl(
83-
path.join(templateRoot, fn),
84-
this.destinationPath(outputFn),
85-
this._answers
86-
);
119+
// Exclude test-specific files (unless the user has said they want tests)
120+
const isTestSpecificFile = testSpecificPaths.some(regex => regex.test(outputFn));
121+
if (this._answers.tests || !isTestSpecificFile) {
122+
const inputFullPath = path.join(templateRoot, fn);
123+
if (path.basename(fn) === 'package.json') {
124+
// Special handling for package.json, because we rewrite it dynamically
125+
this.fs.writeJSON(
126+
this.destinationPath(outputFn),
127+
rewritePackageJson(JSON.parse(fs.readFileSync(inputFullPath, 'utf8')), this._answers.tests),
128+
/* replacer */ null,
129+
/* space */ 2
130+
);
131+
} else {
132+
// Regular file - copy as template
133+
this.fs.copyTpl(
134+
inputFullPath,
135+
this.destinationPath(outputFn),
136+
this._answers
137+
);
138+
}
139+
}
87140
});
88141
}
89142

@@ -125,5 +178,34 @@ function assertNpmVersionIsAtLeast(minVersion: string) {
125178
}
126179
}
127180

181+
function rewritePackageJson(contents, includeTests) {
182+
if (!includeTests) {
183+
// Delete any test-specific packages from dependencies and devDependencies
184+
['dependencies', 'devDependencies'].forEach(dependencyListName => {
185+
var packageList = contents[dependencyListName];
186+
if (packageList) {
187+
testSpecificNpmPackages.forEach(packageToRemove => {
188+
delete packageList[packageToRemove];
189+
});
190+
191+
if (Object.getOwnPropertyNames(packageList).length === 0) {
192+
delete contents[dependencyListName];
193+
}
194+
}
195+
});
196+
197+
// Delete any script called 'test'
198+
const scripts = contents.scripts;
199+
if (scripts.test) {
200+
delete scripts.test;
201+
if (Object.getOwnPropertyNames(scripts).length === 0) {
202+
delete contents.scripts;
203+
}
204+
}
205+
}
206+
207+
return contents;
208+
}
209+
128210
declare var module: any;
129211
(module).exports = MyGenerator;

0 commit comments

Comments
 (0)