|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
|
|
|
import { createCurr } from '@/glob/lib/curr_engine.ts';
|
|
|
|
|
import { createLing, p } from '@/ling/lib/engine.ts';
|
|
|
|
|
import type { CurrDefinition } from '../lib/curr_types.ts';
|
|
|
|
|
|
|
|
|
|
// =============================================================================
|
|
|
|
|
// FIXTURES
|
|
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
|
|
const ling = createLing({ common: { ok: { es: 'Aceptar', en: 'OK' } } } as const, 'es');
|
|
|
|
|
|
|
|
|
|
const definitions: Record<string, CurrDefinition> = {
|
|
|
|
|
EUR: {
|
|
|
|
|
symbol : '€',
|
|
|
|
|
code : 'EUR',
|
|
|
|
|
name : p({ es: { one: 'euro', other: 'euros' }, en: { one: 'euro', other: 'euros' } }),
|
|
|
|
|
conversionValue: 1,
|
|
|
|
|
},
|
|
|
|
|
USD: {
|
|
|
|
|
symbol : '$',
|
|
|
|
|
code : 'USD',
|
|
|
|
|
name : p({ es: { one: 'dólar', other: 'dólares' }, en: { one: 'dollar', other: 'dollars' } }),
|
|
|
|
|
conversionValue: 1.08,
|
|
|
|
|
},
|
|
|
|
|
MXN: {
|
|
|
|
|
symbol : '$',
|
|
|
|
|
code : 'MXN',
|
|
|
|
|
name : p({ es: { one: 'peso mexicano', other: 'pesos mexicanos' }, en: { one: 'Mexican peso', other: 'Mexican pesos' } }),
|
|
|
|
|
conversionValue: 18.5,
|
|
|
|
|
},
|
|
|
|
|
GBP: {
|
|
|
|
|
symbol : '£',
|
|
|
|
|
code : 'GBP',
|
|
|
|
|
name : p({ es: { one: 'libra esterlina', other: 'libras esterlinas' }, en: { one: 'pound sterling', other: 'pounds sterling' } }),
|
|
|
|
|
conversionValue: 0.85,
|
|
|
|
|
},
|
|
|
|
|
JPY: {
|
|
|
|
|
symbol : '¥',
|
|
|
|
|
code : 'JPY',
|
|
|
|
|
name : p({ es: { one: 'yen', other: 'yenes' }, en: { one: 'yen', other: 'yen' } }),
|
|
|
|
|
conversionValue: null, // sin conversión disponible
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// =============================================================================
|
|
|
|
|
// CURR — Formato y conversión de moneda
|
|
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
|
|
describe('createCurr', () => {
|
|
|
|
|
|
|
|
|
|
describe('selectedCurrency', () => {
|
|
|
|
|
|
|
|
|
|
it('usa la primera moneda definida por defecto', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
expect(curr.getCurrency()).toBe('EUR');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('acepta selectedCurrency en la configuración', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'MXN' }, 'es');
|
|
|
|
|
expect(curr.getCurrency()).toBe('MXN');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('setCurrency cambia la moneda activa', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
curr.setCurrency('USD');
|
|
|
|
|
expect(curr.getCurrency()).toBe('USD');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('setCurrency acepta minúsculas', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
curr.setCurrency('gbp');
|
|
|
|
|
expect(curr.getCurrency()).toBe('GBP');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('f() — display symbol (por defecto)', () => {
|
|
|
|
|
|
|
|
|
|
it('formatea con símbolo en es', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.f(99.5)).toBe('99,50 €');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('formatea con símbolo en en', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'en');
|
|
|
|
|
expect(curr.f(99.5)).toBe('99.50 €');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('usa selectedCurrency activa', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
curr.setCurrency('GBP');
|
|
|
|
|
expect(curr.f(99.5)).toBe('99,50 £');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('f() — display code', () => {
|
|
|
|
|
|
|
|
|
|
it('formatea con código ISO', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.f(99.5, 'code')).toBe('99,50 EUR');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('f() — display name (pluralización)', () => {
|
|
|
|
|
|
|
|
|
|
it('singular en es', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.f(1, 'name')).toBe('1,00 euro');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('plural en es', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.f(99.5, 'name')).toBe('99,50 euros');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('singular en en', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'en');
|
|
|
|
|
expect(curr.f(1, 'name')).toBe('1.00 euro');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('plural MXN en es', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'MXN' }, 'es');
|
|
|
|
|
expect(curr.f(2, 'name')).toBe('2,00 pesos mexicanos');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('f() — locale reactivo via función', () => {
|
|
|
|
|
|
|
|
|
|
it('responde a cambios de locale sin recrear el módulo', () => {
|
|
|
|
|
let locale = 'es';
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, () => locale);
|
|
|
|
|
|
|
|
|
|
expect(curr.f(99.5)).toContain(',50 €');
|
|
|
|
|
|
|
|
|
|
locale = 'en';
|
|
|
|
|
expect(curr.f(99.5)).toContain('.50 €');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('f() — moneda no registrada', () => {
|
|
|
|
|
|
|
|
|
|
it('fallback al código ISO si la moneda no está definida', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
curr.setCurrency('XXX');
|
|
|
|
|
expect(curr.f(99.5)).toBe('99,50 XXX');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('convert()', () => {
|
|
|
|
|
|
|
|
|
|
it('convierte EUR a USD', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'USD')).toBeCloseTo(108, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('convierte EUR a MXN', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'MXN')).toBeCloseTo(1850, 0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('misma moneda devuelve el mismo valor', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'EUR')).toBe(100);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('devuelve null si conversionValue es null', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'JPY')).toBeNull();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('conversionValue como función dinámica', () => {
|
|
|
|
|
let rate = 1.08;
|
|
|
|
|
const defs = {
|
|
|
|
|
EUR: { ...definitions.EUR },
|
|
|
|
|
USD: { ...definitions.USD, conversionValue: () => rate },
|
|
|
|
|
};
|
|
|
|
|
const curr = createCurr(defs, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'USD')).toBeCloseTo(108, 1);
|
|
|
|
|
|
|
|
|
|
rate = 1.20;
|
|
|
|
|
expect(curr.convert(100, 'EUR', 'USD')).toBeCloseTo(120, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('convertTo()', () => {
|
|
|
|
|
|
|
|
|
|
it('convierte desde selectedCurrency a otra moneda', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
expect(curr.convertTo(100, 'USD')).toBeCloseTo(108, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('respeta la moneda activa cambiada con setCurrency', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, { selectedCurrency: 'EUR' }, 'es');
|
|
|
|
|
curr.setCurrency('USD');
|
|
|
|
|
expect(curr.convertTo(108, 'EUR')).toBeCloseTo(100, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('get()', () => {
|
|
|
|
|
|
|
|
|
|
it('devuelve la definición de una moneda registrada', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
expect(curr.get('EUR')?.symbol).toBe('€');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('devuelve undefined para moneda no registrada', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
expect(curr.get('XXX')).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('acepta minúsculas', () => {
|
|
|
|
|
const curr = createCurr(definitions, ling, {}, 'es');
|
|
|
|
|
expect(curr.get('eur')).toBeDefined();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
});
|