forked from
tokono.ma/diffuse
A music player that connects to your cloud/distributed storage.
1import { describe, it } from "@std/testing/bdd";
2import { expect } from "@std/expect";
3
4import { testWeb } from "@tests/common/index.ts";
5
6describe("components/configurator/scrobbles", () => {
7 it("scrobblers returns empty array when there are no children", async () => {
8 const result = await testWeb(async () => {
9 const mod = await import(
10 "~/components/configurator/scrobbles/element.js"
11 );
12 const configurator = new mod.CLASS();
13 document.body.append(configurator);
14 return configurator.scrobblers().length;
15 });
16
17 expect(result).toBe(0);
18 });
19
20 it("nowPlaying resolves without throwing when there are no active scrobblers", async () => {
21 const result = await testWeb(async () => {
22 const mod = await import(
23 "~/components/configurator/scrobbles/element.js"
24 );
25 const configurator = new mod.CLASS();
26 document.body.append(configurator);
27
28 const track = {
29 $type: "sh.diffuse.output.track" as const,
30 id: "t1",
31 uri: "https://example.com/audio.mp3",
32 };
33
34 await configurator.nowPlaying(track);
35 return true;
36 });
37
38 expect(result).toBe(true);
39 });
40
41 it("scrobble resolves without throwing when there are no active scrobblers", async () => {
42 const result = await testWeb(async () => {
43 const mod = await import(
44 "~/components/configurator/scrobbles/element.js"
45 );
46 const configurator = new mod.CLASS();
47 document.body.append(configurator);
48
49 const track = {
50 $type: "sh.diffuse.output.track" as const,
51 id: "t1",
52 uri: "https://example.com/audio.mp3",
53 };
54
55 await configurator.scrobble(track, Date.now());
56 return true;
57 });
58
59 expect(result).toBe(true);
60 });
61
62 it("scrobblers includes child elements that have the scrobble interface", async () => {
63 const result = await testWeb(async () => {
64 const mod = await import(
65 "~/components/configurator/scrobbles/element.js"
66 );
67 const configurator = new mod.CLASS();
68
69 // Mock scrobbler with the required interface
70 const mock = document.createElement("div");
71 (mock as any).isAuthenticated = () => true;
72 (mock as any).nowPlaying = async () => {};
73 (mock as any).scrobble = async () => {};
74 configurator.appendChild(mock);
75
76 document.body.append(configurator);
77
78 return configurator.scrobblers().length;
79 });
80
81 expect(result).toBe(1);
82 });
83
84 it("scrobblers excludes children that do not have the scrobble interface", async () => {
85 const result = await testWeb(async () => {
86 const mod = await import(
87 "~/components/configurator/scrobbles/element.js"
88 );
89 const configurator = new mod.CLASS();
90
91 // Plain element without scrobble methods
92 const plain = document.createElement("div");
93 configurator.appendChild(plain);
94
95 document.body.append(configurator);
96
97 return configurator.scrobblers().length;
98 });
99
100 expect(result).toBe(0);
101 });
102
103 it("nowPlaying calls all authenticated scrobblers", async () => {
104 const result = await testWeb(async () => {
105 const mod = await import(
106 "~/components/configurator/scrobbles/element.js"
107 );
108 const configurator = new mod.CLASS();
109
110 const calls: string[] = [];
111
112 const auth = document.createElement("div");
113 (auth as any).isAuthenticated = () => true;
114 (auth as any).nowPlaying = async () => { calls.push("auth"); };
115 (auth as any).scrobble = async () => {};
116
117 const unauth = document.createElement("div");
118 (unauth as any).isAuthenticated = () => false;
119 (unauth as any).nowPlaying = async () => { calls.push("unauth"); };
120 (unauth as any).scrobble = async () => {};
121
122 configurator.appendChild(auth);
123 configurator.appendChild(unauth);
124 document.body.append(configurator);
125
126 const track = {
127 $type: "sh.diffuse.output.track" as const,
128 id: "t1",
129 uri: "https://example.com/audio.mp3",
130 };
131
132 await configurator.nowPlaying(track);
133 return calls;
134 });
135
136 expect(result).toEqual(["auth"]);
137 });
138
139 it("scrobble calls all authenticated scrobblers", async () => {
140 const result = await testWeb(async () => {
141 const mod = await import(
142 "~/components/configurator/scrobbles/element.js"
143 );
144 const configurator = new mod.CLASS();
145
146 const calls: string[] = [];
147
148 const auth = document.createElement("div");
149 (auth as any).isAuthenticated = () => true;
150 (auth as any).nowPlaying = async () => {};
151 (auth as any).scrobble = async () => { calls.push("auth"); };
152
153 const unauth = document.createElement("div");
154 (unauth as any).isAuthenticated = () => false;
155 (unauth as any).nowPlaying = async () => {};
156 (unauth as any).scrobble = async () => { calls.push("unauth"); };
157
158 configurator.appendChild(auth);
159 configurator.appendChild(unauth);
160 document.body.append(configurator);
161
162 const track = {
163 $type: "sh.diffuse.output.track" as const,
164 id: "t1",
165 uri: "https://example.com/audio.mp3",
166 };
167
168 await configurator.scrobble(track, Date.now());
169 return calls;
170 });
171
172 expect(result).toEqual(["auth"]);
173 });
174});