A music player that connects to your cloud/distributed storage. diffuse.sh
Something went wrong. Try again.
11 kB · 322 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323import { describe, it } from "@std/testing/bdd";import { expect } from "@std/expect";
import { testWeb } from "@tests/common/index.ts";import { tracks } from "~/testing/sample/tracks.js";
describe("components/engine/queue", () => { it("adds tracks", async () => { const items = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); return engine.future(); });
const futureIds = items.map((i) => i.id).join("/"); const sampleIds = tracks.map((t) => t.id).join("/");
expect(futureIds).toEqual(sampleIds); });
it("pools + fills tracks and shifts the queue", async () => { const item = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.supply({ trackIds: tracks.map((t) => t.id) }); await engine.fill({ amount: 1, shuffled: false }); await engine.shift();
return engine.now(); });
expect(item?.id).toBe(tracks[0].id); });
it("[shared worker] adds tracks and shifts + unshifts the queue", async () => { const item = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS(); engine.setAttribute("group", "tests");
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); await engine.shift(); await engine.shift(); await engine.unshift();
return engine.now(); });
expect(item?.id).toBe(tracks[0].id); });
it("adds tracks to the front with inFront: true", async () => { const items = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: [tracks[1].id] }); await engine.add({ inFront: true, trackIds: [tracks[0].id] }); return engine.future(); });
expect(items[0].id).toBe(tracks[0].id); expect(items[1].id).toBe(tracks[1].id); });
it("clears only auto-filled items when keepManual is true", async () => { const items = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.supply({ trackIds: tracks.map((t) => t.id) }); await engine.add({ trackIds: [tracks[0].id] }); await engine.fill({ amount: 2, shuffled: false }); await engine.clear({ keepManual: true }); return engine.future(); });
expect(items.length).toBe(1); expect(items[0].manualEntry).toBe(true); });
it("clears all items when keepManual is false", async () => { const count = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); await engine.clear({ keepManual: false }); return (await engine.future()).length; });
expect(count).toBe(0); });
it("supply fingerprint is consistent for the same track IDs", async () => { const [fp1, fp2, fp3] = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js"); const trackIds = tracks.map((t) => t.id);
await engine.supply({ trackIds }); const fp1 = await engine.supplyFingerprint();
await engine.supply({ trackIds }); const fp2 = await engine.supplyFingerprint();
await engine.supply({ trackIds: [trackIds[0]] }); const fp3 = await engine.supplyFingerprint();
return [fp1, fp2, fp3]; });
expect(fp1).toBe(fp2); expect(fp1).not.toBe(fp3); });
it("fill with augment adds on top of existing auto items", async () => { const count = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.supply({ trackIds: tracks.map((t) => t.id) }); await engine.fill({ amount: 2, shuffled: true }); await engine.fill({ augment: true, amount: 1, shuffled: true }); return (await engine.future()).length; });
expect(count).toBe(3); });
it("moves a future item to a new position", async () => { const ids = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.slice(0, 3).map((t) => t.id) }); await engine.move({ key: "1", to: 2 }); return engine.future().map((i) => i.id); });
expect(ids[0]).toBe(tracks[1].id); expect(ids[1]).toBe(tracks[2].id); expect(ids[2]).toBe(tracks[0].id); });
it("move preserves now when reordering around it", async () => { const result = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.slice(0, 3).map((t) => t.id) }); await engine.shift(); // flat list: [past[0]=tracks[0]], now=tracks[1], future=[tracks[2]] // move future item (idx 2) before now (idx 1) await engine.move({ key: "3", to: 0 });
return { now: engine.now()?.id, past: engine.past().map((i) => i.id), future: engine.future().map((i) => i.id), }; });
// shift() moved tracks[0] to now; move({ from:2, to:0 }) put tracks[2] // before now, so: past=[tracks[2]], now=tracks[0], future=[tracks[1]] expect(result.now).toBe(tracks[0].id); expect(result.past[0]).toBe(tracks[2].id); expect(result.future[0]).toBe(tracks[1].id); });
it("move does nothing when from === to", async () => { const ids = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.slice(0, 3).map((t) => t.id) }); await engine.move({ key: "2", to: 1 }); return engine.future().map((i) => i.id); });
expect(ids[0]).toBe(tracks[0].id); expect(ids[1]).toBe(tracks[1].id); expect(ids[2]).toBe(tracks[2].id); });
it("move does nothing for out-of-bounds indices", async () => { const ids = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.slice(0, 2).map((t) => t.id) }); await engine.move({ key: "1", to: 99 }); return engine.future().map((i) => i.id); });
expect(ids[0]).toBe(tracks[0].id); expect(ids[1]).toBe(tracks[1].id); });
it("[shared worker] has the correct past", async () => { const item = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS(); engine.setAttribute("group", "tests");
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); await engine.shift(); await engine.shift();
return engine.past()[0]; });
expect(item?.id).toBe(tracks[0].id); });
it("shift with by advances multiple positions in one call", async () => { const result = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); await engine.shift(); // now = tracks[0] await engine.shift({ by: 2 }); // skip tracks[1], now = tracks[2]
return { now: engine.now()?.id, past: engine.past().map((i) => i.id), future: engine.future().map((i) => i.id), }; });
expect(result.now).toBe(tracks[2].id); expect(result.past).toEqual([tracks[0].id, tracks[1].id]); expect(result.future).toEqual([]); });
it("unshift with by rewinds multiple positions in one call", async () => { const result = await testWeb(async () => { const QueueEngine = await import("~/components/engine/queue/element.js"); const engine = new QueueEngine.CLASS();
document.body.append(engine);
const { tracks } = await import("~/testing/sample/tracks.js");
await engine.add({ trackIds: tracks.map((t) => t.id) }); await engine.shift(); // now = tracks[0] await engine.shift(); // now = tracks[1] await engine.shift(); // now = tracks[2] await engine.unshift({ by: 2 }); // rewind to tracks[0]
return { now: engine.now()?.id, past: engine.past().map((i) => i.id), future: engine.future().map((i) => i.id), }; });
expect(result.now).toBe(tracks[0].id); expect(result.past).toEqual([]); expect(result.future).toEqual([tracks[1].id, tracks[2].id]); });});