fix tests
Some checks failed
Traceability Validation / Check Requirement Traces (push) Has been cancelled
🏗️ Build and Test JellyTau / Build APK and Run Tests (push) Has been cancelled

This commit is contained in:
Duncan Tourolle 2026-02-14 16:39:46 +01:00
parent b8363aa993
commit 59270e8a4f
14 changed files with 86 additions and 37 deletions

View File

@ -84,6 +84,7 @@ RUN cd src-tauri && cargo fetch && cd ..
FROM builder AS test
WORKDIR /app
RUN echo "Running tests..." && \
bunx svelte-kit sync && \
bun run test && \
cd src-tauri && cargo test && cd .. && \
echo "All tests passed!"

View File

@ -12,7 +12,7 @@ services:
- .:/app
environment:
- RUST_BACKTRACE=1
command: bash -c "bun test && cd src-tauri && cargo test && cd .. && echo 'All tests passed!'"
command: bash -c "bunx svelte-kit sync && bun test && cd src-tauri && cargo test && cd .. && echo 'All tests passed!'"
# Android build service - builds APK after tests pass
android-build:

View File

@ -369,6 +369,7 @@ pub fn repository_get_image_url(
/// Get subtitle URL for a media item
#[tauri::command]
#[allow(dead_code)]
pub fn repository_get_subtitle_url(
manager: State<'_, RepositoryManagerWrapper>,
handle: String,
@ -383,6 +384,7 @@ pub fn repository_get_subtitle_url(
/// Get video download URL with quality preset
#[tauri::command]
#[allow(dead_code)]
pub fn repository_get_video_download_url(
manager: State<'_, RepositoryManagerWrapper>,
handle: String,

View File

@ -147,6 +147,8 @@ pub trait MediaRepository: Send + Sync {
) -> String;
/// Get subtitle URL (synchronous - just constructs URL)
/// Called by frontend via Tauri invoke (getSubtitleUrl in VideoPlayer.svelte)
#[allow(dead_code)]
fn get_subtitle_url(
&self,
item_id: &str,
@ -156,6 +158,8 @@ pub trait MediaRepository: Send + Sync {
) -> String;
/// Get video download URL (synchronous - just constructs URL)
/// Called by frontend via Tauri invoke (getVideoDownloadUrl in VideoDownloadButton.svelte)
#[allow(dead_code)]
fn get_video_download_url(
&self,
item_id: &str,

View File

@ -6,6 +6,21 @@
import { invoke } from "@tauri-apps/api/core";
export interface AutoplaySettings {
enabled: boolean;
countdownSeconds: number;
}
export async function getAutoplaySettings(): Promise<AutoplaySettings> {
return invoke("player_get_autoplay_settings");
}
export async function setAutoplaySettings(
settings: AutoplaySettings
): Promise<AutoplaySettings> {
return invoke("player_set_autoplay_settings", { settings });
}
export async function cancelAutoplayCountdown(): Promise<void> {
return invoke("player_cancel_autoplay_countdown");
}

View File

@ -2,7 +2,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { invoke } from "@tauri-apps/api/core";
import { RepositoryClient } from "./repository-client";
vi.mock("@tauri-apps/api/core");
const mockInvoke = vi.fn();
vi.mock("@tauri-apps/api/core", () => ({
invoke: mockInvoke,
}));
/**
* Integration tests documenting Phase 1 & 2 refactoring:

View File

@ -2,7 +2,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { invoke } from "@tauri-apps/api/core";
import { RepositoryClient } from "./repository-client";
vi.mock("@tauri-apps/api/core");
const mockInvoke = vi.fn();
vi.mock("@tauri-apps/api/core", () => ({
invoke: mockInvoke,
}));
describe("RepositoryClient", () => {
let client: RepositoryClient;

View File

@ -25,8 +25,8 @@
playlist: { singular: "playlist", plural: "playlists" },
};
const labels = itemTypeLabels[itemType] || { singular: itemType, plural: `${itemType}s` };
const label = count === 1 ? labels.singular : labels.plural;
const labels = $derived(itemTypeLabels[itemType] || { singular: itemType, plural: `${itemType}s` });
const label = $derived(count === 1 ? labels.singular : labels.plural);
</script>
<p class={`text-sm text-gray-400 ${className}`}>

View File

@ -160,6 +160,7 @@
</script>
<div
role="region"
class="relative h-[500px] rounded-xl overflow-hidden group mb-8 touch-pan-y"
ontouchstart={handleTouchStart}
ontouchmove={handleTouchMove}

View File

@ -39,7 +39,7 @@
};
const circumference = 2 * Math.PI * 15;
const offset = circumference - (state.progress || 0) * circumference;
const offset = $derived(circumference - (state.progress || 0) * circumference);
</script>
<button

View File

@ -156,13 +156,14 @@
}
}
const aspectRatioClass = config.itemDisplayMode === "poster" ? "aspect-[2/3]" : "aspect-square";
const gridColsClass =
const aspectRatioClass = $derived(config.itemDisplayMode === "poster" ? "aspect-[2/3]" : "aspect-square");
const gridColsClass = $derived(
config.itemDisplayMode === "poster"
? "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5"
: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6";
const searchPlaceholder = config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`;
const noItemsMessage = config.noItemsMessage || `No ${config.itemTypes[0]?.toLowerCase() || "items"} found in this genre`;
: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6"
);
const searchPlaceholder = $derived(config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`);
const noItemsMessage = $derived(config.noItemsMessage || `No ${config.itemTypes[0]?.toLowerCase() || "items"} found in this genre`);
</script>
<div class="space-y-6">

View File

@ -42,10 +42,14 @@
let loading = $state(true);
let searchQuery = $state("");
let debouncedSearchQuery = $state("");
let sortBy = $state<string>(config.defaultSort);
let sortBy = $state<string>("");
let sortOrder = $state<"Ascending" | "Descending">("Ascending");
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
$effect(() => {
sortBy = config.defaultSort;
});
const { markLoaded } = useServerReachabilityReload(async () => {
await loadItems();
});
@ -117,7 +121,7 @@
goto(config.backPath);
}
const searchPlaceholder = config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`;
const searchPlaceholder = $derived(config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`);
function handleItemClick(item: MediaItem) {
// Navigate to detail page for browseable items

View File

@ -254,13 +254,15 @@
<div class="text-gray-300 truncate flex flex-wrap items-center gap-1">
{#if track.artistItems && track.artistItems.length > 0}
{#each track.artistItems as artist, idx}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline truncate"
onkeydown={(e) => e.key === 'Enter' && handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline truncate cursor-pointer"
>
{artist.name}
</button>
</span>
{#if idx < track.artistItems.length - 1}
<span>,</span>
{/if}
@ -275,13 +277,15 @@
{#if showAlbum}
<div class="text-gray-300 truncate">
{#if track.albumId}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline truncate"
onkeydown={(e) => e.key === 'Enter' && handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline truncate cursor-pointer"
>
{track.albumName || "-"}
</button>
</span>
{:else}
{track.albumName || "-"}
{/if}
@ -361,13 +365,15 @@
{#if showArtist && showAlbum}
{#if track.artistItems && track.artistItems.length > 0}
{#each track.artistItems as artist, idx}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline"
onkeydown={(e) => e.key === 'Enter' && handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline cursor-pointer"
>
{artist.name}
</button>
</span>
{#if idx < track.artistItems.length - 1}
<span>,</span>
{/if}
@ -377,26 +383,30 @@
{/if}
<span></span>
{#if track.albumId}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline"
onkeydown={(e) => e.key === 'Enter' && handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline cursor-pointer"
>
{track.albumName || "-"}
</button>
</span>
{:else}
{track.albumName || "-"}
{/if}
{:else if showArtist}
{#if track.artistItems && track.artistItems.length > 0}
{#each track.artistItems as artist, idx}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline"
onkeydown={(e) => e.key === 'Enter' && handleArtistClick(artist.id, e)}
class="text-[var(--color-jellyfin)] hover:underline cursor-pointer"
>
{artist.name}
</button>
</span>
{#if idx < track.artistItems.length - 1}
<span>,</span>
{/if}
@ -406,13 +416,15 @@
{/if}
{:else if showAlbum}
{#if track.albumId}
<button
type="button"
<span
role="button"
tabindex="0"
onclick={(e) => handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline"
onkeydown={(e) => e.key === 'Enter' && handleAlbumClick(track.albumId, e)}
class="text-[var(--color-jellyfin)] hover:underline cursor-pointer"
>
{track.albumName || "-"}
</button>
</span>
{:else}
{track.albumName || "-"}
{/if}

View File

@ -284,6 +284,7 @@
</button>
<div
role="region"
class="px-4 py-3 flex items-center gap-4 touch-pan-y relative"
ontouchstart={handleTouchStart}
ontouchmove={handleTouchMove}