1'use strict'; 2 3const assert = require('assert'); 4const dedent = require('dedent'); 5const RewritingStream = require('../lib'); 6const loadSAXParserTestData = require('../../../test/utils/load-sax-parser-test-data'); 7const { getStringDiffMsg, writeChunkedToStream, WritableStreamStub } = require('../../../test/utils/common'); 8 9const srcHtml = dedent` 10 <!DOCTYPE html ""> 11 <html> 12 <!-- comment1 --> 13 <head /// 123> 14 </head> 15 <!-- comment2 --> 16 <body =123> 17 <div>Hey ya</div> 18 </body> 19 </html> 20`; 21 22function createRewriterTest({ src, expected, assignTokenHandlers = () => {} }) { 23 return done => { 24 const rewriter = new RewritingStream(); 25 const writable = new WritableStreamStub(); 26 27 writable.once('finish', () => { 28 assert.ok(writable.writtenData === expected, getStringDiffMsg(writable.writtenData, expected)); 29 done(); 30 }); 31 32 rewriter.pipe(writable); 33 34 assignTokenHandlers(rewriter); 35 writeChunkedToStream(src, rewriter); 36 }; 37} 38 39// Raw data tests 40loadSAXParserTestData().forEach( 41 // NOTE: if we don't have any event handlers assigned, stream should use raw 42 // data for the serialization, so serialized content should identical to the original. 43 (test, idx) => 44 (exports[`RewritingStream - Raw token serialization - ${idx + 1}.${test.name}`] = createRewriterTest({ 45 src: test.src, 46 expected: test.src 47 })) 48); 49 50exports['RewritingStream - rewrite start tags'] = createRewriterTest({ 51 src: srcHtml, 52 expected: dedent` 53 <!DOCTYPE html ""> 54 <html> 55 <!-- comment1 --> 56 <body 123=""> 57 </head> 58 <!-- comment2 --> 59 <head =123=""> 60 <div>Hey ya</div> 61 </body> 62 </html> 63 `, 64 assignTokenHandlers: rewriter => { 65 rewriter.on('startTag', token => { 66 if (token.tagName === 'head') { 67 token.tagName = 'body'; 68 } else if (token.tagName === 'body') { 69 token.tagName = 'head'; 70 } 71 72 rewriter.emitStartTag(token); 73 }); 74 } 75}); 76 77exports['RewritingStream - rewrite end tags'] = createRewriterTest({ 78 src: srcHtml, 79 expected: dedent` 80 <!DOCTYPE html ""> 81 <html> 82 <!-- comment1 --> 83 <head /// 123> 84 </rewritten> 85 <!-- comment2 --> 86 <body =123> 87 <div>Hey ya</rewritten> 88 </rewritten> 89 </rewritten> 90 `, 91 assignTokenHandlers: rewriter => { 92 rewriter.on('endTag', token => { 93 token.tagName = 'rewritten'; 94 95 rewriter.emitEndTag(token); 96 }); 97 } 98}); 99 100exports['RewritingStream - rewrite text'] = createRewriterTest({ 101 src: srcHtml, 102 expected: dedent` 103 <!DOCTYPE html ""> 104 <html> 105 <!-- comment1 --> 106 <head /// 123> 107 </head> 108 <!-- comment2 --> 109 <body =123> 110 <div>42</div> 111 </body> 112 </html> 113 `, 114 assignTokenHandlers: rewriter => { 115 rewriter.on('text', token => { 116 if (token.text.trim().length > 0) { 117 token.text = '42'; 118 } 119 120 rewriter.emitText(token); 121 }); 122 } 123}); 124 125exports['RewritingStream - rewrite comment'] = createRewriterTest({ 126 src: srcHtml, 127 expected: dedent` 128 <!DOCTYPE html ""> 129 <html> 130 <!--42--> 131 <head /// 123> 132 </head> 133 <!--42--> 134 <body =123> 135 <div>Hey ya</div> 136 </body> 137 </html> 138 `, 139 assignTokenHandlers: rewriter => { 140 rewriter.on('comment', token => { 141 token.text = '42'; 142 143 rewriter.emitComment(token); 144 }); 145 } 146}); 147 148exports['RewritingStream - rewrite doctype'] = createRewriterTest({ 149 src: srcHtml, 150 expected: dedent` 151 <!DOCTYPE html PUBLIC "42" "hey"> 152 <html> 153 <!-- comment1 --> 154 <head /// 123> 155 </head> 156 <!-- comment2 --> 157 <body =123> 158 <div>Hey ya</div> 159 </body> 160 </html> 161 `, 162 assignTokenHandlers: rewriter => { 163 rewriter.on('doctype', token => { 164 token.publicId = '42'; 165 token.systemId = 'hey'; 166 167 rewriter.emitDoctype(token); 168 }); 169 } 170}); 171 172exports['RewritingStream - emit multiple'] = createRewriterTest({ 173 src: srcHtml, 174 expected: dedent` 175 <!DOCTYPE html ""> 176 <wrap><html></wrap> 177 <!-- comment1 --> 178 <wrap><head 123=""></wrap> 179 </head> 180 <!-- comment2 --> 181 <wrap><body =123=""></wrap> 182 <wrap><div></wrap>Hey ya</div> 183 </body> 184 </html> 185 `, 186 assignTokenHandlers: rewriter => { 187 rewriter.on('startTag', token => { 188 rewriter.emitRaw('<wrap>'); 189 rewriter.emitStartTag(token); 190 rewriter.emitRaw('</wrap>'); 191 }); 192 } 193}); 194 195exports['RewritingStream - rewrite raw'] = createRewriterTest({ 196 src: srcHtml, 197 expected: dedent` 198 <!DOCTYPE html "">42 199 <html>42 200 <!-- comment1 -->42 201 <head /// 123>42 202 </head>42 203 <!-- comment2 -->42 204 <body =123>42 205 <div>42Hey ya</div>42 206 </body>42 207 </html>42 208 `, 209 assignTokenHandlers: rewriter => { 210 const rewriteRaw = (_, raw) => { 211 rewriter.emitRaw(raw + '42'); 212 }; 213 214 rewriter 215 .on('doctype', rewriteRaw) 216 .on('startTag', rewriteRaw) 217 .on('endTag', rewriteRaw) 218 .on('comment', rewriteRaw); 219 } 220}); 221 222exports['RewritingStream - Should escape entities in attributes and text'] = createRewriterTest({ 223 src: dedent` 224 <!DOCTYPE html ""> 225 <html> 226 <head foo='bar"baz"'> 227 </head> 228 <body> 229 <div>foo&bar</div> 230 </body> 231 </html> 232 `, 233 expected: dedent` 234 <!DOCTYPE html ""> 235 <html> 236 <head foo="bar"baz""> 237 </head> 238 <body> 239 <div>foo&bar</div> 240 </body> 241 </html> 242 `, 243 assignTokenHandlers: rewriter => { 244 rewriter.on('startTag', token => rewriter.emitStartTag(token)); 245 rewriter.on('text', token => rewriter.emitText(token)); 246 } 247}); 248 249exports['Regression - RewritingStream - Last text chunk must be flushed (GH-271)'] = done => { 250 const parser = new RewritingStream(); 251 let foundText = false; 252 253 parser.on('text', ({ text }) => { 254 foundText = true; 255 assert.strictEqual(text, 'text'); 256 }); 257 258 parser.once('finish', () => { 259 assert.ok(foundText); 260 done(); 261 }); 262 263 parser.write('text'); 264 parser.end(); 265}; 266 267exports['Regression - RewritingStream - Should not accept binary input (GH-269)'] = () => { 268 const stream = new RewritingStream(); 269 const buf = Buffer.from('test'); 270 271 assert.throws(() => stream.write(buf), TypeError); 272}; 273