Files
Playtube-StreamDock/tests/actions.test.js
T

113 lines
5.3 KiB
JavaScript

'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const {
DEFINITIONS, PREFIX, actionIdFromUuid, buildRequest, normalizeSettings, renderAction, wrapTitle,
} = require('../src/actions');
const STATE = {
activeTab: 'music',
visibleTab: 'music',
tabs: {
music: { playing: true, title: 'Ein sehr langer Songtitel', volume: 42.4, muted: false, likeStatus: 'like',
repeatMode: 'ALL', hasVideo: true, thumbnail: 'https://example.test/c=w60-h60' },
youtube: { playing: false, title: 'Video', volume: 80, muted: true, likeStatus: 'none', repeatMode: 'NONE' },
},
};
test('actionIdFromUuid erkennt nur bekannte Aktionen', () => {
assert.equal(actionIdFromUuid(`${PREFIX}volumeup`), 'volumeup');
assert.equal(actionIdFromUuid(`${PREFIX}gibtesnicht`), null);
assert.equal(actionIdFromUuid('com.other.volumeup'), null);
assert.equal(actionIdFromUuid(undefined), null);
});
test('normalizeSettings begrenzt Werte und ersetzt ungueltige durch Standardwerte', () => {
const settings = normalizeSettings({ step: '999', volume: -5, seconds: 'abc', target: 'x', tab: 'y' });
assert.equal(settings.step, 25);
assert.equal(settings.volume, 0);
assert.equal(settings.seconds, 10);
assert.equal(settings.target, 'auto');
assert.equal(settings.tab, 'toggle');
});
test('normalizeSettings: showTitle nutzt den Standard der Aktion, wenn nichts gespeichert ist', () => {
assert.equal(normalizeSettings({}, true).showTitle, true);
assert.equal(normalizeSettings({}, false).showTitle, false);
assert.equal(normalizeSettings({ showTitle: false }, true).showTitle, false);
assert.equal(normalizeSettings({ showTitle: 'true' }, false).showTitle, true);
});
test('Lauter/Leiser senden volume_change mit Vorzeichen und Schrittweite', () => {
assert.deepEqual(buildRequest('volumeup', { step: 7 }), { cmd: 'volume_change', fields: { target: 'auto', value: 7 } });
assert.deepEqual(buildRequest('volumedown', { step: 7, target: 'music' }),
{ cmd: 'volume_change', fields: { target: 'music', value: -7 } });
});
test('Lautstaerke setzen und Spulen', () => {
assert.deepEqual(buildRequest('volumeset', { volume: 55 }), { cmd: 'set_volume', fields: { target: 'auto', value: 55 } });
assert.deepEqual(buildRequest('seekback', { seconds: 15 }), { cmd: 'seek', fields: { target: 'auto', value: -15 } });
assert.deepEqual(buildRequest('seekforward', {}), { cmd: 'seek', fields: { target: 'auto', value: 10 } });
});
test('Playlist-Taste ohne ID sendet nichts, mit ID play_playlist', () => {
assert.equal(buildRequest('playlist', {}), null);
assert.deepEqual(buildRequest('playlist', { playlistId: ' PL123 ' }),
{ cmd: 'play_playlist', fields: { playlist: 'PL123' } });
});
test('Tab wechseln: "toggle" wird zu auto', () => {
assert.equal(buildRequest('switchtab', {}).fields.target, 'auto');
assert.equal(buildRequest('switchtab', { tab: 'youtube' }).fields.target, 'youtube');
});
test('jede Aktion hat request() und liefert gueltiges cmd', () => {
for (const id of Object.keys(DEFINITIONS)) {
const request = buildRequest(id, { playlistId: 'PLx' });
assert.ok(request && typeof request.cmd === 'string', id);
}
});
test('Play/Pause-Zustand folgt dem aktiven Tab bzw. dem gewaehlten Ziel', () => {
assert.equal(renderAction('playpause', {}, STATE, true).state, 1);
assert.equal(renderAction('playpause', { target: 'youtube' }, STATE, true).state, 0);
});
test('Lautstaerke-Tasten zeigen die gerundete Lautstaerke', () => {
assert.equal(renderAction('volumeup', {}, STATE, true).title, '42%');
assert.equal(renderAction('volumedown', { target: 'youtube' }, STATE, true).title, '80%');
});
test('offline: Titel leer bzw. Offline-Hinweis, Zustand 0', () => {
assert.equal(renderAction('volumeup', {}, null, false).title, '');
const view = renderAction('playpause', { showTitle: true }, null, false);
assert.equal(view.state, 0);
assert.match(view.title, /offline/);
});
test('Mute, Like und Repeat bilden den Playtube-Zustand auf State-Indizes ab', () => {
assert.equal(renderAction('mute', { target: 'youtube' }, STATE, true).state, 1);
assert.equal(renderAction('mute', {}, STATE, true).state, 0);
assert.equal(renderAction('like', {}, STATE, true).state, 1);
assert.equal(renderAction('repeat', {}, STATE, true).state, 1);
assert.equal(renderAction('repeat', { target: 'youtube' }, STATE, true).state, 0);
const one = { ...STATE, tabs: { ...STATE.tabs, music: { ...STATE.tabs.music, repeatMode: 'ONE' } } };
assert.equal(renderAction('repeat', {}, one, true).state, 2);
});
test('Cover-Taste liefert die Thumbnail-URL nur bei vorhandenem Video/Titel', () => {
assert.equal(renderAction('nowplaying', {}, STATE, true).coverUrl, 'https://example.test/c=w60-h60');
assert.equal(renderAction('nowplaying', { target: 'youtube' }, STATE, true).coverUrl, null);
assert.equal(renderAction('nowplaying', {}, null, false).coverUrl, null);
});
test('wrapTitle bricht um, trennt lange Woerter und kuerzt', () => {
assert.equal(wrapTitle('Hello World'), 'Hello\nWorld');
assert.equal(wrapTitle('Supercalifragilistic'), 'Supercal\nifragili\nstic');
const lines = wrapTitle('eins zwei drei vier fuenf sechs sieben acht neun zehn').split('\n');
assert.equal(lines.length, 3);
assert.ok(lines[2].endsWith('..'));
assert.equal(wrapTitle(''), '');
});