test: 💍 add tests for config and utils

This commit is contained in:
Christian Kaisermann 2019-11-26 13:05:17 -03:00
parent 817adb6e4e
commit e56bfbd333
11 changed files with 205 additions and 123 deletions

View File

@ -7,7 +7,7 @@ import {
CallExpression,
Identifier,
} from 'estree'
import resolvePath from 'object-resolve-path'
import delve from 'dlv'
import { walk } from 'estree-walker'
import { Ast } from 'svelte/types/compiler/interfaces'
import { parse } from 'svelte/compiler'
@ -209,7 +209,7 @@ export function extractMessages(
} else {
if (
overwrite === false &&
typeof resolvePath(accumulator, message.meta.id) !== 'undefined'
typeof delve(accumulator, message.meta.id) !== 'undefined'
) {
return
}

View File

@ -2,9 +2,20 @@ import { getClientLocale } from './includes/utils'
import { ConfigureOptions } from './types'
import { $locale } from './stores/locale'
let fallbackLocale: string = null
let loadingDelay = 200
const formats: any = {
interface Formats {
number: Record<string, any>
date: Record<string, any>
time: Record<string, any>
}
interface Options {
fallbackLocale: string
initialLocale: string
formats: Formats
loadingDelay: number
}
export const defaultFormats: Formats = {
number: {
scientific: { notation: 'scientific' },
engineering: { notation: 'engineering' },
@ -35,33 +46,44 @@ const formats: any = {
},
}
export function getFallbackLocale() {
return fallbackLocale
export const defaultOptions: Options = {
fallbackLocale: null,
initialLocale: null,
loadingDelay: 200,
formats: defaultFormats,
}
export function getLoadingDelay() {
return loadingDelay
}
const options: Options = defaultOptions
export function getFormats() {
return formats
export function getOptions() {
return options
}
export function configure(opts: ConfigureOptions) {
fallbackLocale = opts.fallbackLocale
const fallbackLocale = (options.fallbackLocale = opts.fallbackLocale)
if (opts.initialLocale) {
$locale.set(getClientLocale(opts.initialLocale) || fallbackLocale)
} else {
$locale.set(fallbackLocale)
}
const initialLocale = opts.initialLocale
? typeof opts.initialLocale === 'string'
? opts.initialLocale
: getClientLocale(opts.initialLocale) || fallbackLocale
: fallbackLocale
$locale.set(initialLocale)
options.initialLocale = initialLocale
if (opts.formats) {
if ('number' in opts.formats)
Object.assign(formats.number, opts.formats.number)
if ('date' in opts.formats) Object.assign(formats.date, opts.formats.date)
if ('time' in opts.formats) Object.assign(formats.time, opts.formats.time)
if ('number' in opts.formats) {
Object.assign(options.formats.number, opts.formats.number)
}
if ('date' in opts.formats) {
Object.assign(options.formats.date, opts.formats.date)
}
if ('time' in opts.formats) {
Object.assign(options.formats.time, opts.formats.time)
}
}
if (loadingDelay != null) loadingDelay = loadingDelay
if (opts.loadingDelay != null) {
options.loadingDelay = opts.loadingDelay
}
}

View File

@ -16,15 +16,13 @@ export function lower(str: string) {
return str.toLocaleLowerCase()
}
const getFromURL = (urlPart: string, key: string) => {
const keyVal = urlPart
.substr(1)
.split('&')
.find(i => i.indexOf(key) === 0)
const getFromQueryString = (queryString: string, key: string) => {
const keyVal = queryString.split('&').find(i => i.indexOf(`${key}=`) === 0)
if (keyVal) {
return keyVal.split('=').pop()
}
return null
}
const getFirstMatch = (base: string, pattern: RegExp) => {
@ -42,7 +40,8 @@ export const getClientLocale = ({
}: GetClientLocaleOptions) => {
let locale
if (typeof window === 'undefined') return fallback
// istanbul ignore next
if (typeof window === 'undefined') return null
if (hostname) {
locale = getFirstMatch(window.location.hostname, hostname)
@ -61,18 +60,12 @@ export const getClientLocale = ({
}
if (search) {
locale =
typeof search === 'string'
? getFromURL(window.location.search, search)
: getFirstMatch(window.location.search, search)
locale = getFromQueryString(window.location.search.substr(1), search)
if (locale) return locale
}
if (hash) {
locale =
typeof hash === 'string'
? getFromURL(window.location.hash, hash)
: getFirstMatch(window.location.hash, hash)
locale = getFromQueryString(window.location.hash.substr(1), hash)
if (locale) return locale
}

View File

@ -1,11 +1,9 @@
import { writable } from 'svelte/store'
import { flushQueue, hasLocaleQueue } from '../includes/loaderQueue'
import { getClientLocale } from '../includes/utils'
import { GetClientLocaleOptions } from '../types'
import { getOptions } from '../configs'
import { getClosestAvailableLocale } from './dictionary'
import { setFallbackLocale, getFallbackLocale } from '../configs'
let current: string
const $locale = writable(null)
@ -25,8 +23,10 @@ export function isRelatedLocale(localeA: string, localeB: string) {
export function getFallbackOf(locale: string) {
const index = locale.lastIndexOf('-')
if (index > 0) return locale.slice(0, index)
if (getFallbackLocale() && !isRelatedLocale(locale, getFallbackLocale())) {
return getFallbackLocale()
const { fallbackLocale } = getOptions()
if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
return fallbackLocale
}
return null
}
@ -36,8 +36,9 @@ export function getRelatedLocalesOf(locale: string): string[] {
.split('-')
.map((_, i, arr) => arr.slice(0, i + 1).join('-'))
if (getFallbackLocale() && !isRelatedLocale(locale, getFallbackLocale())) {
return locales.concat(getRelatedLocalesOf(getFallbackLocale()))
const { fallbackLocale } = getOptions()
if (fallbackLocale && !isRelatedLocale(locale, fallbackLocale)) {
return locales.concat(getRelatedLocalesOf(fallbackLocale))
}
return locales
}

View File

@ -50,16 +50,15 @@ export interface MessagesLoader {
export interface GetClientLocaleOptions {
navigator?: boolean
hash?: string | RegExp
search?: string | RegExp
default?: string
hash?: string
search?: string
pathname?: RegExp
hostname?: RegExp
}
export interface ConfigureOptions {
fallbackLocale: string
initialLocale?: GetClientLocaleOptions
initialLocale?: string | GetClientLocaleOptions
formats?: Partial<Formats>
loadingDelay?: number
}

View File

@ -1,14 +1,65 @@
import { get } from 'svelte/store'
import {
getFallbackLocale,
getLoadingDelay,
getFormats,
configure,
getOptions,
defaultOptions,
defaultFormats,
} from '../../src/client/configs'
import { $locale } from '../../src/client/stores/locale'
beforeEach(() => {
configure(defaultOptions)
})
test('configures the fallback locale', () => {
expect(getFallbackLocale()).toBe(null)
expect(getOptions().fallbackLocale).toBe(null)
configure({
fallbackLocale: 'en',
})
expect(getFallbackLocale()).toBe('en')
expect(getOptions().fallbackLocale).toBe('en')
})
test('configures the initial locale by string', () => {
configure({
fallbackLocale: 'pt',
initialLocale: 'en',
})
expect(getOptions().initialLocale).toBe('en')
expect(get($locale)).toBe('en')
})
test('configures the initial locale by client heuristics', () => {
delete window.location
window.location = {
search: '?lang=en-US&foo',
pathname: '/',
hostname: 'example.com',
hash: '',
} as any
configure({
fallbackLocale: 'pt',
initialLocale: {
search: 'lang',
},
})
expect(getOptions().initialLocale).toBe('en-US')
expect(get($locale)).toBe('en-US')
})
test('adds custom formats for time, date and number values', () => {
const customFormats = require('../fixtures/formats.json')
configure({
fallbackLocale: 'en',
formats: customFormats,
})
expect(getOptions().formats).toMatchObject(defaultFormats)
expect(getOptions().formats).toMatchObject(customFormats)
})
test('sets the minimum delay to set the loading store value', () => {
configure({ fallbackLocale: 'en', loadingDelay: 300 })
expect(getOptions().loadingDelay).toBe(300)
})

View File

@ -99,47 +99,6 @@
// })
// describe('utilities', () => {
// describe('get locale', () => {
// beforeEach(() => {
// delete window.location
// window.location = {
// pathname: '/',
// hostname: 'example.com',
// hash: '',
// search: '',
// } as any
// })
// it('should get the locale based on the passed hash parameter', () => {
// window.location.hash = '#locale=en-US&lang=pt-BR'
// expect(getClientLocale({ hash: 'lang' })).toBe('pt-BR')
// })
// it('should get the locale based on the passed search parameter', () => {
// window.location.search = '?locale=en-US&lang=pt-BR'
// expect(getClientLocale({ search: 'lang' })).toBe('pt-BR')
// })
// it('should get the locale based on the navigator language', () => {
// expect(getClientLocale({ navigator: true })).toBe(
// window.navigator.language
// )
// })
// it('should get the default locale', () => {
// expect(getClientLocale({ default: 'pt' })).toBe('pt')
// })
// it('should get the fallback locale', () => {
// window.location.pathname = '/en-US/foo/'
// expect(getClientLocale({ pathname: /^\/(.*?)\// })).toBe('en-US')
// })
// it('should get the fallback locale', () => {
// window.location.hostname = 'pt.example.com'
// expect(getClientLocale({ hostname: /^(.*?)\./ })).toBe('pt')
// })
// })
// describe('format utils', () => {
// beforeAll(async () => {
@ -184,31 +143,6 @@
// })
// describe('custom formats', () => {
// beforeAll(async () => {
// await locale.set('pt-BR')
// })
// it('should have default number custom formats', () => {
// expect(customFormats.number).toMatchObject({
// scientific: { notation: 'scientific' },
// engineering: { notation: 'engineering' },
// compactLong: { notation: 'compact', compactDisplay: 'long' },
// compactShort: { notation: 'compact', compactDisplay: 'short' },
// })
// })
// it('should allow to add custom formats', () => {
// addCustomFormats({
// number: {
// usd: { style: 'currency', currency: 'USD' },
// },
// })
// expect(customFormats.number).toMatchObject({
// usd: { style: 'currency', currency: 'USD' },
// })
// })
// it('should format messages with custom formats', async () => {
// addCustomFormats({
// number: {

View File

@ -8,7 +8,7 @@ import {
$locale,
isRelatedLocale,
} from '../../src/client/stores/locale'
import { getFallbackLocale, configure } from '../../src/client/configs'
import { getOptions, configure } from '../../src/client/configs'
beforeEach(() => {
configure({ fallbackLocale: undefined })
@ -17,7 +17,7 @@ beforeEach(() => {
test('sets and gets the fallback locale', () => {
configure({ fallbackLocale: 'en' })
expect(getFallbackLocale()).toBe('en')
expect(getOptions().fallbackLocale).toBe('en')
})
test('checks if a locale is a fallback locale of another locale', () => {
@ -104,7 +104,7 @@ test('gets the current locale', () => {
test('if no initial locale is set, set the locale to the fallback', () => {
configure({ fallbackLocale: 'pt' })
expect(get($locale)).toBe('pt')
expect(getFallbackLocale()).toBe('pt')
expect(getOptions().fallbackLocale).toBe('pt')
})
test('if no initial locale was found, set to the fallback locale', () => {
@ -115,5 +115,5 @@ test('if no initial locale was found, set to the fallback locale', () => {
},
})
expect(get($locale)).toBe('en')
expect(getFallbackLocale()).toBe('en')
expect(getOptions().fallbackLocale).toBe('en')
})

65
test/client/utils.test.ts Normal file
View File

@ -0,0 +1,65 @@
import {
getClientLocale,
capital,
title,
upper,
lower,
} from '../../src/client/includes/utils'
describe('getting client locale', () => {
beforeEach(() => {
delete window.location
window.location = {
pathname: '/',
hostname: 'example.com',
hash: '',
search: '',
} as any
})
test('gets the locale based on the passed hash parameter', () => {
window.location.hash = '#locale=en-US&lang=pt-BR'
expect(getClientLocale({ hash: 'lang' })).toBe('pt-BR')
})
test('gets the locale based on the passed search parameter', () => {
window.location.search = '?locale=en-US&lang=pt-BR'
expect(getClientLocale({ search: 'lang' })).toBe('pt-BR')
})
test('gets the locale based on the navigator language', () => {
expect(getClientLocale({ navigator: true })).toBe(window.navigator.language)
})
test('gets the locale based on the pathname', () => {
window.location.pathname = '/en-US/foo/'
expect(getClientLocale({ pathname: /^\/(.*?)\// })).toBe('en-US')
})
test('gets the locale base on the hostname', () => {
window.location.hostname = 'pt.example.com'
expect(getClientLocale({ hostname: /^(.*?)\./ })).toBe('pt')
})
test('returns null if no locale was found', () => {
expect(getClientLocale({ search: 'lang' })).toBe(null)
})
})
describe('string utilities', () => {
test('transforms a string into capital case', () => {
expect(capital('lowercase string')).toMatch('Lowercase string')
})
test('transforms a string into title case', () => {
expect(title('lowercase string')).toMatch('Lowercase String')
})
test('transforms a string into uppercase', () => {
expect(upper('lowercase string')).toMatch('LOWERCASE STRING')
})
test('transforms a string into lowercase', () => {
expect(lower('UPPERCASE STRING')).toMatch('uppercase string')
})
})

12
test/fixtures/formats.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"number": {
"usd": { "style": "currency", "currency": "USD" },
"brl": { "style": "currency", "currency": "BRL" }
},
"date": {
"customDate": { "year": "numeric", "era": "short" }
},
"time": {
"customTime": { "hour": "2-digit", "minute": "2-digit" }
}
}

View File

@ -1928,6 +1928,11 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
dlv@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
doctrine@1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"