mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-17 05:10:40 -07:00
refactor: remove /dist from repo
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
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: ","}}', '')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
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"}')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
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 < 2 & 3'))
|
||||
it('should not escape twice',
|
||||
() => test('{{ "1 < 2 & 3" | escape_once }}', '1 < 2 & 3'))
|
||||
})
|
||||
describe('strip_html', function () {
|
||||
it('should strip all tags', function () {
|
||||
return test('{{ "Have <em>you</em> read <cite><a href="https://en.wikipedia.org/wiki/Ulysses_(novel)">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 }}', '')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,64 @@
|
||||
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'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
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'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,176 @@
|
||||
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...')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
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'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,79 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,35 @@
|
||||
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/)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,51 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
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('')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,58 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,204 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,113 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,147 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,47 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,136 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,22 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,78 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
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('')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,52 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,82 @@
|
||||
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')
|
||||
})
|
||||
it('1 < empty should be false', async function () {
|
||||
const src = '{%if 1 < empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('false')
|
||||
})
|
||||
it('1 <= empty should be false', async function () {
|
||||
const src = '{%if 1 <= empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('false')
|
||||
})
|
||||
it('1 > empty should be false', async function () {
|
||||
const src = '{%if 1 > empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('false')
|
||||
})
|
||||
it('1 >= empty should be false', async function () {
|
||||
const src = '{%if 1 >= empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('false')
|
||||
})
|
||||
it('1 == empty should be false', async function () {
|
||||
const src = '{%if 1 == empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('false')
|
||||
})
|
||||
it('1 != empty should be true', async function () {
|
||||
const src = '{%if 1 != empty %}true{%else%}false{% endif %}'
|
||||
const html = await liquid.parseAndRender(src)
|
||||
expect(html).to.equal('true')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,36 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,38 @@
|
||||
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'))
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
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')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
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([])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,72 @@
|
||||
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\/"/)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
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/)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,84 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,266 @@
|
||||
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+\)/)
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user