mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-22 13:42:12 -03:00
- Remove unused isNewer variable calculation - Use dividerThresholdVersionId instead of latestLibraryVersionId for badge logic - Add test case to verify newer version badge appears with same-base strategy - Ensures correct badge display when filtering by same base model versions
353 lines
10 KiB
JavaScript
353 lines
10 KiB
JavaScript
import { describe, it, beforeEach, afterEach, expect, vi } from 'vitest';
|
|
|
|
const {
|
|
MODEL_VERSIONS_MODULE,
|
|
API_FACTORY_MODULE,
|
|
DOWNLOAD_MANAGER_MODULE,
|
|
UI_HELPERS_MODULE,
|
|
STATE_MODULE,
|
|
I18N_HELPERS_MODULE,
|
|
UTILS_MODULE,
|
|
} = vi.hoisted(() => ({
|
|
MODEL_VERSIONS_MODULE: new URL('../../../static/js/components/shared/ModelVersionsTab.js', import.meta.url).pathname,
|
|
API_FACTORY_MODULE: new URL('../../../static/js/api/modelApiFactory.js', import.meta.url).pathname,
|
|
DOWNLOAD_MANAGER_MODULE: new URL('../../../static/js/managers/DownloadManager.js', import.meta.url).pathname,
|
|
UI_HELPERS_MODULE: new URL('../../../static/js/utils/uiHelpers.js', import.meta.url).pathname,
|
|
STATE_MODULE: new URL('../../../static/js/state/index.js', import.meta.url).pathname,
|
|
I18N_HELPERS_MODULE: new URL('../../../static/js/utils/i18nHelpers.js', import.meta.url).pathname,
|
|
UTILS_MODULE: new URL('../../../static/js/components/shared/utils.js', import.meta.url).pathname,
|
|
}));
|
|
|
|
vi.mock(DOWNLOAD_MANAGER_MODULE, () => ({
|
|
downloadManager: {
|
|
downloadVersionWithDefaults: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
vi.mock(UI_HELPERS_MODULE, () => ({
|
|
showToast: vi.fn(),
|
|
}));
|
|
|
|
const stateMock = {
|
|
global: {
|
|
settings: {
|
|
autoplay_on_hover: false,
|
|
update_flag_strategy: 'any',
|
|
},
|
|
},
|
|
};
|
|
vi.mock(STATE_MODULE, () => ({
|
|
state: stateMock,
|
|
}));
|
|
|
|
vi.mock(I18N_HELPERS_MODULE, () => ({
|
|
translate: vi.fn((_, __, fallback) => fallback ?? ''),
|
|
}));
|
|
|
|
vi.mock(UTILS_MODULE, () => ({
|
|
formatFileSize: vi.fn(() => '1 MB'),
|
|
}));
|
|
|
|
vi.mock(API_FACTORY_MODULE, () => ({
|
|
getModelApiClient: vi.fn(),
|
|
}));
|
|
|
|
describe('ModelVersionsTab media rendering', () => {
|
|
let getModelApiClient;
|
|
let fetchModelUpdateVersions;
|
|
|
|
beforeEach(async () => {
|
|
vi.resetModules();
|
|
document.body.innerHTML = `
|
|
<div id="model-versions-modal">
|
|
<div id="versions-tab">
|
|
<div class="model-versions-tab"></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
stateMock.global.settings.autoplay_on_hover = false;
|
|
stateMock.global.settings.update_flag_strategy = 'any';
|
|
({ getModelApiClient } = await import(API_FACTORY_MODULE));
|
|
fetchModelUpdateVersions = vi.fn();
|
|
getModelApiClient.mockReturnValue({
|
|
fetchModelUpdateVersions,
|
|
setModelUpdateIgnore: vi.fn(),
|
|
setVersionUpdateIgnore: vi.fn(),
|
|
deleteModel: vi.fn(),
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
document.body.innerHTML = '';
|
|
});
|
|
|
|
it('renders video preview when preview URL references a video file in a query parameter', async () => {
|
|
const previewUrl = '/api/lm/previews?path=%2Fhome%2Fexample%2Fvideo-preview.mp4';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [2],
|
|
versions: [
|
|
{
|
|
versionId: 2,
|
|
name: 'v1.0',
|
|
previewUrl,
|
|
baseModel: 'SDXL',
|
|
sizeBytes: 1024,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 123,
|
|
currentVersionId: null,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
const videoElement = document.querySelector('.version-media video');
|
|
expect(videoElement).toBeTruthy();
|
|
expect(videoElement?.getAttribute('src')).toBe(previewUrl);
|
|
expect(document.querySelector('.version-media img')).toBeFalsy();
|
|
});
|
|
|
|
it('renders image preview when preview URL does not reference a video', async () => {
|
|
const previewUrl = '/api/lm/previews?path=%2Fhome%2Fexample%2Fpreview-image.png';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [3],
|
|
versions: [
|
|
{
|
|
versionId: 3,
|
|
name: 'v1.1',
|
|
previewUrl,
|
|
baseModel: 'SDXL',
|
|
sizeBytes: 2048,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 456,
|
|
currentVersionId: null,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
const imageElement = document.querySelector('.version-media img');
|
|
expect(imageElement).toBeTruthy();
|
|
expect(imageElement?.getAttribute('src')).toBe(previewUrl);
|
|
expect(document.querySelector('.version-media video')).toBeFalsy();
|
|
});
|
|
|
|
it('shows a stable label with a short state indicator', async () => {
|
|
stateMock.global.settings.update_flag_strategy = 'any';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [5],
|
|
versions: [
|
|
{
|
|
versionId: 5,
|
|
name: 'base',
|
|
baseModel: 'SDXL',
|
|
previewUrl: '/api/lm/previews/v-base.png',
|
|
sizeBytes: 1024,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 321,
|
|
currentVersionId: 5,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
const toggleText = document.querySelector('.versions-filter-toggle .sr-only');
|
|
expect(toggleText?.textContent?.trim()).toBe('Base filter: All versions');
|
|
});
|
|
|
|
it('filters versions to the current base model when strategy is same_base', async () => {
|
|
stateMock.global.settings.update_flag_strategy = 'same_base';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [10],
|
|
versions: [
|
|
{
|
|
versionId: 10,
|
|
name: 'v1.0',
|
|
baseModel: 'SDXL',
|
|
previewUrl: '/api/lm/previews/v1.png',
|
|
sizeBytes: 1024,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
{
|
|
versionId: 11,
|
|
name: 'v1.1',
|
|
baseModel: 'Realistic',
|
|
previewUrl: '/api/lm/previews/v1-1.png',
|
|
sizeBytes: 2048,
|
|
isInLibrary: false,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 789,
|
|
currentVersionId: 10,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
expect(document.querySelectorAll('.model-version-row').length).toBe(1);
|
|
});
|
|
|
|
it('toggle button can switch to display all versions', async () => {
|
|
stateMock.global.settings.update_flag_strategy = 'same_base';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [10],
|
|
versions: [
|
|
{
|
|
versionId: 10,
|
|
name: 'v1.0',
|
|
baseModel: 'SDXL',
|
|
previewUrl: '/api/lm/previews/v1.png',
|
|
sizeBytes: 1024,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
{
|
|
versionId: 11,
|
|
name: 'v1.1',
|
|
baseModel: 'Realistic',
|
|
previewUrl: '/api/lm/previews/v1-1.png',
|
|
sizeBytes: 2048,
|
|
isInLibrary: false,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 987,
|
|
currentVersionId: 10,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
expect(document.querySelectorAll('.model-version-row').length).toBe(1);
|
|
const toggleButton = document.querySelector('[data-versions-action="toggle-version-display-mode"]');
|
|
expect(toggleButton).toBeTruthy();
|
|
const toggleTextBefore = document.querySelector('.versions-filter-toggle .sr-only');
|
|
expect(toggleTextBefore?.textContent?.trim()).toContain('Same base');
|
|
toggleButton?.click();
|
|
expect(document.querySelectorAll('.model-version-row').length).toBe(2);
|
|
const toggleTextAfter = document.querySelector('.versions-filter-toggle .sr-only');
|
|
expect(toggleTextAfter?.textContent?.trim()).toContain('All versions');
|
|
});
|
|
|
|
it('shows a newer version badge when viewing same-base results', async () => {
|
|
stateMock.global.settings.update_flag_strategy = 'same_base';
|
|
fetchModelUpdateVersions.mockResolvedValue({
|
|
success: true,
|
|
record: {
|
|
shouldIgnore: false,
|
|
inLibraryVersionIds: [3, 1],
|
|
versions: [
|
|
{
|
|
versionId: 4,
|
|
name: 'V4',
|
|
baseModel: 'Base IL',
|
|
previewUrl: '/api/lm/previews/v4.png',
|
|
sizeBytes: 1024,
|
|
isInLibrary: false,
|
|
shouldIgnore: false,
|
|
},
|
|
{
|
|
versionId: 3,
|
|
name: 'V3',
|
|
baseModel: 'Base IL',
|
|
previewUrl: '/api/lm/previews/v3.png',
|
|
sizeBytes: 2048,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
{
|
|
versionId: 2,
|
|
name: 'V2',
|
|
baseModel: 'Base Flux',
|
|
previewUrl: '/api/lm/previews/v2.png',
|
|
sizeBytes: 4096,
|
|
isInLibrary: false,
|
|
shouldIgnore: false,
|
|
},
|
|
{
|
|
versionId: 1,
|
|
name: 'V1',
|
|
baseModel: 'Base Flux',
|
|
previewUrl: '/api/lm/previews/v1.png',
|
|
sizeBytes: 8192,
|
|
isInLibrary: true,
|
|
shouldIgnore: false,
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
|
const controller = initVersionsTab({
|
|
modalId: 'model-versions-modal',
|
|
modelType: 'loras',
|
|
modelId: 333,
|
|
currentVersionId: 1,
|
|
});
|
|
|
|
await controller.load();
|
|
|
|
const rows = document.querySelectorAll('.model-version-row');
|
|
expect(rows.length).toBe(2);
|
|
const firstBadges = Array.from(rows[0].querySelectorAll('.version-badge')).map(
|
|
badge => badge.textContent?.trim()
|
|
);
|
|
expect(firstBadges).toContain('Newer Version');
|
|
});
|
|
});
|