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.
113 lines
3.6 KiB
TypeScript
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);
|
|
});
|
|
});
|