test: 💍 add test for lookup and loader queue

This commit is contained in:
Christian Kaisermann 2019-11-26 22:00:23 -03:00
parent 21afa3d6b1
commit b3098ba67b
7 changed files with 114 additions and 12 deletions

View File

@ -6,11 +6,17 @@ import {
} from '../stores/dictionary' } from '../stores/dictionary'
import { getCurrentLocale, getRelatedLocalesOf } from '../stores/locale' import { getCurrentLocale, getRelatedLocalesOf } from '../stores/locale'
import { $isLoading } from '../stores/loading' import { $isLoading } from '../stores/loading'
import { getLoadingDelay } from '../configs' import { getOptions } from '../configs'
type Queue = Set<MessagesLoader> type Queue = Set<MessagesLoader>
const loaderQueue: Record<string, Queue> = {} const loaderQueue: Record<string, Queue> = {}
export function resetQueues() {
Object.keys(loaderQueue).forEach(key => {
delete loaderQueue[key]
})
}
function createLocaleQueue(locale: string) { function createLocaleQueue(locale: string) {
loaderQueue[locale] = new Set() loaderQueue[locale] = new Set()
} }
@ -39,10 +45,6 @@ export function hasLocaleQueue(locale: string) {
.some(getLocaleQueue) .some(getLocaleQueue)
} }
export function addLoaderToQueue(locale: string, loader: MessagesLoader) {
loaderQueue[locale].add(loader)
}
const activeLocaleFlushes: { [key: string]: Promise<void> } = {} const activeLocaleFlushes: { [key: string]: Promise<void> } = {}
export async function flushQueue(locale: string = getCurrentLocale()) { export async function flushQueue(locale: string = getCurrentLocale()) {
if (!hasLocaleQueue(locale)) return if (!hasLocaleQueue(locale)) return
@ -50,14 +52,18 @@ export async function flushQueue(locale: string = getCurrentLocale()) {
// get queue of XX-YY and XX locales // get queue of XX-YY and XX locales
const queues = getLocalesQueues(locale) const queues = getLocalesQueues(locale)
// istanbul ignore if
if (queues.length === 0) return if (queues.length === 0) return
removeLocaleFromQueue(locale) const loadingDelay = setTimeout(
const loadingDelay = setTimeout(() => $isLoading.set(true), getLoadingDelay()) () => $isLoading.set(true),
getOptions().loadingDelay
)
// TODO what happens if some loader fails // TODO what happens if some loader fails
activeLocaleFlushes[locale] = Promise.all( activeLocaleFlushes[locale] = Promise.all(
queues.map(([locale, queue]) => { queues.map(([locale, queue]) => {
removeLocaleFromQueue(locale)
return Promise.all(queue.map(loader => loader())).then(partials => { return Promise.all(queue.map(loader => loader())).then(partials => {
partials = partials.map(partial => partial.default || partial) partials = partials.map(partial => partial.default || partial)
addMessages(locale, ...partials) addMessages(locale, ...partials)
@ -76,6 +82,7 @@ export function registerLocaleLoader(locale: string, loader: MessagesLoader) {
if (!getLocaleQueue(locale)) createLocaleQueue(locale) if (!getLocaleQueue(locale)) createLocaleQueue(locale)
const queue = getLocaleQueue(locale) const queue = getLocaleQueue(locale)
// istanbul ignore if
if (getLocaleQueue(locale).has(loader)) return if (getLocaleQueue(locale).has(loader)) return
if (!hasLocaleDictionary(locale)) { if (!hasLocaleDictionary(locale)) {

View File

@ -1,7 +1,7 @@
import { getMessageFromDictionary } from '../stores/dictionary' import { getMessageFromDictionary } from '../stores/dictionary'
import { getFallbackOf } from '../stores/locale' import { getFallbackOf } from '../stores/locale'
const lookupCache: Record<string, Record<string, string>> = {} export const lookupCache: Record<string, Record<string, string>> = {}
const addToCache = (path: string, locale: string, message: string) => { const addToCache = (path: string, locale: string, message: string) => {
if (!message) return message if (!message) return message

View File

@ -0,0 +1,47 @@
import {
hasLocaleQueue,
flushQueue,
registerLocaleLoader,
resetQueues,
} from '../../../src/client/includes/loaderQueue'
import { getMessageFromDictionary } from '../../../src/client/stores/dictionary'
beforeEach(() => {
resetQueues()
})
const loader = (content: any) => () => new Promise((res, rej) => res(content))
test('registers a locale loader', () => {
expect(hasLocaleQueue('pt-BR')).toBe(false)
registerLocaleLoader('pt-BR', loader({ message: 'Mensagem' }))
expect(hasLocaleQueue('pt-BR')).toBe(true)
})
test('checks queues of locale and its fallbacks', () => {
registerLocaleLoader('en', loader({ field: 'Name' }))
expect(hasLocaleQueue('en-US')).toBe(true)
})
test('flushes the queue of a locale and its fallbacks and merge the result with the dictionary', async () => {
registerLocaleLoader('en', loader({ field: 'Name' }))
registerLocaleLoader('en-US', loader({ field_2: 'Lastname' }))
await flushQueue('en-US')
expect(getMessageFromDictionary('en', 'field')).toBe('Name')
expect(getMessageFromDictionary('en-US', 'field_2')).toBe('Lastname')
expect(hasLocaleQueue('en')).toBe(false)
expect(hasLocaleQueue('en-US')).toBe(false)
})
test('consecutive flushes return the same promise', () => {
// const promiseA = () => new Promise((res, rej) => setTimeout(res, 50))
registerLocaleLoader('en', async () => {})
const flushA = flushQueue('en')
const flushB = flushQueue('en')
expect(flushB).toStrictEqual(flushA)
})

View File

@ -0,0 +1,48 @@
import { lookupMessage, lookupCache } from '../../../src/client/includes/lookup'
import { $dictionary, addMessages } from '../../../src/client/stores/dictionary'
beforeEach(() => {
$dictionary.set({})
})
test('returns null if no locale was passed', () => {
expect(lookupMessage('message.id', undefined)).toBe(null)
expect(lookupMessage('message.id', null)).toBe(null)
})
test('gets a shallow message of a locale dictionary', () => {
addMessages('en', { field: 'name' })
expect(lookupMessage('field', 'en')).toBe('name')
})
test('gets a deep message of a locale dictionary', () => {
addMessages('en', { deep: { field: 'lastname' } })
expect(lookupMessage('deep.field', 'en')).toBe('lastname')
})
test('gets a message from the fallback dictionary', () => {
addMessages('en', { field: 'name' })
expect(lookupMessage('field', 'en-US')).toBe('name')
})
test('caches found messages by locale', () => {
addMessages('en', { field: 'name' })
addMessages('pt', { field: 'nome' })
lookupMessage('field', 'en-US')
lookupMessage('field', 'pt-BR')
expect(lookupCache).toMatchObject({
'en-US': { field: 'name' },
'pt-BR': { field: 'nome' },
})
})
test("doesn't cache falsy messages", () => {
addMessages('en', { field: 'name' })
addMessages('pt', { field: 'nome' })
lookupMessage('field_2', 'en-US')
lookupMessage('field_2', 'pt-BR')
expect(lookupCache).not.toMatchObject({
'en-US': { field_2: 'name' },
'pt-BR': { field_2: 'nome' },
})
})

View File

@ -4,7 +4,7 @@ import {
title, title,
upper, upper,
lower, lower,
} from '../../src/client/includes/utils' } from '../../../src/client/includes/utils'
describe('getting client locale', () => { describe('getting client locale', () => {
beforeEach(() => { beforeEach(() => {

View File

@ -7,7 +7,7 @@ import {
$dictionary, $dictionary,
$locales, $locales,
getLocaleDictionary, getLocaleDictionary,
} from '../../src/client/stores/dictionary' } from '../../../src/client/stores/dictionary'
import { get } from 'svelte/store' import { get } from 'svelte/store'
beforeEach(() => { beforeEach(() => {

View File

@ -7,8 +7,8 @@ import {
getCurrentLocale, getCurrentLocale,
$locale, $locale,
isRelatedLocale, isRelatedLocale,
} from '../../src/client/stores/locale' } from '../../../src/client/stores/locale'
import { getOptions, configure } from '../../src/client/configs' import { getOptions, configure } from '../../../src/client/configs'
beforeEach(() => { beforeEach(() => {
configure({ fallbackLocale: undefined }) configure({ fallbackLocale: undefined })