fix tests
This commit is contained in:
parent
b8363aa993
commit
59270e8a4f
@ -84,6 +84,7 @@ RUN cd src-tauri && cargo fetch && cd ..
|
|||||||
FROM builder AS test
|
FROM builder AS test
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN echo "Running tests..." && \
|
RUN echo "Running tests..." && \
|
||||||
|
bunx svelte-kit sync && \
|
||||||
bun run test && \
|
bun run test && \
|
||||||
cd src-tauri && cargo test && cd .. && \
|
cd src-tauri && cargo test && cd .. && \
|
||||||
echo "All tests passed!"
|
echo "All tests passed!"
|
||||||
|
|||||||
@ -12,7 +12,7 @@ services:
|
|||||||
- .:/app
|
- .:/app
|
||||||
environment:
|
environment:
|
||||||
- RUST_BACKTRACE=1
|
- 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 service - builds APK after tests pass
|
||||||
android-build:
|
android-build:
|
||||||
|
|||||||
@ -369,6 +369,7 @@ pub fn repository_get_image_url(
|
|||||||
|
|
||||||
/// Get subtitle URL for a media item
|
/// Get subtitle URL for a media item
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn repository_get_subtitle_url(
|
pub fn repository_get_subtitle_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
@ -383,6 +384,7 @@ pub fn repository_get_subtitle_url(
|
|||||||
|
|
||||||
/// Get video download URL with quality preset
|
/// Get video download URL with quality preset
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn repository_get_video_download_url(
|
pub fn repository_get_video_download_url(
|
||||||
manager: State<'_, RepositoryManagerWrapper>,
|
manager: State<'_, RepositoryManagerWrapper>,
|
||||||
handle: String,
|
handle: String,
|
||||||
|
|||||||
@ -147,6 +147,8 @@ pub trait MediaRepository: Send + Sync {
|
|||||||
) -> String;
|
) -> String;
|
||||||
|
|
||||||
/// Get subtitle URL (synchronous - just constructs URL)
|
/// Get subtitle URL (synchronous - just constructs URL)
|
||||||
|
/// Called by frontend via Tauri invoke (getSubtitleUrl in VideoPlayer.svelte)
|
||||||
|
#[allow(dead_code)]
|
||||||
fn get_subtitle_url(
|
fn get_subtitle_url(
|
||||||
&self,
|
&self,
|
||||||
item_id: &str,
|
item_id: &str,
|
||||||
@ -156,6 +158,8 @@ pub trait MediaRepository: Send + Sync {
|
|||||||
) -> String;
|
) -> String;
|
||||||
|
|
||||||
/// Get video download URL (synchronous - just constructs URL)
|
/// 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(
|
fn get_video_download_url(
|
||||||
&self,
|
&self,
|
||||||
item_id: &str,
|
item_id: &str,
|
||||||
|
|||||||
@ -6,6 +6,21 @@
|
|||||||
|
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
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> {
|
export async function cancelAutoplayCountdown(): Promise<void> {
|
||||||
return invoke("player_cancel_autoplay_countdown");
|
return invoke("player_cancel_autoplay_countdown");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { RepositoryClient } from "./repository-client";
|
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:
|
* Integration tests documenting Phase 1 & 2 refactoring:
|
||||||
|
|||||||
@ -2,7 +2,11 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { RepositoryClient } from "./repository-client";
|
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", () => {
|
describe("RepositoryClient", () => {
|
||||||
let client: RepositoryClient;
|
let client: RepositoryClient;
|
||||||
|
|||||||
@ -25,8 +25,8 @@
|
|||||||
playlist: { singular: "playlist", plural: "playlists" },
|
playlist: { singular: "playlist", plural: "playlists" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const labels = itemTypeLabels[itemType] || { singular: itemType, plural: `${itemType}s` };
|
const labels = $derived(itemTypeLabels[itemType] || { singular: itemType, plural: `${itemType}s` });
|
||||||
const label = count === 1 ? labels.singular : labels.plural;
|
const label = $derived(count === 1 ? labels.singular : labels.plural);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<p class={`text-sm text-gray-400 ${className}`}>
|
<p class={`text-sm text-gray-400 ${className}`}>
|
||||||
|
|||||||
@ -160,6 +160,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
role="region"
|
||||||
class="relative h-[500px] rounded-xl overflow-hidden group mb-8 touch-pan-y"
|
class="relative h-[500px] rounded-xl overflow-hidden group mb-8 touch-pan-y"
|
||||||
ontouchstart={handleTouchStart}
|
ontouchstart={handleTouchStart}
|
||||||
ontouchmove={handleTouchMove}
|
ontouchmove={handleTouchMove}
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const circumference = 2 * Math.PI * 15;
|
const circumference = 2 * Math.PI * 15;
|
||||||
const offset = circumference - (state.progress || 0) * circumference;
|
const offset = $derived(circumference - (state.progress || 0) * circumference);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -156,13 +156,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const aspectRatioClass = config.itemDisplayMode === "poster" ? "aspect-[2/3]" : "aspect-square";
|
const aspectRatioClass = $derived(config.itemDisplayMode === "poster" ? "aspect-[2/3]" : "aspect-square");
|
||||||
const gridColsClass =
|
const gridColsClass = $derived(
|
||||||
config.itemDisplayMode === "poster"
|
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-5"
|
||||||
: "grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6";
|
: "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`;
|
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>
|
</script>
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="space-y-6">
|
||||||
|
|||||||
@ -42,10 +42,14 @@
|
|||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let searchQuery = $state("");
|
let searchQuery = $state("");
|
||||||
let debouncedSearchQuery = $state("");
|
let debouncedSearchQuery = $state("");
|
||||||
let sortBy = $state<string>(config.defaultSort);
|
let sortBy = $state<string>("");
|
||||||
let sortOrder = $state<"Ascending" | "Descending">("Ascending");
|
let sortOrder = $state<"Ascending" | "Descending">("Ascending");
|
||||||
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
|
let searchTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
sortBy = config.defaultSort;
|
||||||
|
});
|
||||||
|
|
||||||
const { markLoaded } = useServerReachabilityReload(async () => {
|
const { markLoaded } = useServerReachabilityReload(async () => {
|
||||||
await loadItems();
|
await loadItems();
|
||||||
});
|
});
|
||||||
@ -117,7 +121,7 @@
|
|||||||
goto(config.backPath);
|
goto(config.backPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchPlaceholder = config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`;
|
const searchPlaceholder = $derived(config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`);
|
||||||
|
|
||||||
function handleItemClick(item: MediaItem) {
|
function handleItemClick(item: MediaItem) {
|
||||||
// Navigate to detail page for browseable items
|
// Navigate to detail page for browseable items
|
||||||
|
|||||||
@ -254,13 +254,15 @@
|
|||||||
<div class="text-gray-300 truncate flex flex-wrap items-center gap-1">
|
<div class="text-gray-300 truncate flex flex-wrap items-center gap-1">
|
||||||
{#if track.artistItems && track.artistItems.length > 0}
|
{#if track.artistItems && track.artistItems.length > 0}
|
||||||
{#each track.artistItems as artist, idx}
|
{#each track.artistItems as artist, idx}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleArtistClick(artist.id, e)}
|
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}
|
{artist.name}
|
||||||
</button>
|
</span>
|
||||||
{#if idx < track.artistItems.length - 1}
|
{#if idx < track.artistItems.length - 1}
|
||||||
<span>,</span>
|
<span>,</span>
|
||||||
{/if}
|
{/if}
|
||||||
@ -275,13 +277,15 @@
|
|||||||
{#if showAlbum}
|
{#if showAlbum}
|
||||||
<div class="text-gray-300 truncate">
|
<div class="text-gray-300 truncate">
|
||||||
{#if track.albumId}
|
{#if track.albumId}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleAlbumClick(track.albumId, e)}
|
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 || "-"}
|
{track.albumName || "-"}
|
||||||
</button>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
{track.albumName || "-"}
|
{track.albumName || "-"}
|
||||||
{/if}
|
{/if}
|
||||||
@ -361,13 +365,15 @@
|
|||||||
{#if showArtist && showAlbum}
|
{#if showArtist && showAlbum}
|
||||||
{#if track.artistItems && track.artistItems.length > 0}
|
{#if track.artistItems && track.artistItems.length > 0}
|
||||||
{#each track.artistItems as artist, idx}
|
{#each track.artistItems as artist, idx}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleArtistClick(artist.id, e)}
|
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}
|
{artist.name}
|
||||||
</button>
|
</span>
|
||||||
{#if idx < track.artistItems.length - 1}
|
{#if idx < track.artistItems.length - 1}
|
||||||
<span>,</span>
|
<span>,</span>
|
||||||
{/if}
|
{/if}
|
||||||
@ -377,26 +383,30 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<span>•</span>
|
<span>•</span>
|
||||||
{#if track.albumId}
|
{#if track.albumId}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleAlbumClick(track.albumId, e)}
|
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 || "-"}
|
{track.albumName || "-"}
|
||||||
</button>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
{track.albumName || "-"}
|
{track.albumName || "-"}
|
||||||
{/if}
|
{/if}
|
||||||
{:else if showArtist}
|
{:else if showArtist}
|
||||||
{#if track.artistItems && track.artistItems.length > 0}
|
{#if track.artistItems && track.artistItems.length > 0}
|
||||||
{#each track.artistItems as artist, idx}
|
{#each track.artistItems as artist, idx}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleArtistClick(artist.id, e)}
|
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}
|
{artist.name}
|
||||||
</button>
|
</span>
|
||||||
{#if idx < track.artistItems.length - 1}
|
{#if idx < track.artistItems.length - 1}
|
||||||
<span>,</span>
|
<span>,</span>
|
||||||
{/if}
|
{/if}
|
||||||
@ -406,13 +416,15 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{:else if showAlbum}
|
{:else if showAlbum}
|
||||||
{#if track.albumId}
|
{#if track.albumId}
|
||||||
<button
|
<span
|
||||||
type="button"
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
onclick={(e) => handleAlbumClick(track.albumId, e)}
|
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 || "-"}
|
{track.albumName || "-"}
|
||||||
</button>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
{track.albumName || "-"}
|
{track.albumName || "-"}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@ -284,6 +284,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
role="region"
|
||||||
class="px-4 py-3 flex items-center gap-4 touch-pan-y relative"
|
class="px-4 py-3 flex items-center gap-4 touch-pan-y relative"
|
||||||
ontouchstart={handleTouchStart}
|
ontouchstart={handleTouchStart}
|
||||||
ontouchmove={handleTouchMove}
|
ontouchmove={handleTouchMove}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user