From 56c7992b767cc6aca80a559bf897dffa008fb934 Mon Sep 17 00:00:00 2001 From: harttle Date: Sat, 23 Feb 2019 03:11:07 +0800 Subject: [PATCH] fix: default length for truncate and truncatewords --- package.json | 5 +++-- src/builtin/filters/string.ts | 10 +++++----- src/scope/scope.ts | 2 +- test/unit/builtin/filters/string.ts | 19 +++++++++++++++++-- test/unit/fs/browser.ts | 26 ++++++++++++++++---------- test/unit/fs/node.ts | 19 ++++++------------- test/unit/liquid/liquid-options.ts | 15 +++++++++++++++ test/unit/liquid/liquid.ts | 10 ++++++++++ test/unit/render/render.ts | 2 +- test/unit/scope/scope.ts | 13 +++++++++++++ test/unit/util/underscore.ts | 4 ++++ 11 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 test/unit/liquid/liquid-options.ts diff --git a/package.json b/package.json index 9c9568958..e86c7e550 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 0e8bf3eb9..d929af196 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 31f3017f6..93dd5b699 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 a424187f0..fcb00f2cb 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 b36d8b3b9..06308d9b7 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 c7ec20212..628ce977d 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 000000000..6d1dd55af --- /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 edf81a36d..8dd1b1226 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 9f169114b..ead6c0702 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 b24050927..dd4428390 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 585b01fa6..8e037d3e4 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')