Skip to content

Commit

Permalink
👕 test: improve code coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed May 26, 2017
1 parent a37939a commit 39234d5
Show file tree
Hide file tree
Showing 14 changed files with 195 additions and 36 deletions.
6 changes: 1 addition & 5 deletions src/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@
import { warn, isObject } from './util'

export default class BaseFormatter {
_options: FormatterOptions
_caches: { [key: string]: Array<Token> }

constructor (options: FormatterOptions = {}) {
this._options = options
constructor () {
this._caches = Object.create(null)
}

get options (): FormatterOptions { return this._options }

interpolate (message: string, values: any): Array<any> {
let tokens: Array<Token> = this._caches[message]
if (!tokens) {
Expand Down
8 changes: 8 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export default class VueI18n {
}

watchLocale (fn: Function): ?Function {
/* istanbul ignore if */
if (!this._sync || !this._root) { return null }
const target: any = this._vm
return this._root.vm.$watch('locale', (val) => {
Expand Down Expand Up @@ -161,6 +162,7 @@ export default class VueI18n {

let ret: mixed
if (isNull(pathRet)) {
/* istanbul ignore else */
if (isPlainObject(message)) {
ret = message[key]
if (typeof ret !== 'string') {
Expand All @@ -173,6 +175,7 @@ export default class VueI18n {
return null
}
} else {
/* istanbul ignore else */
if (typeof pathRet === 'string') {
ret = pathRet
} else {
Expand Down Expand Up @@ -246,6 +249,7 @@ export default class VueI18n {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
warn(`Fall back to translate the keypath '${key}' with root locale.`)
}
/* istanbul ignore if */
if (!this._root) { throw Error('unexpected error') }
return this._root.t(key, ...values)
} else {
Expand All @@ -272,6 +276,7 @@ export default class VueI18n {
}

i (key: Path, ...values: any): TranslateResult {
/* istanbul ignore if */
if (!key) { return '' }

let locale: Locale = this.locale
Expand Down Expand Up @@ -342,6 +347,7 @@ export default class VueI18n {
}

_d (value: number | Date, _locale: Locale, key: ?string): DateTimeFormatResult {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.dateTimeFormat) {
warn('Cannot format a Date value due to not support Intl.DateTimeFormat.')
return ''
Expand Down Expand Up @@ -411,6 +417,7 @@ export default class VueI18n {
}

_n (value: number, _locale: Locale, key: ?string): NumberFormatResult {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.numberFormat) {
warn('Cannot format a Date value due to not support Intl.NumberFormat.')
return ''
Expand Down Expand Up @@ -475,6 +482,7 @@ VueI18n.availabilities = {
VueI18n.install = install
VueI18n.version = '__VERSION__'

/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(VueI18n)
}
2 changes: 2 additions & 0 deletions src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ export function install (_Vue) {
Vue = _Vue

const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && install.installed) {
warn('already installed.')
return
}
install.installed = true

/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && version < 2) {
warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
return
Expand Down
16 changes: 5 additions & 11 deletions src/path.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @flow */

import { isObject, isPlainObject, hasOwn } from './util'
import { isObject } from './util'

/**
* Path paerser
Expand Down Expand Up @@ -263,18 +263,12 @@ export type PathValueObject = { [key: string]: PathValue }
export type PathValueArray = Array<PathValue>

function empty (target: any): boolean {
if (target === null || target === undefined) { return true }

/* istanbul ignore else */
if (Array.isArray(target)) {
if (target.length > 0) { return false }
if (target.length === 0) { return true }
} else if (isPlainObject(target)) {
for (const key in target) {
if (hasOwn(target, key)) { return false }
}
return target.length === 0
} else {
return false
}

return true
}

export default class I18nPath {
Expand Down
22 changes: 3 additions & 19 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,13 @@
export function warn (msg: string, err: ?Error): void {
if (typeof console !== 'undefined') {
console.warn('[vue-i18n] ' + msg)
/* istanbul ignore if */
if (err) {
console.warn(err.stack)
}
}
}

const hasOwnProperty: Function = Object.prototype.hasOwnProperty
export function hasOwn (obj: Object, key: string): boolean {
return hasOwnProperty.call(obj, key)
}

export function bind (fn: Function, ctx: Object): Function {
function boundFn (a) {
const l: number = arguments.length
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
// record original fn length
boundFn._length = fn.length
return boundFn
}

export function isObject (obj: mixed): boolean {
return obj !== null && typeof obj === 'object'
}
Expand Down Expand Up @@ -59,6 +41,7 @@ export function parseArgs (...args: Array<mixed>): Object {
if (typeof args[0] === 'string') {
locale = args[0]
}
/* istanbul ignore if */
if (isObject(args[1]) || Array.isArray(args[1])) {
params = args[1]
}
Expand All @@ -84,6 +67,7 @@ function getChoiceIndex (choice: number, choicesLength: number): number {
}

export function fetchChoice (message: string, choice: number): ?string {
/* istanbul ignore if */
if (!message && typeof message !== 'string') { return null }
const choices: Array<string> = message.split('|')

Expand Down
12 changes: 12 additions & 0 deletions test/unit/datetime.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import dateTimeFormats from './fixture/datetime'

const desc = VueI18n.availabilities.dateTimeFormat ? describe : describe.skip
desc('datetime format', () => {
describe('dateTimeFormats', () => {
it('should be worked', done => {
const i18n = new VueI18n({
locale: 'en-US',
dateTimeFormats
})
nextTick(() => {
assert.deepEqual(dateTimeFormats, i18n.dateTimeFormats)
}).then(done)
})
})

describe('getDateTimeFormat / setDateTimeFormat', () => {
it('should be worked', done => {
const i18n = new VueI18n({
Expand Down
38 changes: 38 additions & 0 deletions test/unit/format.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,42 @@ describe('compile', () => {
assert.equal(compiled[3], '0x20')
})
})

describe('unknown token', () => {
it('should be compiled', () => {
const spy = sinon.spy(console, 'warn')

const tokens = parse('name: { name1}, email: {%email}')
const compiled = compile(tokens, ['kazupon', '0x20'])
assert(compiled.length === 2)
assert.equal(compiled[0], 'name: ')
assert.equal(compiled[1], ', email: ')

assert(spy.notCalled === false)
assert(spy.callCount === 2)
spy.restore()
})
})

describe('values unknown mode', () => {
it('should be compiled with empty', () => {
const compiled = compile([], 1)
assert.deepEqual(compiled, [])
})
})

describe('unmatch values mode', () => {
it('should be warned', () => {
const spy = sinon.spy(console, 'warn')

const tokens1 = parse('name: {0}, age: {1}') // list tokens
compile(tokens1, { name: 'kazupon', age: '0x20' }) // named values
const tokens2 = parse('name: {name}, age: {age}') // named tokens
compile(tokens2, ['kazupon', '0x20']) // list values

assert(spy.notCalled === false)
assert(spy.callCount === 4)
spy.restore()
})
})
})
19 changes: 19 additions & 0 deletions test/unit/format_custom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,23 @@ describe('custom formatter', () => {
vm.$t('message.hello', [1, 2, 3])
})
})

describe('i18n format getter/settter', () => {
it('should be worked', done => {
const i18n = new VueI18n({
locale: 'en',
messages
})

assert(i18n.formatter.constructor.name === 'BaseFormatter')
const formatter = {
interpolate: (message, values) => {
assert.deepEqual([1, 2, 3], values)
done()
}
}
i18n.formatter = formatter
i18n.t('message.hello', [1, 2, 3])
})
})
})
43 changes: 42 additions & 1 deletion test/unit/interpolation.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import Component from '../../src/component'

const messages = {
en: {
text: 'one: {0}',
premitive: 'one: {0}, two: {1}',
component: 'element: {0}, component: {1}',
link: '@:premitive',
term: 'I accept xxx {0}.',
tos: 'Term of service'
tos: 'Term of service',
fallback: 'fallback from {0}'
},
ja: {
text: '一: {0}'
Expand All @@ -19,6 +22,16 @@ const components = {
render (h) {
return h('p', [this.msg])
}
},
fallback: {
i18n: {
locale: 'en'
},
render (h) {
return h('i18n', { props: { path: 'fallback' } }, [
h('p', ['child'])
])
}
}
}

Expand Down Expand Up @@ -84,6 +97,22 @@ describe('component interpolation', () => {
})
})

describe('fallback', () => {
it('should be interpolated', done => {
const el = document.createElement('div')
const vm = new Vue({
i18n,
components,
render (h) {
return h('fallback')
}
}).$mount(el)
nextTick(() => {
assert.equal(vm.$el.innerHTML, 'fallback from <p>child</p>')
}).then(done)
})
})

describe('nested components', () => {
it('should be interpolated', done => {
const el = document.createElement('div')
Expand Down Expand Up @@ -166,4 +195,16 @@ describe('component interpolation', () => {
}).then(done)
})
})

describe('warnning in render', () => {
it('should be warned', () => {
const spy = sinon.spy(console, 'warn')

Component.render(() => {}, { children: [], parent: {} })
assert(spy.notCalled === false)
assert(spy.callCount === 1)

spy.restore()
})
})
})
6 changes: 6 additions & 0 deletions test/unit/message.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ describe('message', () => {
i18n.setLocaleMessage('ja', orgJaLocaleMessage)
})

describe('messages', () => {
it('should be workd', () => {
assert.deepEqual(messages, i18n.messages)
})
})

describe('getLocaleMessage / setLocaleMessage', () => {
it('should be worked', done => {
const vm = new Vue({
Expand Down
19 changes: 19 additions & 0 deletions test/unit/missing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,23 @@ describe('missing', () => {
vm.$t('foo.bar.buz')
})
})

describe('i18n missing getter/setter', () => {
it('should be worked', done => {
const missing = (locale, key) => {
assert(false)
}
const i18n = new VueI18n({
locale: 'en',
missing
})

assert.equal(missing, i18n.missing)

i18n.missing = (locale, key, vm) => {
done()
}
i18n.t('foo.bar.buz')
})
})
})
26 changes: 26 additions & 0 deletions test/unit/mixin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import mixin from '../../src/mixin'

describe('mixin', () => {
describe('beforeCreate', () => {
describe('invalid i18n option', () => {
it('should be warned', () => {
const spy = sinon.spy(console, 'warn')
// called from Vue core
new Vue({ i18n: 1 })

assert(spy.notCalled === false)
assert(spy.callCount === 1)

spy.restore()
})
})
})

describe('beforeDestroy', () => {
describe('not assign VueI18n instance', () => {
it('should be succeeded', () => {
assert(mixin.beforeDestroy() === undefined)
})
})
})
})
Loading

0 comments on commit 39234d5

Please sign in to comment.