mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-29 15:15:23 -07:00
refactor: remove mock-fs from dev dependency
This commit is contained in:
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js: "lts/*"
|
||||||
- "8"
|
|
||||||
- "6"
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- stage: test
|
- stage: test
|
||||||
|
|||||||
+2
-2
@@ -50,7 +50,7 @@ export default [{
|
|||||||
exclude: [ 'test' ],
|
exclude: [ 'test' ],
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
module: 'ES2015',
|
module: 'ES2015',
|
||||||
paths: { 'template': ['src/parser/template-browser'] }
|
paths: { 'src/fs': ['src/fs/browser'] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -71,7 +71,7 @@ export default [{
|
|||||||
exclude: [ 'test' ],
|
exclude: [ 'test' ],
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
module: 'ES2015',
|
module: 'ES2015',
|
||||||
paths: { 'template': ['src/parser/template-browser'] }
|
paths: { 'src/fs': ['src/fs/browser'] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { assign } from 'src/util/underscore'
|
|
||||||
import html from './html'
|
import html from './html'
|
||||||
import str from './string'
|
import str from './string'
|
||||||
import math from './math'
|
import math from './math'
|
||||||
@@ -7,6 +6,4 @@ import array from './array'
|
|||||||
import date from './date'
|
import date from './date'
|
||||||
import obj from './object'
|
import obj from './object'
|
||||||
|
|
||||||
const filters = assign({}, html, str, math, url, date, obj, array)
|
export default { ...html, ...str, ...math, ...url, ...date, ...obj, ...array }
|
||||||
|
|
||||||
export default filters
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default {
|
|||||||
if (this.with) {
|
if (this.with) {
|
||||||
hash[filepath] = evalValue(this.with, scope)
|
hash[filepath] = evalValue(this.with, scope)
|
||||||
}
|
}
|
||||||
const templates = await this.liquid.getTemplate(filepath, scope.opts.root)
|
const templates = await this.liquid.getTemplate(filepath, scope.opts)
|
||||||
scope.push(hash)
|
scope.push(hash)
|
||||||
const html = await this.liquid.renderer.renderTemplates(templates, scope)
|
const html = await this.liquid.renderer.renderTemplates(templates, scope)
|
||||||
scope.pop(hash)
|
scope.pop(hash)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default {
|
|||||||
if (scope.blocks[''] === undefined) {
|
if (scope.blocks[''] === undefined) {
|
||||||
scope.blocks[''] = html
|
scope.blocks[''] = html
|
||||||
}
|
}
|
||||||
const templates = await this.liquid.getTemplate(layout, scope.opts.root)
|
const templates = await this.liquid.getTemplate(layout, scope.opts)
|
||||||
scope.push(hash)
|
scope.push(hash)
|
||||||
scope.blockMode = BlockMode.OUTPUT
|
scope.blockMode = BlockMode.OUTPUT
|
||||||
const partial = await this.liquid.renderer.renderTemplates(templates, scope)
|
const partial = await this.liquid.renderer.renderTemplates(templates, scope)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { last, isArray } from '../util/underscore'
|
import { last } from '../util/underscore'
|
||||||
|
import IFS from './ifs'
|
||||||
|
|
||||||
function domResolve (root, path) {
|
function domResolve (root, path) {
|
||||||
const base = document.createElement('base')
|
const base = document.createElement('base')
|
||||||
@@ -15,25 +16,17 @@ function domResolve (root, path) {
|
|||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolve (filepath, root, options) {
|
function resolve (root, filepath, ext) {
|
||||||
root = root || options.root
|
if (root.length && last(root) !== '/') root += '/'
|
||||||
if (isArray(root)) {
|
|
||||||
root = root[0]
|
|
||||||
}
|
|
||||||
if (root.length && last(root) !== '/') {
|
|
||||||
root += '/'
|
|
||||||
}
|
|
||||||
const url = domResolve(root, filepath)
|
const url = domResolve(root, filepath)
|
||||||
return url.replace(/^(\w+:\/\/[^/]+)(\/[^?]+)/, (str, origin, path) => {
|
return url.replace(/^(\w+:\/\/[^/]+)(\/[^?]+)/, (str, origin, path) => {
|
||||||
const last = path.split('/').pop()
|
const last = path.split('/').pop()
|
||||||
if (/\.\w+$/.test(last)) {
|
if (/\.\w+$/.test(last)) return str
|
||||||
return str
|
return origin + path + ext
|
||||||
}
|
|
||||||
return origin + path + options.extname
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function read (url: string): Promise<string> {
|
async function readFile (url: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest()
|
const xhr = new XMLHttpRequest()
|
||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
@@ -50,3 +43,9 @@ export async function read (url: string): Promise<string> {
|
|||||||
xhr.send()
|
xhr.send()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function exists () {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { readFile, resolve, exists } as IFS
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default interface IFS {
|
||||||
|
exists: (filepath?: string) => Promise<boolean>
|
||||||
|
readFile: (filepath:string) => Promise<string>
|
||||||
|
resolve: (root: string, file: string, ext: string) => string
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import * as _ from '../util/underscore'
|
||||||
|
import { resolve, extname } from 'path'
|
||||||
|
import { stat, readFile } from 'fs'
|
||||||
|
import IFS from './ifs'
|
||||||
|
|
||||||
|
const statAsync = _.promisify(stat) as (filepath: string) => Promise<object>
|
||||||
|
const readFileAsync = _.promisify(readFile) as (filepath: string, encoding: string) => Promise<string>
|
||||||
|
|
||||||
|
const fs: IFS = {
|
||||||
|
exists: filepath => {
|
||||||
|
return statAsync(filepath).then(() => true).catch(() => false)
|
||||||
|
},
|
||||||
|
readFile: filepath => {
|
||||||
|
return readFileAsync(filepath, 'utf8')
|
||||||
|
},
|
||||||
|
resolve: (root: string, file: string, ext: string) => {
|
||||||
|
if (!extname(file)) file += ext
|
||||||
|
return resolve(root, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fs
|
||||||
+21
-1
@@ -1,3 +1,5 @@
|
|||||||
|
import * as _ from './util/underscore'
|
||||||
|
|
||||||
export interface LiquidOptions {
|
export interface LiquidOptions {
|
||||||
/** `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`. If an array, the files are looked up in the order they occur in the array. Defaults to `["."]` */
|
/** `root` is a directory or an array of directories to resolve layouts and includes, as well as the filename passed in when calling `.renderFile()`. If an array, the files are looked up in the order they occur in the array. Defaults to `["."]` */
|
||||||
root?: string | string[]
|
root?: string | string[]
|
||||||
@@ -23,7 +25,11 @@ export interface LiquidOptions {
|
|||||||
greedy?: boolean
|
greedy?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultOptions: LiquidOptions = {
|
export interface NormalizedOptions extends LiquidOptions {
|
||||||
|
root?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultOptions: NormalizedOptions = {
|
||||||
root: ['.'],
|
root: ['.'],
|
||||||
cache: false,
|
cache: false,
|
||||||
extname: '',
|
extname: '',
|
||||||
@@ -36,3 +42,17 @@ export const defaultOptions: LiquidOptions = {
|
|||||||
strict_filters: false,
|
strict_filters: false,
|
||||||
strict_variables: false
|
strict_variables: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function normalize (options: LiquidOptions): NormalizedOptions {
|
||||||
|
options = options || {}
|
||||||
|
if (options.hasOwnProperty('root')) {
|
||||||
|
options.root = normalizeStringArray(options.root)
|
||||||
|
}
|
||||||
|
return options as NormalizedOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeStringArray (value: string | string[]): string[] {
|
||||||
|
if (_.isArray(value)) return value as string[]
|
||||||
|
if (_.isString(value)) return [value as string]
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|||||||
+30
-37
@@ -1,6 +1,6 @@
|
|||||||
import Scope from './scope/scope'
|
import Scope from './scope/scope'
|
||||||
import * as Types from './types'
|
import * as Types from './types'
|
||||||
import * as template from 'template'
|
import fs from 'src/fs'
|
||||||
import * as _ from './util/underscore'
|
import * as _ from './util/underscore'
|
||||||
import ITemplate from './template/itemplate'
|
import ITemplate from './template/itemplate'
|
||||||
import Tokenizer from './parser/tokenizer'
|
import Tokenizer from './parser/tokenizer'
|
||||||
@@ -13,19 +13,17 @@ import Value from './template/value'
|
|||||||
import { isTruthy, isFalsy, evalExp, evalValue } from './render/syntax'
|
import { isTruthy, isFalsy, evalExp, evalValue } from './render/syntax'
|
||||||
import builtinTags from './builtin/tags'
|
import builtinTags from './builtin/tags'
|
||||||
import builtinFilters from './builtin/filters'
|
import builtinFilters from './builtin/filters'
|
||||||
import { LiquidOptions, defaultOptions } from './liquid-options'
|
import { LiquidOptions, NormalizedOptions, defaultOptions, normalize } from './liquid-options'
|
||||||
|
|
||||||
export default class Liquid {
|
export default class Liquid {
|
||||||
public options: LiquidOptions
|
public options: NormalizedOptions
|
||||||
private cache: object
|
private cache: object
|
||||||
private parser: Parser
|
private parser: Parser
|
||||||
private renderer: Render
|
private renderer: Render
|
||||||
private tokenizer: Tokenizer
|
private tokenizer: Tokenizer
|
||||||
|
|
||||||
constructor (options: LiquidOptions = {}) {
|
constructor (opts: LiquidOptions = {}) {
|
||||||
options = _.assign({}, defaultOptions, options)
|
const options = { ...defaultOptions, ...normalize(opts) }
|
||||||
options.root = normalizeStringArray(options.root)
|
|
||||||
|
|
||||||
if (options.cache) {
|
if (options.cache) {
|
||||||
this.cache = {}
|
this.cache = {}
|
||||||
}
|
}
|
||||||
@@ -42,37 +40,38 @@ export default class Liquid {
|
|||||||
return this.parser.parse(tokens)
|
return this.parser.parse(tokens)
|
||||||
}
|
}
|
||||||
render (tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions) {
|
render (tpl: Array<ITemplate>, ctx?: object, opts?: LiquidOptions) {
|
||||||
opts = _.assign({}, this.options, opts)
|
const options = { ...this.options, ...normalize(opts) }
|
||||||
const scope = new Scope(ctx, opts)
|
const scope = new Scope(ctx, options)
|
||||||
return this.renderer.renderTemplates(tpl, scope)
|
return this.renderer.renderTemplates(tpl, scope)
|
||||||
}
|
}
|
||||||
async parseAndRender (html: string, ctx?: object, opts?: LiquidOptions) {
|
async parseAndRender (html: string, ctx?: object, opts?: LiquidOptions) {
|
||||||
const tpl = await this.parse(html)
|
const tpl = await this.parse(html)
|
||||||
return this.render(tpl, ctx, opts)
|
return this.render(tpl, ctx, opts)
|
||||||
}
|
}
|
||||||
async getTemplate (file, root) {
|
async getTemplate (file, opts?: LiquidOptions) {
|
||||||
const filepath = await template.resolve(file, root, this.options)
|
const options = normalize(opts)
|
||||||
return this.respectCache(filepath, async () => {
|
const roots = options.root ? [...options.root, ...this.options.root] : this.options.root
|
||||||
const str = await template.read(filepath)
|
const paths = roots.map(root => fs.resolve(root, file, this.options.extname))
|
||||||
return this.parse(str, filepath)
|
|
||||||
})
|
for (const filepath of paths) {
|
||||||
|
if (!(await fs.exists(filepath))) continue
|
||||||
|
|
||||||
|
if (this.options.cache && this.cache[filepath]) return this.cache[filepath]
|
||||||
|
const value = this.parse(await fs.readFile(filepath), filepath)
|
||||||
|
if (this.options.cache) this.cache[filepath] = value
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const err = new Error('ENOENT') as any
|
||||||
|
err.message = `ENOENT: Failed to lookup "${file}" in "${roots}"`
|
||||||
|
err.code = 'ENOENT'
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
async renderFile (file, ctx?: object, opts?: LiquidOptions) {
|
async renderFile (file, ctx?: object, opts?: LiquidOptions) {
|
||||||
opts = _.assign({}, opts)
|
const options = normalize(opts)
|
||||||
const templates = await this.getTemplate(file, opts.root)
|
const templates = await this.getTemplate(file, options)
|
||||||
return this.render(templates, ctx, opts)
|
return this.render(templates, ctx, opts)
|
||||||
}
|
}
|
||||||
async respectCache (key, getter) {
|
|
||||||
const cacheEnabled = this.options.cache
|
|
||||||
if (cacheEnabled && this.cache[key]) {
|
|
||||||
return this.cache[key]
|
|
||||||
}
|
|
||||||
const value = await getter()
|
|
||||||
if (cacheEnabled) {
|
|
||||||
this.cache[key] = value
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
evalValue (str: string, scope: Scope) {
|
evalValue (str: string, scope: Scope) {
|
||||||
return new Value(str, this.options.strict_filters).value(scope)
|
return new Value(str, this.options.strict_filters).value(scope)
|
||||||
}
|
}
|
||||||
@@ -85,10 +84,10 @@ export default class Liquid {
|
|||||||
plugin (plugin) {
|
plugin (plugin) {
|
||||||
return plugin.call(this, Liquid)
|
return plugin.call(this, Liquid)
|
||||||
}
|
}
|
||||||
express (opts: LiquidOptions = {}) {
|
express () {
|
||||||
const self = this
|
const self = this
|
||||||
return function (filePath, ctx, cb) {
|
return function (filePath: string, ctx: object, cb: (err: Error, html?: string) => void) {
|
||||||
opts.root = this.root
|
const opts = { root: this.root }
|
||||||
self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb)
|
self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,9 +98,3 @@ export default class Liquid {
|
|||||||
static evalValue = evalValue
|
static evalValue = evalValue
|
||||||
static Types = Types
|
static Types = Types
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeStringArray (value) {
|
|
||||||
if (_.isArray(value)) return value
|
|
||||||
if (_.isString(value)) return [value]
|
|
||||||
throw new TypeError('illegal root: ' + value)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
import * as _ from '../util/underscore'
|
|
||||||
import * as path from 'path'
|
|
||||||
import { anySeries } from '../util/promise'
|
|
||||||
import { stat, readFile } from 'fs'
|
|
||||||
|
|
||||||
export const fs = {
|
|
||||||
stat: _.promisify(stat) as ((filepath: string) => Promise<object>),
|
|
||||||
readFile: _.promisify(readFile) as ((filepath: string, encoding: string) => Promise<string>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function resolve (filepath, root, options) {
|
|
||||||
if (!path.extname(filepath)) {
|
|
||||||
filepath += options.extname
|
|
||||||
}
|
|
||||||
root = options.root.concat(root || [])
|
|
||||||
root = _.uniq(root)
|
|
||||||
const paths = root.map(root => path.resolve(root, filepath))
|
|
||||||
return anySeries(paths, async path => {
|
|
||||||
try {
|
|
||||||
await fs.stat(path)
|
|
||||||
return path
|
|
||||||
} catch (e) {
|
|
||||||
e.message = `${e.code}: Failed to lookup ${filepath} in: ${root}`
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function read (filepath): Promise<string> {
|
|
||||||
return fs.readFile(filepath, 'utf8')
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
import { assign } from 'src/util/underscore'
|
|
||||||
import DelimitedToken from 'src/parser/delimited-token'
|
import DelimitedToken from 'src/parser/delimited-token'
|
||||||
import Token from 'src/parser/token'
|
import Token from 'src/parser/token'
|
||||||
import TagToken from 'src/parser/tag-token'
|
import TagToken from 'src/parser/tag-token'
|
||||||
import { LiquidOptions } from 'src/liquid-options'
|
import { LiquidOptions } from 'src/liquid-options'
|
||||||
|
|
||||||
export default function whiteSpaceCtrl (tokens: Token[], options: LiquidOptions) {
|
export default function whiteSpaceCtrl (tokens: Token[], options: LiquidOptions) {
|
||||||
options = assign({ greedy: true }, options)
|
options = { greedy: true, ...options }
|
||||||
let inRaw = false
|
let inRaw = false
|
||||||
|
|
||||||
tokens.forEach((token: Token, i: number) => {
|
tokens.forEach((token: Token, i: number) => {
|
||||||
|
|||||||
+6
-11
@@ -1,21 +1,16 @@
|
|||||||
import * as _ from '../util/underscore'
|
import * as _ from '../util/underscore'
|
||||||
import * as lexical from '../parser/lexical'
|
import * as lexical from '../parser/lexical'
|
||||||
import assert from '../util/assert'
|
import assert from '../util/assert'
|
||||||
import { LiquidOptions, defaultOptions } from '../liquid-options'
|
import { NormalizedOptions, defaultOptions } from '../liquid-options'
|
||||||
import BlockMode from './block-mode'
|
import BlockMode from './block-mode'
|
||||||
|
|
||||||
export default class Scope {
|
export default class Scope {
|
||||||
opts: LiquidOptions
|
opts: NormalizedOptions
|
||||||
contexts: Array<object>
|
contexts: Array<object>
|
||||||
blocks: object = {}
|
blocks: object = {}
|
||||||
blockMode: BlockMode = BlockMode.OUTPUT
|
blockMode: BlockMode = BlockMode.OUTPUT
|
||||||
constructor (ctx: object = {}, opts: LiquidOptions = defaultOptions) {
|
constructor (ctx: object = {}, opts: NormalizedOptions = defaultOptions) {
|
||||||
this.opts = _.assign({
|
this.opts = { ...defaultOptions, ...opts }
|
||||||
dynamicPartials: true,
|
|
||||||
strict_variables: false,
|
|
||||||
strict_filters: false,
|
|
||||||
root: []
|
|
||||||
}, opts)
|
|
||||||
this.contexts = [ctx || {}]
|
this.contexts = [ctx || {}]
|
||||||
}
|
}
|
||||||
getAll () {
|
getAll () {
|
||||||
@@ -43,10 +38,10 @@ export default class Scope {
|
|||||||
scope = scope[key]
|
scope = scope[key]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
unshift (ctx: object): any {
|
unshift (ctx: object) {
|
||||||
return this.contexts.unshift(ctx)
|
return this.contexts.unshift(ctx)
|
||||||
}
|
}
|
||||||
push (ctx: object): any {
|
push (ctx: object) {
|
||||||
return this.contexts.push(ctx)
|
return this.contexts.push(ctx)
|
||||||
}
|
}
|
||||||
pop (ctx?: object): object {
|
pop (ctx?: object): object {
|
||||||
|
|||||||
+2
-2
@@ -48,7 +48,7 @@ TokenizationError.prototype.constructor = TokenizationError
|
|||||||
export class ParseError extends LiquidError {
|
export class ParseError extends LiquidError {
|
||||||
constructor (err, token) {
|
constructor (err, token) {
|
||||||
super(err, token)
|
super(err, token)
|
||||||
_.assign(this, err)
|
this.message = err.message
|
||||||
super.captureStackTrace(this)
|
super.captureStackTrace(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ ParseError.prototype.constructor = ParseError
|
|||||||
export class RenderError extends LiquidError {
|
export class RenderError extends LiquidError {
|
||||||
constructor (err, tpl) {
|
constructor (err, tpl) {
|
||||||
super(err, tpl.token)
|
super(err, tpl.token)
|
||||||
_.assign(this, err)
|
this.message = err.message
|
||||||
super.captureStackTrace(this)
|
super.captureStackTrace(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ const _date = {
|
|||||||
return num + d.getDate()
|
return num + d.getDate()
|
||||||
},
|
},
|
||||||
|
|
||||||
// Startday is an integer of which day to start the week measuring from
|
|
||||||
// TODO: that comment was retarted. fix it.
|
|
||||||
getWeekOfYear: function (d, startDay) {
|
getWeekOfYear: function (d, startDay) {
|
||||||
// Skip to startDay of this week
|
// Skip to startDay of this week
|
||||||
const now = this.getDayOfYear(d) + (startDay - d.getDay())
|
const now = this.getDayOfYear(d) + (startDay - d.getDay())
|
||||||
|
|||||||
+16
-37
@@ -1,16 +1,19 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import * as request from 'supertest'
|
import * as request from 'supertest'
|
||||||
import * as express from 'express'
|
import * as express from 'express'
|
||||||
import { mock, restore } from 'test/stub/mockfs'
|
import { resolve } from 'path'
|
||||||
import Liquid from '../..'
|
import Liquid from '../..'
|
||||||
|
|
||||||
describe('express()', function () {
|
describe('express()', function () {
|
||||||
var app, engine
|
const root = resolve(__dirname, '../stub/root')
|
||||||
|
const views = resolve(__dirname, '../stub/views')
|
||||||
|
const partials = resolve(__dirname, '../stub/partials')
|
||||||
|
let app, engine
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
app = express()
|
app = express()
|
||||||
engine = new Liquid({
|
engine = new Liquid({
|
||||||
root: '/root',
|
root,
|
||||||
extname: '.html'
|
extname: '.html'
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -24,14 +27,18 @@ describe('express()', function () {
|
|||||||
file: req.params.file
|
file: req.params.file
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
after(restore)
|
it('should respect express views(array)', function (done) {
|
||||||
it('should render express views', function (done) {
|
app.set('views', [views])
|
||||||
mock({ '/views/name.html': 'My name is {{name}}.' })
|
|
||||||
app.set('views', ['/views'])
|
|
||||||
request(app).get('/name')
|
request(app).get('/name')
|
||||||
.expect('My name is harttle.')
|
.expect('My name is harttle.')
|
||||||
.expect(200, done)
|
.expect(200, done)
|
||||||
})
|
})
|
||||||
|
it('should respect express views(string)', function (done) {
|
||||||
|
app.set('views', views)
|
||||||
|
request(app).get('/include/bar')
|
||||||
|
.expect('bar')
|
||||||
|
.expect(200, done)
|
||||||
|
})
|
||||||
it('should pass error when file not found', function (done) {
|
it('should pass error when file not found', function (done) {
|
||||||
const view = {
|
const view = {
|
||||||
root: []
|
root: []
|
||||||
@@ -49,41 +56,13 @@ describe('express()', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('should respect root option when lookup', function (done) {
|
it('should respect root option when lookup', function (done) {
|
||||||
mock({
|
app.set('views', [views])
|
||||||
'/root/foo.html': 'foo',
|
|
||||||
'/views/include.html': '{% include file %}'
|
|
||||||
})
|
|
||||||
app.set('views', ['/views'])
|
|
||||||
request(app).get('/include/foo')
|
request(app).get('/include/foo')
|
||||||
.expect('foo')
|
.expect('foo')
|
||||||
.expect(200, done)
|
.expect(200, done)
|
||||||
})
|
})
|
||||||
it('should respect express views (Array) when lookup', function (done) {
|
it('should respect express views (Array) when lookup', function (done) {
|
||||||
mock({
|
app.set('views', [views, partials])
|
||||||
'/views/include.html': '{% include file %}',
|
|
||||||
'/partials/bar.html': 'bar'
|
|
||||||
})
|
|
||||||
app.set('views', ['/views', '/partials'])
|
|
||||||
request(app).get('/include/bar')
|
|
||||||
.expect('bar')
|
|
||||||
.expect(200, done)
|
|
||||||
})
|
|
||||||
it('should respect express views (String) when lookup', function (done) {
|
|
||||||
mock({
|
|
||||||
'/views/include.html': '{% include file %}',
|
|
||||||
'/views/bar.html': 'bar'
|
|
||||||
})
|
|
||||||
app.set('views', '/views')
|
|
||||||
request(app).get('/include/bar')
|
|
||||||
.expect('bar')
|
|
||||||
.expect(200, done)
|
|
||||||
})
|
|
||||||
it('should respect express views (undefined) when lookup', function (done) {
|
|
||||||
const files = {}
|
|
||||||
files[process.cwd() + '/views/include.html'] = '{% include file %}'
|
|
||||||
files[process.cwd() + '/views/bar.html'] = 'bar'
|
|
||||||
mock(files)
|
|
||||||
|
|
||||||
request(app).get('/include/bar')
|
request(app).get('/include/bar')
|
||||||
.expect('bar')
|
.expect('bar')
|
||||||
.expect(200, done)
|
.expect(200, done)
|
||||||
|
|||||||
+25
-37
@@ -1,61 +1,53 @@
|
|||||||
import { expect } from 'chai'
|
|
||||||
import Liquid from '../..'
|
import Liquid from '../..'
|
||||||
import { mock, restore } from '../stub/mockfs'
|
import { expect, use } from 'chai'
|
||||||
|
import * as chaiAsPromised from 'chai-as-promised'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
|
||||||
|
use(chaiAsPromised)
|
||||||
|
|
||||||
describe('#renderFile()', function () {
|
describe('#renderFile()', function () {
|
||||||
var engine
|
const root = resolve(__dirname, '../stub/root')
|
||||||
|
const views = resolve(__dirname, '../stub/views')
|
||||||
|
let engine
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
engine = new Liquid({
|
engine = new Liquid({
|
||||||
root: '/root/',
|
root,
|
||||||
extname: '.html'
|
extname: '.html'
|
||||||
})
|
})
|
||||||
mock({
|
|
||||||
'/root/files/bar': 'bar',
|
|
||||||
'/root/files/foo.html': 'foo',
|
|
||||||
'/root/files/name.html': 'My name is {{name}}.',
|
|
||||||
'/un-readable.html': { mode: '0000' }
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
afterEach(restore)
|
|
||||||
it('should render file', async function () {
|
it('should render file', async function () {
|
||||||
const html = await engine.renderFile('/root/files/foo.html', {})
|
const html = await engine.renderFile(resolve(root, 'foo.html'), {})
|
||||||
return expect(html).to.equal('foo')
|
return expect(html).to.equal('foo')
|
||||||
})
|
})
|
||||||
it('should find files without extname', async function () {
|
it('should find files without extname', async function () {
|
||||||
var engine = new Liquid({ root: '/root' })
|
var engine = new Liquid({ root })
|
||||||
const html = await engine.renderFile('/root/files/bar', {})
|
const html = await engine.renderFile(resolve(root, 'bar'), {})
|
||||||
return expect(html).to.equal('bar')
|
return expect(html).to.equal('bar')
|
||||||
})
|
})
|
||||||
it('should accept relative path', async function () {
|
it('should accept relative path', async function () {
|
||||||
const html = await engine.renderFile('files/foo.html')
|
const html = await engine.renderFile('foo.html')
|
||||||
return expect(html).to.equal('foo')
|
return expect(html).to.equal('foo')
|
||||||
})
|
})
|
||||||
it('should resolve array as root', async function () {
|
it('should traverse root array', async function () {
|
||||||
engine = new Liquid({
|
|
||||||
root: ['/boo', '/root/'],
|
|
||||||
extname: '.html'
|
|
||||||
})
|
|
||||||
const html = await engine.renderFile('files/foo.html')
|
|
||||||
return expect(html).to.equal('foo')
|
|
||||||
})
|
|
||||||
it('should default root to cwd', async function () {
|
|
||||||
var files = {}
|
|
||||||
files[process.cwd() + '/foo.html'] = 'FOO'
|
|
||||||
mock(files)
|
|
||||||
|
|
||||||
engine = new Liquid({
|
engine = new Liquid({
|
||||||
|
root: ['/boo', root],
|
||||||
extname: '.html'
|
extname: '.html'
|
||||||
})
|
})
|
||||||
const html = await engine.renderFile('foo.html')
|
const html = await engine.renderFile('foo.html')
|
||||||
return expect(html).to.equal('FOO')
|
return expect(html).to.equal('foo')
|
||||||
|
})
|
||||||
|
it('should default root to cwd', async function () {
|
||||||
|
engine = new Liquid()
|
||||||
|
const html = await engine.renderFile('package.json')
|
||||||
|
return expect(html).to.contain('"name": "liquidjs"')
|
||||||
})
|
})
|
||||||
it('should render file with context', async function () {
|
it('should render file with context', async function () {
|
||||||
const html = await engine.renderFile('/root/files/name.html', { name: 'harttle' })
|
const html = await engine.renderFile(resolve(views, 'name.html'), { name: 'harttle' })
|
||||||
return expect(html).to.equal('My name is harttle.')
|
return expect(html).to.equal('My name is harttle.')
|
||||||
})
|
})
|
||||||
it('should use default extname', async function () {
|
it('should use default extname', async function () {
|
||||||
const html = await engine.renderFile('files/name', { name: 'harttle' })
|
const html = await engine.renderFile(resolve(root, 'foo'))
|
||||||
return expect(html).to.equal('My name is harttle.')
|
return expect(html).to.equal('foo')
|
||||||
})
|
})
|
||||||
it('should throw with lookup list when file not exist', function () {
|
it('should throw with lookup list when file not exist', function () {
|
||||||
engine = new Liquid({
|
engine = new Liquid({
|
||||||
@@ -63,10 +55,6 @@ describe('#renderFile()', function () {
|
|||||||
extname: '.html'
|
extname: '.html'
|
||||||
})
|
})
|
||||||
return expect(engine.renderFile('/not/exist.html')).to
|
return expect(engine.renderFile('/not/exist.html')).to
|
||||||
.be.rejectedWith(/failed to lookup \/not\/exist.html in: \/boo,\/root\//i)
|
.be.rejectedWith(/Failed to lookup "\/not\/exist.html" in "\/boo,\/root\/"/)
|
||||||
})
|
|
||||||
it('should throw when file not readable', function () {
|
|
||||||
return expect(engine.renderFile('/un-readable.html')).to
|
|
||||||
.be.rejectedWith(/EACCES/)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
+17
-14
@@ -1,31 +1,34 @@
|
|||||||
import { fs } from 'src/parser/template'
|
|
||||||
import { isString } from 'src/util/underscore'
|
import { isString } from 'src/util/underscore'
|
||||||
|
import fs from 'src/fs'
|
||||||
const readFile = fs.readFile
|
|
||||||
const stat = fs.stat
|
|
||||||
|
|
||||||
type fileDescriptor = { mode: string, content: string }
|
type fileDescriptor = { mode: string, content: string }
|
||||||
|
|
||||||
export function mock (files: { [path: string]: (string | fileDescriptor) }) {
|
let files: { [path: string]: fileDescriptor } = {}
|
||||||
for (const [key, val] of Object.entries(files)) {
|
const readFile = fs.readFile
|
||||||
|
const exists = fs.exists
|
||||||
|
|
||||||
|
export function mock (options: { [path: string]: (string | fileDescriptor) }) {
|
||||||
|
for (const [key, val] of Object.entries(options)) {
|
||||||
files[key] = isString(val)
|
files[key] = isString(val)
|
||||||
? { mode: '33188', content: val as string }
|
? { mode: '33188', content: val as string }
|
||||||
: val
|
: val as fileDescriptor
|
||||||
}
|
}
|
||||||
fs.readFile = async function (path) {
|
fs.readFile = async function (path) {
|
||||||
const file = files[path] as fileDescriptor
|
console.log('mock fs read called', path)
|
||||||
|
const file = files[path]
|
||||||
if (file === undefined) throw new Error('ENOENT')
|
if (file === undefined) throw new Error('ENOENT')
|
||||||
if (file.mode === '000') throw new Error('EACCES')
|
if (file.mode === '0000') throw new Error('EACCES')
|
||||||
return file.content
|
return file.content
|
||||||
}
|
}
|
||||||
fs.stat = async function (path) {
|
|
||||||
const file = files[path] as fileDescriptor
|
fs.exists = async function (path) {
|
||||||
if (file === undefined) throw new Error('ENOENT')
|
console.log('mock fs exists called', path)
|
||||||
return file
|
return !!files[path]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function restore () {
|
export function restore () {
|
||||||
|
files = {}
|
||||||
fs.readFile = readFile
|
fs.readFile = readFile
|
||||||
fs.stat = stat
|
fs.exists = exists
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
bar
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import Liquid from 'src/liquid'
|
||||||
|
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 () {},
|
||||||
|
posts: [{ category: 'foo' }, { category: 'bar' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function test (src, dst) {
|
||||||
|
const html = await liquid.parseAndRender(src, ctx)
|
||||||
|
return expect(html).to.equal(dst)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
bar
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
foo
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
bar
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{% include file %}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
My name is {{name}}.
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { test, ctx, liquid } 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, liquid } 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, ctx, liquid } 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, ctx, liquid } 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, ctx, liquid } 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,161 @@
|
|||||||
|
import { test, ctx, liquid } 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 default to 16', function () {
|
||||||
|
return test('{{ "1234567890abcdefghi" | truncate }}', '1234567890abc...')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { test, ctx, liquid } 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'))
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,425 +0,0 @@
|
|||||||
import { expect } from 'chai'
|
|
||||||
import Liquid from '../../src/liquid'
|
|
||||||
|
|
||||||
const ctx = {
|
|
||||||
date: new Date(),
|
|
||||||
foo: 'bar',
|
|
||||||
arr: [-2, 'a'],
|
|
||||||
obj: {
|
|
||||||
foo: 'bar'
|
|
||||||
},
|
|
||||||
func: function () {},
|
|
||||||
posts: [{
|
|
||||||
category: 'foo'
|
|
||||||
}, {
|
|
||||||
category: 'bar'
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
let liquid
|
|
||||||
|
|
||||||
async function test (src, dst) {
|
|
||||||
const html = await liquid.parseAndRender(src, ctx)
|
|
||||||
return expect(html).to.equal(dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('filters', function () {
|
|
||||||
before(() => { liquid = 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 convert string', () => test('{{ "-3" | abs }}', '3'))
|
|
||||||
})
|
|
||||||
|
|
||||||
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 support capitalize', () => test('{{ "i am good" | capitalize }}', 'I am good'))
|
|
||||||
|
|
||||||
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('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('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"}')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
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('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('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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support split/first', function () {
|
|
||||||
const src = '{% assign my_array = "apples, oranges, peaches, plums" | split: ", " %}' +
|
|
||||||
'{{ my_array | first }}'
|
|
||||||
return test(src, 'apples')
|
|
||||||
})
|
|
||||||
|
|
||||||
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('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 lstrip', function () {
|
|
||||||
const src = '{{ " So much room for activities! " | lstrip }}'
|
|
||||||
return test(src, 'So much room for activities! ')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support map', function () {
|
|
||||||
return test('{{posts | map: "category"}}', '["foo","bar"]')
|
|
||||||
})
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
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 reverse', function () {
|
|
||||||
return test('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}',
|
|
||||||
'.moT rojaM ot lortnoc dnuorG')
|
|
||||||
})
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support rstrip', function () {
|
|
||||||
return test('{{ " So much room for activities! " | rstrip }}',
|
|
||||||
' So much room for activities!')
|
|
||||||
})
|
|
||||||
|
|
||||||
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')
|
|
||||||
})
|
|
||||||
|
|
||||||
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!')
|
|
||||||
})
|
|
||||||
|
|
||||||
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 }}', '')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support strip_newlines', function () {
|
|
||||||
return test('{% capture string_with_newlines %}\n' +
|
|
||||||
'Hello\nthere\n{% endcapture %}' +
|
|
||||||
'{{ string_with_newlines | strip_newlines }}',
|
|
||||||
'Hellothere')
|
|
||||||
})
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
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 default to 16', function () {
|
|
||||||
return test('{{ "1234567890abcdefghi" | truncate }}', '1234567890abc...')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
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: ","}}', '')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should support upcase', () => test('{{ "Parker Moore" | upcase }}', 'PARKER MOORE'))
|
|
||||||
|
|
||||||
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'))
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('obj_test', function () {
|
|
||||||
before(() => {
|
|
||||||
liquid.registerFilter('obj_test', function () {
|
|
||||||
return Array.prototype.slice.call(arguments).join(',')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
it('should support object', () => test(`{{ "a" | obj_test: k1: "v1", k2: foo }}`, 'a,k1,v1,k2,bar'))
|
|
||||||
it('should support mixed object', () => test(`{{ "a" | obj_test: "something", k1: "v1", k2: foo }}`, 'a,something,k1,v1,k2,bar'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import fs from 'src/fs/browser'
|
||||||
|
import * as sinon from 'sinon'
|
||||||
|
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 () {
|
||||||
|
if (+process.version.match(/^v(\d+)/)[1] < 8) {
|
||||||
|
console.info('jsdom not supported, skipping template-browser...')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const JSDOM = require('jsdom').JSDOM
|
||||||
|
beforeEach(function () {
|
||||||
|
const dom = new JSDOM(``, {
|
||||||
|
url: 'https://example.com/foo/bar/',
|
||||||
|
contentType: 'text/html',
|
||||||
|
includeNodeLocations: true
|
||||||
|
});
|
||||||
|
(global as any).document = dom.window.document
|
||||||
|
})
|
||||||
|
afterEach(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')
|
||||||
|
})
|
||||||
|
it('should treat root as directory', function () {
|
||||||
|
expect(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')
|
||||||
|
})
|
||||||
|
it('should support empty root', function () {
|
||||||
|
expect(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')
|
||||||
|
})
|
||||||
|
it('should add extname when absent', function () {
|
||||||
|
expect(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')
|
||||||
|
})
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('#readFile()', () => {
|
||||||
|
let server
|
||||||
|
beforeEach(() => {
|
||||||
|
server = sinon.createFakeServer()
|
||||||
|
server.autoRespond = true
|
||||||
|
server.respondWith('GET', 'https://example.com/views/hello.html',
|
||||||
|
[200, { 'Content-Type': 'text/plain' }, 'hello {{name}}']);
|
||||||
|
(global as any).XMLHttpRequest = sinon.useFakeXMLHttpRequest()
|
||||||
|
})
|
||||||
|
afterEach(() => {
|
||||||
|
server.restore()
|
||||||
|
delete (global as any).XMLHttpRequest
|
||||||
|
})
|
||||||
|
it('should get corresponding text', async function () {
|
||||||
|
const html = await fs.readFile('https://example.com/views/hello.html')
|
||||||
|
return expect(html).to.equal('hello {{name}}')
|
||||||
|
})
|
||||||
|
it('should throw 404', () => {
|
||||||
|
return expect(fs.readFile('https://example.com/not/exist.html'))
|
||||||
|
.to.be.rejectedWith('Not Found')
|
||||||
|
})
|
||||||
|
it('should throw error', function () {
|
||||||
|
const result = expect(fs.readFile('https://example.com/views/hello.html'))
|
||||||
|
.to.be.rejectedWith('An error occurred whilst receiving the response.')
|
||||||
|
server.requests[0].error()
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
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')
|
||||||
|
const expected = path.resolve('/foo/bar.html')
|
||||||
|
return expect(filepath).to.equal(expected)
|
||||||
|
})
|
||||||
|
it('should add extension if it has no extension', async function () {
|
||||||
|
const filepath = fs.resolve('/foo', 'bar', '.liquid')
|
||||||
|
const expected = path.resolve('/foo/bar.liquid')
|
||||||
|
return expect(filepath).to.equal(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('#exists', () => {
|
||||||
|
it('should resolve as false if not exists', async () => {
|
||||||
|
const result = await fs.exists('/foo/foo.html')
|
||||||
|
return expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('should resolve as true if exists', async () => {
|
||||||
|
const result = await fs.exists('/foo/bar.html')
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
it('should throw when file not readable', function () {
|
||||||
|
return expect(fs.readFile('/un-readable.html')).to
|
||||||
|
.be.rejectedWith(/EACCES/)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import Liquid from '../../src/liquid'
|
import Liquid from 'src/liquid'
|
||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import { mock, restore } from 'test/stub/mockfs'
|
import { mock, restore } from 'test/stub/mockfs'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
describe('Liquid', function () {
|
describe('Liquid', function () {
|
||||||
describe('#constructor()', function () {
|
|
||||||
it('should throw on illegal root', function () {
|
|
||||||
expect(() => new (Liquid as any)({ root: {} })).to.throw(/illegal root/)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('#plugin()', function () {
|
describe('#plugin()', function () {
|
||||||
it('should call plugin on the instance', async function () {
|
it('should call plugin on the instance', async function () {
|
||||||
const engine = new Liquid()
|
const engine = new Liquid()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import Liquid from '../../../src/liquid'
|
import Liquid from 'src/liquid'
|
||||||
|
|
||||||
describe('LiquidOptions#trimming', function () {
|
describe('LiquidOptions#trimming', function () {
|
||||||
const ctx = { name: 'harttle' }
|
const ctx = { name: 'harttle' }
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
const lexical = require('../../src/parser/lexical')
|
const lexical = require('src/parser/lexical')
|
||||||
|
|
||||||
describe('lexical', function () {
|
describe('lexical', function () {
|
||||||
it('should test filter syntax', function () {
|
it('should test filter syntax', function () {
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import Scope from '../../src/scope/scope'
|
import Scope from 'src/scope/scope'
|
||||||
import Token from '../../src/parser/token'
|
import Token from 'src/parser/token'
|
||||||
import Tag from 'src/template/tag/tag'
|
import Tag from 'src/template/tag/tag'
|
||||||
import Filter from 'src/template/filter'
|
import Filter from 'src/template/filter'
|
||||||
import Render from '../../src/render/render'
|
import Render from 'src/render/render'
|
||||||
import HTML from 'src/template/html'
|
import HTML from 'src/template/html'
|
||||||
|
|
||||||
describe('render', function () {
|
describe('render', function () {
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import { resolve } from '../../src/parser/template-browser'
|
|
||||||
import { expect } from 'chai'
|
|
||||||
|
|
||||||
describe('template-browser', function () {
|
|
||||||
if (+process.version.match(/^v(\d+)/)[1] < 8) {
|
|
||||||
console.info('jsdom not supported, skipping template-browser...')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const JSDOM = require('jsdom').JSDOM
|
|
||||||
beforeEach(function () {
|
|
||||||
const dom = new JSDOM(``, {
|
|
||||||
url: 'https://example.com/foo/bar/',
|
|
||||||
contentType: 'text/html',
|
|
||||||
includeNodeLocations: true
|
|
||||||
});
|
|
||||||
(global as any).document = dom.window.document
|
|
||||||
})
|
|
||||||
afterEach(function () {
|
|
||||||
delete (global as any).document
|
|
||||||
})
|
|
||||||
describe('resolve', function () {
|
|
||||||
it('should support relative root', function () {
|
|
||||||
expect(resolve('foo', './views/', {
|
|
||||||
extname: '',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/foo/bar/views/foo')
|
|
||||||
})
|
|
||||||
it('should treat root as directory', function () {
|
|
||||||
expect(resolve('foo', './views', {
|
|
||||||
extname: '',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/foo/bar/views/foo')
|
|
||||||
})
|
|
||||||
it('should support absolute root', function () {
|
|
||||||
expect(resolve('foo', '/views', {
|
|
||||||
extname: '',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/views/foo')
|
|
||||||
})
|
|
||||||
it('should support empty root', function () {
|
|
||||||
expect(resolve('page.html', '', {
|
|
||||||
extname: '',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/foo/bar/page.html')
|
|
||||||
})
|
|
||||||
it('should support full url as root', function () {
|
|
||||||
expect(resolve('page.html', 'https://example.com/views/', {
|
|
||||||
extname: '',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/views/page.html')
|
|
||||||
})
|
|
||||||
it('should use options.root when root argument absent', function () {
|
|
||||||
expect(resolve('page.html', null, {
|
|
||||||
extname: '',
|
|
||||||
root: ['https://example.com/views', 'https://google.com/views']
|
|
||||||
})).to.equal('https://example.com/views/page.html')
|
|
||||||
})
|
|
||||||
it('should add extname when absent', function () {
|
|
||||||
expect(resolve('page', 'https://example.com/views/', {
|
|
||||||
extname: '.html',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/views/page.html')
|
|
||||||
})
|
|
||||||
it('should add extname for urls have searchParams', function () {
|
|
||||||
expect(resolve('page?foo=bar', 'https://example.com/views/', {
|
|
||||||
extname: '.html',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/views/page.html?foo=bar')
|
|
||||||
})
|
|
||||||
it('should not add extname when full url is given', function () {
|
|
||||||
expect(resolve('https://google.com/page.php', 'https://example.com/views/', {
|
|
||||||
extname: '.html',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://google.com/page.php')
|
|
||||||
})
|
|
||||||
it('should not add extname when already have one', function () {
|
|
||||||
expect(resolve('page.php', 'https://example.com/views/', {
|
|
||||||
extname: '.html',
|
|
||||||
root: ['.']
|
|
||||||
})).to.equal('https://example.com/views/page.php')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { resolve } from '../../src/parser/template'
|
|
||||||
import * as path from 'path'
|
|
||||||
import { expect, use } from 'chai'
|
|
||||||
import * as chaiAsPromised from 'chai-as-promised'
|
|
||||||
import { mock, restore } from '../stub/mockfs'
|
|
||||||
|
|
||||||
use(chaiAsPromised)
|
|
||||||
|
|
||||||
describe('template', function () {
|
|
||||||
before(() => mock({ '/foo/bar.html': 'bar' }))
|
|
||||||
after(restore)
|
|
||||||
|
|
||||||
describe('#resolve()', function () {
|
|
||||||
it('should resolve based on root', async function () {
|
|
||||||
const filepath = await resolve('bar.html', '/foo', { root: [] })
|
|
||||||
const expected = path.resolve('/foo/bar.html')
|
|
||||||
return expect(filepath).to.equal(expected)
|
|
||||||
})
|
|
||||||
it('should resolve based on root', function () {
|
|
||||||
return expect(resolve('foo.html', '/foo', { root: [] }))
|
|
||||||
.to.rejectedWith(/Failed to lookup foo.html in: \/foo/)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import Scope from '../../src/scope/scope'
|
import Scope from 'src/scope/scope'
|
||||||
import Output from '../../src/template/output'
|
import Output from 'src/template/output'
|
||||||
import OutputToken from 'src/parser/output-token'
|
import OutputToken from 'src/parser/output-token'
|
||||||
import Filter from 'src/template/filter'
|
import Filter from 'src/template/filter'
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import * as sinonChai from 'sinon-chai'
|
import * as sinonChai from 'sinon-chai'
|
||||||
import * as sinon from 'sinon'
|
import * as sinon from 'sinon'
|
||||||
import Scope from '../../src/scope/scope'
|
import Scope from 'src/scope/scope'
|
||||||
import Filter from 'src/template/filter'
|
import Filter from 'src/template/filter'
|
||||||
import Value from 'src/template/value'
|
import Value from 'src/template/value'
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import assert from '../../../src/util/assert'
|
import assert from 'src/util/assert'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as sinonChai from 'sinon-chai'
|
|||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
chai.use(sinonChai)
|
chai.use(sinonChai)
|
||||||
|
|
||||||
const P = require('../../../src/util/promise')
|
const P = require('src/util/promise')
|
||||||
|
|
||||||
describe('util/promise', function () {
|
describe('util/promise', function () {
|
||||||
describe('.anySeries()', function () {
|
describe('.anySeries()', function () {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import t from '../../../src/util/strftime'
|
import t from 'src/util/strftime'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import * as chai from 'chai'
|
import * as chai from 'chai'
|
||||||
import * as sinonChai from 'sinon-chai'
|
import * as sinonChai from 'sinon-chai'
|
||||||
import * as sinon from 'sinon'
|
import * as sinon from 'sinon'
|
||||||
import { RenderError, RenderBreakError } from '../../../src/util/error'
|
import { RenderError, RenderBreakError } from 'src/util/error'
|
||||||
import * as _ from '../../../src/util/underscore'
|
import * as _ from 'src/util/underscore'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
chai.use(sinonChai)
|
chai.use(sinonChai)
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { read } from 'src/parser/template-browser'
|
|
||||||
import * as sinon from 'sinon'
|
|
||||||
import { expect, use } from 'chai'
|
|
||||||
import * as chaiAsPromised from 'chai-as-promised'
|
|
||||||
|
|
||||||
use(chaiAsPromised)
|
|
||||||
|
|
||||||
describe('xhr', () => {
|
|
||||||
if (+process.version.match(/^v(\d+)/)[1] < 8) {
|
|
||||||
console.info('jsdom not supported, skipping xhr...')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let server
|
|
||||||
beforeEach(() => {
|
|
||||||
server = sinon.createFakeServer()
|
|
||||||
server.autoRespond = true
|
|
||||||
server.respondWith('GET', 'https://example.com/views/hello.html',
|
|
||||||
[200, { 'Content-Type': 'text/plain' }, 'hello {{name}}']);
|
|
||||||
(global as any).XMLHttpRequest = sinon.useFakeXMLHttpRequest()
|
|
||||||
})
|
|
||||||
afterEach(() => {
|
|
||||||
server.restore()
|
|
||||||
delete (global as any).XMLHttpRequest
|
|
||||||
})
|
|
||||||
describe('#read()', () => {
|
|
||||||
it('should get corresponding text', async function () {
|
|
||||||
const html = await read('https://example.com/views/hello.html')
|
|
||||||
return expect(html).to.equal('hello {{name}}')
|
|
||||||
})
|
|
||||||
it('should throw 404', () => {
|
|
||||||
return expect(read('https://example.com/not/exist.html'))
|
|
||||||
.to.be.rejectedWith('Not Found')
|
|
||||||
})
|
|
||||||
it('should throw error', function (done) {
|
|
||||||
read('https://example.com/views/hello.html')
|
|
||||||
.then(() => done('should not be resolved'))
|
|
||||||
.catch(function (e) {
|
|
||||||
expect(e.message).to.equal('An error occurred whilst receiving the response.')
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
server.requests[0].error()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
"template": ["src/parser/template"],
|
"src/fs": ["src/fs/node"],
|
||||||
"src/*": ["src/*"],
|
"src/*": ["src/*"],
|
||||||
"test/*": ["test/*"]
|
"test/*": ["test/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user