1 | [](http://badge.fury.io/js/markdown-doctest)
|
2 | [](https://travis-ci.org/Widdershin/markdown-doctest)
|
3 | [](https://greenkeeper.io/)
|
4 |
|
5 | * * *
|
6 |
|
7 | # markdown-doctest
|
8 |
|
9 | Test all the code in your markdown docs!
|
10 |
|
11 | Why on earth?
|
12 | ---
|
13 |
|
14 | As an open source developer, there are few things more embarassing than a user opening an issue to inform you that your README example is broken! With `markdown-doctest`, you can rest easy knowing that your example code is *actually runnable*.
|
15 |
|
16 | Installation
|
17 | ---
|
18 | Just `npm install markdown-doctest` and run `markdown-doctest`. It will run all of the Javascript code examples tucked away in your markdown, and let you know if any blow up.
|
19 |
|
20 | Okay, how do I use it?
|
21 | ---
|
22 |
|
23 | Let's try it on this repo!
|
24 |
|
25 | ```js
|
26 | var a = 5;
|
27 |
|
28 | var b = 10;
|
29 |
|
30 | console.log(a + c);
|
31 | ```
|
32 |
|
33 | There's a problem with that example. `markdown-doctest` finds it for us:
|
34 |
|
35 | ```bash
|
36 | $ markdown-doctest
|
37 | x..
|
38 |
|
39 | Failed - README.md:32:17
|
40 | evalmachine.<anonymous>:7
|
41 | console.log(a + c);
|
42 | ^
|
43 |
|
44 | ReferenceError: c is not defined
|
45 | ```
|
46 |
|
47 | Awesome! No excuse for broken documentation ever again, right? :wink:
|
48 |
|
49 | We can also run specific files or folders by running `markdown-doctest` with a glob, like `markdown-doctest docs/**/*.md`. By default `markdown-doctest` will recursively run all the `.md` or `.markdown` files starting with the current directory, with the exception of the `node_modules` directory.
|
50 |
|
51 | Note: `markdown-doctest` doesn't actually attempt to provide any guarantee that your code worked, only that it didn't explode in a horrible fashion. If you would like to use `markdown-doctest` for actually testing the correctness of your code, you can add some `assert`s to your examples.
|
52 |
|
53 | `markdown-doctest` is not a replacement for your test suite. It's designed to run with your CI build and give you peace of mind that all of your examples are at least vaguely runnable.
|
54 |
|
55 | So how do I write those examples?
|
56 | ---
|
57 |
|
58 | In your markdown files, anything inside of code blocks with 'js' or 'es6' will be run. E.g:
|
59 |
|
60 | ```js
|
61 | console.log("Yay, tests in my docs");
|
62 | ```
|
63 |
|
64 | ```es6
|
65 | const a = 5;
|
66 | console.log({a, foo: 'test'});
|
67 | ```
|
68 |
|
69 | I have a code example I don't want tested!
|
70 | ---
|
71 | You can tell `markdown-doctest` to skip examples by adding `<!-- skip-example -->` before the example. E.g:
|
72 |
|
73 | <!-- skip-example -->
|
74 | ```js
|
75 | // not a runnable example
|
76 |
|
77 | var foo = download(...);
|
78 | ```
|
79 |
|
80 | How do requires work? And other setup logic?
|
81 | ---
|
82 |
|
83 | You can `require` any needed modules or example helpers in `.markdown-doctest-setup.js`. E.g:
|
84 |
|
85 |
|
86 | ```js
|
87 | // .markdown-doctest-setup.js
|
88 | module.exports = {
|
89 | require: {
|
90 | Rx: require('rx')
|
91 | },
|
92 |
|
93 | globals: {
|
94 | $: require('jquery')
|
95 | }
|
96 | }
|
97 | ```
|
98 |
|
99 | Anything exported under `require` will then be used by any examples that `require` that key.
|
100 | You must explicitly configure all of the dependencies used in your examples.
|
101 |
|
102 | Anything exported under `globals` will be available globally across all examples.
|
103 |
|
104 | You can also specify a regexRequire section to handle anything more complex than an exact string match!
|
105 |
|
106 |
|
107 | ```js
|
108 | // .markdown-doctest-setup.js
|
109 | module.exports = {
|
110 | require: {
|
111 | Rx: require('rx')
|
112 | },
|
113 |
|
114 | regexRequire: {
|
115 | 'rx/(.*)': function (fullPath, matchedModuleName) {
|
116 | return require('./dist/' + matchedModuleName);
|
117 | }
|
118 | }
|
119 | }
|
120 | ```
|
121 |
|
122 | Do I have to enable es6 support?
|
123 | ---
|
124 |
|
125 | Nope, ES6 support is on by default. You can disable `babel` support
|
126 | in your `.markdown-doctest-setup.js` file.
|
127 | This will speed things up drastically:
|
128 |
|
129 |
|
130 | ```js
|
131 | //.markdown-doctest-setup.js
|
132 | module.exports = {
|
133 | babel: false
|
134 | }
|
135 | ```
|
136 |
|
137 | What if I have global state that needs to be reset after my examples run?
|
138 | ---
|
139 |
|
140 | ```js
|
141 | //.markdown-doctest-setup.js
|
142 | module.exports = {
|
143 | beforeEach: function () {
|
144 | // reset your awesome global state
|
145 | }
|
146 | }
|
147 | ```
|
148 |
|
149 | You can specify a function to be run before each example in your `.markdown-doctest-setup.js`.
|
150 |
|
151 | What if I want to remove custom syntax from examples before processing?
|
152 | ---
|
153 |
|
154 |
|
155 | ```js
|
156 | //.markdown-doctest-setup.js
|
157 | module.exports = {
|
158 | transformCode(code) {
|
159 | // Remove ... from code syntax
|
160 | return code.replace(/\.\.\./g, "");
|
161 | }
|
162 | }
|
163 | ```
|
164 |
|
165 | Who uses markdown-doctest?
|
166 | ---
|
167 |
|
168 | All of these projects either run `markdown-doctest` with `npm test` or as part of their CI process:
|
169 |
|
170 | * [lodash](https://github.com/lodash/lodash)
|
171 | * [Moment](https://github.com/moment/momentjs.com)
|
172 | * [RxJS](https://github.com/ReactiveX/RxJS)
|
173 | * [most](https://github.com/cujojs/most)
|
174 | * [xstream](https://github.com/staltz/xstream)
|
175 | * [cyclejs/time](https://github.com/cyclejs/time)
|
176 | * [rx.schedulers](https://github.com/Reactive-Extensions/rx.schedulers)
|
177 | * [rx.priorityqueue](https://github.com/Reactive-Extensions/rx.priorityqueue)
|
178 | * [rx.disposables](https://github.com/Reactive-Extensions/rx.disposables)
|
179 | * [rx-undoable](https://github.com/Widdershin/rx-undoable)
|