A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4 259 lines 8.1 kB view raw
1import { describe, it } from "@std/testing/bdd"; 2import { expect } from "@std/expect"; 3 4import { testWeb } from "@tests/common/index.ts"; 5import type { Track } from "~/definitions/types.d.ts"; 6 7describe("components/configurator/input", () => { 8 it("listCached returns an empty array initially", async () => { 9 const result = await testWeb(async () => { 10 const mod = await import( 11 "~/components/configurator/input/element.js" 12 ); 13 const configurator = new mod.CLASS(); 14 document.body.append(configurator); 15 return configurator.listCached(); 16 }); 17 18 expect(result).toEqual([]); 19 }); 20 21 it("consult with an unsupported scheme returns supported: false", async () => { 22 const result = await testWeb(async () => { 23 const mod = await import( 24 "~/components/configurator/input/element.js" 25 ); 26 const configurator = new mod.CLASS(); 27 document.body.append(configurator); 28 return configurator.consult("ipfs://QmSomeCid"); 29 }); 30 31 expect(result.supported).toBe(false); 32 }); 33 34 it("resolve with an unsupported scheme returns undefined", async () => { 35 const result = await testWeb(async () => { 36 const mod = await import( 37 "~/components/configurator/input/element.js" 38 ); 39 const configurator = new mod.CLASS(); 40 document.body.append(configurator); 41 const r = await configurator.resolve({ uri: "ipfs://QmSomeCid" }); 42 return r ?? null; 43 }); 44 45 expect(result).toBe(null); 46 }); 47 48 it("detach with no matching input returns all tracks unchanged", async () => { 49 const result = await testWeb(async () => { 50 const mod = await import( 51 "~/components/configurator/input/element.js" 52 ); 53 const configurator = new mod.CLASS(); 54 document.body.append(configurator); 55 56 const tracks: Track[] = [ 57 { $type: "sh.diffuse.output.track", id: "t1", uri: "ipfs://Qm1" }, 58 { $type: "sh.diffuse.output.track", id: "t2", uri: "ipfs://Qm2" }, 59 ]; 60 61 return configurator.detach({ fileUriOrScheme: "ipfs", tracks }); 62 }); 63 64 expect(result.map((t) => t.id)).toEqual(["t1", "t2"]); 65 }); 66 67 it("groupConsult marks unsupported schemes as unavailable", async () => { 68 const result = await testWeb(async () => { 69 const mod = await import( 70 "~/components/configurator/input/element.js" 71 ); 72 const configurator = new mod.CLASS(); 73 document.body.append(configurator); 74 75 return configurator.groupConsult([ 76 "ipfs://QmA", 77 "ipfs://QmB", 78 ]); 79 }); 80 81 expect(result["ipfs"]?.available).toBe(false); 82 expect(result["ipfs"]?.uris).toEqual(["ipfs://QmA", "ipfs://QmB"]); 83 }); 84 85 it("artwork with an unsupported scheme returns null", async () => { 86 const result = await testWeb(async () => { 87 const mod = await import( 88 "~/components/configurator/input/element.js" 89 ); 90 const configurator = new mod.CLASS(); 91 document.body.append(configurator); 92 return configurator.artwork("ipfs://QmSomeCid"); 93 }); 94 95 expect(result).toBe(null); 96 }); 97 98 it("artwork delegates to the appropriate input and returns null", async () => { 99 const result = await testWeb(async () => { 100 const mod = await import( 101 "~/components/configurator/input/element.js" 102 ); 103 const HttpsInput = await import( 104 "~/components/input/https/element.js" 105 ); 106 107 const configurator = new mod.CLASS(); 108 const httpsInput = new HttpsInput.CLASS(); 109 configurator.appendChild(httpsInput); 110 document.body.append(configurator); 111 112 return configurator.artwork("https://example.com/audio.mp3"); 113 }); 114 115 expect(result).toBe(null); 116 }); 117 118 it("inputs maps child input elements by their SCHEME", async () => { 119 const result = await testWeb(async () => { 120 const mod = await import( 121 "~/components/configurator/input/element.js" 122 ); 123 const HttpsInput = await import( 124 "~/components/input/https/element.js" 125 ); 126 127 const configurator = new mod.CLASS(); 128 const httpsInput = new HttpsInput.CLASS(); 129 configurator.appendChild(httpsInput); 130 document.body.append(configurator); 131 132 return Object.keys(configurator.inputs()); 133 }); 134 135 expect(result).toContain("https"); 136 }); 137 138 it("consult with an HTTPS URI delegates to the HTTPS input", async () => { 139 const result = await testWeb(async () => { 140 const mod = await import( 141 "~/components/configurator/input/element.js" 142 ); 143 const HttpsInput = await import( 144 "~/components/input/https/element.js" 145 ); 146 147 const configurator = new mod.CLASS(); 148 const httpsInput = new HttpsInput.CLASS(); 149 configurator.appendChild(httpsInput); 150 document.body.append(configurator); 151 152 return configurator.consult("https://example.com/audio.mp3"); 153 }); 154 155 expect(result.supported).toBe(true); 156 }); 157 158 it("cacheBlob stores a blob and returns an ephemeral+cache:// URI", async () => { 159 const result = await testWeb(async () => { 160 const mod = await import( 161 "~/components/configurator/input/element.js" 162 ); 163 const configurator = new mod.CLASS(); 164 document.body.append(configurator); 165 166 const blob = new Blob(["audio data"], { type: "audio/mpeg" }); 167 return configurator.cacheBlob(blob); 168 }); 169 170 expect(result).toMatch(/^ephemeral\+cache:\/\//); 171 }); 172 173 it("cacheBlob returns the same URI for identical blobs", async () => { 174 const [uri1, uri2] = await testWeb(async () => { 175 const mod = await import( 176 "~/components/configurator/input/element.js" 177 ); 178 const configurator = new mod.CLASS(); 179 document.body.append(configurator); 180 181 const uri1 = await configurator.cacheBlob( 182 new Blob(["same content"], { type: "audio/mpeg" }), 183 ); 184 const uri2 = await configurator.cacheBlob( 185 new Blob(["same content"], { type: "audio/mpeg" }), 186 ); 187 return [uri1, uri2]; 188 }); 189 190 expect(uri1).toBe(uri2); 191 }); 192 193 it("cacheBlob returns different URIs for different blobs", async () => { 194 const [uri1, uri2] = await testWeb(async () => { 195 const mod = await import( 196 "~/components/configurator/input/element.js" 197 ); 198 const configurator = new mod.CLASS(); 199 document.body.append(configurator); 200 201 const uri1 = await configurator.cacheBlob( 202 new Blob(["content A"], { type: "audio/mpeg" }), 203 ); 204 const uri2 = await configurator.cacheBlob( 205 new Blob(["content B"], { type: "audio/mpeg" }), 206 ); 207 return [uri1, uri2]; 208 }); 209 210 expect(uri1).not.toBe(uri2); 211 }); 212 213 it("removeFromCache deletes a previously cached blob", async () => { 214 const result = await testWeb(async () => { 215 const IDB = await import("idb-keyval"); 216 const { CACHE_KEY_PREFIX } = await import( 217 "~/components/input/ephemeral-cache/constants.js" 218 ); 219 const mod = await import( 220 "~/components/configurator/input/element.js" 221 ); 222 const configurator = new mod.CLASS(); 223 document.body.append(configurator); 224 225 const uri = await configurator.cacheBlob( 226 new Blob(["to be removed"], { type: "audio/mpeg" }), 227 ); 228 await configurator.removeFromCache([uri]); 229 230 const stored = await IDB.get(CACHE_KEY_PREFIX + uri); 231 return stored ?? null; 232 }); 233 234 expect(result).toBe(null); 235 }); 236 237 it("resolve with an HTTPS URI returns a url via the HTTPS input", async () => { 238 const result = await testWeb(async () => { 239 const mod = await import( 240 "~/components/configurator/input/element.js" 241 ); 242 const HttpsInput = await import( 243 "~/components/input/https/element.js" 244 ); 245 246 const configurator = new mod.CLASS(); 247 const httpsInput = new HttpsInput.CLASS(); 248 configurator.appendChild(httpsInput); 249 document.body.append(configurator); 250 251 return configurator.resolve({ uri: "https://example.com/audio.mp3" }); 252 }); 253 254 expect(result).not.toBe(null); 255 if (result && "url" in result) { 256 expect(result.url).toBe("https://example.com/audio.mp3"); 257 } 258 }); 259});