69 lines
2.6 KiB
TypeScript
69 lines
2.6 KiB
TypeScript
|
|
import { describe, test } from 'node:test';
|
||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { migrateUserSoundboardContent, slugifyClipName, uniqueShortcode } from './utils';
|
||
|
|
|
||
|
|
describe('slugifyClipName', () => {
|
||
|
|
test('lowercases, replaces spaces, strips punctuation', () => {
|
||
|
|
assert.equal(slugifyClipName(' Air Horn!! '), 'air_horn');
|
||
|
|
assert.equal(slugifyClipName('Ba-Dum Tss'), 'ba-dum_tss');
|
||
|
|
});
|
||
|
|
test('falls back to "clip" when empty', () => {
|
||
|
|
assert.equal(slugifyClipName(' '), 'clip');
|
||
|
|
assert.equal(slugifyClipName('!!!'), 'clip');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('uniqueShortcode', () => {
|
||
|
|
test('returns the slug when free', () => {
|
||
|
|
assert.equal(uniqueShortcode('Airhorn', new Set()), 'airhorn');
|
||
|
|
});
|
||
|
|
test('suffixes on collision', () => {
|
||
|
|
assert.equal(uniqueShortcode('Airhorn', new Set(['airhorn'])), 'airhorn-2');
|
||
|
|
assert.equal(uniqueShortcode('Airhorn', new Set(['airhorn', 'airhorn-2'])), 'airhorn-3');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('migrateUserSoundboardContent', () => {
|
||
|
|
test('migrates the v1 flat list into a v2 pack keyed by slug', () => {
|
||
|
|
const v1 = {
|
||
|
|
clips: [
|
||
|
|
{ id: 'a', name: 'Air Horn', url: 'mxc://x/1', mimetype: 'audio/mpeg', size: 100 },
|
||
|
|
{ id: 'b', name: 'Applause', url: 'mxc://x/2' },
|
||
|
|
],
|
||
|
|
};
|
||
|
|
const out = migrateUserSoundboardContent(v1);
|
||
|
|
assert.deepEqual(Object.keys(out.clips ?? {}).sort(), ['air_horn', 'applause']);
|
||
|
|
assert.equal(out.clips?.air_horn.url, 'mxc://x/1');
|
||
|
|
assert.equal(out.clips?.air_horn.body, 'Air Horn');
|
||
|
|
assert.equal(out.clips?.air_horn.info?.mimetype, 'audio/mpeg');
|
||
|
|
assert.ok(out.pack?.display_name);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('dedupes colliding v1 names', () => {
|
||
|
|
const v1 = {
|
||
|
|
clips: [
|
||
|
|
{ id: 'a', name: 'Horn', url: 'mxc://x/1' },
|
||
|
|
{ id: 'b', name: 'Horn', url: 'mxc://x/2' },
|
||
|
|
],
|
||
|
|
};
|
||
|
|
const out = migrateUserSoundboardContent(v1);
|
||
|
|
assert.deepEqual(Object.keys(out.clips ?? {}).sort(), ['horn', 'horn-2']);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('skips v1 entries without a url', () => {
|
||
|
|
const out = migrateUserSoundboardContent({ clips: [{ id: 'a', name: 'Bad' } as never] });
|
||
|
|
assert.deepEqual(out.clips, {});
|
||
|
|
});
|
||
|
|
|
||
|
|
test('passes a v2 pack through unchanged', () => {
|
||
|
|
const v2 = { pack: { display_name: 'P' }, clips: { horn: { url: 'mxc://x/1', volume: 50 } } };
|
||
|
|
assert.deepEqual(migrateUserSoundboardContent(v2), v2);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('handles empty / non-object input', () => {
|
||
|
|
assert.deepEqual(migrateUserSoundboardContent({}), {});
|
||
|
|
assert.deepEqual(migrateUserSoundboardContent(null), {});
|
||
|
|
assert.deepEqual(migrateUserSoundboardContent(undefined), {});
|
||
|
|
});
|
||
|
|
});
|