@@ -22,11 +22,13 @@ Utilities for testing babel plugins
22
22
23
23
## The problem
24
24
25
-
25
+ You're writing a babel plugin and want to write tests for it.
26
26
27
27
## This solution
28
28
29
-
29
+ This is a fairly simple abstraction to help you write tests for your babel
30
+ plugin. It works with ` jest ` (my personal favorite) and most of it should also
31
+ work with ` mocha ` and ` jasmine ` .
30
32
31
33
## Installation
32
34
@@ -39,11 +41,233 @@ npm install --save-dev babel-plugin-tester
39
41
40
42
## Usage
41
43
44
+ ### import
45
+
46
+ ``` javascript
47
+ import pluginTester from ' babel-plugin-tester'
48
+ // or
49
+ const pluginTester = require (' babel-plugin-tester' )
50
+ ```
51
+
52
+ ### Invoke
53
+
54
+ ``` javascript
55
+ import yourPlugin from ' ../your-plugin'
56
+
57
+ pluginTester ({
58
+ plugin: yourPlugin,
59
+ tests: [
60
+ /* your test objects */
61
+ ],
62
+ })
63
+ ```
64
+
65
+ ### options
66
+
67
+ #### plugin
68
+
69
+ Your babel plugin. For example:
70
+
71
+ ``` javascript
72
+ pluginTester ({
73
+ plugin: identifierReversePlugin,
74
+ tests: [
75
+ /* your test objects */
76
+ ],
77
+ })
78
+
79
+ // normally you would import this from your plugin module
80
+ function identifierReversePlugin () {
81
+ return {
82
+ name: ' identifier reverse' ,
83
+ visitor: {
84
+ Identifier (idPath ) {
85
+ idPath .node .name = idPath .node .name .split (' ' ).reverse ().join (' ' )
86
+ },
87
+ },
88
+ }
89
+ }
90
+ ```
91
+
92
+ #### pluginName
93
+
94
+ This is used for the ` describe ` title as well as the test titles. If it
95
+ can be inferred from the ` plugin ` 's ` name ` then it will be and you don't need
96
+ to provide this option.
97
+
98
+ #### title
99
+
100
+ This can be used to specify a title for the describe block (rather than using
101
+ the ` pluginName ` ).
102
+
103
+ #### fixtures
104
+
105
+ This is used in combination with the test object's ` fixture ` and ` outputFixture `
106
+ options. This is used as the base directory with which to resolve relative
107
+ paths for those options.
108
+
109
+ Note: you really only need to specify this option if one of your test objects
110
+ uses ` fixture ` or ` outputFixture ` without absolute paths.
111
+
112
+ #### tests
113
+
114
+ You provide test objects as the ` tests ` option to ` babel-plugin-tester ` . You can
115
+ either provide the ` tests ` as an object of test objects or an array of test
116
+ objects.
117
+
118
+ If you provide the tests as an object, the key will be used as the title of the
119
+ test.
120
+
121
+ If you provide an array, the title will be derived from it's index and a
122
+ specified ` title ` property or the ` pluginName ` .
123
+
124
+ Read more about test objects below.
125
+
126
+ #### ...rest
42
127
128
+ The rest of the options you provide will be [ ` lodash.merge ` ] [ lodash-merge ] d
129
+ with each test object. Read more about those next!
130
+
131
+ ### Test Objects
132
+
133
+ A minimal test object can be:
134
+
135
+ 1 . A ` string ` representing code
136
+ 2 . An ` object ` with a ` code ` property
137
+
138
+ Here are the available properties if you provide an object:
139
+
140
+ #### code
141
+
142
+ The code that you want to run through your babel plugin. This must be provided
143
+ unless you provide a ` fixture ` instead. If there's no ` output ` or ` outputFixture `
144
+ and ` snapshot ` is not ` true ` , then the assertion is that this code is unchanged
145
+ by the plugin.
146
+
147
+ #### title
148
+
149
+ If provided, this will be used instead of the ` pluginName ` . If you're using the
150
+ object API, then the ` key ` of this object will be the title (see example below).
151
+
152
+ #### output
153
+
154
+ If this is provided, the result of the plugin will be compared with this output
155
+ for the assertion. It will have any indentation stripped and will be trimmed as
156
+ a convenience for template literals.
157
+
158
+ #### fixture
159
+
160
+ If you'd rather put your ` code ` in a separate file, you can specify a filename
161
+ here. If it's an absolute path, that's the file that will be loaded, otherwise,
162
+ this will be ` path.join ` ed with the ` fixtures ` path.
163
+
164
+ #### outputFixture
165
+
166
+ If you'd rather put your ` output ` in a separate file, you can specify this
167
+ instead (works the same as ` fixture ` ).
168
+
169
+ #### snapshot
170
+
171
+ If you'd prefer to take a snapshot of your output rather than compare it to
172
+ something you hard-code, then specify ` snapshot: true ` . This will take a
173
+ snapshot with both the source code and the output, making the snapshot easier
174
+ to understand.
175
+
176
+ ## Examples
177
+
178
+ ``` javascript
179
+ import pluginTester from ' babel-plugin-tester'
180
+ import identifierReversePlugin from ' ../identifier-reverse-plugin'
181
+
182
+ pluginTester ({
183
+ // required
184
+ plugin: identifierReversePlugin,
185
+
186
+ // unnecessary if it's returned with the plugin
187
+ pluginName: ' identifier reverse' ,
188
+
189
+ // defaults to the plugin name
190
+ title: ' describe block title' ,
191
+
192
+ // only necessary if you use fixture or outputFixture in your tests
193
+ fixtures: path .join (__dirname , ' __fixtures__' ),
194
+
195
+ // these will be `lodash.merge`d with the test objects
196
+ // below are the defaults:
197
+ babelOptions: {
198
+ parserOpts: {parser: recast .parse },
199
+ generatorOpts: {generator: recast .print , lineTerminator: ' \n ' },
200
+ babelrc: false ,
201
+ },
202
+ snapshot: false , // use jest snapshots (only works with jest)
203
+
204
+ // tests as objects
205
+ tests: {
206
+ // the key is the title
207
+ // the value is the code that is unchanged (because `snapshot: false`)
208
+ // test title will be: `1. does not change code with no identifiers`
209
+ ' does not change code with no identifiers' : ' "hello";' ,
210
+
211
+ // test title will be: `2. changes this code`
212
+ ' changes this code' : {
213
+ // input to the plugin
214
+ code: ' var hello = "hi";' ,
215
+ // expected output
216
+ output: ' var olleh = "hi";' ,
217
+ },
218
+ },
219
+
220
+ // tests as an array
221
+ tests: [
222
+ // should be unchanged by the plugin (because `snapshot: false`)
223
+ // test title will be: `1. identifier reverse`
224
+ ' "hello";' ,
225
+ {
226
+ // test title will be: `2. identifier reverse`
227
+ code: ' var hello = "hi";' ,
228
+ output: ' var olleh = "hi";' ,
229
+ },
230
+ {
231
+ // test title will be: `3. unchanged code`
232
+ title: ' unchanged code' ,
233
+ // because this is an absolute path, the `fixtures` above will not be
234
+ // used to resolve this path.
235
+ fixture: path .join (__dirname , ' some-path' , ' unchanged.js' ),
236
+ // no output, outputFixture, or snapshot, so the assertion will be that
237
+ // the plugin does not change this code.
238
+ },
239
+ {
240
+ // because these are not absolute paths, they will be joined with the
241
+ // `fixtures` path provided above
242
+ fixture: ' changed.js' ,
243
+ // because outputFixture is provided, the assertion will be that the
244
+ // plugin will change the contents of `changed.js` to the contents of
245
+ // `changed-output.js`
246
+ outputFixture: ' changed-output.js' ,
247
+ },
248
+ {
249
+ // as a convenience, this will have the indentation striped and it will
250
+ // be trimmed.
251
+ code: `
252
+ function sayHi(person) {
253
+ return 'Hello ' + person + '!'
254
+ }
255
+ ` ,
256
+ // this will take a jest snapshot. The snapshot will have both the
257
+ // source code and the transformed version to make the snapshot file
258
+ // easier to understand.
259
+ snapshot: true ,
260
+ },
261
+ ],
262
+ })
263
+ ```
43
264
44
265
## Inspiration
45
266
267
+ I've been thinking about this for a while. The API was inspired by:
46
268
269
+ - ESLint's [ RuleTester] [ RuleTester ]
270
+ - [ @thejameskyle ] [ @thejameskyle ] 's [ tweet] [ jamestweet ]
47
271
48
272
## Other Solutions
49
273
98
322
[ twitter-badge ] : https://img.shields.io/twitter/url/https/github.com/kentcdodds/babel-plugin-tester.svg?style=social
99
323
[ emojis ] : https://github.com/kentcdodds/all-contributors#emoji-key
100
324
[ all-contributors ] : https://github.com/kentcdodds/all-contributors
325
+ [ lodash.merge ] : https://lodash.com/docs/4.17.4#merge
326
+ [ RuleTester ] : http://eslint.org/docs/developer-guide/working-with-rules#rule-unit-tests
327
+ [ @thejameskyle ] : https://github.com/thejameskyle
328
+ [ jamestweet ] : https://twitter.com/thejameskyle/status/864359438819262465
0 commit comments