summaryrefslogtreecommitdiffstats
path: root/src/test/index.ts
diff options
context:
space:
mode:
authorChristoph Schlosser <2466365+cschlosser@users.noreply.github.com>2021-04-17 22:12:38 +0200
committerGitHub <noreply@github.com>2021-04-17 22:12:38 +0200
commitdbcf5dc87d83ee59fc23e4eaa225a15655d17d2d (patch)
treed22cb94be324153581658e80a8596765755971a0 /src/test/index.ts
parent703019a593c1e4118b580015b1af8bcfbb86b135 (diff)
downloaddoxdocgen-dbcf5dc87d83ee59fc23e4eaa225a15655d17d2d.tar.gz
Prepare release 1.2.0 (#213)1.2.0
* Prepare release 1.2.0 * Update versions * Lint * update appveyor * Update travis * Use yarn * Add nyc * Run cov instead of test * remove package-lock.json * Remove istanbul
Diffstat (limited to 'src/test/index.ts')
-rw-r--r--src/test/index.ts277
1 files changed, 63 insertions, 214 deletions
diff --git a/src/test/index.ts b/src/test/index.ts
index 5dfa541..89f953b 100644
--- a/src/test/index.ts
+++ b/src/test/index.ts
@@ -1,220 +1,69 @@
-"use strict";
-
-import * as fs from "fs";
import * as glob from "glob";
-import * as paths from "path";
-
-import istanbul = require("istanbul");
-import remapIstanbul = require("remap-istanbul");
-// tslint:disable-next-line:no-var-requires
-const tty = require("tty");
-// tslint:disable-next-line:no-var-requires
-const Mocha = require("mocha");
-
-// Linux: prevent a weird NPE when mocha on Linux requires the window size from the TTY
-// Since we are not running in a tty environment, we just implementt he method statically
-if (!tty.getWindowSize) {
- tty.getWindowSize = (): number[] => {
- return [80, 75];
- };
-}
-
-let mocha = new Mocha({
- ui: "tdd",
- useColors: true,
-});
-
-function configure(mochaOpts): void {
- mocha = new Mocha(mochaOpts);
-}
-exports.configure = configure;
-
-function _mkDirIfExists(dir: string): void {
- if (!fs.existsSync(dir)) {
- fs.mkdirSync(dir);
- }
-}
-
-function _readCoverOptions(testsRoot: string): ITestRunnerOptions {
- const coverConfigPath = paths.join(testsRoot, "..", "..", "coverconfig.json");
- let coverConfig: ITestRunnerOptions;
- if (fs.existsSync(coverConfigPath)) {
- const configContent = fs.readFileSync(coverConfigPath, "utf-8");
- coverConfig = JSON.parse(configContent);
- }
- return coverConfig;
-}
-
-function run(testsRoot, clb): any {
- // Enable source map support
- require("source-map-support").install();
-
- // Read configuration for the coverage file
- const coverOptions: ITestRunnerOptions = _readCoverOptions(testsRoot);
- if (coverOptions && coverOptions.enabled) {
- // Setup coverage pre-test, including post-test hook to report
- const coverageRunner = new CoverageRunner(coverOptions, testsRoot, clb);
- coverageRunner.setupCoverage();
- }
-
- // Glob test files
- glob("**/**.test.js", { cwd: testsRoot }, (error, files): any => {
- if (error) {
- return clb(error);
- }
- try {
- // Fill into Mocha
- files.forEach((f): Mocha => {
- return mocha.addFile(paths.join(testsRoot, f));
- });
- // Run the tests
- let failureCount = 0;
-
- mocha.run()
- .on("fail", (test, err): void => {
- failureCount++;
- })
- .on("end", (): void => {
- clb(undefined, failureCount);
- });
- } catch (error) {
- return clb(error);
- }
+import * as Mocha from "mocha";
+import * as path from "path";
+
+function setupNyc() {
+ const NYC = require("nyc");
+ // create an nyc instance, config here is the same as your package.json
+ const nyc = new NYC({
+ cache: false,
+ cwd: path.join(__dirname, "..", ".."),
+ exclude: [
+ "**/**.test.js",
+ ],
+ extension: [
+ ".ts",
+ ".tsx",
+ ],
+ hookRequire: true,
+ hookRunInContext: true,
+ hookRunInThisContext: true,
+ instrument: true,
+ reporter: ["text", "lcov", "cobertura"],
+ require: [
+ "ts-node/register",
+ "source-map-support/register",
+ ],
+ sourceMap: true,
});
+ nyc.reset();
+ nyc.wrap();
+ return nyc;
}
-exports.run = run;
-
-interface ITestRunnerOptions {
- enabled?: boolean;
- relativeCoverageDir: string;
- relativeSourcePath: string;
- ignorePatterns: string[];
- includePid?: boolean;
- reports?: string[];
- verbose?: boolean;
-}
-
-class CoverageRunner {
-
- private coverageVar: string = "$$cov_" + new Date().getTime() + "$$";
- private transformer: any = undefined;
- private matchFn: any = undefined;
- private instrumenter: any = undefined;
-
- constructor(private options: ITestRunnerOptions, private testsRoot: string, private endRunCallback: any) {
- if (!options.relativeSourcePath) {
- return endRunCallback("Error - relativeSourcePath must be defined for code coverage to work");
- }
-
- }
- public setupCoverage(): void {
- // Set up Code Coverage, hooking require so that instrumented code is returned
- this.instrumenter = new istanbul.Instrumenter({ coverageVariable: this.coverageVar });
- const sourceRoot = paths.join(this.testsRoot, this.options.relativeSourcePath);
-
- // Glob source files
- const srcFiles = glob.sync("**/**.js", {
- cwd: sourceRoot,
- ignore: this.options.ignorePatterns,
- });
-
- // Create a match function - taken from the run-with-cover.js in istanbul.
- const decache = require("decache");
- const fileMap = {};
- srcFiles.forEach( (file) => {
- const fullPath = paths.join(sourceRoot, file);
- fileMap[fullPath] = true;
-
- // On Windows, extension is loaded pre-test hooks and this mean we lose
- // our chance to hook the Require call. In order to instrument the code
- // we have to decache the JS file so on next load it gets instrumented.
- // This doesn"t impact tests, but is a concern if we had some integration
- // tests that relied on VSCode accessing our module since there could be
- // some shared global state that we lose.
- decache(fullPath);
- });
-
- this.matchFn = (file): boolean => fileMap[file];
- this.matchFn.files = Object.keys(fileMap);
-
- // Hook up to the Require function so that when this is called, if any of our source files
- // are required, the instrumented version is pulled in instead. These instrumented versions
- // write to a global coverage variable with hit counts whenever they are accessed
- this.transformer = this.instrumenter.instrumentSync.bind(this.instrumenter);
- const hookOpts = { verbose: false, extensions: [".js"]};
- istanbul.hook.hookRequire(this.matchFn, this.transformer, hookOpts);
-
- // initialize the global variable to stop mocha from complaining about leaks
- global[this.coverageVar] = {};
-
- // Hook the process exit event to handle reporting
- // Only report coverage if the process is exiting successfully
- process.on("exit", (code) => {
- this.reportCoverage();
- });
- }
-
- /**
- * Writes a coverage report.
- * Note that as this is called in the process exit callback, all calls must be synchronous.
- *
- * @returns {void}
- *
- * @memberOf CoverageRunner
- */
- public reportCoverage(): void {
- istanbul.hook.unhookRequire();
- let cov: any;
- if (typeof global[this.coverageVar] === "undefined" || Object.keys(global[this.coverageVar]).length === 0) {
- // tslint:disable:no-console
- console.error("No coverage information was collected, exit without writing coverage information");
- return;
- } else {
- cov = global[this.coverageVar];
- }
-
- // TODO consider putting this under a conditional flag
- // Files that are not touched by code ran by the test runner is manually instrumented, to
- // illustrate the missing coverage.
- this.matchFn.files.forEach( (file) => {
- if (!cov[file]) {
- this.transformer(fs.readFileSync(file, "utf-8"), file);
-
- // When instrumenting the code, istanbul will give each FunctionDeclaration a value of 1 in
- // coverState.s, presumably to compensate for function hoisting. We need to reset this, as the function
- // was not hoisted, as it was never loaded.
- Object.keys(this.instrumenter.coverState.s).forEach( (key) => {
- this.instrumenter.coverState.s[key] = 0;
- });
-
- cov[file] = this.instrumenter.coverState;
- }
- });
-
- // TODO Allow config of reporting directory with
- const reportingDir = paths.join(this.testsRoot, this.options.relativeCoverageDir);
- const includePid = this.options.includePid;
- const pidExt = includePid ? ("-" + process.pid) : "";
- const coverageFile = paths.resolve(reportingDir, "coverage" + pidExt + ".json");
-
- // yes, do this again since some test runners could clean the dir initially created
- _mkDirIfExists(reportingDir);
- fs.writeFileSync(coverageFile, JSON.stringify(cov), "utf8");
-
- const remappedCollector = remapIstanbul.remap(cov, {warn: (warning) => {
- // We expect some warnings as any JS file without a typescript mapping will cause this.
- // By default, we"ll skip printing these to the console as it clutters it up
- if (this.options.verbose) {
- console.warn(warning);
- }
- }});
-
- const reporter = new istanbul.Reporter(undefined, reportingDir);
- const reportTypes = (this.options.reports instanceof Array) ? this.options.reports : ["lcov"];
- reporter.addAll(reportTypes);
- reporter.write(remappedCollector, true, () => {
- console.log(`reports written to ${reportingDir}`);
+export function run(): Promise<void> {
+ // Create the mocha test
+ const mocha = new Mocha({
+ ui: "tdd",
+ });
+
+ const nyc = setupNyc();
+ const testsRoot = path.resolve(__dirname, ".");
+
+ return new Promise((c, e) => {
+ glob("**/**.test.js", { cwd: testsRoot }, (err, files) => {
+ if (err) {
+ return e(err);
+ }
+
+ // Add files to the test suite
+ files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
+
+ try {
+ // Run the mocha test
+ mocha.run((failures) => {
+ if (failures > 0) {
+ e(new Error(`${failures} tests failed.`));
+ } else {
+ c();
+ }
});
- }
+ } catch (err) {
+ e(err);
+ } finally {
+ nyc.writeCoverageFile();
+ nyc.report();
+ }
+ });
+ });
}