1 | const fs = require('fs')
|
2 | const path = require('path')
|
3 | const test = require('ava')
|
4 | const rimraf = require('rimraf')
|
5 | const sinon = require('sinon')
|
6 | const markdownMagic= require('../index')
|
7 |
|
8 | const DEBUG = false
|
9 | const testMarkdownPath = path.join(__dirname, 'fixtures', 'test.md')
|
10 | const outputDir = path.join(__dirname, 'fixtures', 'output')
|
11 | const delay = (ms) => new Promise(res => setTimeout(res, ms))
|
12 | const matchWord = 'AUTO-GENERATED-CONTENTX'
|
13 | const defaultConfig = {
|
14 | matchWord: matchWord
|
15 | }
|
16 |
|
17 |
|
18 |
|
19 | test('if valid string path supplied', t => {
|
20 | markdownMagic(testMarkdownPath, defaultConfig)
|
21 | t.pass()
|
22 |
|
23 | })
|
24 |
|
25 | test('if valid glob pattern supplied', t => {
|
26 | const config = {
|
27 | outputDir: outputDir
|
28 | }
|
29 | markdownMagic(['test/fixtures/**/*md', '!test/fixtures/output/*.md'], config)
|
30 | t.pass()
|
31 |
|
32 |
|
33 | })
|
34 |
|
35 | test('if valid config supplied', t => {
|
36 | markdownMagic(testMarkdownPath, defaultConfig)
|
37 | t.pass()
|
38 |
|
39 | })
|
40 |
|
41 | test.cb('if callback function supplied, call it once', t => {
|
42 | const callback = sinon.spy()
|
43 | markdownMagic(testMarkdownPath, defaultConfig, () => {
|
44 | callback()
|
45 | t.true(callback.calledOnce)
|
46 | t.end()
|
47 | })
|
48 |
|
49 | })
|
50 |
|
51 | test.cb('if callback function supplied, as second arg, call it once', t => {
|
52 | const callback = sinon.spy()
|
53 | markdownMagic(testMarkdownPath, defaultConfig, () => {
|
54 | callback()
|
55 | t.true(callback.calledOnce)
|
56 | t.end()
|
57 | })
|
58 |
|
59 |
|
60 | })
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | test.cb('if config.outputDir supplied, make new file', t => {
|
67 | const config = {
|
68 | outputDir: outputDir,
|
69 | ...defaultConfig
|
70 | }
|
71 | markdownMagic(testMarkdownPath, config, function() {
|
72 | const newfile = path.join(outputDir, 'test.md')
|
73 | const fileWasCreated = filePathExists(newfile)
|
74 | t.true(fileWasCreated)
|
75 | t.end()
|
76 |
|
77 |
|
78 | })
|
79 | })
|
80 |
|
81 | test.cb('if config.matchWord supplied, use it for comment matching', t => {
|
82 | const filePath = path.join(__dirname, 'fixtures', 'custom-match-word-test.md')
|
83 | const config = {
|
84 | matchWord: 'YOLO',
|
85 | outputDir: outputDir
|
86 | }
|
87 | markdownMagic(filePath, config, () => {
|
88 | const newfile = path.join(config.outputDir, 'custom-match-word-test.md')
|
89 | const newContent = fs.readFileSync(newfile, 'utf8')
|
90 | t.regex(newContent, /module\.exports\.run/, 'local code snippet inserted')
|
91 | t.end()
|
92 | })
|
93 |
|
94 |
|
95 | })
|
96 |
|
97 | test.cb('<!-- AUTO-GENERATED-CONTENT:START (TOC)-->', t => {
|
98 | const filePath = path.join(__dirname, 'fixtures', 'TOC-test.md')
|
99 | const config = {
|
100 | outputDir: outputDir
|
101 | }
|
102 | markdownMagic(filePath, config, () => {
|
103 | const newfile = path.join(config.outputDir, 'TOC-test.md')
|
104 | const newContent = fs.readFileSync(newfile, 'utf8')
|
105 |
|
106 | const expectedTest1 = `
|
107 | <!-- AUTO-GENERATED-CONTENT:START (TOC) - Test #1: without option and the content with empty line -->
|
108 | - [Title A](#title-a)
|
109 | * [Subtitle z](#subtitle-z)
|
110 | * [Subtitle x](#subtitle-x)
|
111 | - [Title B](#title-b)
|
112 | - [Title C](#title-c)
|
113 | <!-- AUTO-GENERATED-CONTENT:END -->`
|
114 | const regexTest1 = new RegExp(`(?=${expectedTest1.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')})`, "i")
|
115 | t.regex(newContent, regexTest1, 'Test #1 : without option and the content with empty line')
|
116 |
|
117 | const expectedTest2 = `
|
118 | <!-- AUTO-GENERATED-CONTENT:START (TOC:collapse=true&collapseText=Click Me) - Test #2: with collapse options and the content with 'aaaaaaaaa' -->
|
119 | <details>
|
120 | <summary>Click Me</summary>
|
121 |
|
122 | - [Title A](#title-a)
|
123 | * [Subtitle z](#subtitle-z)
|
124 | * [Subtitle x](#subtitle-x)
|
125 | - [Title B](#title-b)
|
126 | - [Title C](#title-c)
|
127 |
|
128 | </details>
|
129 | <!-- AUTO-GENERATED-CONTENT:END -->`
|
130 | const regexTest2 = new RegExp(`(?=${expectedTest2.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')})`, "i")
|
131 | t.regex(newContent, regexTest2, "Test #2: with collapse options and the content with 'aaaaaaaaa'")
|
132 |
|
133 | const expectedTest3 = `
|
134 | <!-- AUTO-GENERATED-CONTENT:START (TOC:collapse=true&collapseText=Click Me=I have the power) - Test #3: with collapseText contains character '=' -->
|
135 | <details>
|
136 | <summary>Click Me=I have the power</summary>
|
137 |
|
138 | - [Title A](#title-a)
|
139 | * [Subtitle z](#subtitle-z)
|
140 | * [Subtitle x](#subtitle-x)
|
141 | - [Title B](#title-b)
|
142 | - [Title C](#title-c)
|
143 |
|
144 | </details>
|
145 | <!-- AUTO-GENERATED-CONTENT:END -->`
|
146 | const regexTest3 = new RegExp(`(?=${expectedTest3.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')})`, "i")
|
147 | t.regex(newContent, regexTest3, "Test #3: with collapseText contains character '='")
|
148 |
|
149 | const expectedTest4 = `
|
150 | <!-- AUTO-GENERATED-CONTENT:START (TOC) - Test #4: without option and the content is empty -->
|
151 | - [Title A](#title-a)
|
152 | * [Subtitle z](#subtitle-z)
|
153 | * [Subtitle x](#subtitle-x)
|
154 | - [Title B](#title-b)
|
155 | - [Title C](#title-c)
|
156 | <!-- AUTO-GENERATED-CONTENT:END -->`
|
157 | const regexTest4 = new RegExp(`(?=${expectedTest4.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')})`, "i")
|
158 | t.regex(newContent, regexTest4, 'Test #4 : without option and the content is empty')
|
159 |
|
160 | const expectedTest5 = `
|
161 | <!-- AUTO-GENERATED-CONTENT:START (TOC) - Test #5: without option and tags with same line -->
|
162 | - [Title A](#title-a)
|
163 | * [Subtitle z](#subtitle-z)
|
164 | * [Subtitle x](#subtitle-x)
|
165 | - [Title B](#title-b)
|
166 | - [Title C](#title-c)
|
167 | <!-- AUTO-GENERATED-CONTENT:END -->`
|
168 | const regexTest5 = new RegExp(`(?=${expectedTest5.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')})`, "i")
|
169 | t.regex(newContent, regexTest5, 'Test #5 : without option and tags with same line')
|
170 |
|
171 | t.end()
|
172 | })
|
173 |
|
174 | })
|
175 |
|
176 |
|
177 |
|
178 |
|
179 | test.cb('<!-- AUTO-GENERATED-CONTENT:START (CODE)-->', t => {
|
180 | const filePath = path.join(__dirname, 'fixtures', 'CODE-test.md')
|
181 | const config = { outputDir: outputDir }
|
182 | const newfile = path.join(config.outputDir, 'CODE-test.md')
|
183 |
|
184 | markdownMagic(filePath, config, function(err, data) {
|
185 |
|
186 | const newContent = fs.readFileSync(newfile, 'utf8')
|
187 |
|
188 | t.regex(newContent, /module\.exports\.run/, 'local code snippet inserted')
|
189 |
|
190 | t.regex(newContent, /```js\n const baz = 'foobar'\n console\.log\(`Hello \${baz}`\)\n```/, 'local code snippet with range lines inserted')
|
191 |
|
192 | t.regex(newContent, /require\('dox'\)/, 'remote code snippet inserted')
|
193 |
|
194 | t.regex(newContent, /```json\n "author": "David Wells",\n "license": "MIT",\n```/, 'remote code snippet with range lines inserted')
|
195 |
|
196 | t.end()
|
197 | })
|
198 |
|
199 | if (filePathExists(newfile)) {
|
200 |
|
201 | }
|
202 |
|
203 | })
|
204 |
|
205 | test.cb('<!-- AUTO-GENERATED-CONTENT:START (REMOTE)-->', t => {
|
206 | const filePath = path.join(__dirname, 'fixtures', 'REMOTE-test.md')
|
207 |
|
208 | const config = { outputDir: outputDir }
|
209 | markdownMagic(filePath, config, function() {
|
210 | const newfile = path.join(config.outputDir, 'REMOTE-test.md')
|
211 | const newContent = fs.readFileSync(newfile, 'utf8')
|
212 |
|
213 | t.regex(newContent, /Markdown Magic/, 'word "Markdown Magic" not found in remote block')
|
214 | t.end()
|
215 |
|
216 |
|
217 | })
|
218 | })
|
219 |
|
220 | test.cb('<!-- AUTO-GENERATED-CONTENT:START (customTransform)-->', t => {
|
221 | const filePath = path.join(__dirname, 'fixtures', 'CUSTOM-test.md')
|
222 |
|
223 | const config = {
|
224 | outputDir: outputDir,
|
225 | transforms: {
|
226 |
|
227 | customTransform(content, options) {
|
228 |
|
229 | return `This will replace all the contents of inside the comment ${options.optionOne}`
|
230 | }
|
231 | }
|
232 | }
|
233 | markdownMagic(filePath, config, function() {
|
234 | console.log('Callback')
|
235 | const newfile = path.join(config.outputDir, 'CUSTOM-test.md')
|
236 | console.log('newfile', newfile)
|
237 | const newContent = fs.readFileSync(newfile, 'utf8')
|
238 | console.log('newContent', newContent)
|
239 |
|
240 | t.regex(newContent, /will replace all the contents/, 'has custom transform data')
|
241 | t.end()
|
242 |
|
243 |
|
244 | })
|
245 | })
|
246 |
|
247 | test.cb('Async <!-- AUTO-GENERATED-CONTENT:START (customAsync)-->', t => {
|
248 | const filePath = path.join(__dirname, 'fixtures', 'CUSTOM-async.md')
|
249 |
|
250 | const config = {
|
251 | outputDir: outputDir,
|
252 | transforms: {
|
253 |
|
254 | async customAsync(content, options) {
|
255 | await delay(500)
|
256 |
|
257 | return `async data here ${options.optionOne}`
|
258 | }
|
259 | }
|
260 | }
|
261 | markdownMagic(filePath, config, function() {
|
262 | const newfile = path.join(config.outputDir, 'CUSTOM-async.md')
|
263 | const newContent = fs.readFileSync(newfile, 'utf8')
|
264 |
|
265 | t.regex(newContent, /async data here hi/, 'has custom transform data')
|
266 | t.end()
|
267 |
|
268 |
|
269 | })
|
270 | })
|
271 |
|
272 | test.after.always('cleanup', async t => {
|
273 | rimraf.sync(outputDir)
|
274 | })
|
275 |
|
276 |
|
277 |
|
278 |
|
279 | function filePathExists(fp) {
|
280 | try {
|
281 | fs.accessSync(fp)
|
282 | return true
|
283 | } catch (err) {
|
284 | return false
|
285 | }
|
286 | }
|
287 |
|
288 | function emptyDirectory(filePath, callBack) {
|
289 | rimraf.sync(filePath)
|
290 | callBack && callBack(null)
|
291 | }
|