1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.printResults = exports.runTests = void 0;
|
4 | var fs_1 = require("fs");
|
5 | var vm_1 = require("vm");
|
6 | var core_1 = require("@babel/core");
|
7 | var preset_env_1 = require("@babel/preset-env");
|
8 | var chalk_1 = require("chalk");
|
9 | function flatten(arr) {
|
10 | return Array.prototype.concat.apply([], arr);
|
11 | }
|
12 | var parse_code_snippets_from_markdown_1 = require("./parse-code-snippets-from-markdown");
|
13 | function runTests(files, config) {
|
14 | var results = files
|
15 | .map(read)
|
16 | .map(parse_code_snippets_from_markdown_1.default)
|
17 | .map(testFile(config));
|
18 | return flatten(results);
|
19 | }
|
20 | exports.runTests = runTests;
|
21 | function read(fileName) {
|
22 | return { contents: fs_1.readFileSync(fileName, "utf8"), fileName: fileName };
|
23 | }
|
24 | function makeTestSandbox(config) {
|
25 | function sandboxRequire(moduleName) {
|
26 | for (var regexRequire in config.regexRequire) {
|
27 | var regex = new RegExp(regexRequire);
|
28 | var match = regex.exec(moduleName);
|
29 | var handler = config.regexRequire[regexRequire];
|
30 | if (match) {
|
31 | return handler.apply(void 0, match);
|
32 | }
|
33 | }
|
34 | if (config.require[moduleName] === undefined) {
|
35 | throw moduleNotFoundError(moduleName);
|
36 | }
|
37 | return config.require[moduleName];
|
38 | }
|
39 | var sandboxConsole = {
|
40 | log: function () { return null; },
|
41 | };
|
42 | var sandboxGlobals = { require: sandboxRequire, console: sandboxConsole };
|
43 | var sandbox = Object.assign({}, sandboxGlobals, config.globals);
|
44 | return sandbox;
|
45 | }
|
46 | function testFile(config) {
|
47 | return function testFileWithConfig(args) {
|
48 | var codeSnippets = args.codeSnippets;
|
49 | var fileName = args.fileName;
|
50 | var shareCodeInFile = args.shareCodeInFile;
|
51 | var results;
|
52 | if (shareCodeInFile) {
|
53 | var sandbox = makeTestSandbox(config);
|
54 | results = codeSnippets.map(test(config, fileName, sandbox));
|
55 | }
|
56 | else {
|
57 | results = codeSnippets.map(test(config, fileName));
|
58 | }
|
59 | return results;
|
60 | };
|
61 | }
|
62 | function test(config, filename, sandbox) {
|
63 | return function (codeSnippet) {
|
64 | if (codeSnippet.skip) {
|
65 | return { status: "skip", codeSnippet: codeSnippet, stack: "" };
|
66 | }
|
67 | var success = false;
|
68 | var stack = "";
|
69 | var code = codeSnippet.code;
|
70 | if (config.transformCode) {
|
71 | try {
|
72 | code = config.transformCode(code);
|
73 | }
|
74 | catch (e) {
|
75 | return { status: "fail", codeSnippet: codeSnippet, stack: "Encountered an error while transforming snippet: \n" + e.stack };
|
76 | }
|
77 | }
|
78 | var perSnippetSandbox;
|
79 | if (sandbox === undefined) {
|
80 | perSnippetSandbox = makeTestSandbox(config);
|
81 | }
|
82 | if (config.beforeEach) {
|
83 | config.beforeEach();
|
84 | }
|
85 | var options = {
|
86 | presets: [preset_env_1.default],
|
87 | };
|
88 | try {
|
89 | if (config.babel !== false) {
|
90 | code = core_1.transformSync(code, options).code;
|
91 | }
|
92 | vm_1.runInNewContext(code, perSnippetSandbox || sandbox);
|
93 | success = true;
|
94 | }
|
95 | catch (e) {
|
96 | stack = e.stack || "";
|
97 | }
|
98 | var status = success ? "pass" : "fail";
|
99 | process.stdout.write(success ? chalk_1.default.green(".") : chalk_1.default.red("x"));
|
100 | return { status: status, codeSnippet: codeSnippet, stack: stack };
|
101 | };
|
102 | }
|
103 | function printResults(results) {
|
104 | results.filter(function (result) { return result.status === "fail"; }).forEach(printFailure);
|
105 | var passingCount = results.filter(function (result) { return result.status === "pass"; })
|
106 | .length;
|
107 | var failingCount = results.filter(function (result) { return result.status === "fail"; })
|
108 | .length;
|
109 | var skippingCount = results.filter(function (result) { return result.status === "skip"; })
|
110 | .length;
|
111 | function successfulRun() {
|
112 | return failingCount === 0;
|
113 | }
|
114 | console.log(chalk_1.default.green("Passed: " + passingCount));
|
115 | if (skippingCount > 0) {
|
116 | console.log(chalk_1.default.yellow("Skipped: " + skippingCount));
|
117 | }
|
118 | if (successfulRun()) {
|
119 | console.log(chalk_1.default.green("\nSuccess!"));
|
120 | }
|
121 | else {
|
122 | console.log(chalk_1.default.red("Failed: " + failingCount));
|
123 | }
|
124 | }
|
125 | exports.printResults = printResults;
|
126 | function printFailure(result) {
|
127 | console.log(chalk_1.default.red("Failed - " + markDownErrorLocation(result)));
|
128 | var stackDetails = relevantStackDetails(result.stack);
|
129 | console.log(stackDetails);
|
130 | var variableNotDefined = stackDetails.match(/(\w+) is not defined/);
|
131 | if (variableNotDefined) {
|
132 | var variableName = variableNotDefined[1];
|
133 | console.log("You can declare " + chalk_1.default.blue(variableName) + " in the " + chalk_1.default.blue("globals") + " section in " + chalk_1.default.grey(".markdown-doctest-setup.js"));
|
134 | console.log("\nFor example:\n" + chalk_1.default.grey("// .markdown-doctest-setup.js") + "\nmodule.exports = {\n globals: {\n " + chalk_1.default.blue(variableName) + ": ...\n }\n}\n ");
|
135 | }
|
136 | }
|
137 | function relevantStackDetails(stack) {
|
138 | var match = stack.match(/([\w\W]*?)at eval/) ||
|
139 | stack.match(/([\w\W]*)at [\w*\/]*?doctest.js/);
|
140 | if (match !== null) {
|
141 | return match[1];
|
142 | }
|
143 | return stack;
|
144 | }
|
145 | function moduleNotFoundError(moduleName) {
|
146 | return new Error("\nAttempted to require '" + chalk_1.default.blue(moduleName) + "' but was not found in config.\nYou need to include it in the require section of your " + chalk_1.default.grey(".markdown-doctest-setup.js") + " file.\n\nFor example:\n" + chalk_1.default.grey("// .markdown-doctest-setup.js") + "\nmodule.exports = {\n require: {\n " + chalk_1.default.blue("'" + moduleName + "': require('" + moduleName + "')") + "\n }\n}\n ");
|
147 | }
|
148 | function markDownErrorLocation(result) {
|
149 | var match = result.stack.match(/eval.*<.*>:(\d+):(\d+)/);
|
150 | if (match) {
|
151 | var mdLineNumber = parseInt(match[1], 10);
|
152 | var columnNumber = parseInt(match[2], 10);
|
153 | var lineNumber = result.codeSnippet.lineNumber + mdLineNumber;
|
154 | return result.codeSnippet.fileName + ":" + lineNumber + ":" + columnNumber;
|
155 | }
|
156 | return result.codeSnippet.fileName + ":" + result.codeSnippet.lineNumber;
|
157 | }
|