Skip to content

Commit ae7f286

Browse files
feat: unit-test-runner 3.0 with optional coverage report handling (#5610)
* feat: unit-test-runner 3.0 with optional coverage report handling * refactor: cleanup logging * fix: spec regex for js projects Co-authored-by: Igor Randjelovic <rigor789@gmail.com>
1 parent 676630b commit ae7f286

File tree

10 files changed

+7182
-7379
lines changed

10 files changed

+7182
-7379
lines changed

config/test-dependencies.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
[
2+
{
3+
"name": "@jsdevtools/coverage-istanbul-loader"
4+
},
25
{
36
"name": "karma"
47
},
58
{
6-
"name": "karma-nativescript-launcher"
9+
"name": "karma-coverage"
710
},
811
{
9-
"name": "karma-webpack",
10-
"excludedPeerDependencies": ["webpack"]
12+
"name": "karma-nativescript-launcher"
1113
},
1214
{
1315
"name": "mocha",
@@ -48,5 +50,8 @@
4850
"name": "@types/qunit",
4951
"framework": "qunit",
5052
"projectType": ".ts"
53+
},
54+
{
55+
"name": "nyc"
5156
}
5257
]

lib/commands/test-init.ts

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class TestInitCommand implements ICommand {
134134
this.$projectData
135135
);
136136

137+
this.$logger.clearScreen();
138+
139+
const bufferedLogs = [];
140+
137141
const testsDir = path.join(this.$projectData.appDirectoryPath, "tests");
138142
const projectTestsDir = path.relative(
139143
this.$projectData.projectDir,
@@ -145,8 +149,13 @@ class TestInitCommand implements ICommand {
145149
);
146150
let shouldCreateSampleTests = true;
147151
if (this.$fs.exists(testsDir)) {
148-
this.$logger.info(
149-
`${projectTestsDir} directory already exists, will not create an example test project.`
152+
const specFilenamePattern = `<filename>.spec${projectFilesExtension}`;
153+
bufferedLogs.push(
154+
[
155+
`Note: The "${projectTestsDir}" directory already exists, will not create example tests in the project.`,
156+
`You may create "${specFilenamePattern}" files anywhere you'd like.`,
157+
"",
158+
].join("\n").yellow
150159
);
151160
shouldCreateSampleTests = false;
152161
}
@@ -172,23 +181,76 @@ class TestInitCommand implements ICommand {
172181
const exampleFilePath = this.$resources.resolvePath(
173182
`test/example.${frameworkToInstall}${projectFilesExtension}`
174183
);
184+
const targetExampleTestPath = path.join(
185+
testsDir,
186+
`example.spec${projectFilesExtension}`
187+
);
175188

176189
if (shouldCreateSampleTests && this.$fs.exists(exampleFilePath)) {
177-
this.$fs.copyFile(
178-
exampleFilePath,
179-
path.join(testsDir, `example${projectFilesExtension}`)
190+
this.$fs.copyFile(exampleFilePath, targetExampleTestPath);
191+
const targetExampleTestRelativePath = path.relative(
192+
projectDir,
193+
targetExampleTestPath
180194
);
181-
this.$logger.info(
182-
`\nExample test file created in ${projectTestsDir}`.yellow
195+
bufferedLogs.push(
196+
`Added example test: ${targetExampleTestRelativePath.yellow}`
183197
);
184-
} else {
185-
this.$logger.info(
186-
`\nPlace your test files under ${projectTestsDir}`.yellow
198+
}
199+
200+
// test main entry
201+
const testMainResourcesPath = this.$resources.resolvePath(
202+
`test/test-main${projectFilesExtension}`
203+
);
204+
const testMainPath = path.join(
205+
this.$projectData.appDirectoryPath,
206+
`test${projectFilesExtension}`
207+
);
208+
209+
if (!this.$fs.exists(testMainPath)) {
210+
this.$fs.copyFile(testMainResourcesPath, testMainPath);
211+
const testMainRelativePath = path.relative(projectDir, testMainPath);
212+
bufferedLogs.push(
213+
`Main test entrypoint created: ${testMainRelativePath.yellow}`
187214
);
188215
}
189216

217+
const testTsConfigTemplate = this.$resources.readText(
218+
"test/tsconfig.spec.json"
219+
);
220+
const testTsConfig = _.template(testTsConfigTemplate)({
221+
basePath: this.$projectData.getAppDirectoryRelativePath(),
222+
});
223+
224+
this.$fs.writeFile(
225+
path.join(projectDir, "tsconfig.spec.json"),
226+
testTsConfig
227+
);
228+
bufferedLogs.push(`Added/replaced ${"tsconfig.spec.json".yellow}`);
229+
230+
const greyDollarSign = "$".grey;
190231
this.$logger.info(
191-
'Run your tests using the "$ ns test <platform>" command.'.yellow
232+
[
233+
[
234+
`Tests using`.green,
235+
frameworkToInstall.cyan,
236+
`were successfully initialized.`.green,
237+
].join(" "),
238+
"",
239+
...bufferedLogs,
240+
"",
241+
`Note: @nativescript/unit-test-runner was included in "dependencies" as a convenience to automatically adjust your app's Info.plist on iOS and AndroidManifest.xml on Android to ensure the socket connects properly.`
242+
.yellow,
243+
"",
244+
`For production you may want to move to "devDependencies" and manage the settings yourself.`
245+
.yellow,
246+
"",
247+
"",
248+
`You can now run your tests:`,
249+
"",
250+
` ${greyDollarSign} ${"ns test ios".green}`,
251+
` ${greyDollarSign} ${"ns test android".green}`,
252+
"",
253+
].join("\n")
192254
);
193255
}
194256
}

lib/controllers/migrate-controller.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export class MigrateController
235235
{
236236
packageName: "@nativescript/unit-test-runner",
237237
minVersion: "1.0.0",
238-
desiredVersion: "~2.0.5",
238+
desiredVersion: "~3.0.0",
239239
async shouldMigrateAction(
240240
dependency: IMigrationDependency,
241241
projectData: IProjectData,
@@ -1167,10 +1167,7 @@ export class MigrateController
11671167
const dependencies: IMigrationDependency[] = [
11681168
{
11691169
packageName: "karma-webpack",
1170-
minVersion: "3.0.5",
1171-
desiredVersion: "~5.0.0",
1172-
isDev: true,
1173-
shouldAddIfMissing: true,
1170+
shouldRemove: true,
11741171
},
11751172
{
11761173
packageName: "karma-jasmine",

lib/services/test-execution-service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ export class TestExecutionService implements ITestExecutionService {
190190
path: this.$options.path,
191191
tns: process.argv[1],
192192
node: process.execPath,
193+
env: this.$options.env,
193194
options: {
194195
debugTransport: this.$options.debugTransport,
195196
debugBrk: this.$options.debugBrk,

package-lock.json

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/test/karma.conf.js

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
const filePatterns = [${ testFiles }];
21
module.exports = function (config) {
32
const options = {
43

@@ -11,8 +10,8 @@ module.exports = function (config) {
1110
frameworks: [${ frameworks }],
1211

1312

14-
// list of files / patterns to load in the browser
15-
files: filePatterns,
13+
// list of files / patterns to load in the browser. Leave empty for webpack projects
14+
// files: [],
1615

1716

1817
// list of files to exclude
@@ -31,6 +30,16 @@ module.exports = function (config) {
3130
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
3231
reporters: ['progress'],
3332

33+
// configure optional coverage, enable via --env.codeCoverage
34+
coverageReporter: {
35+
dir: require('path').join(__dirname, './coverage'),
36+
subdir: '.',
37+
reporters: [
38+
{ type: 'html' },
39+
{ type: 'text-summary' }
40+
]
41+
},
42+
3443

3544
// web server port
3645
port: 9876,
@@ -74,41 +83,9 @@ module.exports = function (config) {
7483
singleRun: false
7584
};
7685

77-
setWebpackPreprocessor(config, options);
78-
setWebpack(config, options);
79-
80-
config.set(options);
81-
}
82-
module.exports.filePatterns = filePatterns;
83-
// You can also use RegEx if you'd like:
84-
// module.exports.filesRegex = /\.\/tests\/.*\.ts$/;
85-
86-
function setWebpackPreprocessor(config, options) {
87-
if (config && config.bundle) {
88-
if (!options.preprocessors) {
89-
options.preprocessors = {};
90-
}
91-
92-
options.files.forEach(file => {
93-
if (!options.preprocessors[file]) {
94-
options.preprocessors[file] = [];
95-
}
96-
options.preprocessors[file].push('webpack');
97-
});
86+
if(config._NS && config._NS.env && config._NS.env.codeCoverage) {
87+
options.reporters = (options.reporters || []).concat(['coverage']);
9888
}
99-
}
10089

101-
function setWebpack(config, options) {
102-
if (config && config.bundle) {
103-
const env = {};
104-
env[config.platform] = true;
105-
env.sourceMap = config.debugBrk;
106-
env.appPath = config.appPath;
107-
env.karmaWebpack = true;
108-
options.webpack = require('./webpack.config')(env);
109-
delete options.webpack.entry;
110-
delete options.webpack.output.libraryTarget;
111-
const invalidPluginsForUnitTesting = ["GenerateBundleStarterPlugin", "GenerateNativeScriptEntryPointsPlugin"];
112-
options.webpack.plugins = options.webpack.plugins.filter(p => !invalidPluginsForUnitTesting.includes(p.constructor.name));
113-
}
90+
config.set(options);
11491
}

resources/test/test-main.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { runTestApp } from "@nativescript/unit-test-runner";
2+
// import other polyfills here
3+
4+
runTestApp({
5+
runTests: () => {
6+
const tests = require.context("./", true, /\.spec\.js$/);
7+
tests.keys().map(tests);
8+
},
9+
});

resources/test/test-main.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { runTestApp } from "@nativescript/unit-test-runner";
2+
// import other polyfills here
3+
4+
declare let require: any;
5+
6+
runTestApp({
7+
runTests: () => {
8+
const tests = require.context("./", true, /\.spec\.ts$/);
9+
tests.keys().map(tests);
10+
},
11+
});

resources/test/tsconfig.spec.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"sourceMap": true
5+
},
6+
"files": ["${ basePath }/test.ts"],
7+
"include": ["${ basePath }/**/*.spec.ts", "${ basePath }/**/*.d.ts"],
8+
"exclude": ["node_modules", "platforms", "e2e"]
9+
}

0 commit comments

Comments
 (0)