import { InMemoryMusicService } from "./in_memory_music_service"; import { AuthSuccess, MusicLibrary, artistToArtistSummary, albumToAlbumSummary, } from "../src/music_service"; import { v4 as uuid } from "uuid"; import { anArtist, anAlbum, aTrack, POP, ROCK, METAL, HIP_HOP, SKA } from "./builders"; describe("InMemoryMusicService", () => { const service = new InMemoryMusicService(); describe("generateToken", () => { it("should be able to generate a token and then use it to log in", async () => { const credentials = { username: "bob", password: "smith" }; service.hasUser(credentials); const token = (await service.generateToken(credentials)) as AuthSuccess; expect(token.userId).toEqual(credentials.username); expect(token.nickname).toEqual(credentials.username); const musicLibrary = service.login(token.authToken); expect(musicLibrary).toBeDefined(); }); it("should fail with an exception if an invalid token is used", async () => { const credentials = { username: "bob", password: "smith" }; service.hasUser(credentials); const token = (await service.generateToken(credentials)) as AuthSuccess; service.clear(); return expect(service.login(token.authToken)).rejects.toEqual( "Invalid auth token" ); }); }); describe("artistToArtistSummary", () => { it("should map fields correctly", () => { const artist = anArtist({ id: uuid(), name: "The Artist", image: { small: "/path/to/small/jpg", medium: "/path/to/medium/jpg", large: "/path/to/large/jpg", }, }); expect(artistToArtistSummary(artist)).toEqual({ id: artist.id, name: artist.name, }); }); }); describe("Music Library", () => { const user = { username: "user100", password: "password100" }; let musicLibrary: MusicLibrary; beforeEach(async () => { service.clear(); service.hasUser(user); const token = (await service.generateToken(user)) as AuthSuccess; musicLibrary = (await service.login(token.authToken)) as MusicLibrary; }); describe("artists", () => { const artist1 = anArtist(); const artist2 = anArtist(); const artist3 = anArtist(); const artist4 = anArtist(); const artist5 = anArtist(); beforeEach(() => { service.hasArtists(artist1, artist2, artist3, artist4, artist5); }); describe("fetching all in one page", () => { it("should provide an array of artists", async () => { expect( await musicLibrary.artists({ _index: 0, _count: 100 }) ).toEqual({ results: [ artistToArtistSummary(artist1), artistToArtistSummary(artist2), artistToArtistSummary(artist3), artistToArtistSummary(artist4), artistToArtistSummary(artist5), ], total: 5, }); }); }); describe("fetching the second page", () => { it("should provide an array of artists", async () => { expect(await musicLibrary.artists({ _index: 2, _count: 2 })).toEqual({ results: [ artistToArtistSummary(artist3), artistToArtistSummary(artist4), ], total: 5, }); }); }); describe("fetching the last page", () => { it("should provide an array of artists", async () => { expect(await musicLibrary.artists({ _index: 4, _count: 2 })).toEqual({ results: [artistToArtistSummary(artist5)], total: 5, }); }); }); }); describe("artist", () => { const artist1 = anArtist({ id: uuid(), name: "Artist 1" }); const artist2 = anArtist({ id: uuid(), name: "Artist 2" }); beforeEach(() => { service.hasArtists(artist1, artist2); }); describe("when it exists", () => { it("should provide an artist", async () => { expect(await musicLibrary.artist(artist1.id)).toEqual(artist1); expect(await musicLibrary.artist(artist2.id)).toEqual(artist2); }); }); describe("when it doesnt exist", () => { it("should blow up", async () => { return expect(musicLibrary.artist("-1")).rejects.toEqual( "No artist with id '-1'" ); }); }); }); describe("tracks", () => { const artist1Album1 = anAlbum(); const artist1Album2 = anAlbum(); const artist1 = anArtist({ albums: [artist1Album1, artist1Album2] }); const track1 = aTrack({ album: artist1Album1, artist: artist1 }); const track2 = aTrack({ album: artist1Album1, artist: artist1 }); const track3 = aTrack({ album: artist1Album2, artist: artist1 }); const track4 = aTrack({ album: artist1Album2, artist: artist1 }); beforeEach(() => { service.hasArtists(artist1); service.hasTracks(track1, track2, track3, track4); }); describe("fetching tracks for an album", () => { it("should return only tracks on that album", async () => { expect(await musicLibrary.tracks(artist1Album1.id)).toEqual([ track1, track2, ]); }); }); describe("fetching tracks for an album that doesnt exist", () => { it("should return empty array", async () => { expect(await musicLibrary.tracks("non existant album id")).toEqual( [] ); }); }); describe("fetching a single track", () => { describe("when it exists", () => { it("should return the track", async () => { expect(await musicLibrary.track(track3.id)).toEqual(track3); }); }); }); }); describe("albums", () => { const artist1_album1 = anAlbum({ genre: POP }); const artist1_album2 = anAlbum({ genre: ROCK }); const artist1_album3 = anAlbum({ genre: METAL }); const artist1_album4 = anAlbum({ genre: POP }); const artist1_album5 = anAlbum({ genre: POP }); const artist2_album1 = anAlbum({ genre: METAL }); const artist3_album1 = anAlbum({ genre: HIP_HOP }); const artist3_album2 = anAlbum({ genre: POP }); const totalAlbumCount = 8; const artist1 = anArtist({ albums: [ artist1_album1, artist1_album2, artist1_album3, artist1_album4, artist1_album5, ], }); const artist2 = anArtist({ albums: [artist2_album1] }); const artist3 = anArtist({ albums: [artist3_album1, artist3_album2] }); const artistWithNoAlbums = anArtist({ albums: [] }); beforeEach(() => { service.hasArtists(artist1, artist2, artist3, artistWithNoAlbums); }); describe("fetching multiple albums", () => { describe("with no filtering", () => { describe("fetching all on one page", () => { it("should return all the albums for all the artists", async () => { expect( await musicLibrary.albums({ _index: 0, _count: 100 }) ).toEqual({ results: [ albumToAlbumSummary(artist1_album1), albumToAlbumSummary(artist1_album2), albumToAlbumSummary(artist1_album3), albumToAlbumSummary(artist1_album4), albumToAlbumSummary(artist1_album5), albumToAlbumSummary(artist2_album1), albumToAlbumSummary(artist3_album1), albumToAlbumSummary(artist3_album2), ], total: totalAlbumCount, }); }); }); describe("fetching a page", () => { it("should return only that page", async () => { expect(await musicLibrary.albums({ _index: 4, _count: 3 })).toEqual( { results: [ albumToAlbumSummary(artist1_album5), albumToAlbumSummary(artist2_album1), albumToAlbumSummary(artist3_album1), ], total: totalAlbumCount, } ); }); }); describe("fetching the last page", () => { it("should return only that page", async () => { expect( await musicLibrary.albums({ _index: 6, _count: 100 }) ).toEqual({ results: [ albumToAlbumSummary(artist3_album1), albumToAlbumSummary(artist3_album2), ], total: totalAlbumCount, }); }); }); }); describe("filtering by genre", () => { describe("fetching all on one page", () => { it("should return all the albums of that genre for all the artists", async () => { expect( await musicLibrary.albums({ genre: POP.id, _index: 0, _count: 100, }) ).toEqual({ results: [ albumToAlbumSummary(artist1_album1), albumToAlbumSummary(artist1_album4), albumToAlbumSummary(artist1_album5), albumToAlbumSummary(artist3_album2), ], total: 4, }); }); }); describe("when the genre has more albums than a single page", () => { describe("can fetch a single page", () => { it("should return only the albums for that page", async () => { expect( await musicLibrary.albums({ genre: POP.id, _index: 1, _count: 2, }) ).toEqual({ results: [ albumToAlbumSummary(artist1_album4), albumToAlbumSummary(artist1_album5), ], total: 4, }); }); }); describe("can fetch the last page", () => { it("should return only the albums for the last page", async () => { expect( await musicLibrary.albums({ genre: POP.id, _index: 3, _count: 100, }) ).toEqual({ results: [albumToAlbumSummary(artist3_album2)], total: 4, }); }); }); }); it("should return empty list if there are no albums for the genre", async () => { expect( await musicLibrary.albums({ genre: "genre with no albums", _index: 0, _count: 100, }) ).toEqual({ results: [], total: 0, }); }); }); }); describe("fetching a single album", () => { describe("when it exists", () => { it("should provide an album", async () => { expect(await musicLibrary.album(artist1_album5.id)).toEqual( artist1_album5 ); }); }); describe("when it doesnt exist", () => { it("should blow up", async () => { return expect(musicLibrary.album("-1")).rejects.toEqual( "No album with id '-1'" ); }); }); }); }); describe("genres", () => { const artist1 = anArtist({ albums: [ anAlbum({ genre: POP }), anAlbum({ genre: ROCK }), anAlbum({ genre: POP }), ], }); const artist2 = anArtist({ albums: [ anAlbum({ genre: HIP_HOP }), anAlbum({ genre: SKA }), anAlbum({ genre: POP }), ], }); beforeEach(() => { service.hasArtists(artist1, artist2); }); describe("fetching all in one page", () => { it("should provide an array of artists", async () => { expect(await musicLibrary.genres()).toEqual([ HIP_HOP, POP, ROCK, SKA, ]); }); }); }); }); });