1 |
|
2 |
|
3 |
|
4 | const flow = require('../lib/xml-flow');
|
5 | const fs = require('fs');
|
6 |
|
7 |
|
8 | require('chai').should();
|
9 |
|
10 | function getFlow(fileName, options) {
|
11 | return flow(fs.createReadStream(fileName), options);
|
12 | }
|
13 |
|
14 | describe('xml-flow', () => {
|
15 | describe('invoke', () => {
|
16 | it('should create an emitter when invoked with a stream and options', () => {
|
17 | const inStream = fs.createReadStream('./test/simple.xml');
|
18 | inStream.pause();
|
19 | const simpleStream = flow(inStream);
|
20 |
|
21 | simpleStream.on.should.be.a('function');
|
22 | simpleStream.pause();
|
23 | simpleStream.resume();
|
24 | });
|
25 | });
|
26 |
|
27 | describe('.on(\'end\')', () => {
|
28 | it('should emit after the file has been read', done => {
|
29 | const simpleStream = getFlow('./test/simple.xml');
|
30 | simpleStream.on('end', () => {
|
31 | done();
|
32 | });
|
33 | });
|
34 | });
|
35 |
|
36 | describe('.on(\'tag:...\')', () => {
|
37 | it('should emit the right number of nodes', done => {
|
38 | const simpleStream = getFlow('./test/simple.xml');
|
39 | let count = 0;
|
40 |
|
41 | simpleStream.on('tag:item', () => {
|
42 | count++;
|
43 | });
|
44 |
|
45 | simpleStream.on('end', () => {
|
46 | count.should.equal(3);
|
47 | done();
|
48 | });
|
49 | });
|
50 |
|
51 | it('should make non-attributed data look really simple', done => {
|
52 | const simpleStream = getFlow('./test/test.xml');
|
53 | const output = {
|
54 | $name: 'no-attrs',
|
55 | person: [
|
56 | { name: 'Bill', id: '1', age: '27' },
|
57 | { name: 'Joe', id: '2', age: '29' },
|
58 | { name: 'Smitty', id: '3', age: '37' }
|
59 | ]
|
60 | };
|
61 |
|
62 |
|
63 | simpleStream.on('tag:no-attrs', node => {
|
64 | node.should.deep.equal(output);
|
65 | done();
|
66 | });
|
67 | });
|
68 |
|
69 | it('should make all-attributed data look really simple', done => {
|
70 | const simpleStream = getFlow('./test/test.xml');
|
71 | const output = {
|
72 | $name: 'all-attrs',
|
73 | person: [
|
74 | { name: 'Bill', id: '1', age: '27' },
|
75 | { name: 'Joe', id: '2', age: '29' },
|
76 | { name: 'Smitty', id: '3', age: '37' }
|
77 | ]
|
78 | };
|
79 |
|
80 |
|
81 | simpleStream.on('tag:all-attrs', node => {
|
82 | node.should.deep.equal(output);
|
83 | done();
|
84 | });
|
85 | });
|
86 |
|
87 | it('should handle tags with both attributes and other stuff', done => {
|
88 | const simpleStream = getFlow('./test/test.xml');
|
89 | const output = {
|
90 | $name: 'mixed',
|
91 | person: [
|
92 | { $attrs: { name: 'Bill', id: '1', age: '27' }, $text: 'some text' },
|
93 | { $attrs: { name: 'Joe', id: '2', age: '29' }, p: 'some paragraph' },
|
94 | { $attrs: { name: 'Smitty', id: '3', age: '37' }, thing: { id: '999', ref: 'blah' }}
|
95 | ]
|
96 | };
|
97 |
|
98 |
|
99 | simpleStream.on('tag:mixed', node => {
|
100 | node.should.deep.equal(output);
|
101 | done();
|
102 | });
|
103 | });
|
104 |
|
105 | it('should preserve markup when things get more complex', done => {
|
106 | const simpleStream = getFlow('./test/test.xml');
|
107 | const output = {
|
108 | $name: 'markup',
|
109 | $markup: [
|
110 | 'Some unwrapped text',
|
111 | { $name: 'person', $attrs: { name: 'Bill', id: '1', age: '27' }, $text: 'some text' },
|
112 | 'Some more unwrapped text',
|
113 | { $name: 'person', $attrs: { name: 'Joe', id: '2', age: '29' }, p: 'some paragraph' },
|
114 | { $name: 'person', $attrs: { name: 'Smitty', id: '3', age: '37' }, thing: { id: '999', ref: 'blah' }}
|
115 | ]
|
116 | };
|
117 |
|
118 |
|
119 | simpleStream.on('tag:markup', node => {
|
120 | node.should.deep.equal(output);
|
121 | done();
|
122 | });
|
123 | });
|
124 |
|
125 | it('should handle scripts', done => {
|
126 | const simpleStream = getFlow('./test/test.xml');
|
127 | const output = {
|
128 | $name: 'has-scripts',
|
129 | script: [
|
130 | 'var x = 3;',
|
131 | { $attrs: { type: 'text/javascript' }, $script: '//this is a comment' }
|
132 | ]
|
133 | };
|
134 |
|
135 | simpleStream.on('tag:has-scripts', node => {
|
136 | node.should.deep.equal(output);
|
137 | done();
|
138 | });
|
139 | });
|
140 |
|
141 | it('should handle CDATA', done => {
|
142 | const simpleStream = getFlow('./test/test.xml');
|
143 | const output = {
|
144 | $name: 'has-cdata',
|
145 | $text: 'here comes the cdata...',
|
146 | $cdata: 'this is <span>cdata!</span>'
|
147 | };
|
148 |
|
149 | simpleStream.on('tag:has-cdata', node => {
|
150 | node.should.deep.equal(output);
|
151 | done();
|
152 | });
|
153 | });
|
154 |
|
155 | it('should handle bad formatting', done => {
|
156 | const simpleStream = getFlow('./test/badFormatting.xml');
|
157 | const output = {
|
158 | $name: 'section',
|
159 | $markup: [
|
160 | 'Text1</p>',
|
161 | { $name: 'p', $text: 'Text2' },
|
162 | { $name: 'p', $text: 'Text3' },
|
163 | 'Text4',
|
164 | { $name: 'p' }
|
165 | ]
|
166 | };
|
167 |
|
168 | simpleStream.on('tag:section', node => {
|
169 | node.should.deep.equal(output);
|
170 | done();
|
171 | });
|
172 | });
|
173 | });
|
174 |
|
175 | describe('options', () => {
|
176 | it('should normalize whitespace by default', done => {
|
177 | const simpleStream = getFlow('./test/test.xml');
|
178 | const output = 'This is some text with extra whitespace.';
|
179 |
|
180 | simpleStream.on('tag:extra-whitespace', node => {
|
181 | node.$text.should.equal(output);
|
182 | done();
|
183 | });
|
184 | });
|
185 |
|
186 | it('should not normalize whitespace when asked not to', done => {
|
187 | const simpleStream = getFlow('./test/test.xml', { normalize: false });
|
188 | const output = 'This is some text with extra whitespace.';
|
189 |
|
190 | simpleStream.on('tag:extra-whitespace', node => {
|
191 | node.$text.should.equal(output);
|
192 | done();
|
193 | });
|
194 | });
|
195 |
|
196 | it('should trim by default', done => {
|
197 | const simpleStream = getFlow('./test/test.xml');
|
198 | const output = 'This is some text with extra whitespace.';
|
199 |
|
200 | simpleStream.on('tag:extra-whitespace', node => {
|
201 | node.$text.should.equal(output);
|
202 | done();
|
203 | });
|
204 | });
|
205 |
|
206 | it('should not trim when asked not to', done => {
|
207 | const simpleStream = getFlow('./test/test.xml', { trim: false });
|
208 | const output = 'This is some text with extra whitespace. ';
|
209 |
|
210 | simpleStream.on('tag:extra-whitespace', node => {
|
211 | node.$text.should.equal(output);
|
212 | done();
|
213 | });
|
214 | });
|
215 |
|
216 | it('should not preserve markup when told to never do so', done => {
|
217 | const simpleStream = getFlow('./test/test.xml', { preserveMarkup: flow.NEVER });
|
218 | const output = {
|
219 | $name: 'markup',
|
220 | $text: [
|
221 | 'Some unwrapped text',
|
222 | 'Some more unwrapped text'
|
223 | ],
|
224 | person: [
|
225 | { $attrs: { name: 'Bill', id: '1', age: '27' }, $text: 'some text' },
|
226 | { $attrs: { name: 'Joe', id: '2', age: '29' }, p: 'some paragraph' },
|
227 | { $attrs: { name: 'Smitty', id: '3', age: '37' }, thing: { id: '999', ref: 'blah' }}
|
228 | ]
|
229 | };
|
230 |
|
231 | simpleStream.on('tag:markup', node => {
|
232 | node.should.deep.equal(output);
|
233 | done();
|
234 | });
|
235 | });
|
236 |
|
237 | it('should always preserve markup when told to do so', done => {
|
238 | const simpleStream = getFlow('./test/test.xml', { preserveMarkup: flow.ALWAYS });
|
239 | const output = {
|
240 | $name: 'mixed',
|
241 | $markup: [
|
242 | {
|
243 | $name: 'person',
|
244 | $attrs: { name: 'Bill', id: '1', age: '27' },
|
245 | $markup: [ 'some text' ]
|
246 | },
|
247 | {
|
248 | $name: 'person',
|
249 | $attrs: { name: 'Joe', id: '2', age: '29' },
|
250 | $markup: [{ $name: 'p', $markup: [ 'some paragraph' ]}]
|
251 | },
|
252 | {
|
253 | $name: 'person',
|
254 | $attrs: { name: 'Smitty', id: '3', age: '37' },
|
255 | $markup: [{ $name: 'thing', id: '999', ref: 'blah' }]
|
256 | }
|
257 | ]
|
258 | };
|
259 |
|
260 | simpleStream.on('tag:mixed', node => {
|
261 | node.should.deep.equal(output);
|
262 | done();
|
263 | });
|
264 | });
|
265 |
|
266 | it('should handle CDATA as text when asked', done => {
|
267 | const simpleStream = getFlow('./test/test.xml', { cdataAsText: true });
|
268 | const output = {
|
269 | $name: 'has-cdata',
|
270 | $text: 'here comes the cdata...this is <span>cdata!</span>'
|
271 | };
|
272 |
|
273 | simpleStream.on('tag:has-cdata', node => {
|
274 | node.should.deep.equal(output);
|
275 | done();
|
276 | });
|
277 | });
|
278 |
|
279 | it('should completely drop arrays when asked', done => {
|
280 | const simpleStream = getFlow('./test/test.xml', { useArrays: flow.NEVER });
|
281 | const output = {
|
282 | $name: 'two-items',
|
283 | p: 'one'
|
284 | };
|
285 |
|
286 | simpleStream.on('tag:two-items', node => {
|
287 | node.should.deep.equal(output);
|
288 | done();
|
289 | });
|
290 | });
|
291 |
|
292 | it('should keep things as arrays when asked', done => {
|
293 | const simpleStream = getFlow('./test/test.xml', { useArrays: flow.ALWAYS });
|
294 | const output = {
|
295 | $name: 'one-item',
|
296 | p: [ 'this is one item' ]
|
297 | };
|
298 |
|
299 | simpleStream.on('tag:one-item', node => {
|
300 | node.should.deep.equal(output);
|
301 | done();
|
302 | });
|
303 | });
|
304 | });
|
305 |
|
306 | describe('toXml()', () => {
|
307 | it('should convert $attrs as expected', () => {
|
308 | const input = { $name: 'tag', $attrs: { id: 3 }};
|
309 | const output = '<tag id="3"/>';
|
310 |
|
311 | flow.toXml(input).should.equal(output);
|
312 | });
|
313 |
|
314 | it('should convert $text as expected', () => {
|
315 | const input = { $name: 'tag', $attrs: { id: 3 }, $text: 'some text' };
|
316 | const output = '<tag id="3">some text</tag>';
|
317 |
|
318 | flow.toXml(input).should.equal(output);
|
319 | });
|
320 |
|
321 | it('should convert random fields as expected', () => {
|
322 | const input = { $name: 'tag', $attrs: { id: 3 }, $text: 'some text', p: 'other text', j: [ 'text1', 'text2' ]};
|
323 | const output = '<tag id="3">some text<p>other text</p><j>text1</j><j>text2</j></tag>';
|
324 |
|
325 | flow.toXml(input).should.equal(output);
|
326 | });
|
327 |
|
328 | it('should convert $markup', () => {
|
329 | const input = { $name: 'tag', $markup: [ 'text', { $name: 'j', $text: 'stuff' }]};
|
330 | const output = '<tag>text<j>stuff</j></tag>';
|
331 |
|
332 | flow.toXml(input).should.equal(output);
|
333 | });
|
334 |
|
335 | it('should convert $script', () => {
|
336 | const input = { $name: 'tag', $script: 'console.log(\'stuff\');' };
|
337 | const output = '<tag><script>console.log(\'stuff\');</script></tag>';
|
338 |
|
339 | flow.toXml(input).should.equal(output);
|
340 | });
|
341 |
|
342 | it('should convert $cdata', () => {
|
343 | const input = { $name: 'tag', $cdata: '<<science>>' };
|
344 | const output = '<tag><![CDATA[<<science>>]]></tag>';
|
345 |
|
346 | flow.toXml(input).should.equal(output);
|
347 | });
|
348 |
|
349 | it('should pretty-print', () => {
|
350 | const input = {
|
351 | $name: 'tag',
|
352 | $markup: [
|
353 | 'text',
|
354 | {
|
355 | $name: 'tag',
|
356 | $text: 'moar text'
|
357 | }
|
358 | ]
|
359 | };
|
360 | const output = '<tag>\n text\n <tag>\n moar text\n </tag>\n</tag>';
|
361 |
|
362 | flow.toXml(input, { indent: ' ' }).should.equal(output);
|
363 | });
|
364 |
|
365 | it('should not do self-closing if asked', () => {
|
366 | const input = { $name: 'tag', $attrs: { id: 3 }};
|
367 | const output = '<tag id="3"></tag>';
|
368 |
|
369 | flow.toXml(input, { selfClosing: false }).should.equal(output);
|
370 | });
|
371 |
|
372 | it('should escape html entities', () => {
|
373 | const input = { $name: 'tag', $text: '<br><br><table class=\'data\' ></table>' };
|
374 | const output = '<tag><br><br><table class=\'data\' ></table></tag>';
|
375 |
|
376 | flow.toXml(input).should.equal(output);
|
377 | });
|
378 | });
|
379 | });
|