mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 15:39:40 +02:00
Add new @manacore/wallpaper-generator package for creating device wallpapers from QR codes and images. Features: - 30 device presets (phones, tablets, desktops) - 3 layout types (center, corner, pattern) - 5 gradient presets + solid color backgrounds - Browser (Canvas) and Node.js (Sharp) renderers - Svelte WallpaperModal UI component Integrations: - @manacore/qr-export: toWallpaper() function - @manacore/spiral-db: toWallpaper() function - QRExportModal: "Als Wallpaper" button Also includes the full @manacore/qr-export package which was previously untracked. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
153 lines
4.1 KiB
TypeScript
153 lines
4.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { encode, decode, estimateSize, willFitInQR, MANA_QR_PREFIX } from './encoder';
|
|
import { createManaQRExport, contact, event, todo } from './builder';
|
|
import type { ManaQRExport } from './types';
|
|
|
|
describe('encoder', () => {
|
|
const sampleExport: ManaQRExport = {
|
|
v: 1,
|
|
ts: 1708185600,
|
|
u: {
|
|
n: 'Till',
|
|
z: 'Europe/Berlin',
|
|
l: 'de',
|
|
w: 'Berlin',
|
|
},
|
|
c: [
|
|
{ n: 'Mama', p: '+491701234567', r: 1 },
|
|
{ n: 'Papa', p: '+491707654321', r: 1 },
|
|
],
|
|
e: [
|
|
{ t: 'Zahnarzt', s: 1708272000, d: 60, l: 'Praxis Dr. Weber' },
|
|
{ t: 'Team Meeting', s: 1708358400, d: 30 },
|
|
],
|
|
t: [
|
|
{ t: 'Steuererklärung abgeben', p: 1, d: 14 },
|
|
{ t: 'Backup machen', p: 3 },
|
|
],
|
|
};
|
|
|
|
describe('encode', () => {
|
|
it('should encode data with correct prefix', () => {
|
|
const result = encode(sampleExport);
|
|
|
|
expect(result.data.startsWith(MANA_QR_PREFIX)).toBe(true);
|
|
expect(result.size).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('should report fitsInQR correctly for small data', () => {
|
|
const result = encode(sampleExport);
|
|
|
|
expect(result.fitsInQR).toBe(true);
|
|
expect(result.size).toBeLessThan(2500);
|
|
});
|
|
|
|
it('should compress data significantly', () => {
|
|
const jsonSize = JSON.stringify(sampleExport).length;
|
|
const result = encode(sampleExport);
|
|
|
|
// Encoded should be smaller than raw JSON
|
|
expect(result.size).toBeLessThan(jsonSize);
|
|
});
|
|
});
|
|
|
|
describe('decode', () => {
|
|
it('should decode encoded data correctly', () => {
|
|
const encoded = encode(sampleExport);
|
|
const decoded = decode(encoded.data);
|
|
|
|
expect(decoded.success).toBe(true);
|
|
if (decoded.success) {
|
|
expect(decoded.data.u.n).toBe('Till');
|
|
expect(decoded.data.c).toHaveLength(2);
|
|
expect(decoded.data.e).toHaveLength(2);
|
|
expect(decoded.data.t).toHaveLength(2);
|
|
}
|
|
});
|
|
|
|
it('should fail for invalid prefix', () => {
|
|
const result = decode('INVALID:xyz');
|
|
|
|
expect(result.success).toBe(false);
|
|
if (!result.success) {
|
|
expect(result.error).toBe('INVALID_PREFIX');
|
|
}
|
|
});
|
|
|
|
it('should fail for invalid base64', () => {
|
|
const result = decode(MANA_QR_PREFIX + '!!!invalid!!!');
|
|
|
|
expect(result.success).toBe(false);
|
|
if (!result.success) {
|
|
expect(result.error).toBe('INVALID_BASE64');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('roundtrip', () => {
|
|
it('should preserve all data through encode/decode', () => {
|
|
const encoded = encode(sampleExport);
|
|
const decoded = decode(encoded.data);
|
|
|
|
expect(decoded.success).toBe(true);
|
|
if (decoded.success) {
|
|
expect(decoded.data).toEqual(sampleExport);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('estimateSize', () => {
|
|
it('should estimate size within reasonable range', () => {
|
|
const estimated = estimateSize(sampleExport);
|
|
const actual = encode(sampleExport).size;
|
|
|
|
// Estimate should be within 50% of actual
|
|
expect(estimated).toBeGreaterThan(actual * 0.5);
|
|
expect(estimated).toBeLessThan(actual * 1.5);
|
|
});
|
|
});
|
|
|
|
describe('willFitInQR', () => {
|
|
it('should return true for small data', () => {
|
|
expect(willFitInQR(sampleExport)).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('builder', () => {
|
|
it('should build export with fluent API', () => {
|
|
const result = createManaQRExport()
|
|
.user({ n: 'Test', z: 'UTC', l: 'en' })
|
|
.addContact(contact('Alice', '+1234567890', 1))
|
|
.addEvent(event('Meeting', new Date('2024-02-20T10:00:00Z'), 60))
|
|
.addTodo(todo('Task 1', 1, 7))
|
|
.build();
|
|
|
|
expect(result.v).toBe(1);
|
|
expect(result.u.n).toBe('Test');
|
|
expect(result.c).toHaveLength(1);
|
|
expect(result.e).toHaveLength(1);
|
|
expect(result.t).toHaveLength(1);
|
|
});
|
|
|
|
it('should encode to valid QR string', () => {
|
|
const result = createManaQRExport()
|
|
.userName('Test')
|
|
.timezone('UTC')
|
|
.addContact({ n: 'Bob', r: 3 })
|
|
.encode();
|
|
|
|
expect(result.data.startsWith(MANA_QR_PREFIX)).toBe(true);
|
|
expect(result.fitsInQR).toBe(true);
|
|
});
|
|
|
|
it('should estimate size correctly', () => {
|
|
const builder = createManaQRExport().userName('Test').addContact({ n: 'Alice', r: 1 });
|
|
|
|
const estimated = builder.estimateSize();
|
|
const _actual = builder.encode().size;
|
|
|
|
expect(estimated).toBeGreaterThan(0);
|
|
expect(builder.willFit()).toBe(true);
|
|
});
|
|
});
|