119 lines
3.4 KiB
TypeScript
119 lines
3.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
encodeCharacterURL,
|
|
decodeCharacterURL,
|
|
encodeTemplateURL,
|
|
decodeTemplateURL
|
|
} from './sharing';
|
|
import { presets } from './presets';
|
|
import type { Character, Template } from './types';
|
|
|
|
const standardPreset = presets.find((p) => p.id === 'preset:standard')!;
|
|
|
|
const testCharacter: Character = {
|
|
id: 'abc-123',
|
|
template: standardPreset,
|
|
data: {
|
|
name: 'Yury Zakharov',
|
|
species: 'human',
|
|
'employment-history': 'Shaft Miner'
|
|
}
|
|
};
|
|
|
|
const customTemplate: Template = {
|
|
id: 'custom:test',
|
|
name: 'Custom',
|
|
description: 'A custom template.',
|
|
schemaVersion: 1,
|
|
records: [
|
|
{
|
|
type: 'public',
|
|
fields: [
|
|
{ label: 'Name', type: 'text' },
|
|
{ label: 'Species', type: 'species' }
|
|
]
|
|
}
|
|
]
|
|
};
|
|
|
|
describe('character URL encoding', () => {
|
|
it('round-trips preset character data', () => {
|
|
const encoded = encodeCharacterURL(testCharacter);
|
|
const decoded = decodeCharacterURL(encoded);
|
|
expect(decoded.data).toEqual(testCharacter.data);
|
|
expect(decoded.template.name).toBe('Standard');
|
|
});
|
|
|
|
it('uses short encoding for preset templates', () => {
|
|
const encoded = encodeCharacterURL(testCharacter);
|
|
const customChar = { ...testCharacter, template: customTemplate };
|
|
const customEncoded = encodeCharacterURL(customChar);
|
|
expect(encoded.length).toBeLessThan(customEncoded.length);
|
|
});
|
|
|
|
it('round-trips custom template character', () => {
|
|
const char: Character = { ...testCharacter, template: customTemplate };
|
|
const encoded = encodeCharacterURL(char);
|
|
const decoded = decodeCharacterURL(encoded);
|
|
expect(decoded.data).toEqual(testCharacter.data);
|
|
expect(decoded.template.name).toBe('Custom');
|
|
});
|
|
|
|
it('starts with c1. prefix', () => {
|
|
const encoded = encodeCharacterURL(testCharacter);
|
|
expect(encoded.startsWith('c1.')).toBe(true);
|
|
});
|
|
|
|
it('prunes empty values from data', () => {
|
|
const char: Character = {
|
|
...testCharacter,
|
|
data: { name: 'Yury Zakharov', species: '', 'hair-color': '' }
|
|
};
|
|
const encoded = encodeCharacterURL(char);
|
|
const decoded = decodeCharacterURL(encoded);
|
|
expect(decoded.data).toEqual({ name: 'Yury Zakharov' });
|
|
});
|
|
});
|
|
|
|
describe('template URL encoding', () => {
|
|
it('round-trips template structure', () => {
|
|
const encoded = encodeTemplateURL(customTemplate);
|
|
const decoded = decodeTemplateURL(encoded);
|
|
expect(decoded.name).toBe('Custom');
|
|
expect(decoded.records).toEqual(customTemplate.records);
|
|
});
|
|
|
|
it('starts with t1. prefix', () => {
|
|
const encoded = encodeTemplateURL(customTemplate);
|
|
expect(encoded.startsWith('t1.')).toBe(true);
|
|
});
|
|
|
|
it('strips id', () => {
|
|
const encoded = encodeTemplateURL(customTemplate);
|
|
const decoded = decodeTemplateURL(encoded);
|
|
expect(decoded).not.toHaveProperty('id');
|
|
});
|
|
});
|
|
|
|
describe('unicode support', () => {
|
|
it('round-trips unicode content', () => {
|
|
const char: Character = {
|
|
...testCharacter,
|
|
data: { name: "Ka'Akaix'Lak Zo'ra", species: 'vaurca' }
|
|
};
|
|
const encoded = encodeCharacterURL(char);
|
|
const decoded = decodeCharacterURL(encoded);
|
|
expect(decoded.data.name).toBe("Ka'Akaix'Lak Zo'ra");
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
it('throws on invalid character input', () => {
|
|
expect(() => decodeCharacterURL('c1.invaliddata!!!')).toThrow();
|
|
});
|
|
|
|
it('throws on wrong prefix', () => {
|
|
const encoded = encodeCharacterURL(testCharacter);
|
|
expect(() => decodeTemplateURL(encoded)).toThrow();
|
|
});
|
|
});
|