You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leaflet-components/test/core/props.test.ts

113 lines
3.6 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { bool, choice, disabled, json, kebab, num, positional, str } from '../../src/core/props.ts';
const noopGet = () => 1;
describe('kebab', () => {
it('converts camelCase to kebab-case', () => {
expect(kebab('fillColor')).toBe('fill-color');
expect(kebab('zIndex')).toBe('z-index');
expect(kebab('zIndexOffset')).toBe('z-index-offset');
});
it('leaves single lowercase words unchanged', () => {
expect(kebab('opacity')).toBe('opacity');
});
});
describe('num', () => {
it('defaults to 0 and decodes/encodes via Number/String', () => {
const def = num();
expect(def.default).toBe(0);
expect(def.decode('42')).toBe(42);
expect(def.encode(42)).toBe('42');
});
it('accepts a custom default and passes through extra opts', () => {
const def = num(10, { get: noopGet });
expect(def.default).toBe(10);
expect(def.get).toBe(noopGet);
});
});
describe('str', () => {
it('defaults to empty string and decode/encode are identity', () => {
const def = str();
expect(def.default).toBe('');
expect(def.decode('hello')).toBe('hello');
expect(def.encode('hello')).toBe('hello');
});
});
describe('choice', () => {
it('decode/encode are identity, typed as the literal union', () => {
const def = choice<'a' | 'b'>('a');
expect(def.default).toBe('a');
expect(def.decode('b')).toBe('b');
expect(def.encode('b')).toBe('b');
});
});
describe('bool', () => {
it('decodes any value other than the literal string "false" as true', () => {
const def = bool();
expect(def.decode('')).toBe(true);
expect(def.decode('true')).toBe(true);
expect(def.decode('anything')).toBe(true);
expect(def.decode('false')).toBe(false);
});
it('encode returns null when the value matches the default (removes the attribute)', () => {
const defFalse = bool(false);
expect(defFalse.encode(false)).toBeNull();
expect(defFalse.encode(true)).toBe('');
const defTrue = bool(true);
expect(defTrue.encode(true)).toBeNull();
expect(defTrue.encode(false)).toBe('false');
});
});
describe('disabled', () => {
it('names its attribute disable-<kebab-name>', () => {
const def = disabled();
expect(def.attribute).toBeTypeOf('function');
expect((def.attribute as (name: string) => string)('dragging')).toBe('disable-dragging');
});
it('defaults to true (enabled); presence of the attribute disables unless its value is "false"', () => {
const def = disabled();
expect(def.default).toBe(true);
// Bare `disable-foo` (raw === '') means "disable this" -> false.
expect(def.decode('')).toBe(false);
expect(def.decode('anything')).toBe(false);
// `disable-foo="false"` is a double-negative escape hatch -> stays enabled.
expect(def.decode('false')).toBe(true);
});
it('encodes false as a present attribute, true as absent', () => {
const def = disabled();
expect(def.encode(true)).toBeNull();
expect(def.encode(false)).toBe('');
});
});
describe('json', () => {
it('decodes via JSON.parse and encodes via JSON.stringify', () => {
const def = json<{ a: number }>({ a: 0 });
expect(def.decode('{"a":5}')).toEqual({ a: 5 });
expect(def.encode({ a: 5 })).toBe('{"a":5}');
});
});
describe('positional', () => {
it('adds option: false while preserving every other field', () => {
const base = num(5, { get: () => 1 });
const pos = positional(base);
expect(pos.option).toBe(false);
expect(pos.default).toBe(5);
expect(pos.get).toBe(base.get);
expect(pos.decode).toBe(base.decode);
});
});