diff --git a/package.json b/package.json index 9c9568958b..e86c7e550e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "unit": "mocha 'test/unit/**/*.ts'", "e2e": "npm run build && mocha 'test/e2e/**/*.ts'", "test": "npm run unit && npm run e2e", - "coverage-html": "nyc npm run unit && nyc report --reporter=html", + "coverage-html": "nyc --reporter=html npm run unit", "coverage-coveralls": "nyc npm run unit && nyc report --reporter=text-lcov | coveralls", "build": "rollup -c rollup.config.ts && ls -lh dist", "version": "npm run build && git add -A dist" @@ -98,5 +98,6 @@ "extension": [ ".ts" ] - } + }, + "dependencies": {} } diff --git a/src/builtin/filters/string.ts b/src/builtin/filters/string.ts index 0e8bf3eb95..d929af1961 100644 --- a/src/builtin/filters/string.ts +++ b/src/builtin/filters/string.ts @@ -16,15 +16,15 @@ export default { 'split': (v: string, arg: string) => String(v).split(arg), 'strip': (v: string) => String(v).trim(), 'strip_newlines': (v: string) => String(v).replace(/\n/g, ''), - 'truncate': (v: string, l: number = 16, o: string = '...') => { + 'truncate': (v: string, l: number = 50, o: string = '...') => { v = String(v) if (v.length <= l) return v return v.substr(0, l - o.length) + o }, - 'truncatewords': (v: string, l: number = v.length, o: string = '...') => { - const arr = v.split(' ') + 'truncatewords': (v: string, l: number = 15, o: string = '...') => { + const arr = v.split(/\s+/) let ret = arr.slice(0, l).join(' ') - if (arr.length > l) ret += o + if (arr.length >= l) ret += o return ret } -} as {[key: string]: FilterImpl} \ No newline at end of file +} as {[key: string]: FilterImpl} diff --git a/src/scope/scope.ts b/src/scope/scope.ts index 31f3017f64..93dd5b6991 100644 --- a/src/scope/scope.ts +++ b/src/scope/scope.ts @@ -68,7 +68,7 @@ export default class Scope { } return null } - readProperty (obj: IContext, key: string) { + private readProperty (obj: IContext, key: string) { let val if (_.isNil(obj)) { val = undefined diff --git a/test/unit/builtin/filters/string.ts b/test/unit/builtin/filters/string.ts index a424187f09..fcb00f2cb7 100644 --- a/test/unit/builtin/filters/string.ts +++ b/test/unit/builtin/filters/string.ts @@ -136,8 +136,14 @@ describe('filters/string', function () { it('should not truncate when short enough', function () { return test('{{ "12345" | truncate: 5 }}', '12345') }) - it('should default to 16', function () { - return test('{{ "1234567890abcdefghi" | truncate }}', '1234567890abc...') + 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 () { @@ -157,5 +163,14 @@ describe('filters/string', 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...') + }) }) }) diff --git a/test/unit/fs/browser.ts b/test/unit/fs/browser.ts index b36d8b3b91..06308d9b76 100644 --- a/test/unit/fs/browser.ts +++ b/test/unit/fs/browser.ts @@ -4,7 +4,6 @@ import { expect, use } from 'chai' import * as chaiAsPromised from 'chai-as-promised' use(chaiAsPromised) -const resolve = fs.resolve describe('fs/browser', function () { describe('#resolve()', function () { @@ -25,31 +24,38 @@ describe('fs/browser', function () { delete (global as any).document }) it('should support relative root', function () { - expect(resolve('./views/', 'foo', '')).to.equal('https://example.com/foo/bar/views/foo') + expect(fs.resolve('./views/', 'foo', '')).to.equal('https://example.com/foo/bar/views/foo') }) it('should treat root as directory', function () { - expect(resolve('./views', 'foo', '')).to.equal('https://example.com/foo/bar/views/foo') + expect(fs.resolve('./views', 'foo', '')).to.equal('https://example.com/foo/bar/views/foo') }) it('should support absolute root', function () { - expect(resolve('/views', 'foo', '')).to.equal('https://example.com/views/foo') + expect(fs.resolve('/views', 'foo', '')).to.equal('https://example.com/views/foo') }) it('should support empty root', function () { - expect(resolve('', 'page.html', '')).to.equal('https://example.com/foo/bar/page.html') + expect(fs.resolve('', 'page.html', '')).to.equal('https://example.com/foo/bar/page.html') }) it('should support full url as root', function () { - expect(resolve('https://example.com/views/', 'page.html', '')).to.equal('https://example.com/views/page.html') + expect(fs.resolve('https://example.com/views/', 'page.html', '')).to.equal('https://example.com/views/page.html') }) it('should add extname when absent', function () { - expect(resolve('https://example.com/views/', 'page', '.html')).to.equal('https://example.com/views/page.html') + expect(fs.resolve('https://example.com/views/', 'page', '.html')).to.equal('https://example.com/views/page.html') }) it('should add extname for urls have searchParams', function () { - expect(resolve('https://example.com/views/', 'page?foo=bar', '.html')).to.equal('https://example.com/views/page.html?foo=bar') + expect(fs.resolve('https://example.com/views/', 'page?foo=bar', '.html')).to.equal('https://example.com/views/page.html?foo=bar') }) it('should not add extname when full url is given', function () { - expect(resolve('https://example.com/views/', 'https://google.com/page.php', '.html')).to.equal('https://google.com/page.php') + expect(fs.resolve('https://example.com/views/', 'https://google.com/page.php', '.html')).to.equal('https://google.com/page.php') }) it('should not add extname when already have one', function () { - expect(resolve('https://example.com/views/', 'page.php', '.html')).to.equal('https://example.com/views/page.php') + expect(fs.resolve('https://example.com/views/', 'page.php', '.html')).to.equal('https://example.com/views/page.php') + }) + }) + + describe('#exists()', () => { + it('should always return true', async function () { + const val = await fs.exists('/foo/bar') + expect(val).to.equal(true) }) }) diff --git a/test/unit/fs/node.ts b/test/unit/fs/node.ts index c7ec20212c..628ce977d7 100644 --- a/test/unit/fs/node.ts +++ b/test/unit/fs/node.ts @@ -2,17 +2,10 @@ import fs from 'src/fs/node' import * as path from 'path' import { expect, use } from 'chai' import * as chaiAsPromised from 'chai-as-promised' -import { mock, restore } from 'test/stub/mockfs' use(chaiAsPromised) describe('fs', function () { - before(() => mock({ - '/foo/bar.html': 'bar', - '/un-readable.html': { mode: '0000', content: '' } - })) - after(restore) - describe('#resolve()', function () { it('should resolve based on root', async function () { const filepath = fs.resolve('/foo', 'bar.html', '.liquid') @@ -27,21 +20,21 @@ describe('fs', function () { }) describe('#exists', () => { it('should resolve as false if not exists', async () => { - const result = await fs.exists('/foo/foo.html') + const result = await fs.exists('/foo/bar') return expect(result).to.be.false }) it('should resolve as true if exists', async () => { - const result = await fs.exists('/foo/bar.html') + const result = await fs.exists(__filename) return expect(result).to.be.true }) }) describe('#readFile', function () { it('should throw when not exist', function () { - return expect(fs.readFile('/foo/foo.html')).to.rejectedWith('ENOENT') + return expect(fs.readFile('/foo/bar')).to.rejectedWith('ENOENT') }) - it('should throw when file not readable', function () { - return expect(fs.readFile('/un-readable.html')).to - .be.rejectedWith(/EACCES/) + it('should read content if exists', async function () { + const content = await fs.readFile(__filename) + return expect(content).to.contain('should read content if exists') }) }) }) diff --git a/test/unit/liquid/liquid-options.ts b/test/unit/liquid/liquid-options.ts new file mode 100644 index 0000000000..6d1dd55afb --- /dev/null +++ b/test/unit/liquid/liquid-options.ts @@ -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([]) + }) + }) +}) diff --git a/test/unit/liquid/liquid.ts b/test/unit/liquid/liquid.ts index edf81a36d7..8dd1b12263 100644 --- a/test/unit/liquid/liquid.ts +++ b/test/unit/liquid/liquid.ts @@ -47,4 +47,14 @@ describe('Liquid', function () { }) }) }) + 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\/"/) + }) + }) }) diff --git a/test/unit/render/render.ts b/test/unit/render/render.ts index 9f169114b1..ead6c07026 100644 --- a/test/unit/render/render.ts +++ b/test/unit/render/render.ts @@ -2,7 +2,7 @@ import { expect } from 'chai' import Scope from 'src/scope/scope' import Token from 'src/parser/token' import Tag from 'src/template/tag/tag' -import Filter from 'src/template/filter/Filter' +import Filter from 'src/template/filter/filter' import Render from 'src/render/render' import HTML from 'src/template/html' diff --git a/test/unit/scope/scope.ts b/test/unit/scope/scope.ts index b24050927b..dd44283909 100644 --- a/test/unit/scope/scope.ts +++ b/test/unit/scope/scope.ts @@ -10,6 +10,7 @@ describe('scope', function () { ctx = { foo: 'zoo', one: 1, + zoo: { size: 4 }, bar: { zoo: 'coo', 'Mr.Smith': 'John', @@ -133,6 +134,18 @@ describe('scope', function () { it('should return undefined when not exist', function () { expect(scope.get('foo.foo.foo')).to.be.undefined }) + it('should return string length as size', function () { + expect(scope.get('foo.size')).to.equal(3) + }) + it('should return array length as size', function () { + expect(scope.get('bar.arr.size')).to.equal(2) + }) + it('should return size property if exists', function () { + expect(scope.get('zoo.size')).to.equal(4) + }) + it('should return undefined if do not have size and length', function () { + expect(scope.get('one.size')).to.equal(undefined) + }) }) describe('#set', function () { diff --git a/test/unit/util/underscore.ts b/test/unit/util/underscore.ts index 585b01fa67..8e037d3e43 100644 --- a/test/unit/util/underscore.ts +++ b/test/unit/util/underscore.ts @@ -52,6 +52,10 @@ describe('util/underscore', function () { it('should return "" for undefined', function () { expect(_.stringify(undefined)).to.equal('') }) + it('should use Object.prototype.toString if no toString method exists', function () { + const obj = { toString: undefined } + expect(_.stringify(obj)).to.equal('[object Object]') + }) it('should return regex string for RegExp', function () { const reg = /foo/g expect(_.stringify(reg)).to.equal('/foo/g')