diff options
Diffstat (limited to 'player-server/web/js/tests/shuffle.test.js')
| -rw-r--r-- | player-server/web/js/tests/shuffle.test.js | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/player-server/web/js/tests/shuffle.test.js b/player-server/web/js/tests/shuffle.test.js new file mode 100644 index 0000000..2472543 --- /dev/null +++ b/player-server/web/js/tests/shuffle.test.js @@ -0,0 +1,165 @@ +import { initKeyboard } from '../keyboard.js'; +import { enable, isOn, revision, toggle } from '../shuffle.js'; +import { state } from '../state.js'; +import { initMediaGrid, loadMedia } from '../views/media-grid.js'; + +const failures = []; +const requests = []; +let keydownHandler = null; + +const button = { + active: false, + classList: { + toggle(name, enabled) { + if (name === 'active') button.active = enabled; + }, + }, +}; +const grid = mockElement(); +const emptyHint = mockElement(); +const breadcrumb = mockElement(); +const resultCount = mockElement(); + +globalThis.document = { + activeElement: null, + fullscreenElement: null, + addEventListener(type, handler) { + if (type === 'keydown') keydownHandler = handler; + }, + getElementById(id) { + if (id === 'shuffle-toggle') return button; + if (id === 'media-grid') return grid; + if (id === 'empty-hint') return emptyHint; + if (id === 'breadcrumb-bar') return breadcrumb; + if (id === 'result-count') return resultCount; + return null; + }, +}; +globalThis.location = { pathname: '/index.html', href: '' }; +globalThis.fetch = async (url) => { + requests.push(String(url)); + return { + ok: true, + status: 200, + headers: { get: () => 'application/json' }, + json: async () => [], + }; +}; + +function assert(cond, msg) { + if (!cond) failures.push(msg || 'assertion failed'); +} + +function mockElement() { + return { + classList: { + add() {}, + remove() {}, + toggle() {}, + contains() { return false; }, + }, + innerHTML: '', + textContent: '', + addEventListener() {}, + querySelectorAll() { return []; }, + querySelector() { return null; }, + }; +} + +function testEnableTurnsShuffleOn() { + enable(); + assert(isOn(), 'enable should turn shuffle on'); + assert(button.active, 'enable should update the shuffle button active state'); +} + +function testRepeatedEnableKeepsShuffleOnAndAdvancesRevision() { + const before = revision(); + enable(); + assert(isOn(), 'repeated enable should keep shuffle on'); + assert(revision() > before, 'repeated enable should advance revision for a fresh random load'); +} + +function testToggleCanStillTurnShuffleOff() { + toggle(); + assert(!isOn(), 'toggle should still turn shuffle off for the toolbar button'); + assert(!button.active, 'toggle should update the shuffle button inactive state'); +} + +async function testKeyboardReshuffleRequestsRandomMediaWithNewRevision() { + state.selectedSetId = null; + state.selectedSetIds = []; + state.folderPath = ''; + state.mediaPage = 0; + Object.assign(state.filters, { + type: '', + search: '', + favorites: false, + tags: '', + sort: '', + minDuration: '', + maxDuration: '', + minFileSize: '', + maxFileSize: '', + }); + requests.length = 0; + + initMediaGrid({ + isShuffle: isOn, + shuffleRevision: revision, + }); + initKeyboard({ + shuffle: () => { + enable(); + loadMedia(); + }, + }); + + pressKey('r'); + await waitForRequests(1); + pressKey('r'); + await waitForRequests(2); + + const first = new URL(requests[0], 'http://player.test'); + const second = new URL(requests[1], 'http://player.test'); + assert(first.pathname === '/api/media', 'keyboard shuffle should request media'); + assert(first.searchParams.get('sort') === 'random', 'keyboard shuffle should request random sort'); + assert(second.searchParams.get('sort') === 'random', 'keyboard reshuffle should keep random sort'); + assert(first.searchParams.get('shuffle_revision'), 'keyboard shuffle should include shuffle revision'); + assert(second.searchParams.get('shuffle_revision'), 'keyboard reshuffle should include shuffle revision'); + assert( + second.searchParams.get('shuffle_revision') !== first.searchParams.get('shuffle_revision'), + 'keyboard reshuffle should change shuffle revision in the media request', + ); +} + +function pressKey(key) { + keydownHandler?.({ + key, + code: `Key${key.toUpperCase()}`, + target: { tagName: 'BODY', isContentEditable: false }, + preventDefault() {}, + }); +} + +async function waitForRequests(count) { + for (let i = 0; i < 10; i += 1) { + if (requests.length >= count) return; + await Promise.resolve(); + } + assert(false, `expected ${count} request(s), got ${requests.length}`); +} + +console.log('Running shuffle tests...'); +testEnableTurnsShuffleOn(); +testRepeatedEnableKeepsShuffleOnAndAdvancesRevision(); +testToggleCanStillTurnShuffleOff(); +await testKeyboardReshuffleRequestsRandomMediaWithNewRevision(); + +if (failures.length) { + console.error('FAILURES:'); + failures.forEach((m) => console.error(' - ' + m)); + process.exit(1); +} else { + console.log('All shuffle tests passed.'); + process.exit(0); +} |
