refactor: remove /dist from repo

This commit is contained in:
harttle
2019-02-24 23:03:12 +08:00
parent f9f35ebd6c
commit 407ac6d0a4
185 changed files with 44 additions and 6025 deletions
-66
View File
@@ -1,66 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/array', function () {
describe('join', function () {
it('should support join', function () {
const src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
'{{ beatles | join: " and " }}'
return test(src, 'John and Paul and George and Ringo')
})
it('should default separator to space', function () {
const src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
'{{ beatles | join }}'
return test(src, 'John Paul George Ringo')
})
})
it('should support split/last', function () {
const src = '{% assign my_array = "zebra, octopus, giraffe, tiger" | split: ", " %}' +
'{{ my_array|last }}'
return test(src, 'tiger')
})
it('should support map', function () {
return test('{{posts | map: "category"}}', '["foo","bar"]')
})
it('should support reverse', function () {
return test('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}',
'.moT rojaM ot lortnoc dnuorG')
})
describe('size', function () {
it('should return string length',
() => test('{{ "Ground control to Major Tom." | size }}', '28'))
it('should return array size', function () {
return test('{% assign my_array = "apples, oranges, peaches, plums"' +
' | split: ", " %}{{ my_array | size }}',
'4')
})
it('should also be used with dot notation - string',
() => test('{% assign my_string = "Ground control to Major Tom." %}{{ my_string.size }}', '28'))
it('should also be used with dot notation - array',
() => test('{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}{{ my_array.size }}', '4'))
})
describe('slice', function () {
it('should slice first char by 0', () => test('{{ "Liquid" | slice: 0 }}', 'L'))
it('should slice third char by 2', () => test('{{ "Liquid" | slice: 2 }}', 'q'))
it('should slice substr by 2,5', () => test('{{ "Liquid" | slice: 2, 5 }}', 'quid'))
it('should slice substr by -3,2', () => test('{{ "Liquid" | slice: -3, 2 }}', 'ui'))
it('should support array', () => test('{{ "1,2,3,4" | split: "," | slice: 1,2 | join }}', '2 3'))
})
it('should support sort', function () {
return test('{% assign my_array = "zebra, octopus, giraffe, Sally Snake"' +
' | split: ", " %}' +
'{{ my_array | sort | join: ", " }}',
'Sally Snake, giraffe, octopus, zebra')
})
describe('uniq', function () {
it('should uniq string list', function () {
return test(
'{% assign my_array = "ants, bugs, bees, bugs, ants" | split: ", " %}' +
'{{ my_array | uniq | join: ", " }}',
'ants, bugs, bees'
)
})
it('should uniq falsy value', function () {
return test('{{"" | uniq | join: ","}}', '')
})
})
})
-20
View File
@@ -1,20 +0,0 @@
import { test, ctx } from 'test/stub/render'
describe('filters/date', function () {
it('should support date: %a %b %d %Y', function () {
const str = ctx.date.toDateString()
return test('{{ date | date:"%a %b %d %Y"}}', str)
})
it('should create a new Date when given "now"', function () {
return test('{{ "now" | date: "%Y"}}', (new Date()).getFullYear().toString())
})
it('should parse as Date when given UTC string', function () {
return test('{{ "1991-02-22T00:00:00" | date: "%Y"}}', '1991')
})
it('should render string as string if not valid', function () {
return test('{{ "foo" | date: "%Y"}}', 'foo')
})
it('should render object as string if not valid', function () {
return test('{{ obj | date: "%Y"}}', '{"foo":"bar"}')
})
})
-43
View File
@@ -1,43 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/html', function () {
describe('escape', function () {
it('should escape \' and &', function () {
return test('{{ "Have you read \'James & the Giant Peach\'?" | escape }}',
'Have you read 'James & the Giant Peach'?')
})
it('should escape normal string', function () {
return test('{{ "Tetsuro Takara" | escape }}', 'Tetsuro Takara')
})
it('should escape function', function () {
return test('{{ func | escape }}', 'function () { }')
})
})
describe('escape_once', function () {
it('should do escape', () =>
test('{{ "1 < 2 & 3" | escape_once }}', '1 &lt; 2 &amp; 3'))
it('should not escape twice',
() => test('{{ "1 &lt; 2 &amp; 3" | escape_once }}', '1 &lt; 2 &amp; 3'))
})
describe('strip_html', function () {
it('should strip all tags', function () {
return test('{{ "Have <em>you</em> read <cite><a href=&quot;https://en.wikipedia.org/wiki/Ulysses_(novel)&quot;>Ulysses</a></cite>?" | strip_html }}',
'Have you read Ulysses?')
})
it('should strip all comment tags', function () {
return test('{{ "<!--Have you read-->Ulysses?" | strip_html }}',
'Ulysses?')
})
it('should strip all style tags and their contents', function () {
return test('{{ "<style>cite { font-style: italic; }</style><cite>Ulysses<cite>?" | strip_html }}',
'Ulysses?')
})
it('should strip all scripts tags and their contents', function () {
return test('{{ "<script async>console.log(\'hello world\')</script><cite>Ulysses<cite>?" | strip_html }}',
'Ulysses?')
})
it('should strip until empty', function () {
return test('{{"<br/><br />< p ></p></ p >" | strip_html }}', '')
})
})
})
-64
View File
@@ -1,64 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/math', function () {
describe('abs', function () {
it('should return 3 for -3', () => test('{{ -3 | abs }}', '3'))
it('should return 2 for arr[0]', () => test('{{ arr[0] | abs }}', '2'))
it('should return convert string', () => test('{{ "-3" | abs }}', '3'))
})
describe('ceil', function () {
it('should return "2" for 1.2', () => test('{{ 1.2 | ceil }}', '2'))
it('should return "2" for 2.0', () => test('{{ 2.0 | ceil }}', '2'))
it('should return "4" for 3.5', () => test('{{ "3.5" | ceil }}', '4'))
it('should return "184" for 183.357', () => test('{{ 183.357 | ceil }}', '184'))
})
describe('divided_by', function () {
it('should return 2 for 4,2', () => test('{{4 | divided_by: 2}}', '2'))
it('should return 4 for 16,4', () => test('{{16 | divided_by: 4}}', '4'))
it('should return 1 for 5,3', () => test('{{5 | divided_by: 3}}', (5 / 3).toString()))
it('should convert string to number', () => test('{{"6" | divided_by: "3"}}', '2'))
})
describe('floor', function () {
it('should return "1" for 1.2', () => test('{{ 1.2 | floor }}', '1'))
it('should return "2" for 2.0', () => test('{{ 2.0 | floor }}', '2'))
it('should return "183" for 183.357', () => test('{{ 183.357 | floor }}', '183'))
it('should return "3" for 3.5', () => test('{{ "3.5" | floor }}', '3'))
})
describe('minus', function () {
it('should return "2" for 4,2', () => test('{{ 4 | minus: 2 }}', '2'))
it('should return "12" for 16,4', () => test('{{ 16 | minus: 4 }}', '12'))
it('should return "171.357" for 183.357,12',
() => test('{{ 183.357 | minus: 12 }}', '171.357'))
it('should convert first arg as number', () => test('{{ "4" | minus: 1 }}', '3'))
it('should convert both args as number', () => test('{{ "4" | minus: "1" }}', '3'))
})
describe('modulo', function () {
it('should return "1" for 3,2', () => test('{{ 3 | modulo: 2 }}', '1'))
it('should return "3" for 24,7', () => test('{{ 24 | modulo: 7 }}', '3'))
it('should return "3.357" for 183.357,12',
() => test('{{ 183.357 | modulo: 12 }}', '3.357'))
it('should convert string', () => test('{{ "24" | modulo: "7" }}', '3'))
})
describe('plus', function () {
it('should return "6" for 4,2', () => test('{{ 4 | plus: 2 }}', '6'))
it('should return "20" for 16,4', () => test('{{ 16 | plus: 4 }}', '20'))
it('should return "195.357" for 183.357,12',
() => test('{{ 183.357 | plus: 12 }}', '195.357'))
it('should convert first arg as number', () => test('{{ "4" | plus: 2 }}', '6'))
it('should convert both args as number', () => test('{{ "4" | plus: "2" }}', '6'))
})
describe('round', function () {
it('should return "1" for 1.2', () => test('{{1.2|round}}', '1'))
it('should return "3" for 2.7', () => test('{{2.7|round}}', '3'))
it('should return "183.36" for 183.357,2',
() => test('{{183.357|round: 2}}', '183.36'))
it('should convert string to number', () => test('{{"2.7"|round}}', '3'))
})
describe('times', function () {
it('should return "6" for 3,2', () => test('{{ 3 | times: 2 }}', '6'))
it('should return "168" for 24,7', () => test('{{ 24 | times: 7 }}', '168'))
it('should return "2200.284" for 183.357,12',
() => test('{{ 183.357 | times: 12 }}', '2200.284'))
it('should convert string to number', () => test('{{ "24" | times: "7" }}', '168'))
})
})
-8
View File
@@ -1,8 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/object', function () {
describe('default', function () {
it('should use default when falsy', () => test('{{false |default: "a"}}', 'a'))
it('should not use default when truthy', () => test('{{true |default: "a"}}', 'true'))
})
})
-176
View File
@@ -1,176 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/string', function () {
describe('append', function () {
it('should return "-3abc" for -3, "abc"',
() => test('{{ -3 | append: "abc" }}', '-3abc'))
it('should return "abar" for "a",foo', () => test('{{ "a" | append: foo }}', 'abar'))
})
describe('capitalize', function () {
it('should capitalize first', () => test('{{ "i am good" | capitalize }}', 'I am good'))
})
describe('concat', function () {
it('should concat arrays', () => test(`
{%- assign fruits = "apples, oranges, peaches" | split: ", " -%}
{%- assign vegetables = "carrots, turnips, potatoes" | split: ", " -%}
{%- assign everything = fruits | concat: vegetables -%}
{%- for item in everything -%}
- {{ item }}
{% endfor -%}`, `- apples
- oranges
- peaches
- carrots
- turnips
- potatoes
`))
it('should support chained concat', () => test(`
{%- assign fruits = "apples, oranges, peaches" | split: ", " -%}
{%- assign vegetables = "carrots, turnips, potatoes" | split: ", " -%}
{%- assign furniture = "chairs, tables, shelves" | split: ", " -%}
{%- assign everything = fruits | concat: vegetables | concat: furniture -%}
{%- for item in everything -%}
- {{ item }}
{% endfor -%}`, `- apples
- oranges
- peaches
- carrots
- turnips
- potatoes
- chairs
- tables
- shelves
`))
})
describe('downcase', function () {
it('should return "parker moore" for "Parker Moore"',
() => test('{{ "Parker Moore" | downcase }}', 'parker moore'))
it('should return "apple" for "apple"',
() => test('{{ "apple" | downcase }}', 'apple'))
})
describe('split', function () {
it('should support split/first', function () {
const src = '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}' +
'{{ my_array | first }}'
return test(src, 'apples')
})
})
it('should support upcase', () => test('{{ "Parker Moore" | upcase }}', 'PARKER MOORE'))
it('should support lstrip', function () {
const src = '{{ " So much room for activities! " | lstrip }}'
return test(src, 'So much room for activities! ')
})
it('should support string_with_newlines', function () {
const src = '{% capture string_with_newlines %}\n' +
'Hello\n' +
'there\n' +
'{% endcapture %}' +
'{{ string_with_newlines | newline_to_br }}'
const dst = '<br />' +
'Hello<br />' +
'there<br />'
return test(src, dst)
})
it('should support prepend', function () {
return test('{% assign url = "liquidmarkup.com" %}' +
'{{ "/index.html" | prepend: url }}',
'liquidmarkup.com/index.html')
})
it('should support remove', function () {
return test('{{ "I strained to see the train through the rain" | remove: "rain" }}',
'I sted to see the t through the ')
})
it('should support remove_first', function () {
return test('{{ "I strained to see the train through the rain" | remove_first: "rain" }}',
'I sted to see the train through the rain')
})
it('should support replace', function () {
return test('{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }}',
'Take your protein pills and put your helmet on')
})
it('should support replace_first', function () {
return test('{% assign my_string = "Take my protein pills and put my helmet on" %}\n' +
'{{ my_string | replace_first: "my", "your" }}',
'\nTake your protein pills and put my helmet on')
})
it('should support rstrip', function () {
return test('{{ " So much room for activities! " | rstrip }}',
' So much room for activities!')
})
it('should support split', function () {
return test('{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
'{% for member in beatles %}' +
'{{ member }} ' +
'{% endfor %}',
'John Paul George Ringo ')
})
it('should support strip', function () {
return test('{{ " So much room for activities! " | strip }}',
'So much room for activities!')
})
it('should support strip_newlines', function () {
return test('{% capture string_with_newlines %}\n' +
'Hello\nthere\n{% endcapture %}' +
'{{ string_with_newlines | strip_newlines }}',
'Hellothere')
})
describe('truncate', function () {
it('should truncate when string too long', function () {
return test('{{ "Ground control to Major Tom." | truncate: 20 }}',
'Ground control to...')
})
it('should not truncate when string not long enough', function () {
return test('{{ "Ground control to Major Tom." | truncate: 80 }}',
'Ground control to Major Tom.')
})
it('should truncate with custom ellipsis', function () {
return test('{{ "Ground control to Major Tom." | truncate: 25,", and so on" }}',
'Ground control, and so on')
})
it('should truncate with empty custom ellipsis', function () {
return test('{{ "Ground control to Major Tom." | truncate: 20, "" }}',
'Ground control to Ma')
})
it('should not truncate when short enough', function () {
return test('{{ "12345" | truncate: 5 }}', '12345')
})
it('should truncate to "..." when len <= 3', function () {
return test('{{ "12345" | truncate: 2 }}', '...')
})
it('should not truncate if length is exactly len', function () {
return test('{{ "12345" | truncate: 5 }}', '12345')
})
it('should default to 50', function () {
return test('{{ "1234567890123456789012345678901234567890123456789abc" | truncate }}', '12345678901234567890123456789012345678901234567...')
})
})
describe('truncatewords', function () {
it('should truncate when too many words', function () {
return test('{{ "Ground control to Major Tom." | truncatewords: 3 }}',
'Ground control to...')
})
it('should not truncate when not enough words', function () {
return test('{{ "Ground control to Major Tom." | truncatewords: 8 }}',
'Ground control to Major Tom.')
})
it('should truncate with custom ellipsis', function () {
return test('{{ "Ground control to Major Tom." | truncatewords: 3, "--" }}',
'Ground control to--')
})
it('should truncate with empty custom ellipsis', function () {
return test('{{ "Ground control to Major Tom." | truncatewords: 3, "" }}',
'Ground control to')
})
it('should allow multiple space chars between', function () {
return test('{{ "1 \t2 3 \n4" | truncatewords: 3 }}', '1 2 3...')
})
it('should show ellipsis if length is exactly len', function () {
return test('{{ "1 2 3" | truncatewords: 3 }}', '1 2 3...')
})
it('should default len to 15', function () {
return test('{{ "1 2 3 4 5 6 7 8 9 a b c d e f" | truncatewords }}', '1 2 3 4 5 6 7 8 9 a b c d e f...')
})
})
})
-15
View File
@@ -1,15 +0,0 @@
import { test } from 'test/stub/render'
describe('filters/url', function () {
describe('url_decode', function () {
it('should decode %xx and +',
() => test('{{ "%27Stop%21%27+said+Fred" | url_decode }}', "'Stop!' said Fred"))
})
describe('url_encode', function () {
it('should encode @',
() => test('{{ "[email protected]" | url_encode }}', 'john%40liquid.com'))
it('should encode <space>',
() => test('{{ "Tetsuro Takara" | url_encode }}', 'Tetsuro+Takara'))
})
})
-79
View File
@@ -1,79 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/assign', function () {
const liquid = new Liquid()
it('should throw when variable expression illegal', function () {
const src = '{% assign / %}'
const ctx = {}
return expect(liquid.parseAndRender(src, ctx)).to.be.rejectedWith(/illegal/)
})
it('should support assign to a string', async function () {
const src = '{% assign foo="bar" %}{{foo}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('bar')
})
it('should support assign to a number', async function () {
const src = '{% assign foo=10086 %}{{foo}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('10086')
})
it('should shading rather than overwriting', async function () {
const ctx = { foo: 'foo' }
const src = '{% assign foo="FOO" %}{{foo}}'
const html = await liquid.parseAndRender(src, ctx)
expect(html).to.equal('FOO')
expect(ctx.foo).to.equal('foo')
})
it('should assign as array', async function () {
const src = '{% assign foo=(1..3) %}{{foo}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('[1,2,3]')
})
it('should assign as filter result', async function () {
const src = '{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('A')
})
it('should assign as filter across multiple lines as result', async function () {
const src = `{% assign foo="a b"
| capitalize
| split: " "
| first %}{{foo}}`
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('A')
})
it('should assign var-1', async function () {
const src = '{% assign var-1 = 5 %}{{ var-1 }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('5')
})
it('should assign var-', async function () {
const src = '{% assign var- = 5 %}{{ var- }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('5')
})
it('should assign -var', async function () {
const src = '{% assign -let = 5 %}{{ -let }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('5')
})
it('should assign -5-5', async function () {
const src = '{% assign -5-5 = 5 %}{{ -5-5 }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('5')
})
it('should assign 4-3', async function () {
const src = '{% assign 4-3 = 5 %}{{ 4-3 }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('5')
})
it('should not assign -6', async function () {
const src = '{% assign -6 = 5 %}{{ -6 }}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-6')
})
})
-35
View File
@@ -1,35 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/capture', function () {
const liquid = new Liquid()
it('should support capture', async function () {
const src = '{% capture f %}{{"a" | capitalize}}{%endcapture%}{{f}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('A')
})
it('should shading rather than overwriting', async function () {
const src = '{% capture var %}10{% endcapture %}{{var}}'
const ctx = { 'var': 20 }
const html = await liquid.parseAndRender(src, ctx)
expect(html).to.equal('10')
expect(ctx.var).to.equal(20)
})
it('should throw on invalid identifier', function () {
const src = '{% capture = %}{%endcapture%}'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/= not valid identifier/)
})
it('should throw when capture not closed', function () {
const src = '{%capture c%}{{c}}'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/tag .* not closed/)
})
})
-51
View File
@@ -1,51 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/case', function () {
const liquid = new Liquid()
it('should reject if not closed', function () {
const src = '{% case "foo"%}'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/{% case "foo"%} not closed/)
})
it('should hit the specified case', async function () {
const src = '{% case "foo"%}' +
'{% when "foo" %}foo{% when "bar"%}bar' +
'{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('foo')
})
it('should resolve blank as empty string', async function () {
const src = '{% case blank %}{% when ""%}bar{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('bar')
})
it('should resolve empty as empty string', async function () {
const src = '{% case empty %}{% when ""%}bar{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('bar')
})
it('should accept empty string as branch name', async function () {
const src = '{% case "" %}{% when ""%}bar{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('bar')
})
it('should support boolean case', async function () {
const src = '{% case false %}' +
'{% when "foo" %}foo{% when false%}bar' +
'{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('bar')
})
it('should support else branch', async function () {
const src = '{% case "a" %}' +
'{% when "b" %}b{% when "c"%}c{%else %}d' +
'{%endcase%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('d')
})
})
-34
View File
@@ -1,34 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/comment', function () {
const liquid = new Liquid()
it('should support empty content', function () {
const src = '{% comment %}{% raw%}'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/{% comment %} not closed/)
})
it('should ignore plain string', async function () {
const src = 'My name is {% comment %}super{% endcomment %} Shopify.'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('My name is Shopify.')
})
it('should ignore output tokens', async function () {
const src = '{% comment %}\n{{ foo}} \n{% endcomment %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('')
})
it('should ignore tag tokens', async function () {
const src = '{% comment %}{%if true%}true{%else%}false{%endif%}{% endcomment %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('')
})
it('should ignore un-balenced tag tokens', async function () {
const src = '{% comment %}{%if true%}true{%else%}false{% endcomment %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('')
})
})
-38
View File
@@ -1,38 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/cycle', function () {
const liquid = new Liquid()
it('should support cycle', async function () {
const src = "{% cycle '1', '2', '3' %}"
const html = await liquid.parseAndRender(src + src + src + src)
return expect(html).to.equal('1231')
})
it('should throw when cycle candidates empty', function () {
return expect(liquid.parseAndRender('{%cycle%}'))
.to.be.rejectedWith(/empty candidates/)
})
it('should support cycle in for block', async function () {
const src = '{% for i in (1..5) %}{% cycle one, "e"%}{% endfor %}'
const ctx = {
one: 1
}
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('1e1e1')
})
it('should support cycle group', async function () {
const src = "{% cycle one: '1', '2', '3'%}" +
"{% cycle 1: '1', '2', '3'%}" +
"{% cycle 2: '1', '2', '3'%}"
const ctx = { one: 1 }
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('121')
})
})
-58
View File
@@ -1,58 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/decrement', function () {
const liquid = new Liquid()
it('should throw when variable expression illegal', function () {
const src = '{% decrement / %}{{var}}'
const ctx = {}
return expect(liquid.parseAndRender(src, ctx)).to.be.rejectedWith(/illegal/)
})
it('should decrement undefined variable', async function () {
const src = '{% decrement var %}{% decrement var %}{% decrement var %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-1-2-3')
})
it('should decrement defined variable', async function () {
const src = '{% decrement var %}{% decrement var %}{% decrement var %}'
const ctx = { 'var': 10 }
const html = await liquid.parseAndRender(src, ctx)
expect(html).to.equal('987')
expect(ctx.var).to.equal(7)
})
it('should be independent from assign', async function () {
const src = '{% assign var=10 %}{% decrement var %}{% decrement var %}{% decrement var %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-1-2-3')
})
it('should be independent from capture', async function () {
const src = '{% capture var %}10{% endcapture %}{% decrement var %}{% decrement var %}{% decrement var %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-1-2-3')
})
it('should not shading assign', async function () {
const src = '{% assign var=10 %}{% decrement var %}{% decrement var %}{% decrement var %} {{var}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-1-2-3 10')
})
it('should not shading capture', async function () {
const src = '{% capture var %}10{% endcapture %}{% decrement var %}{% decrement var %}{% decrement var %} {{var}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('-1-2-3 10')
})
it('should share the same variable with increment', async function () {
const src = '{%increment var%}{%increment var%}{%decrement var%}{%decrement var%}{%increment var%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('01100')
})
})
-204
View File
@@ -1,204 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
import { Context } from 'src/scope/scope'
use(chaiAsPromised)
describe('tags/for', function () {
let liquid: Liquid, ctx: Context
before(function () {
liquid = new Liquid()
liquid.registerTag('throwingTag', {
render: function () { throw new Error('intended render error') }
})
ctx = {
one: 1,
// eslint-disable-next-line
strObj: new String(''),
emptyObj: {},
nullProtoObj: Object.create(null),
obj: { foo: 'bar', coo: 'haa' },
alpha: ['a', 'b', 'c'],
emptyArray: []
}
})
it('should support array', async function () {
const src = '{%for c in alpha%}{{c}}{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('abc')
})
it('should support object', async function () {
const src = '{%for item in obj%}{{item[0]}},{{item[1]}}-{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('foo,bar-coo,haa-')
})
describe('scope', function () {
it('should read super scope', async function () {
const src = '{%for a in (1..2)%}{{num}}{%endfor%}'
const html = await liquid.parseAndRender(src, { num: 1 })
return expect(html).to.equal('11')
})
it('should write super scope', async function () {
const src = '{%for a in (1..2)%}{{num}}{%assign num = 2%}{%endfor%}'
const html = await liquid.parseAndRender(src, { num: 1 })
return expect(html).to.equal('12')
})
})
describe('illegal', function () {
it('should reject when for not closed', function () {
const src = '{%for c in alpha%}{{c}}'
return expect(liquid.parseAndRender(src, ctx))
.to.be.rejectedWith(/tag .* not closed/)
})
it('should reject when inner templates rejected', function () {
const src = '{%for c in alpha%}{%throwingTag%}{%endfor%}'
return expect(liquid.parseAndRender(src, ctx))
.to.be.rejectedWith(/intended render error/)
})
})
describe('else', function () {
it('should goto else for empty array', async function () {
const src = '{%for c in emptyArray%}a{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('b')
})
it('should treat non-empty string as one single element', async function () {
const src = '{%for c in "abc"%}x{{c}}{%else%}y{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('xabc')
})
it('should goto else for empty string', async function () {
const src = '{%for c in ""%}a{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('b')
})
it('should goto else for empty string object', async function () {
// it should be false although `new String` is none-conform
const src = '{%for c in strObj%}a{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('b')
})
it('should goto else for empty object', async function () {
const src = '{%for c in emptyObj%}a{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('b')
})
it('should goto else for null-prototyped object', async function () {
const src = '{%for c in nullProtoObj%}a{%else%}b{%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('b')
})
})
it('should support for with forloop', async function () {
const src = '{%for c in alpha%}' +
'{{forloop.first}}.{{forloop.index}}.{{forloop.index0}}.' +
'{{forloop.last}}.{{forloop.length}}.' +
'{{forloop.rindex}}.{{forloop.rindex0}}' +
'{{c}}\n' +
'{%endfor%}'
const dst = 'true.1.0.false.3.3.2a\n' +
'false.2.1.false.3.2.1b\n' +
'false.3.2.true.3.1.0c\n'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal(dst)
})
it('should support for with continue', async function () {
const src = '{% for i in (1..5) %}' +
'{{i}}{% continue %}after' +
'{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('12345')
})
it('should support for with break', async function () {
const src = '{% for i in (one..5) %}' +
'{% if i == 4 %}{% break %}{% endif %}' +
'{{ i }}' +
'{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('123')
})
describe('limit', function () {
it('should support for with limit', async function () {
const src = '{% for i in (1..5) limit:2 %}{{ i }}{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('12')
})
it('should set forloop.last properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.last}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('false true ')
})
it('should set forloop.first properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.first}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('true false ')
})
it('should set forloop.length properly', function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.length}} {%endfor%}'
return expect(liquid.parseAndRender(src, ctx))
.to.eventually.equal('2 2 ')
})
})
describe('offset', function () {
it('should support offset with limit', async function () {
const src = '{% for i in (1..10) limit:2 offset:5%}{{ i }}{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('67')
})
it('should set index properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.index}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('1 2 ')
})
it('should set index0 properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.index0}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('0 1 ')
})
it('should set rindex properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.rindex}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('2 1 ')
})
it('should set rindex0 properly', async function () {
const src = '{%for i in (1..10) limit:2 offset:3%}{{forloop.rindex0}} {%endfor%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('1 0 ')
})
})
describe('reverse', function () {
it('should support for reversed in the last position', async function () {
const src = '{% for i in (1..5) limit:2 reversed %}{{ i }}{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('21')
})
it('should support for reversed in the first position', async function () {
const src = '{% for i in (1..5) reversed limit:2 %}{{ i }}{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('21')
})
it('should support for reversed in the middle position', async function () {
const src = '{% for i in (1..5) offset:2 reversed limit:4 %}{{ i }}{% endfor %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('543')
})
})
})
-113
View File
@@ -1,113 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
describe('tags/if', function () {
const liquid = new Liquid()
const ctx = {
one: 1,
two: 2,
emptyString: '',
emptyArray: []
}
it('should throw if not closed', function () {
const src = '{% if false%}yes'
return expect(liquid.parseAndRender(src, ctx))
.to.be.rejectedWith(/tag {% if false%} not closed/)
})
it('should support nested', async function () {
const src = '{%if false%}{%if true%}{%else%}a{%endif%}{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('')
})
describe('single value as condition', function () {
it('should support boolean', async function () {
const src = '{% if false %}1{%elsif true%}2{%else%}3{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('2')
})
it('should treat Array truthy', async function () {
const src = '{%if emptyArray%}a{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('a')
})
it('should return true if empty string', async function () {
const src = '{%if emptyString%}a{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('a')
})
})
describe('expression as condition', function () {
it('should support ==', async function () {
const src = '{% if 2==3 %}yes{%else%}no{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should support >=', async function () {
const src = '{% if 1>=2 and one<two %}a{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('')
})
it('should support !=', async function () {
const src = '{% if one!=two %}yes{%else%}no{%endif%}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('yes')
})
it('should support value and expression', async function () {
const src = `X{%if version and version != '' %}x{{version}}y{%endif%}Y`
const ctx = { 'version': '' }
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('XY')
})
})
describe('comparasion to null', function () {
it('should evaluate false for null < 10', async function () {
const src = '{% if null < 10 %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for null > 10', async function () {
const src = '{% if null > 10 %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for null <= 10', async function () {
const src = '{% if null <= 10 %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for null >= 10', async function () {
const src = '{% if null >= 10 %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for 10 < null', async function () {
const src = '{% if 10 < null %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for 10 > null', async function () {
const src = '{% if 10 > null %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for 10 <= null', async function () {
const src = '{% if 10 <= null %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
it('should evaluate false for 10 >= null', async function () {
const src = '{% if 10 >= null %}yes{% else %}no{% endif %}'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal('no')
})
})
})
-147
View File
@@ -1,147 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
import { mock, restore } from 'test/stub/mockfs'
describe('tags/include', function () {
let liquid: Liquid
before(function () {
liquid = new Liquid({
root: '/',
extname: '.html'
})
})
afterEach(restore)
it('should support include', async function () {
mock({
'/current.html': 'bar{% include "bar/foo.html" %}bar',
'/bar/foo.html': 'foo'
})
const html = await liquid.renderFile('/current.html')
return expect(html).to.equal('barfoobar')
})
it('should support template string', async function () {
mock({
'/current.html': 'bar{% include "bar/{{name}}" %}bar',
'/bar/foo.html': 'foo'
})
const html = await liquid.renderFile('/current.html', { name: 'foo.html' })
return expect(html).to.equal('barfoobar')
})
it('should throw when not specified', function () {
mock({
'/parent.html': '{%include%}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).to.equal('RenderError')
expect(e.message).to.match(/cannot include with empty filename/)
})
})
it('should throw when not exist', function () {
mock({
'/parent.html': '{%include not-exist%}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).to.equal('RenderError')
expect(e.message).to.match(/cannot include with empty filename/)
})
})
it('should support include with relative path', async function () {
mock({
'/bar/foo.html': 'foo',
'/foo/relative.html': 'bar{% include "../bar/foo.html" %}bar'
})
const html = await liquid.renderFile('foo/relative.html')
return expect(html).to.equal('barfoobar')
})
it('should support include: hash list', async function () {
mock({
'/hash.html': '{% assign name="harttle" %}{% include "user.html", role: "admin", alias: name %}',
'/user.html': '{{name}} : {{role}} : {{alias}}'
})
const html = await liquid.renderFile('hash.html')
return expect(html).to.equal('harttle : admin : harttle')
})
it('should support include: parent scope', async function () {
mock({
'/scope.html': '{% assign shape="triangle" %}{% assign color="yellow" %}{% include "color.html" %}',
'/color.html': 'color:{{color}}, shape:{{shape}}'
})
const html = await liquid.renderFile('scope.html')
return expect(html).to.equal('color:yellow, shape:triangle')
})
it('should support include: with', async function () {
mock({
'/with.html': '{% include "color" with "red", shape: "rect" %}',
'/color.html': 'color:{{color}}, shape:{{shape}}'
})
const html = await liquid.renderFile('with.html')
return expect(html).to.equal('color:red, shape:rect')
})
it('should support nested includes', async function () {
mock({
'/personInfo.html': 'This is a person {% include "card.html" %}',
'/card.html': '<p>{{person.firstName}} {{person.lastName}}<br/>{% include "address" %}</p>',
'/address.html': 'City: {{person.address.city}}'
})
const ctx = {
person: {
firstName: 'Joe',
lastName: 'Shmoe',
address: {
city: 'Dallas'
}
}
}
const html = await liquid.renderFile('personInfo.html', ctx)
return expect(html).to.equal('This is a person <p>Joe Shmoe<br/>City: Dallas</p>')
})
describe('static partial', function () {
it('should support filename with extention', async function () {
mock({
'/parent.html': 'X{% include child.html color:"red" %}Y',
'/child.html': 'child with {{color}}'
})
const staticLiquid = new Liquid({ dynamicPartials: false, root: '/' })
const html = await staticLiquid.renderFile('parent.html')
return expect(html).to.equal('Xchild with redY')
})
it('should support parent paths', async function () {
mock({
'/parent.html': 'X{% include bar/./../foo/child.html %}Y',
'/foo/child.html': 'child'
})
const staticLiquid = new Liquid({ dynamicPartials: false, root: '/' })
const html = await staticLiquid.renderFile('parent.html')
return expect(html).to.equal('XchildY')
})
it('should support subpaths', async function () {
mock({
'/parent.html': 'X{% include foo/child.html %}Y',
'/foo/child.html': 'child'
})
const staticLiquid = new Liquid({ dynamicPartials: false, root: '/' })
const html = await staticLiquid.renderFile('parent.html')
return expect(html).to.equal('XchildY')
})
it('should support comma separated arguments', async function () {
mock({
'/parent.html': 'X{% include child.html, color:"red" %}Y',
'/child.html': 'child with {{color}}'
})
const staticLiquid = new Liquid({ dynamicPartials: false, root: '/' })
const html = await staticLiquid.renderFile('parent.html')
return expect(html).to.equal('Xchild with redY')
})
})
})
-47
View File
@@ -1,47 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/increment', function () {
const liquid = new Liquid()
it('should increment undefined variable', async function () {
const src = '{% increment one %}{% increment one %}{% increment one %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('012')
})
it('should increment defined variable', async function () {
const src = '{% increment one %}{% increment one %}{% increment one %}'
const ctx = { one: 7 }
const html = await liquid.parseAndRender(src, ctx)
expect(html).to.equal('789')
expect(ctx.one).to.equal(10)
})
it('should be independent from assign', async function () {
const src = '{% assign var=10 %}{% increment var %}{% increment var %}{% increment var %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('012')
})
it('should be independent from capture', async function () {
const src = '{% capture var %}10{% endcapture %}{% increment var %}{% increment var %}{% increment var %}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('012')
})
it('should not shading assign', async function () {
const src = '{% assign var=10 %}{% increment var %}{% increment var %}{% increment var %} {{var}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('012 10')
})
it('should not shading capture', async function () {
const src = '{% capture var %}10{% endcapture %}{% increment var %}{% increment var %}{% increment var %} {{var}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('012 10')
})
})
-136
View File
@@ -1,136 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
import { mock, restore } from 'test/stub/mockfs'
describe('tags/layout', function () {
let liquid: Liquid
before(function () {
liquid = new Liquid({
root: '/',
extname: '.html'
})
})
afterEach(restore)
it('should throw when block not closed', function () {
mock({
'/parent.html': 'parent'
})
const src = '{% layout "parent" %}{%block%}A'
return expect(liquid.parseAndRender(src)).to
.be.rejectedWith(/tag {%block%} not closed/)
})
it('should throw when filename not specified', function () {
mock({
'/parent.html': '{%layout%}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).to.equal('RenderError')
expect(e.message).to.match(/cannot apply layout with empty filename/)
})
})
describe('anonymous block', function () {
it('should handle anonymous block', async function () {
mock({
'/parent.html': 'X{%block%}{%endblock%}Y'
})
const src = '{% layout "parent.html" %}{%block%}A{%endblock%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('XAY')
})
it('should handle top level contents as anonymous block', async function () {
mock({
'/parent.html': 'X{%block%}{%endblock%}Y'
})
const src = '{% layout "parent.html" %}A'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('XAY')
})
})
it('should handle named blocks', async function () {
mock({
'/parent.html': 'X{% block "a"%}{% endblock %}Y{% block b%}{%endblock%}Z'
})
const src = '{% layout "parent.html" %}' +
'{%block a%}A{%endblock%}' +
'{%block b%}B{%endblock%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('XAYBZ')
})
it('should support default block content', async function () {
mock({
'/parent.html': 'X{% block "a"%}A{% endblock %}Y{% block b%}B{%endblock%}Z'
})
const src = '{% layout "parent.html" %}{%block a%}a{%endblock%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('XaYBZ')
})
it('should handle nested block', async function () {
mock({
'/grand.html': 'X{%block a%}G{%endblock%}Y',
'/parent.html': '{%layout "grand" %}{%block a%}P{%endblock%}',
'/main.html': '{%layout "parent"%}{%block a%}A{%endblock%}'
})
const html = await liquid.renderFile('/main.html')
return expect(html).to.equal('XAY')
})
it('should not bleed scope into included layout', async function () {
mock({
'/parent.html': 'X{%block a%}{%endblock%}Y{%block b%}{%endblock%}Z',
'/main.html': '{%layout "parent"%}' +
'{%block a%}A{%endblock%}' +
'{%block b%}I{%include "included"%}J{%endblock%}',
'/included.html': '{%layout "parent"%}{%block a%}a{%endblock%}'
})
const html = await liquid.renderFile('main')
return expect(html).to.equal('XAYIXaYZJZ')
})
it('should support hash list', async function () {
mock({
'/parent.html': '{{color}}{%block%}{%endblock%}',
'/main.html': '{% layout "parent.html" color:"black"%}{%block%}A{%endblock%}'
})
const html = await liquid.renderFile('/main.html')
return expect(html).to.equal('blackA')
})
it('should support multiple hash', async function () {
mock({
'/parent.html': '{{color}}{{bg}}{%block%}{%endblock%}',
'/main.html': '{% layout "parent.html" color:"black", bg:"red"%}{%block%}A{%endblock%}'
})
const html = await liquid.renderFile('/main.html')
return expect(html).to.equal('blackredA')
})
describe('static partial', function () {
it('should support filename with extention', async function () {
mock({
'/parent.html': '{{color}}{%block%}{%endblock%}',
'/main.html': '{% layout parent.html color:"black"%}{%block%}A{%endblock%}'
})
const staticLiquid = new Liquid({ root: '/', dynamicPartials: false })
const html = await staticLiquid.renderFile('/main.html')
return expect(html).to.equal('blackA')
})
it('should support parent paths', async function () {
mock({
'/foo/parent.html': '{{color}}{%block%}{%endblock%}',
'/main.html': '{% layout bar/../foo/parent.html color:"black"%}{%block%}A{%endblock%}'
})
const staticLiquid = new Liquid({ root: '/', dynamicPartials: false })
const html = await staticLiquid.renderFile('/main.html')
return expect(html).to.equal('blackA')
})
it('should support subpaths', async function () {
mock({
'/foo/parent.html': '{{color}}{%block%}{%endblock%}',
'/main.html': '{% layout foo/parent.html color:"black"%}{%block%}A{%endblock%}'
})
const staticLiquid = new Liquid({ root: '/', dynamicPartials: false })
const html = await staticLiquid.renderFile('/main.html')
return expect(html).to.equal('blackA')
})
})
})
-22
View File
@@ -1,22 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
describe('tags/raw', function () {
const liquid = new Liquid()
it('should support raw 1', async function () {
const p = liquid.parseAndRender('{% raw%}')
return expect(p).be.rejectedWith(/{% raw%} not closed/)
})
it('should support raw 2', async function () {
const src = '{% raw %}{{ 5 | plus: 6 }}{% endraw %} is equal to 11.'
const dst = '{{ 5 | plus: 6 }} is equal to 11.'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support raw 3', async function () {
const src = '{% raw %}\n{{ foo}} \n{% endraw %}'
const dst = '\n{{ foo}} \n'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
})
-78
View File
@@ -1,78 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
describe('tags/tablerow', function () {
const liquid = new Liquid()
it('should support tablerow', async function () {
const src = '{% tablerow i in (1..3)%}{{ i }}{% endtablerow %}'
const dst = '<tr class="row1"><td class="col1">1</td><td class="col2">2</td><td class="col3">3</td></tr>'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support cols', async function () {
const src = '{% tablerow i in alpha cols:2 %}{{ i }}{% endtablerow %}'
const ctx = {
alpha: ['a', 'b', 'c']
}
const dst =
'<tr class="row1"><td class="col1">a</td><td class="col2">b</td></tr>' +
'<tr class="row2"><td class="col1">c</td></tr>'
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal(dst)
})
it('should support cols set to 0', async function () {
const src = '{% tablerow i in (1..3) cols:0 %}{{ i }}{% endtablerow %}'
const dst = '<tr class="row1"><td class="col1">1</td><td class="col2">2</td><td class="col3">3</td></tr>'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support empty tablerow', async function () {
const src = '{% tablerow i in (1..0) cols:2 %}{{ i }}{% endtablerow %}'
const dst = ''
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support empty array', async function () {
const src = '{% tablerow i in alpha.z cols:2 %}{{ i }}{% endtablerow %}'
const dst = ''
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should throw when tablerow not closed', function () {
const src = '{% tablerow i in (1..0) cols:2 %}{{ i }}'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/tag .* not closed/)
})
it('should support tablerow with range', async function () {
const src = '{% tablerow i in (1..5) cols:2 %}{{ i }}{% endtablerow %}'
const dst =
'<tr class="row1"><td class="col1">1</td><td class="col2">2</td></tr>' +
'<tr class="row2"><td class="col1">3</td><td class="col2">4</td></tr>' +
'<tr class="row3"><td class="col1">5</td></tr>'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support tablerow with limit', async function () {
const src = '{% tablerow i in (1..5) cols:2 limit:3 %}{{ i }}{% endtablerow %}'
const dst =
'<tr class="row1"><td class="col1">1</td><td class="col2">2</td></tr>' +
'<tr class="row2"><td class="col1">3</td></tr>'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should support tablerow with offset', async function () {
const src = '{% tablerow i in (1..5) cols:2 offset:3 %}{{ i }}{% endtablerow %}'
const dst = '<tr class="row1"><td class="col1">4</td><td class="col2">5</td></tr>'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal(dst)
})
})
-37
View File
@@ -1,37 +0,0 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/unless', function () {
let liquid: Liquid
before(() => { liquid = new Liquid() })
it('should render else when predicate yields true', async function () {
// 0 is truthy
const src = '{% unless 0 %}yes{%else%}no{%endunless%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('no')
})
it('should render unless when predicate yields false', async function () {
const src = '{% unless false %}yes{%else%}no{%endunless%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('yes')
})
it('should reject when tag not closed', function () {
const src = '{% unless 1>2 %}yes'
return expect(liquid.parseAndRender(src))
.to.be.rejectedWith(/tag {% unless 1>2 %} not closed/)
})
it('should render unless when predicate yields false and else undefined', async function () {
const src = '{% unless 1>2 %}yes{%endunless%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('yes')
})
it('should render "" when predicate yields false and else undefined', async function () {
const src = '{% unless 1<2 %}yes{%endunless%}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('')
})
})
-52
View File
@@ -1,52 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
describe('drop/blank-drop', function () {
let liquid: Liquid
before(() => (liquid = new Liquid()))
it('render blank drop as blank string', async function () {
const html = await liquid.parseAndRender('{{blank}}')
expect(html).to.equal('')
})
it('blank equals nil', async function () {
const src = '{%if blank == nil %}blank == nil{%else%}blank != nil{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('blank == nil')
})
it('false is blank', async function () {
const src = '{%if false == blank %}false == blank{%else%}false != blank{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('false == blank')
})
it('"" is blank', async function () {
const src = '{%if "" == blank %}"" == blank{%else%}"" != blank{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('"" == blank')
})
it('" " is blank', async function () {
const src = '{%if " " == blank %}" " == blank{%else%}" " != blank{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('" " == blank')
})
it('{} is blank', async function () {
const src = '{%if obj == blank %}{} == blank{%else%}{} != blank{% endif %}'
const html = await liquid.parseAndRender(src, { obj: {} })
expect(html).to.equal('{} == blank')
})
it('{foo: 1} is not blank', async function () {
const src = '{%if obj == blank %}{foo: 1} == blank{%else%}{foo: 1} != blank{% endif %}'
const html = await liquid.parseAndRender(src, { obj: { foo: 1 } })
expect(html).to.equal('{foo: 1} != blank')
})
it('[] is blank', async function () {
const src = '{%if arr == blank %}[] == blank{%else%}[] != blank{% endif %}'
const html = await liquid.parseAndRender(src, { arr: [] })
expect(html).to.equal('[] == blank')
})
it('[1] is not blank', async function () {
const src = '{%if arr == blank %}[1] == blank{%else%}[1] != blank{% endif %}'
const html = await liquid.parseAndRender(src, { arr: [1] })
expect(html).to.equal('[1] != blank')
})
})
-52
View File
@@ -1,52 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
describe('drop/empty-drop', function () {
let liquid: Liquid
before(() => (liquid = new Liquid()))
it('render empty drop as empty string', async function () {
const html = await liquid.parseAndRender('{{empty}}')
expect(html).to.equal('')
})
it('nil is not empty', async function () {
const src = '{%if nil == empty %}nil == empty{%else%}nil != empty{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('nil != empty')
})
it('false is not empty', async function () {
const src = '{%if false == empty %}false == empty{%else%}false != empty{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('false != empty')
})
it('"" is empty', async function () {
const src = '{%if "" == empty %}"" == empty{%else%}"" != empty{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('"" == empty')
})
it('" " is not empty', async function () {
const src = '{%if " " == empty %}" " == empty{%else%}" " != empty{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('" " != empty')
})
it('{} is empty', async function () {
const src = '{%if obj == empty %}{} == empty{%else%}{} != empty{% endif %}'
const html = await liquid.parseAndRender(src, { obj: {} })
expect(html).to.equal('{} == empty')
})
it('{foo: 1} is not empty', async function () {
const src = '{%if obj == empty %}{foo: 1} == empty{%else%}{foo: 1} != empty{% endif %}'
const html = await liquid.parseAndRender(src, { obj: { foo: 1 } })
expect(html).to.equal('{foo: 1} != empty')
})
it('[] is empty', async function () {
const src = '{%if arr == empty %}[] == empty{%else%}[] != empty{% endif %}'
const html = await liquid.parseAndRender(src, { arr: [] })
expect(html).to.equal('[] == empty')
})
it('[1] is not empty', async function () {
const src = '{%if arr == empty %}[1] == empty{%else%}[1] != empty{% endif %}'
const html = await liquid.parseAndRender(src, { arr: [1] })
expect(html).to.equal('[1] != empty')
})
})
-36
View File
@@ -1,36 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
describe('drop/null-drop', function () {
let liquid: Liquid
before(() => (liquid = new Liquid()))
it('render nil as empty string', async function () {
const html = await liquid.parseAndRender('{{nil}}')
expect(html).to.equal('')
})
it('render null as empty string', async function () {
const html = await liquid.parseAndRender('{{null}}')
expect(html).to.equal('')
})
it('undefined variable should equal to null', async function () {
const src = '{%if foo == nil %}foo == nil{%else%}foo != nil{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('foo == nil')
})
it('nil equals blank', async function () {
const src = '{%if nil == blank %}nil == blank{%else%}nil != blank{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('nil == blank')
})
it('0 should not equal to null', async function () {
const src = '{%if 0 == null %}0 == null{%else%}0 != null{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('0 != null')
})
it('nil should equal to null', async function () {
const src = '{%if nil == null %}nil == null{%else%}nil != null{% endif %}'
const html = await liquid.parseAndRender(src)
expect(html).to.equal('nil == null')
})
})
-38
View File
@@ -1,38 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
import { mock, restore } from 'test/stub/mockfs'
describe('LiquidOptions#cache', function () {
let engine: Liquid
beforeEach(function () {
engine = new Liquid({
root: '/root/',
extname: '.html'
})
mock({ '/root/files/foo.html': 'foo' })
})
afterEach(restore)
it('should be disabled by default', function () {
return engine.renderFile('files/foo')
.then(x => expect(x).to.equal('foo'))
.then(() => mock({
'/root/files/foo.html': 'bar'
}))
.then(() => engine.renderFile('files/foo'))
.then(x => expect(x).to.equal('bar'))
})
it('should respect cache=true option', function () {
engine = new Liquid({
root: '/root/',
extname: '.html',
cache: true
})
return engine.renderFile('files/foo')
.then(x => expect(x).to.equal('foo'))
.then(() => mock({
'/root/files/foo.html': 'bar'
}))
.then(() => engine.renderFile('files/foo'))
.then(x => expect(x).to.equal('foo'))
})
})
-31
View File
@@ -1,31 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
describe('LiquidOptions#*_delimiter_*', function () {
it('should respect tag_delimiter_*', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>'
})
const html = await engine.parseAndRender('<%=if true%>foo<%=endif%> ')
return expect(html).to.equal('foo ')
})
it('should respect output_delimiter_*', async function () {
const engine = new Liquid({
output_delimiter_left: '<<',
output_delimiter_right: '>>'
})
const html = await engine.parseAndRender('<< "liquid" | capitalize >>')
return expect(html).to.equal('Liquid')
})
it('should support trimming with tag_delimiter_* set', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>',
trim_tag_left: true,
trim_tag_right: true
})
const html = await engine.parseAndRender(' <%=if true%> \tfoo\t <%=endif%> ')
return expect(html).to.equal('foo')
})
})
-15
View File
@@ -1,15 +0,0 @@
import { normalize } from 'src/liquid-options'
import { expect } from 'chai'
describe('LiquidOptions', function () {
describe('#normalize ()', function () {
it('should normalize string typed root array', function () {
const options = normalize({ root: 'foo' })
expect(options.root).to.eql(['foo'])
})
it('should normalize null typed root as empty array', function () {
const options = normalize({ root: null } as any)
expect(options.root).to.eql([])
})
})
})
-72
View File
@@ -1,72 +0,0 @@
import Liquid from 'src/liquid'
import * as chai from 'chai'
import { mock, restore } from 'test/stub/mockfs'
const expect = chai.expect
describe('Liquid', function () {
describe('#plugin()', function () {
it('should call plugin on the instance', async function () {
const engine = new Liquid()
engine.plugin(function () {
this.registerFilter('foo', x => `foo${x}foo`)
})
const html = await engine.parseAndRender('{{"bar"|foo}}')
expect(html).to.equal('foobarfoo')
})
it('should call plugin with Liquid', async function () {
const engine = new Liquid()
engine.plugin(function (Liquid) {
this.registerFilter('t', x => Liquid.isFalsy(x))
})
const html = await engine.parseAndRender('{{false|t}}')
expect(html).to.equal('true')
})
})
describe('#parseAndRender', function () {
const engine = new Liquid()
it('should parse and render variable output', async function () {
const html = await engine.parseAndRender('{{"foo"}}')
expect(html).to.equal('foo')
})
it('should parse and render complex output', async function () {
const tpl = '{{ "Welcome|to]Liquid" | split: "|" | join: "("}}'
const html = await engine.parseAndRender(tpl)
expect(html).to.equal('Welcome(to]Liquid')
})
})
describe('#express()', function () {
const liquid = new Liquid({ root: '/root' })
const render = liquid.express()
before(function () {
mock({
'/root/foo': 'foo'
})
})
after(restore)
it('should render single template', function (done) {
render.call({ root: '.' }, 'foo', null as any, (err: Error | null, result: string | undefined) => {
if (err) return done(err)
expect(result).to.equal('foo')
done()
})
})
it('should render single template with Array-typed root', function (done) {
render.call({ root: ['.'] }, 'foo', null as any, (err: Error | null, result: string | undefined) => {
if (err) return done(err)
expect(result).to.equal('foo')
done()
})
})
})
describe('#renderFile', function () {
it('should throw with lookup list when file not exist', function () {
const engine = new Liquid({
root: ['/boo', '/root/'],
extname: '.html'
})
return expect(engine.renderFile('/not/exist.html')).to
.be.rejectedWith(/Failed to lookup "\/not\/exist.html" in "\/boo,\/root\/"/)
})
})
})
-33
View File
@@ -1,33 +0,0 @@
import Liquid from 'src/liquid'
import { expect } from 'chai'
describe('LiquidOptions#strict_*', function () {
let engine: Liquid
const ctx = {}
beforeEach(function () {
engine = new Liquid({
root: '/root/',
extname: '.html'
})
})
it('should not throw when strict_variables false (default)', async function () {
const html = await engine.parseAndRender('before{{notdefined}}after', ctx)
return expect(html).to.equal('beforeafter')
})
it('should throw when strict_variables true', function () {
const tpl = engine.parse('before{{notdefined}}after')
const opts = {
strict_variables: true
}
return expect(engine.render(tpl, ctx, opts)).to
.be.rejectedWith(/undefined variable: notdefined/)
})
it('should pass strict_variables to render by parseAndRender', function () {
const html = 'before{{notdefined}}after'
const opts = {
strict_variables: true
}
return expect(engine.parseAndRender(html, ctx, opts)).to
.be.rejectedWith(/undefined variable: notdefined/)
})
})
-84
View File
@@ -1,84 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
describe('LiquidOptions#trimming', function () {
const ctx = { name: 'harttle' }
describe('tag trimming', function () {
it('should respect trim_tag_left', async function () {
const engine = new Liquid({ trim_tag_left: true })
const html = await engine.parseAndRender(' \n \t{%if true%}foo{%endif%} ')
return expect(html).to.equal('foo ')
})
it('should respect trim_tag_right', async function () {
const engine = new Liquid({ trim_tag_right: true })
const html = await engine.parseAndRender('\t{%if true%}foo{%endif%} \n')
return expect(html).to.equal('\tfoo')
})
it('should not trim value', async function () {
const engine = new Liquid({ trim_tag_left: true, trim_tag_right: true })
const html = await engine.parseAndRender('{%if true%}a {{name}} b{%endif%}', ctx)
return expect(html).to.equal('a harttle b')
})
})
describe('value trimming', function () {
it('should respect trim_output_left', async function () {
const engine = new Liquid({ trim_output_left: true })
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal('harttle ')
})
it('should respect trim_output_right', async function () {
const engine = new Liquid({ trim_output_right: true })
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal(' \n \tharttle')
})
it('should respect not trim tag', async function () {
const engine = new Liquid({ trim_output_left: true, trim_output_right: true })
const html = await engine.parseAndRender('\t{% if true %} aha {%endif%}\t')
return expect(html).to.equal('\t aha \t')
})
})
describe('greedy', function () {
const src = '\n {%-if true-%}\n a \n{{-name-}}{%-endif-%}\n '
it('should enable greedy by default', async function () {
const engine = new Liquid()
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.equal('aharttle')
})
it('should respect to greedy:false by default', async function () {
const engine = new Liquid({ greedy: false })
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.equal('\n a \nharttle ')
})
})
describe('markup', function () {
it('should support trim using markup', async function () {
const engine = new Liquid()
const src = [
'{%- assign username = "John G. Chalmers-Smith" -%}',
'{%- if username and username.length > 10 -%}',
' Wow, {{ username }}, you have a long name!',
'{%- else -%}',
' Hello there!',
'{%- endif -%}'
].join('\n')
const dst = 'Wow, John G. Chalmers-Smith, you have a long name!'
const html = await engine.parseAndRender(src)
return expect(html).to.equal(dst)
})
it('should not trim when not specified', async function () {
const engine = new Liquid()
const src = [
'{% assign username = "John G. Chalmers-Smith" %}',
'{% if username and username.length > 10 %}',
' Wow, {{ username }}, you have a long name!',
'{% else %}',
' Hello there!',
'{% endif %}'
].join('\n')
const dst = '\n\n Wow, John G. Chalmers-Smith, you have a long name!\n'
const html = await engine.parseAndRender(src)
return expect(html).to.equal(dst)
})
})
})
-266
View File
@@ -1,266 +0,0 @@
import { expect } from 'chai'
import Liquid from 'src/liquid'
import * as path from 'path'
import { mock, restore } from 'test/stub/mockfs'
let engine = new Liquid()
const strictEngine = new Liquid({
strict_variables: true,
strict_filters: true
})
describe('error', function () {
afterEach(restore)
describe('TokenizationError', function () {
it('should throw TokenizationError when tag illegal', async function () {
const err = await expect(engine.parseAndRender('{% . a %}', {})).be.rejected
expect(err.name).to.equal('TokenizationError')
expect(err.message).to.contain('illegal tag syntax')
})
it('should contain template content in err.message', async function () {
const html = ['1st', '2nd', 'X{% . a %} Y', '4th']
const message = [
' 1| 1st',
' 2| 2nd',
'>> 3| X{% . a %} Y',
' 4| 4th',
'TokenizationError'
]
const err = await expect(engine.parseAndRender(html.join('\n'))).be.rejected
expect(err.message).to.equal('illegal tag syntax, line:3, col:2')
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('TokenizationError')
})
it('should contain the whole template content in err.token.input', async function () {
const html = 'bar\nfoo{% . a %}\nfoo'
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.token.input).to.equal(html)
})
it('should contain line number in err.token.line', async function () {
const err = await expect(engine.parseAndRender('1\n2\n{% . a %}\n4')).be.rejected
expect(err.name).to.equal('TokenizationError')
expect(err.token.line).to.equal(3)
})
it('should contain stack in err.stack', async function () {
const err = await expect(engine.parseAndRender('{% . a %}')).be.rejected
expect(err.message).to.contain('illegal tag syntax')
expect(err.stack).to.contain('at Liquid.parse')
})
describe('captureStackTrace compatibility', function () {
it('should be empty when captureStackTrace undefined', async function () {
const err = await expect(engine.parseAndRender('{% . a %}')).be.rejected
expect(err.stack).to.contain('illegal tag syntax')
expect(err.stack).to.not.contain('at Object.parse')
})
})
it('should throw error with line and pos if tag unmatched', async function () {
const err = await expect(engine.parseAndRender('1\n2\nfoo{% assign a = 4 }\n4')).be.rejected
expect(err.name).to.equal('TokenizationError')
expect(err.token.line).to.equal(3)
expect(err.token.col).to.equal(4)
})
})
describe('RenderError', function () {
beforeEach(function () {
engine = new Liquid({
root: '/'
})
engine.registerTag('throwingTag', {
render: function () {
throw new Error('intended render error')
}
})
engine.registerTag('rejectingTag', {
render: async function () {
throw new Error('intended render reject')
}
})
engine.registerFilter('throwingFilter', () => {
throw new Error('throwed by filter')
})
})
it('should throw RenderError when tag throws', async function () {
const src = '{%throwingTag%}'
const err = await expect(engine.parseAndRender(src)).be.rejected
expect(err.name).to.equal('RenderError')
expect(err.message).to.contain('intended render error')
})
it('should throw RenderError when tag rejects', async function () {
const src = '{%rejectingTag%}'
const err = await expect(engine.parseAndRender(src)).be.rejected
expect(err.name).to.equal('RenderError')
expect(err.message).to.contain('intended render reject')
})
it('should throw RenderError when filter throws', async function () {
const src = '{{1|throwingFilter}}'
const err = await expect(engine.parseAndRender(src)).be.rejected
expect(err.name).to.equal('RenderError')
expect(err.message).to.contain('throwed by filter')
})
it('should not throw when variable undefined by default', async function () {
const html = await engine.parseAndRender('X{{a}}Y')
return expect(html).to.equal('XY')
})
it('should throw RenderError when variable not defined', async function () {
const err = await expect(strictEngine.parseAndRender('{{a}}')).be.rejected
expect(err).to.have.property('name', 'RenderError')
expect(err.message).to.contain('undefined variable: a')
})
it('should contain template context in err.stack', async function () {
const html = ['1st', '2nd', '3rd', 'X{%throwingTag%} Y', '5th', '6th', '7th']
const message = [
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' 5| 5th',
' 6| 6th',
' 7| 7th',
'RenderError'
]
const err = await expect(engine.parseAndRender(html.join('\n'))).be.rejected
expect(err.message).to.equal('intended render error, line:4, col:2')
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('RenderError')
})
it('should contain original error info for {% layout %}', async function () {
mock({
'/throwing-tag.html': [
'1st',
'2nd',
'3rd',
'X{%throwingTag%} Y',
'5th',
'{%block%}{%endblock%}',
'7th'
].join('\n')
})
const html = '{%layout "throwing-tag.html"%}'
const message = [
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' 5| 5th',
' 6| {%block%}{%endblock%}',
' 7| 7th',
'RenderError'
]
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.message).to.equal(`intended render error, file:${path.resolve('/throwing-tag.html')}, line:4, col:2`)
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('RenderError')
})
it('should contain original error info for {% include %}', async function () {
const origin = ['1st', '2nd', '3rd', 'X{%throwingTag%} Y', '5th', '6th', '7th']
mock({
'/throwing-tag.html': origin.join('\n')
})
const html = '{%include "throwing-tag.html"%}'
const message = [
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' 5| 5th',
' 6| 6th',
' 7| 7th',
'RenderError'
]
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.message).to.equal(`intended render error, file:${path.resolve('/throwing-tag.html')}, line:4, col:2`)
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('RenderError')
})
it('should contain line number in err.token.line', async function () {
const src = '1\n2\n{{1|throwingFilter}}\n4'
const err = await expect(engine.parseAndRender(src)).be.rejected
expect(err.token.line).to.equal(3)
expect(err.name).to.equal('RenderError')
})
it('should contain stack in err.stack', async function () {
const err = await expect(engine.parseAndRender('{%rejectingTag%}')).be.rejected
expect(err.message).to.contain('intended render reject')
expect(err.stack).to.match(/at .*:\d+:\d+/)
})
})
describe('ParseError', function () {
beforeEach(function () {
engine = new Liquid()
engine.registerTag('throwsOnParse', {
parse: function () {
throw new Error('intended parse error')
}
})
})
it('should throw ParseError when filter not defined', async function () {
const err = await expect(strictEngine.parseAndRender('{{1 | a}}')).be.rejected
expect(err).to.have.property('name', 'ParseError')
expect(err.message).to.contain('undefined filter: a')
})
it('should throw ParseError when tag not closed', async function () {
const err = await expect(engine.parseAndRender('{% if %}')).be.rejected
expect(err.name).to.equal('ParseError')
expect(err.message).to.contain('tag {% if %} not closed')
})
it('should throw ParseError when tag parse throws', async function () {
const err = await expect(engine.parseAndRender('{%throwsOnParse%}')).be.rejected
expect(err.name).to.equal('ParseError')
expect(err.message).to.contain('intended parse error')
})
it('should throw ParseError when tag not found', async function () {
const src = '{%if true%}\naaa{%endif%}\n{% -a %}\n3'
const err = await expect(engine.parseAndRender(src)).be.rejected
expect(err.name).to.equal('ParseError')
expect(err.message).to.contain('tag -a not found')
})
it('should throw ParseError when tag not exist', async function () {
const err = await expect(engine.parseAndRender('{% a %}')).be.rejected
expect(err.name).to.equal('ParseError')
expect(err.message).to.contain('tag a not found')
})
it('should contain template context in err.stack', async function () {
const html = ['1st', '2nd', '3rd', 'X{% a %} {% enda %} Y', '5th', '6th', '7th']
const message = [
' 2| 2nd',
' 3| 3rd',
'>> 4| X{% a %} {% enda %} Y',
' 5| 5th',
' 6| 6th',
' 7| 7th',
'ParseError: tag a not found'
]
const err = await expect(engine.parseAndRender(html.join('\n'))).be.rejected
expect(err.message).to.equal('tag a not found, line:4, col:2')
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('ParseError')
})
it('should handle err.message when context not enough', async function () {
const html = ['1st', 'X{% a %} {% enda %} Y', '3rd', '4th']
const message = [
' 1| 1st',
'>> 2| X{% a %} {% enda %} Y',
' 3| 3rd',
' 4| 4th',
'ParseError: tag a not found'
]
const err = await expect(engine.parseAndRender(html.join('\n'))).be.rejected
expect(err.message).to.equal('tag a not found, line:2, col:2')
expect(err.stack).to.contain(message.join('\n'))
})
it('should contain line number in err.token.line', async function () {
const html = '<html>\n<head>\n\n{% raw %}\n\n'
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.token.line).to.equal(4)
})
it('should contain stack in err.stack', async function () {
const err = await expect(engine.parseAndRender('{% -a %}')).be.rejected
expect(err.stack).to.contain('ParseError: tag -a not found')
expect(err.stack).to.match(/at .*:\d+:\d+\)/)
})
})
})