diff --git a/src/builtin/filters/array.ts b/src/builtin/filters/array.ts index e9693795a..2e539d9d9 100644 --- a/src/builtin/filters/array.ts +++ b/src/builtin/filters/array.ts @@ -1,4 +1,5 @@ import { isArray, last as arrayLast } from '../../util/underscore' +import { toArray } from '../../util/collection' import { isTruthy } from '../../render/boolean' import { FilterImpl } from '../../template/filter/filter-impl' @@ -10,11 +11,11 @@ export const sort = (v: T[], arg: (lhs: T, rhs: T) => number) => v.sort(arg) export const size = (v: string | any[]) => (v && v.length) || 0 export function map (arr: {[key: string]: T1}[], arg: string): T1[] { - return arr.map(v => v[arg]) + return toArray(arr).map(v => v[arg]) } export function concat (v: T1[], arg: T2[] | T2): (T1 | T2)[] { - return Array.prototype.concat.call(v, arg) + return toArray(v).concat(arg) } export function slice (v: T[], begin: number, length = 1): T[] { @@ -23,8 +24,8 @@ export function slice (v: T[], begin: number, length = 1): T[] { } export function where (this: FilterImpl, arr: T[], property: string, expected?: any): T[] { - return arr.filter(obj => { - const value = this.context.getFromScope(obj, property.split('.')) + return toArray(arr).filter(obj => { + const value = this.context.getFromScope(obj, String(property).split('.')) return expected === undefined ? isTruthy(value) : value === expected }) } diff --git a/src/builtin/tags/for.ts b/src/builtin/tags/for.ts index c2fdcfda1..276be8cc2 100644 --- a/src/builtin/tags/for.ts +++ b/src/builtin/tags/for.ts @@ -1,5 +1,5 @@ import { assert, Tokenizer, evalToken, Emitter, TagToken, TopLevelToken, Context, Template, TagImplOptions, ParseStream } from '../../types' -import { toCollection } from '../../util/collection' +import { toEnumerable } from '../../util/collection' import { ForloopDrop } from '../../drop/forloop-drop' import { Hash } from '../../template/tag/hash' @@ -36,7 +36,7 @@ export default { }, render: function * (ctx: Context, emitter: Emitter) { const r = this.liquid.renderer - let collection = toCollection(evalToken(this.collection, ctx)) + let collection = toEnumerable(evalToken(this.collection, ctx)) if (!collection.length) { yield r.renderTemplates(this.elseTemplates, ctx, emitter) diff --git a/src/builtin/tags/render.ts b/src/builtin/tags/render.ts index 86eda1ba6..f6fe37224 100644 --- a/src/builtin/tags/render.ts +++ b/src/builtin/tags/render.ts @@ -1,6 +1,6 @@ import { assert } from '../../util/assert' import { ForloopDrop } from '../../drop/forloop-drop' -import { toCollection } from '../../util/collection' +import { toEnumerable } from '../../util/collection' import { evalQuotedToken, TypeGuards, Tokenizer, evalToken, Hash, Emitter, TagToken, Context, TagImplOptions } from '../../types' export default { @@ -60,7 +60,7 @@ export default { if (this['for']) { const { value, alias } = this['for'] let collection = evalToken(value, ctx) - collection = toCollection(collection) + collection = toEnumerable(collection) scope['forloop'] = new ForloopDrop(collection.length) for (const item of collection) { scope[alias] = item diff --git a/src/builtin/tags/tablerow.ts b/src/builtin/tags/tablerow.ts index 48bc08817..81d167232 100644 --- a/src/builtin/tags/tablerow.ts +++ b/src/builtin/tags/tablerow.ts @@ -1,4 +1,4 @@ -import { toCollection } from '../../util/collection' +import { toEnumerable } from '../../util/collection' import { assert, evalToken, Emitter, Hash, TagToken, TopLevelToken, Context, Template, TagImplOptions, ParseStream } from '../../types' import { TablerowloopDrop } from '../../drop/tablerowloop-drop' import { Tokenizer } from '../../parser/tokenizer' @@ -30,7 +30,7 @@ export default { }, render: function * (ctx: Context, emitter: Emitter) { - let collection = toCollection(evalToken(this.collection, ctx)) + let collection = toEnumerable(evalToken(this.collection, ctx)) const hash = yield this.hash.render(ctx) const offset = hash.offset || 0 const limit = (hash.limit === undefined) ? collection.length : hash.limit diff --git a/src/template/value.ts b/src/template/value.ts index 36847ab8d..e8ef76563 100644 --- a/src/template/value.ts +++ b/src/template/value.ts @@ -16,7 +16,6 @@ export class Value { const tokenizer = new Tokenizer(str) this.initial = tokenizer.readValue() this.filters = tokenizer.readFilters().map(({ name, args }) => new Filter(name, this.filterMap.get(name), args)) - tokenizer.skipBlank() } public * value (ctx: Context) { let val = yield evalToken(this.initial, ctx) diff --git a/src/util/collection.ts b/src/util/collection.ts index 9f890e479..edbeeb886 100644 --- a/src/util/collection.ts +++ b/src/util/collection.ts @@ -1,8 +1,13 @@ import { isString, isObject, isArray } from './underscore' -export function toCollection (val: any) { +export function toEnumerable (val: any) { if (isArray(val)) return val if (isString(val) && val.length > 0) return [val] if (isObject(val)) return Object.keys(val).map((key) => [key, val[key]]) return [] } + +export function toArray (val: any) { + if (isArray(val)) return val + return [ val ] +} diff --git a/test/integration/builtin/filters/array.ts b/test/integration/builtin/filters/array.ts index d615082b8..e519f7f76 100644 --- a/test/integration/builtin/filters/array.ts +++ b/test/integration/builtin/filters/array.ts @@ -1,14 +1,9 @@ -import { test } from '../../../stub/render' -import { Liquid } from '../../../../src/liquid' +import { test, render } from '../../../stub/render' import { expect, use } from 'chai' import * as chaiAsPromised from 'chai-as-promised' use(chaiAsPromised) describe('filters/array', function () { - let liquid: Liquid - beforeEach(function () { - liquid = new Liquid() - }) describe('index', function () { it('should support index', function () { const src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' + @@ -30,7 +25,7 @@ describe('filters/array', function () { it('should throw when comma missing', async () => { const src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' + '{{ beatles | join " and " }}' - return expect(liquid.parseAndRender(src)).to.be.rejectedWith('unexpected token at "\\" and \\"", line:1, col:65') + return expect(render(src)).to.be.rejectedWith('unexpected token at "\\" and \\"", line:1, col:65') }) }) it('should support split/last', function () { @@ -38,101 +33,70 @@ describe('filters/array', function () { '{{ my_array|last }}' return test(src, 'tiger') }) - it('should support map', function () { - return test('{{posts | map: "category"}}', 'foo,bar') + describe('map', () => { + it('should support map', function () { + const posts = [{ category: 'foo' }, { category: 'bar' }] + return test('{{posts | map: "category"}}', { posts }, 'foo,bar') + }) + it('should normalize non-array input', function () { + const post = { category: 'foo' } + return test('{{post | map: "category"}}', { post }, 'foo') + }) }) describe('reverse', function () { - it('should support reverse', async function () { - const html = await liquid.parseAndRender('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}') - expect(html).to.equal('.moT rojaM ot lortnoc dnuorG') - }) - it('should be pure', async function () { + it('should support reverse', () => test( + '{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}', + '.moT rojaM ot lortnoc dnuorG' + )) + it('should be pure', async () => { const scope = { arr: ['a', 'b', 'c'] } - await liquid.parseAndRender('{{ arr | reverse | join: "" }}', scope) - const html = await liquid.parseAndRender('{{ arr | join: "" }}', scope) + await render('{{ arr | reverse | join: "" }}', scope) + const html = await render('{{ arr | join: "" }}', scope) expect(html).to.equal('abc') }) }) describe('size', function () { - it('should return string length', async () => { - const html = await liquid.parseAndRender('{{ "Ground control to Major Tom." | size }}') - expect(html).to.equal('28') - }) - it('should return array size', async () => { - const html = await liquid.parseAndRender( - '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}{{ my_array | size }}') - expect(html).to.equal('4') - }) - it('should be respected with .size notation', async () => { - const html = await liquid.parseAndRender('{% assign my_string = "Ground control to Major Tom." %}{{ my_string.size }}') - expect(html).to.equal('28') - }) - it('should be respected with .size notation', async () => { - const html = await liquid.parseAndRender('{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}{{ my_array.size }}') - expect(html).to.equal('4') - }) - it('should return 0 for false', async () => { - const html = await liquid.parseAndRender('{{ false | size }}') - expect(html).to.equal('0') - }) - it('should return 0 for nil', async () => { - const html = await liquid.parseAndRender('{{ nil | size }}') - expect(html).to.equal('0') - }) - it('should return 0 for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | size }}') - expect(html).to.equal('0') - }) + it('should return string length', () => test( + '{{ "Ground control to Major Tom." | size }}', + '28' + )) + it('should return array size', () => test( + '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}{{ my_array | size }}', + '4' + )) + it('should be respected with .size notation', () => test( + '{% assign my_string = "Ground control to Major Tom." %}{{ my_string.size }}', + '28' + )) + it('should be respected with .size notation', () => test( + '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}{{ my_array.size }}', + '4' + )) + it('should return 0 for false', () => test('{{ false | size }}', '0')) + it('should return 0 for nil', () => test('{{ nil | size }}', '0')) + it('should return 0 for undefined', () => test('{{ foo | size }}', '0')) }) describe('first', function () { - it('should support first', async () => { - const html = await liquid.parseAndRender( - '{{arr | first}}', - { arr: [ 'zebra', 'tiger' ] } - ) - expect(html).to.equal('zebra') - }) - it('should return empty for nil', async () => { - const html = await liquid.parseAndRender('{{nil | first}}') - expect(html).to.equal('') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{foo | first}}') - expect(html).to.equal('') - }) - it('should return empty for false', async () => { - const html = await liquid.parseAndRender('{{false | first}}') - expect(html).to.equal('') - }) - it('should return empty for string', async () => { - const html = await liquid.parseAndRender('{{"zebra" | first}}') - expect(html).to.equal('') - }) + it('should support first', () => test( + '{{arr | first}}', + { arr: [ 'zebra', 'tiger' ] }, + 'zebra' + )) + it('should return empty for nil', () => test('{{nil | first}}', '')) + it('should return empty for undefined', () => test('{{foo | first}}', '')) + it('should return empty for false', () => test('{{false | first}}', '')) + it('should return empty for string', () => test('{{"zebra" | first}}', '')) }) describe('last', function () { - it('should support last', async () => { - const html = await liquid.parseAndRender( - '{{arr | last}}', - { arr: [ 'zebra', 'tiger' ] } - ) - expect(html).to.equal('tiger') - }) - it('should return empty for nil', async () => { - const html = await liquid.parseAndRender('{{nil | last}}') - expect(html).to.equal('') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{foo | last}}') - expect(html).to.equal('') - }) - it('should return empty for false', async () => { - const html = await liquid.parseAndRender('{{false | last}}') - expect(html).to.equal('') - }) - it('should return empty for string', async () => { - const html = await liquid.parseAndRender('{{"zebra" | last}}') - expect(html).to.equal('') - }) + it('should support last', () => test( + '{{arr | last}}', + { arr: [ 'zebra', 'tiger' ] }, + 'tiger' + )) + it('should return empty for nil', () => test('{{nil | last}}', '')) + it('should return empty for undefined', () => test('{{foo | last}}', '')) + it('should return empty for false', () => test('{{false | last}}', '')) + it('should return empty for string', () => test('{{"zebra" | last}}', '')) }) describe('slice', function () { it('should slice first char by 0', () => test('{{ "Liquid" | slice: 0 }}', 'L')) @@ -161,44 +125,60 @@ describe('filters/array', function () { }) }) describe('where', function () { + const products = [ + { title: 'Vacuum', type: 'living room' }, + { title: 'Spatula', type: 'kitchen' }, + { title: 'Television', type: 'living room' }, + { title: 'Garlic press', type: 'kitchen' }, + { title: 'Coffee mug', available: true }, + { title: 'Limited edition sneakers', available: false }, + { title: 'Boring sneakers', available: true } + ] it('should support filter by property value', function () { return test(`{% assign kitchen_products = products | where: "type", "kitchen" %} -Kitchen products: -{% for product in kitchen_products -%} -- {{ product.title }} -{% endfor %}`, ` -Kitchen products: -- Spatula -- Garlic press -`) + Kitchen products: + {% for product in kitchen_products -%} + - {{ product.title }} + {% endfor %}`, { products }, ` + Kitchen products: + - Spatula + - Garlic press + `) }) it('should support filter truthy property', function () { return test(`{% assign available_products = products | where: "available" %} -Available products: -{% for product in available_products -%} -- {{ product.title }} -{% endfor %}`, ` -Available products: -- Coffee mug -- Boring sneakers -`) + Available products: + {% for product in available_products -%} + - {{ product.title }} + {% endfor %}`, { products }, ` + Available products: + - Coffee mug + - Boring sneakers + `) }) it('should support nested property', async function () { const authors = [ { name: 'Alice', books: { year: 2019 } }, { name: 'Bob', books: { year: 2018 } } ] - const html = await liquid.parseAndRender( + return test( `{% assign recentAuthors = authors | where: 'books.year', 2019 %} -Recent Authors: -{%- for author in recentAuthors %} - - {{author.name}} -{%- endfor %}`, - { authors } - ) - expect(html).to.equal(` -Recent Authors: - - Alice`) + Recent Authors: + {%- for author in recentAuthors %} + - {{author.name}} + {%- endfor %}`, + { authors }, ` + Recent Authors: + - Alice`) + }) + it('should apply to string', async () => { + await test('{{"abc" | where: 1, "b" }}', 'abc') + await test('{{"abc" | where: 1, "a" }}', '') + }) + it('should normalize non-array input', async () => { + const scope = { obj: { foo: 'FOO' } } + await test('{{obj | where: "foo", "FOO" }}', scope, '[object Object]') + await test('{{obj | where: "foo", "BAR" }}', scope, '') }) }) }) diff --git a/test/integration/builtin/filters/date.ts b/test/integration/builtin/filters/date.ts index e39b2edc8..7edc844bc 100644 --- a/test/integration/builtin/filters/date.ts +++ b/test/integration/builtin/filters/date.ts @@ -1,15 +1,9 @@ -import { test, ctx } from '../../../stub/render' -import { expect } from 'chai' -import { Liquid } from '../../../../src/liquid' +import { test } from '../../../stub/render' describe('filters/date', function () { - let liquid: Liquid - beforeEach(function () { - liquid = new Liquid() - }) it('should support date: %a %b %d %Y', function () { - const str = ctx.date.toDateString() - return test('{{ date | date:"%a %b %d %Y"}}', str) + const date = new Date() + return test('{{ date | date:"%a %b %d %Y"}}', { date }, date.toDateString()) }) it('should create a new Date when given "now"', function () { return test('{{ "now" | date: "%Y"}}', (new Date()).getFullYear().toString()) @@ -23,27 +17,21 @@ describe('filters/date', function () { 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"}}', '[object Object]') + it('should render object as string', function () { + return test('{{ obj | date: "%Y"}}', { obj: {} }, '[object Object]') }) it('should create from number', async function () { const time = new Date('2017-03-07T12:00:00').getTime() / 1000 - const src = '{{ time | date: "%Y-%m-%dT%H:%M:%S" }}' - const ctx = { time } - const dst = '2017-03-07T12:00:00' - expect(await liquid.parseAndRender(src, ctx)).to.equal(dst) + return test('{{ time | date: "%Y-%m-%dT%H:%M:%S" }}', { time }, '2017-03-07T12:00:00') }) it('should create from number-like string', async function () { const time = String(new Date('2017-03-07T12:00:00').getTime() / 1000) - const src = '{{ time | date: "%Y-%m-%dT%H:%M:%S" }}' - const ctx = { time } - const dst = '2017-03-07T12:00:00' - expect(await liquid.parseAndRender(src, ctx)).to.equal(dst) + return test('{{ time | date: "%Y-%m-%dT%H:%M:%S" }}', { time }, '2017-03-07T12:00:00') }) it('should support manipulation', async function () { - const src = '{{ date | date: "%s" | minus : 604800 | date: "%Y-%m-%dT%H:%M:%S"}}' - const ctx = { date: new Date('2017-03-07T12:00:00') } - const dst = '2017-02-28T12:00:00' - expect(await liquid.parseAndRender(src, ctx)).to.equal(dst) + return test('{{ date | date: "%s" | minus : 604800 | date: "%Y-%m-%dT%H:%M:%S"}}', + { date: new Date('2017-03-07T12:00:00') }, + '2017-02-28T12:00:00' + ) }) }) diff --git a/test/integration/builtin/filters/html.ts b/test/integration/builtin/filters/html.ts index 0d3055950..fc0e605ff 100644 --- a/test/integration/builtin/filters/html.ts +++ b/test/integration/builtin/filters/html.ts @@ -10,7 +10,7 @@ describe('filters/html', function () { return test('{{ "Tetsuro Takara" | escape }}', 'Tetsuro Takara') }) it('should escape function', function () { - return test('{{ func | escape }}', 'function () { }') + return test('{{ func | escape }}', { func: function () {} }, 'function () { }') }) it('should escape undefined', function () { return test('{{ nonExistent.value | escape }}', '') diff --git a/test/integration/builtin/filters/math.ts b/test/integration/builtin/filters/math.ts index ed995812c..c14c72db5 100644 --- a/test/integration/builtin/filters/math.ts +++ b/test/integration/builtin/filters/math.ts @@ -1,13 +1,10 @@ import { expect } from 'chai' import { test, liquid } from '../../../stub/render' -import { Liquid } from '../../../../src/liquid' describe('filters/math', function () { - const l = new Liquid() - 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 2 for arr[0]', () => test('{{ arr[0] | abs }}', { arr: [-2, 'a'] }, '2')) it('should return convert string', () => test('{{ "-3" | abs }}', '3')) }) describe('at_least', function () { @@ -60,10 +57,7 @@ describe('filters/math', function () { () => 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')) - it('should support variable', async () => { - const html = await l.parseAndRender('{{ 4 | plus: b }}', { b: 2 }) - expect(html).to.equal('6') - }) + it('should support variable', () => test('{{ 4 | plus: b }}', { b: 2 }, '6')) }) describe('sort_natural', function () { @@ -73,55 +67,36 @@ describe('filters/math', function () { 'giraffe, octopus, Sally Snake, zebra' ) }) - it('should sort with specified property', async () => { - const src = '{{ students | sort_natural: "name" | map: "name" | join }}' - const students = [{ name: 'bob' }, { name: 'alice' }, { name: 'carol' }] - const html = await l.parseAndRender(src, { students }) - expect(html).to.equal('alice bob carol') - }) - it('should be stable', async () => { - const src = '{{ students | sort_natural: "age" | map: "name" | join }}' - const students = [ - { name: 'bob', age: 1 }, - { name: 'alice', age: 1 }, - { name: 'carol', age: 1 } - ] - const html = await l.parseAndRender(src, { students }) - expect(html).to.equal('bob alice carol') - }) - it('should be stable when it comes to undefined props', async () => { - const src = '{{ students | sort_natural: "age" | map: "name" | join }}' - const students = [ - { name: 'bob' }, - { name: 'alice', age: 2 }, - { name: 'amber' }, - { name: 'watson' }, - { name: 'michael' }, - { name: 'charlie' } - ] - const html = await l.parseAndRender(src, { students }) - expect(html).to.equal('alice bob amber watson michael charlie') - }) - it('should tolerate undefined props', async () => { - const src = '{{ students | sort_natural: "age" | map: "name" | join }}' - const students = [ - { name: 'bob' }, - { name: 'alice', age: 2 }, - { name: 'carol' } - ] - const html = await l.parseAndRender(src, { students }) - expect(html).to.equal('alice bob carol') - }) - it('should tolerate non array', async () => { - const src = '{{ students | sort_natural: "age" | map: "name" | join }}' - const html = await l.parseAndRender(src, { students: {} }) - expect(html).to.equal('') - }) - it('should tolerate falsy input', async () => { - const src = '{{ students | sort_natural: "age" | map: "name" | join }}' - const html = await l.parseAndRender(src, { students: undefined }) - expect(html).to.equal('') - }) + it('should sort with specified property', () => test( + '{{ students | sort_natural: "name" | map: "name" | join }}', + { students: [{ name: 'bob' }, { name: 'alice' }, { name: 'carol' }] }, + 'alice bob carol' + )) + it('should be stable', () => test( + '{{ students | sort_natural: "age" | map: "name" | join }}', + { students: [{ name: 'bob', age: 1 }, { name: 'alice', age: 1 }, { name: 'carol', age: 1 }] }, + 'bob alice carol' + )) + it('should be stable when it comes to undefined props', () => test( + '{{ students | sort_natural: "age" | map: "name" | join }}', + { students: [{ name: 'bob' }, { name: 'alice', age: 2 }, { name: 'amber' }, { name: 'watson' }, { name: 'michael' }, { name: 'charlie' }] }, + 'alice bob amber watson michael charlie' + )) + it('should tolerate undefined props', () => test( + '{{ students | sort_natural: "age" | map: "name" | join }}', + { students: [{ name: 'bob' }, { name: 'alice', age: 2 }, { name: 'carol' }] }, + 'alice bob carol' + )) + it('should tolerate non array', () => test( + '{{ students | sort_natural: "age" | map: "name" | join }}', + { students: {} }, + '' + )) + it('should tolerate falsy input', () => test( + '{{ students | sort_natural: "age" | map: "name" | join }}', + { students: undefined }, + '' + )) }) describe('round', function () { it('should return "1" for 1.2', () => test('{{1.2|round}}', '1')) diff --git a/test/integration/builtin/filters/string.ts b/test/integration/builtin/filters/string.ts index 1c1acc7ce..29d0998b0 100644 --- a/test/integration/builtin/filters/string.ts +++ b/test/integration/builtin/filters/string.ts @@ -1,19 +1,14 @@ import { test } from '../../../stub/render' -import { Liquid } from '../../../../src/liquid' import { expect, use } from 'chai' import * as chaiAsPromised from 'chai-as-promised' use(chaiAsPromised) describe('filters/string', function () { - let liquid: Liquid - beforeEach(function () { - liquid = new Liquid() - }) 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')) + it('should return "abar" for "a", foo', () => test('{{ "a" | append: foo }}', { foo: 'bar' }, 'abar')) it('should throw if second argument undefined', () => { return expect(test('{{ "abc" | append: undefinedVar }}', 'abc')).to.be.rejectedWith(/2 arguments/) }) @@ -25,7 +20,7 @@ describe('filters/string', function () { describe('prepend', function () { it('should return "-3abc" for -3, "abc"', () => test('{{ -3 | prepend: "abc" }}', 'abc-3')) - it('should return "abar" for "a", foo', () => test('{{ "a" | prepend: foo }}', 'bara')) + it('should return "abar" for "a", foo', () => test('{{ "a" | prepend: foo }}', { foo: 'bar' }, 'bara')) it('should throw if second argument undefined', () => { return expect(test('{{ "abc" | prepend: undefinedVar }}', 'abc')).to.be.rejectedWith(/2 arguments/) }) @@ -35,18 +30,9 @@ describe('filters/string', function () { it('should return "falseabc" for "abc", false', () => test('{{ "abc" | prepend: false }}', 'falseabc')) }) describe('capitalize', function () { - it('should capitalize first', async () => { - const html = await liquid.parseAndRender('{{ "i am good" | capitalize }}') - expect(html).to.equal('I am good') - }) - it('should return empty for nil', async () => { - const html = await liquid.parseAndRender('{{ nil | capitalize }}') - expect(html).to.equal('') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | capitalize }}') - expect(html).to.equal('') - }) + it('should capitalize first', () => test('{{ "i am good" | capitalize }}', 'I am good')) + it('should return empty for nil', () => test('{{ nil | capitalize }}', '')) + it('should return empty for undefined', async () => test('{{ foo | capitalize }}', '')) }) describe('concat', function () { it('should concat arrays', () => test(` @@ -84,18 +70,13 @@ describe('filters/string', function () { `)) }) describe('downcase', function () { - it('should return "parker moore" for "Parker Moore"', async () => { - const html = await liquid.parseAndRender('{{ "Parker Moore" | downcase }}') - expect(html).to.equal('parker moore') - }) - it('should return "apple" for "apple"', async () => { - const html = await liquid.parseAndRender('{{ "apple" | downcase }}') - expect(html).to.equal('apple') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | downcase }}') - expect(html).to.equal('') - }) + it('should return "parker moore" for "Parker Moore"', () => + test('{{ "Parker Moore" | downcase }}', 'parker moore') + ) + it('should return "apple" for "apple"', () => + test('{{ "apple" | downcase }}', 'apple') + ) + it('should return empty for undefined', () => test('{{ foo | downcase }}', '')) }) describe('split', function () { it('should support split/first', function () { @@ -105,14 +86,8 @@ describe('filters/string', function () { }) }) describe('upcase', function () { - it('should support upcase', async () => { - const html = await liquid.parseAndRender('{{ "Parker Moore" | upcase }}') - expect(html).to.equal('PARKER MOORE') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | upcase }}') - expect(html).to.equal('') - }) + it('should support upcase', () => test('{{ "Parker Moore" | upcase }}', 'PARKER MOORE')) + it('should return empty for undefined', () => test('{{ foo | upcase }}', '')) }) it('should support lstrip', function () { const src = '{{ " So much room for activities! " | lstrip }}' @@ -124,24 +99,15 @@ describe('filters/string', function () { 'liquidmarkup.com/index.html') }) describe('remove', function () { - it('should support remove', async () => { - const html = await liquid.parseAndRender('{{ "I strained to see the train through the rain" | remove: "rain" }}') - expect(html).to.equal('I sted to see the t through the ') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | remove: "rain" }}') - expect(html).to.equal('') - }) + it('should support remove', () => test( + '{{ "I strained to see the train through the rain" | remove: "rain" }}', + 'I sted to see the t through the ' + )) + it('should return empty for undefined', () => test('{{ foo | remove: "rain" }}', '')) }) describe('remove_first', function () { - it('should support remove_first', async () => { - const html = await liquid.parseAndRender('{{ "I strained to see the train through the rain" | remove_first: "rain" }}') - expect(html).to.equal('I sted to see the train through the rain') - }) - it('should return empty for undefined', async () => { - const html = await liquid.parseAndRender('{{ foo | remove_first: "r" }}') - expect(html).to.equal('') - }) + it('should support remove_first', () => test('{{ "I strained to see the train through the rain" | remove_first: "rain" }}', 'I sted to see the train through the rain')) + it('should return empty for undefined', () => test('{{ foo | remove_first: "r" }}', '')) }) it('should support replace', function () { return test('{{ "Take my protein pills and put my helmet on" | replace: "my", "your" }}', diff --git a/test/stub/render.ts b/test/stub/render.ts index 10d7d72d2..997be0a61 100644 --- a/test/stub/render.ts +++ b/test/stub/render.ts @@ -3,25 +3,14 @@ import { expect } from 'chai' export const liquid = new Liquid() -export const ctx = { - date: new Date(), - foo: 'bar', - arr: [-2, 'a'], - obj: { foo: 'bar' }, - func: function () {}, // eslint-disable-line - posts: [{ category: 'foo' }, { category: 'bar' }], - products: [ - { title: 'Vacuum', type: 'living room' }, - { title: 'Spatula', type: 'kitchen' }, - { title: 'Television', type: 'living room' }, - { title: 'Garlic press', type: 'kitchen' }, - { title: 'Coffee mug', available: true }, - { title: 'Limited edition sneakers', available: false }, - { title: 'Boring sneakers', available: true } - ] +export function render (src: string, ctx?: object) { + return liquid.parseAndRender(src, ctx) } -export async function test (src: string, dst: string) { - const html = await liquid.parseAndRender(src, ctx) - return expect(html).to.equal(dst) +export async function test (src: string, ctx: object | string, dst?: string) { + if (dst === undefined) { + dst = ctx as string + ctx = {} + } + return expect(await render(src, ctx as object)).to.equal(dst) }