From fd7d2e7cf485902c4662468b744451427066ac60 Mon Sep 17 00:00:00 2001 From: ache Date: Sat, 19 May 2018 10:09:19 +0200 Subject: Add more tests --- __tests__/index.js | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++-- index.js | 22 +++++--- 2 files changed, 156 insertions(+), 11 deletions(-) diff --git a/__tests__/index.js b/__tests__/index.js index 3c86fea..45f1315 100644 --- a/__tests__/index.js +++ b/__tests__/index.js @@ -13,6 +13,13 @@ import plugin from '..'; const Stream = stream.Readable; +const renderDefault = text => unified() + .use(reParse) + .use(plugin) + .use(remark2rehype) + .use(stringify) + .processSync(text); + const render = text => unified() .use(reParse) .use(plugin, {allowDangerousDOMEventHandlers: false, scope: 'permissive'}) @@ -22,13 +29,20 @@ const render = text => unified() const renderRaw = text => unified() .use(reParse) - .use(plugin, {allowDangerousDOMEventHandlers: true, scope: 'permissive'}) + .use(plugin, {allowDangerousDOMEventHandlers: false, scope: 'permissive'}) .use(remark2rehype, {allowDangerousHTML: true}) .use(raw) .use(stringify) .processSync(text); -const mainTestString = `Inline *test*{style="em:4"} paragraphe. Use **multiple**{ style="color:pink"} inline ~~block~~ tag. Line \`tagCode\`{ style="color:yellow"}.`; +/* + * TODO : + * - Invalid scope + * - Invalid extended + * - aria attributes + */ + +const mainTestString = `Inline *test*{style="em:4"} paragraph. Use **multiple**{ style="color:pink"} inline ~~block~~ tag. Line \`tagCode\`{ style="color:yellow"}.`; function string2stream(string) { const stream = new Stream(); @@ -59,6 +73,20 @@ function every(obj, fct) { return true; } +test('basic-default', t => { + const {contents} = renderDefault(mainTestString); + const parser = new parse5.SAXParser(); + + const nbTag = {em: 1, s: 1, code: 1, strong: 1, errorTag: 0}; + parser.on('startTag', name => { + if (name in nbTag) { + nbTag[name] -= 1; + } + }); + string2stream(contents).pipe(parser); + t.true(every(nbTag, x => x === 0)); +}); + test('basic', t => { const {contents} = render(mainTestString); const parser = new parse5.SAXParser(); @@ -88,7 +116,7 @@ test('basic-raw', t => { }); test('em', async t => { - const {contents} = render('textexampleno interest **Important**{style=4em} still no interest'); + const {contents} = render('textexamplenointerest **Important**{style=4em} still no interest'); const parser = new parse5.SAXParser(); parser.on('startTag', (name, attrs) => { @@ -100,6 +128,41 @@ test('em', async t => { await string2stream(contents).pipe(parser); }); +test('readme-default', async t => { + const fileExample = file(join(__dirname, 'readMeTest.txt')); + const {contents} = renderDefault(fileExample); + const parser = new parse5.SAXParser(); + + parser.on('startTag', (name, attrs) => { + switch (name) { + case 'img': + t.true(propEgal({height: 50, alt: 'alt', src: 'img'}, attrs)); + break; + case 'a': + t.true(propEgal({ref: 'external', src: 'https://rms.sexy'}, attrs)); + break; + case 'h3': + t.true(propEgal({style: 'color:red;'}, attrs)); + break; + case 'em': + t.true(propEgal({style: 'color:yellow;'}, attrs)); + break; + case 'strong': + t.true(propEgal({}, attrs)); + break; + case 'del': + t.true(propEgal({style: 'color: grey;'}, attrs)); + break; + case 'code': + t.true(propEgal({}, attrs)); + break; + default: + } + }); + + await string2stream(contents).pipe(parser); +}); + test('readme', async t => { const fileExample = file(join(__dirname, 'readMeTest.txt')); const {contents} = render(fileExample); @@ -123,7 +186,7 @@ test('readme', async t => { t.true(propEgal({awesome: ''}, attrs)); break; case 'del': - t.true(propEgal({style: 'color: grey;'}, attrs)); + t.true(propEgal({style: 'color: gray;'}, attrs)); break; case 'code': t.true(propEgal({lang: 'c'}, attrs)); @@ -135,3 +198,77 @@ test('readme', async t => { await string2stream(contents).pipe(parser); }); +test('extended', async t => { + const renderExtended = text => unified() + .use(reParse) + .use(plugin, {extend: {image: ['quality']}}) + .use(remark2rehype) + .use(stringify) + .process(text, (err, file) => { + const parser = new parse5.SAXParser(); + + t.true(!err); + + parser.on('startTag', (name, attrs) => { + if (name === 'img') { + t.true(propEgal({alt: 'Awesome image', src: 'aws://image.jpg', quality: '80'}, attrs)); + } + }); + string2stream(String(file)).pipe(parser); + }); + + await renderExtended(` +*Wait* ! +This is an awesome image : ![Awesome image](aws://image.jpg){ quality="80" awesomeness="max" } +`); +}); + +test('extended Dangerous', async t => { + const renderExtended = text => unified() + .use(reParse) + .use(plugin, {extend: {image: ['quality', 'onload']}}) + .use(remark2rehype) + .use(stringify) + .process(text, (err, file) => { + const parser = new parse5.SAXParser(); + + t.true(!err); + + parser.on('startTag', (name, attrs) => { + if (name === 'img') { + t.true(propEgal({alt: 'Awesome image', src: 'aws://image.jpg', quality: '80', onload: 'launchAwesomeFunction();'}, attrs)); + } + }); + string2stream(String(file)).pipe(parser); + }); + + await renderExtended(` +*Wait* ! +This is an awesome image : ![Awesome image](aws://image.jpg){ quality="80" awesomeness="max" onload="launchAwesomeFunction();" } +`); +}); + +test('extended-global', async t => { + const renderExtended = text => unified() + .use(reParse) + .use(plugin, {extend: {'*': ['exAttr']}}) + .use(remark2rehype) + .use(stringify) + .process(text, (err, file) => { + const parser = new parse5.SAXParser(); + + t.true(!err); + + parser.on('startTag', (name, attrs) => { + if (name === 'strong') { + t.true(propEgal({exAttr: 'true'}, attrs)); + } + }); + string2stream(String(file)).pipe(parser); + }); + + await renderExtended(` +*Wait* ! You are **beautiful**{ exAttr="true" } ! +`); +}); + diff --git a/index.js b/index.js index ace52e5..b9eba7e 100644 --- a/index.js +++ b/index.js @@ -39,6 +39,7 @@ const convTypeTag = { emphasis: 'em', delete: 's', inlineCode: 'code', + '*': '*', }; /* TODO : @@ -102,6 +103,14 @@ function filterAttributes(prop, config, type) { const {allowDangerousDOMEventHandlers} = config; const specific = htmlElemAttr; + const extendTag = (extend => { + const t = {}; + Object.getOwnPropertyNames(extend).forEach(p => { + t[convTypeTag[p]] = extend[p]; + }); + return t; + })(extend); + Object.getOwnPropertyNames(prop).forEach(p => { if (p !== 'key' && p !== 'class' && p !== 'id') { prop[p] = prop[p] || ''; @@ -109,7 +118,7 @@ function filterAttributes(prop, config, type) { }); const isDangerous = p => DOMEventHandler.indexOf(p) >= 0; - const isSpecific = p => 'type' in specific && specific[type].indexOf(p) >= 0; + const isSpecific = p => type in specific && specific[type].indexOf(p) >= 0; const isGlobal = p => htmlElemAttr['*'].indexOf(p) >= 0; let inScope = _ => false; @@ -127,8 +136,9 @@ function filterAttributes(prop, config, type) { inScope = x => !isDangerous(x); } break; - case 'extented': - inScope = p => extend[type].indexOf(p) >= 0; + case 'extended': + inScope = p => extendTag && type in extendTag && extendTag[type].indexOf(p) >= 0; + inScope = orFunc(inScope, p => '*' in extendTag && extendTag['*'].indexOf(p) >= 0); // Or if it in the specific scope, fallthrough case 'specific': inScope = orFunc(inScope, isSpecific); @@ -141,10 +151,8 @@ function filterAttributes(prop, config, type) { } } - const filterFunction = x => !inScope(x); - Object.getOwnPropertyNames(prop).forEach(p => { - if (filterFunction(p)) { + if (!inScope(p)) { delete prop[p]; } }); @@ -163,7 +171,7 @@ function remarkAttr(userConfig) { allowDangerousDOMEventHandlers: false, elements: supportedElements, extend: {}, - scope: 'specific', + scope: 'extended', }; const config = {...defaultConfig, ...userConfig}; -- cgit v1.2.3