-
-
Notifications
You must be signed in to change notification settings - Fork 601
/
defineTest.ts
135 lines (129 loc) · 5.14 KB
/
defineTest.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import * as fs from "fs";
import * as path from "path";
import { IJSCodeshift, INode } from "./types/NodePath";
interface IModule {
(
jscodeshift: IJSCodeshift,
ast: INode,
initOptions: string | boolean | object,
action: string,
transformName?: string,
): INode;
default: transformType;
parser: string;
}
type transformType = (
jscodeshift: IJSCodeshift,
ast: INode,
initOptions: string | boolean | object,
action: string,
transformName?: string,
) => INode;
/**
* Utility function to run a jscodeshift script within a unit test.
* This makes several assumptions about the environment.
*
* Notes:
* - The test should be located in a subdirectory next to the transform itself.
* Commonly tests are located in a directory called __tests__.
*
* - Test data should be located in a directory called __testfixtures__
* alongside the transform and __tests__ directory.
* @param {String} dirName contains the name of the directory the test is located in. This
* should normally be passed via __dirname.
* @param {String} transformName contains the filename of the transform being tested,
* excluding the .js extension.
* @param {String} [testFilePrefix] Optionally contains the name of the file with the test
* data. If not specified, it defaults to the same value as `transformName`.
* This will be suffixed with ".input.js" for the input file and ".output.js"
* for the expected output. For example, if set to "foo", we will read the
* "foo.input.js" file, pass this to the transform, and expect its output to
* be equal to the contents of "foo.output.js".
* @param {Object|Boolean|String} initOptions TBD
* @param {String} action init, update or remove, decides how to format the AST
* @return {Function} Function that fires of the transforms
*/
function runSingleTransform(
dirName: string,
transformName: string,
testFilePrefix: string,
initOptions: object | boolean | string,
action: string,
): string {
if (!testFilePrefix) {
testFilePrefix = transformName;
}
const fixtureDir: string = path.join(dirName, "__testfixtures__");
const inputPath: string = path.join(fixtureDir, testFilePrefix + ".input.js");
const source: string = fs.readFileSync(inputPath, "utf8");
let module: IModule;
// Assumes transform and test are on the same level
if (action) {
module = require(path.join(dirName, "recursive-parser" + ".js"));
} else {
module = require(path.join(dirName, transformName + ".js"));
}
// Handle ES6 modules using default export for the transform
const transform = module.default ? module.default : module;
// Jest resets the module registry after each test, so we need to always get
// a fresh copy of jscodeshift on every test run.
let jscodeshift: IJSCodeshift = require("jscodeshift/dist/core");
if (module.parser) {
jscodeshift = jscodeshift.withParser(module.parser);
}
const ast: INode = jscodeshift(source);
if (initOptions || typeof initOptions === "boolean") {
return transform(
jscodeshift,
ast,
initOptions,
action,
transformName,
).toSource({
quote: "single",
});
}
return transform(jscodeshift, ast, source, action).toSource({
quote: "single",
});
}
/**
* Handles some boilerplate around defining a simple jest/Jasmine test for a
* jscodeshift transform.
* @param {String} dirName contains the name of the directory the test is located in. This
* should normally be passed via __dirname.
* @param {String} transformName contains the filename of the transform being tested,
* excluding the .js extension.
* @param {String} [testFilePrefix] Optionally contains the name of the file with the test
* data. If not specified, it defaults to the same value as `transformName`.
* This will be suffixed with ".input.js" for the input file and ".output.js"
* for the expected output. For example, if set to "foo", we will read the
* "foo.input.js" file, pass this to the transform, and expect its output to
* be equal to the contents of "foo.output.js".
* @param {any} transformObject Object to be transformed with the transformations
* @param {String} action init, update or remove, decides how to format the AST
* @return {Void} Jest makes sure to execute the globally defined functions
*/
export default function defineTest(
dirName: string,
transformName: string,
testFilePrefix: string,
transformObject: object,
action: string,
): void {
const testName: string = testFilePrefix
? `transforms correctly using "${testFilePrefix}" data`
: "transforms correctly";
describe(transformName, () => {
it(testName, () => {
const output = runSingleTransform(
dirName,
transformName,
testFilePrefix,
transformObject,
action,
);
expect(output).toMatchSnapshot();
});
});
}