Layout and search fix
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 2m4s
🏗️ Build and Test JellyTau / Android Compile Check (push) Has been skipped
Traceability Validation / Check Requirement Traces (push) Successful in 23s
Build & Release / Run Tests (push) Failing after 2m45s
Build & Release / Build Linux (push) Has been skipped
Build & Release / Build Android (push) Has been skipped
Build & Release / Create Release (push) Has been skipped
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 2m4s
🏗️ Build and Test JellyTau / Android Compile Check (push) Has been skipped
Traceability Validation / Check Requirement Traces (push) Successful in 23s
Build & Release / Run Tests (push) Failing after 2m45s
Build & Release / Build Linux (push) Has been skipped
Build & Release / Build Android (push) Has been skipped
Build & Release / Create Release (push) Has been skipped
This commit is contained in:
@@ -54,8 +54,9 @@ import { invoke } from "@tauri-apps/api/core";
|
||||
import TrackList from "./TrackList.svelte";
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import { auth } from "$lib/stores/auth";
|
||||
import { toast } from "$lib/stores/toast";
|
||||
|
||||
describe.skip("TrackList", () => {
|
||||
describe("TrackList", () => {
|
||||
const mockRepository = {
|
||||
getAudioStreamUrl: vi.fn(),
|
||||
getImageUrl: vi.fn(),
|
||||
@@ -118,7 +119,8 @@ describe.skip("TrackList", () => {
|
||||
|
||||
expect(getAllByText("Song 1").length).toBeGreaterThan(0);
|
||||
expect(getAllByText("Song 2").length).toBeGreaterThan(0);
|
||||
expect(getAllByText(/Song 3 with a Very Long Name/).length).toBeGreaterThan(0);
|
||||
// Long names are abbreviated in the middle via truncateMiddle(name, 48).
|
||||
expect(getAllByText(/Song 3 with a Very Long .*Should Be Truncated/).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("shows loading skeleton when loading=true", () => {
|
||||
@@ -137,10 +139,12 @@ describe.skip("TrackList", () => {
|
||||
});
|
||||
|
||||
it("shows artist column by default", () => {
|
||||
const { getByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
const { getByText, getAllByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
|
||||
// Header only exists in the desktop table.
|
||||
expect(getByText("Artist")).toBeTruthy();
|
||||
expect(getByText("Artist 1")).toBeTruthy();
|
||||
// Artist name renders in both desktop and mobile views.
|
||||
expect(getAllByText("Artist 1").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("hides artist column when showArtist=false", () => {
|
||||
@@ -153,10 +157,12 @@ describe.skip("TrackList", () => {
|
||||
});
|
||||
|
||||
it("shows album column by default", () => {
|
||||
const { getByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
const { getByText, getAllByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
|
||||
// Header only exists in the desktop table.
|
||||
expect(getByText("Album")).toBeTruthy();
|
||||
expect(getByText("Album 1")).toBeTruthy();
|
||||
// Album name renders in both desktop and mobile views.
|
||||
expect(getAllByText("Album 1").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("hides album column when showAlbum=false", () => {
|
||||
@@ -185,12 +191,13 @@ describe.skip("TrackList", () => {
|
||||
},
|
||||
];
|
||||
|
||||
// Component renders both desktop and mobile views
|
||||
// formatDuration(undefined) renders an empty string, so the row still
|
||||
// renders without crashing and the track title is present.
|
||||
const { getAllByText } = render(TrackList, {
|
||||
props: { tracks: tracksWithoutDuration },
|
||||
});
|
||||
|
||||
expect(getAllByText("-").length).toBeGreaterThan(0);
|
||||
expect(getAllByText("Song 1").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("handles tracks without artist", () => {
|
||||
@@ -198,20 +205,24 @@ describe.skip("TrackList", () => {
|
||||
{
|
||||
...mockTracks[0],
|
||||
artists: undefined,
|
||||
artistItems: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const { getByText } = render(TrackList, {
|
||||
// The artist fallback renders "-" in both desktop and mobile views.
|
||||
const { getAllByText } = render(TrackList, {
|
||||
props: { tracks: tracksWithoutArtist },
|
||||
});
|
||||
|
||||
expect(getByText("-")).toBeTruthy();
|
||||
expect(getAllByText("-").length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("renders multiple artists joined with comma", () => {
|
||||
const { getByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
// Tracks fall back to artists.join(", ") when artistItems is absent;
|
||||
// the joined string renders in both desktop and mobile views.
|
||||
const { getAllByText } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
|
||||
expect(getByText("Artist 3, Artist 4")).toBeTruthy();
|
||||
expect(getAllByText("Artist 3, Artist 4").length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -278,25 +289,8 @@ describe.skip("TrackList", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("calls getAudioStreamUrl for each track", async () => {
|
||||
// NOTE: This test is skipped because the code was refactored to use player_play_tracks
|
||||
// which sends trackIds to the backend. The backend now handles all metadata/stream fetching.
|
||||
// This test expected the old behavior where frontend called getAudioStreamUrl.
|
||||
});
|
||||
|
||||
it.skip("includes artwork URLs in queue items", async () => {
|
||||
// NOTE: This test is skipped because the code was refactored.
|
||||
// Stream URLs and artwork URLs are no longer fetched by frontend.
|
||||
// Backend handles all metadata and stream URL fetching via player_play_tracks.
|
||||
});
|
||||
|
||||
it.skip("handles tracks without artwork gracefully", async () => {
|
||||
// NOTE: This test is skipped because the code no longer includes artwork URLs
|
||||
// in queue items sent to backend. Backend handles artwork fetching independently.
|
||||
});
|
||||
|
||||
it("shows error alert when playback fails", async () => {
|
||||
const alertSpy = vi.spyOn(window, "alert").mockImplementation(() => {});
|
||||
it("shows error toast when playback fails", async () => {
|
||||
const toastSpy = vi.spyOn(toast, "error").mockImplementation(() => "");
|
||||
(invoke as any).mockRejectedValue(new Error("Network error"));
|
||||
|
||||
const { container } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
@@ -309,16 +303,19 @@ describe.skip("TrackList", () => {
|
||||
await fireEvent.click(firstTrackButton!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(alertSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Failed to play track")
|
||||
expect(toastSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Failed to play track"),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
alertSpy.mockRestore();
|
||||
toastSpy.mockRestore();
|
||||
});
|
||||
|
||||
it("handles auth errors gracefully", async () => {
|
||||
const alertSpy = vi.spyOn(window, "alert").mockImplementation(() => {});
|
||||
const toastSpy = vi.spyOn(toast, "error").mockImplementation(() => "");
|
||||
// No repository → requireHandle() throws "No repository available",
|
||||
// which the default handler surfaces via toast.error.
|
||||
(auth.getRepository as any).mockReturnValue(null as any);
|
||||
|
||||
const { container } = render(TrackList, { props: { tracks: mockTracks } });
|
||||
@@ -331,22 +328,18 @@ describe.skip("TrackList", () => {
|
||||
await fireEvent.click(firstTrackButton!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(alertSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Not authenticated")
|
||||
expect(toastSpy).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Failed to play track"),
|
||||
expect.anything()
|
||||
);
|
||||
});
|
||||
|
||||
alertSpy.mockRestore();
|
||||
toastSpy.mockRestore();
|
||||
|
||||
// Restore mock for other tests
|
||||
(auth.getRepository as any).mockReturnValue(mockRepository as any);
|
||||
});
|
||||
|
||||
it.skip("handles stream URL generation errors", async () => {
|
||||
// NOTE: This test is skipped because stream URLs are no longer fetched by frontend.
|
||||
// The code now uses player_play_tracks which sends trackIds to backend.
|
||||
// Backend handles all stream URL generation, so this error path no longer exists.
|
||||
});
|
||||
});
|
||||
|
||||
describe("Custom Callback Tests", () => {
|
||||
|
||||
Reference in New Issue
Block a user