fix(frontend): correct AppCore example images initialization

This commit is contained in:
pixelpaws
2025-09-24 16:10:27 +08:00
parent 6d41211b07
commit 9d5ec43c4e
3 changed files with 132 additions and 8 deletions
+3 -1
View File
@@ -8,7 +8,7 @@ This roadmap tracks the planned rollout of automated testing for the ComfyUI LoR
| --- | --- | --- | --- | --- |
| Phase 0 | Establish baseline tooling | Add Node test runner, jsdom environment, and seed smoke tests | ✅ Complete | Vitest + jsdom configured, example state tests committed |
| Phase 1 | Cover state management logic | Unit test selectors, derived data helpers, and storage utilities under `static/js/state` and `static/js/utils` | ✅ Complete | Storage helpers and state selectors now exercised via deterministic suites |
| Phase 2 | Test AppCore orchestration | Simulate page bootstrapping, infinite scroll hooks, and manager registration using JSDOM DOM fixtures | 🟡 In Progress | AppCore initialization specs landed; DOM fixtures now cover page feature wiring (context menus + infinite scroll); next focus is scroll hooks and manager wiring |
| Phase 2 | Test AppCore orchestration | Simulate page bootstrapping, infinite scroll hooks, and manager registration using JSDOM DOM fixtures | ✅ Complete | AppCore initialization + page feature suites now validate manager wiring, infinite scroll hooks, and onboarding gating |
| Phase 3 | Validate page-specific managers | Add focused suites for `loras`, `checkpoints`, `embeddings`, and `recipes` managers covering filtering, sorting, and bulk actions | ⚪ Not Started | Consider shared helpers for mocking API modules and storage |
| Phase 4 | Interaction-level regression tests | Exercise template fragments, modals, and menus to ensure UI wiring remains intact | ⚪ Not Started | Evaluate Playwright component testing or happy-path DOM snapshots |
| Phase 5 | Continuous integration & coverage | Integrate frontend tests into CI workflow and track coverage metrics | ⚪ Not Started | Align reporting directories with backend coverage for unified reporting |
@@ -19,7 +19,9 @@ This roadmap tracks the planned rollout of automated testing for the ComfyUI LoR
- [x] Document DOM fixture strategy for reproducing template structures in tests.
- [x] Prototype AppCore initialization test that verifies manager bootstrapping with stubbed dependencies.
- [x] Add AppCore page feature suite exercising context menu creation and infinite scroll registration via DOM fixtures.
- [x] Extend AppCore orchestration tests to cover manager wiring, bulk menu setup, and onboarding gating scenarios.
- [ ] Evaluate integrating coverage reporting once test surface grows (> 20 specs).
- [ ] Create shared fixtures for the loras and checkpoints pages once dedicated manager suites are added.
- [ ] Draft focused test matrix for loras/checkpoints manager filtering and sorting paths ahead of Phase 3.
Maintaining this roadmap alongside code changes will make it easier to append new automated test tasks and update their progress.
+2 -1
View File
@@ -49,7 +49,8 @@ export class AppCore {
bannerService.initialize();
window.modalManager = modalManager;
window.settingsManager = settingsManager;
window.exampleImagesManager = new ExampleImagesManager();
const exampleImagesManager = new ExampleImagesManager();
window.exampleImagesManager = exampleImagesManager;
window.helpManager = helpManager;
window.moveManager = moveManager;
window.bulkManager = bulkManager;
+127 -6
View File
@@ -1,8 +1,14 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { renderTemplate, resetDom } from '../utils/domFixtures.js';
const loadingManagerInstance = { showSimpleLoading: vi.fn(), hide: vi.fn() };
const exampleImagesManagerInitialize = vi.fn();
const exampleImagesManagerInstance = { initialize: exampleImagesManagerInitialize };
const bulkContextMenuInstance = { menu: 'bulk-context' };
const headerManagerInstance = { type: 'header-manager' };
vi.mock('../../../static/js/managers/LoadingManager.js', () => ({
LoadingManager: vi.fn(() => ({})),
LoadingManager: vi.fn(() => loadingManagerInstance),
}));
vi.mock('../../../static/js/managers/ModalManager.js', () => ({
@@ -14,7 +20,7 @@ vi.mock('../../../static/js/managers/UpdateService.js', () => ({
}));
vi.mock('../../../static/js/components/Header.js', () => ({
HeaderManager: vi.fn(() => ({})),
HeaderManager: vi.fn(() => headerManagerInstance),
}));
vi.mock('../../../static/js/managers/SettingsManager.js', () => ({
@@ -35,9 +41,7 @@ vi.mock('../../../static/js/managers/BulkManager.js', () => ({
}));
vi.mock('../../../static/js/managers/ExampleImagesManager.js', () => ({
ExampleImagesManager: vi.fn(() => ({
initialize: vi.fn(),
})),
ExampleImagesManager: vi.fn(() => exampleImagesManagerInstance),
}));
vi.mock('../../../static/js/managers/HelpManager.js', () => ({
@@ -73,7 +77,7 @@ vi.mock('../../../static/js/managers/OnboardingManager.js', () => ({
}));
vi.mock('../../../static/js/components/ContextMenu/BulkContextMenu.js', () => ({
BulkContextMenu: vi.fn(),
BulkContextMenu: vi.fn(() => bulkContextMenuInstance),
}));
vi.mock('../../../static/js/utils/eventManagementInit.js', () => ({
@@ -90,6 +94,21 @@ vi.mock('../../../static/js/components/ContextMenu/index.js', () => ({
}));
import { appCore } from '../../../static/js/core.js';
import { state } from '../../../static/js/state/index.js';
import { LoadingManager } from '../../../static/js/managers/LoadingManager.js';
import { modalManager } from '../../../static/js/managers/ModalManager.js';
import { updateService } from '../../../static/js/managers/UpdateService.js';
import { settingsManager } from '../../../static/js/managers/SettingsManager.js';
import { moveManager } from '../../../static/js/managers/MoveManager.js';
import { bulkManager } from '../../../static/js/managers/BulkManager.js';
import { ExampleImagesManager } from '../../../static/js/managers/ExampleImagesManager.js';
import { helpManager } from '../../../static/js/managers/HelpManager.js';
import { bannerService } from '../../../static/js/managers/BannerService.js';
import { initTheme, initBackToTop } from '../../../static/js/utils/uiHelpers.js';
import { onboardingManager } from '../../../static/js/managers/OnboardingManager.js';
import { BulkContextMenu } from '../../../static/js/components/ContextMenu/BulkContextMenu.js';
import { HeaderManager } from '../../../static/js/components/Header.js';
import { initializeEventManagement } from '../../../static/js/utils/eventManagementInit.js';
import { initializeInfiniteScroll } from '../../../static/js/utils/infiniteScroll.js';
import { createPageContextMenu, createGlobalContextMenu } from '../../../static/js/components/ContextMenu/index.js';
@@ -151,3 +170,105 @@ describe('AppCore page orchestration', () => {
expect(window.globalContextMenuInstance).toBe(existingGlobalMenu);
});
});
describe('AppCore initialization flow', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.clearAllMocks();
resetDom();
document.body.className = '';
appCore.initialized = false;
state.loadingManager = undefined;
state.currentPageType = 'loras';
state.global.settings.card_info_display = 'always';
delete window.modalManager;
delete window.settingsManager;
delete window.exampleImagesManager;
delete window.helpManager;
delete window.moveManager;
delete window.bulkManager;
delete window.headerManager;
delete window.i18n;
delete window.pageContextMenu;
delete window.globalContextMenuInstance;
});
afterEach(async () => {
await vi.runAllTimersAsync();
vi.clearAllTimers();
vi.useRealTimers();
});
it('initializes core managers and global references', async () => {
state.global.settings.card_info_display = 'hover';
const result = await appCore.initialize();
expect(result).toBe(appCore);
expect(window.i18n).toBeDefined();
expect(settingsManager.waitForInitialization).toHaveBeenCalledTimes(1);
expect(LoadingManager).toHaveBeenCalledTimes(1);
expect(state.loadingManager).toBe(loadingManagerInstance);
expect(modalManager.initialize).toHaveBeenCalledTimes(1);
expect(updateService.initialize).toHaveBeenCalledTimes(1);
expect(bannerService.initialize).toHaveBeenCalledTimes(1);
expect(window.modalManager).toBe(modalManager);
expect(window.settingsManager).toBe(settingsManager);
expect(window.moveManager).toBe(moveManager);
expect(window.bulkManager).toBe(bulkManager);
expect(HeaderManager).toHaveBeenCalledTimes(1);
expect(window.headerManager).toBe(headerManagerInstance);
expect(initTheme).toHaveBeenCalledTimes(1);
expect(initBackToTop).toHaveBeenCalledTimes(1);
expect(bulkManager.initialize).toHaveBeenCalledTimes(1);
expect(BulkContextMenu).toHaveBeenCalledTimes(1);
expect(bulkManager.setBulkContextMenu).toHaveBeenCalledWith(bulkContextMenuInstance);
expect(ExampleImagesManager).toHaveBeenCalledTimes(1);
expect(window.exampleImagesManager).toBe(exampleImagesManagerInstance);
expect(exampleImagesManagerInitialize).toHaveBeenCalledTimes(1);
expect(helpManager.initialize).toHaveBeenCalledTimes(1);
expect(document.body.classList.contains('hover-reveal')).toBe(true);
expect(initializeEventManagement).toHaveBeenCalledTimes(1);
expect(onboardingManager.start).not.toHaveBeenCalled();
await vi.runAllTimersAsync();
expect(onboardingManager.start).toHaveBeenCalledTimes(1);
expect(bannerService.isBannerVisible).toHaveBeenCalledWith('version-mismatch');
});
it('does not reinitialize once initialized', async () => {
await appCore.initialize();
await vi.runAllTimersAsync();
vi.clearAllMocks();
const result = await appCore.initialize();
expect(result).toBeUndefined();
expect(LoadingManager).not.toHaveBeenCalled();
expect(modalManager.initialize).not.toHaveBeenCalled();
expect(updateService.initialize).not.toHaveBeenCalled();
expect(ExampleImagesManager).not.toHaveBeenCalled();
expect(onboardingManager.start).not.toHaveBeenCalled();
});
it('skips bulk setup when viewing recipes', async () => {
state.currentPageType = 'recipes';
await appCore.initialize();
expect(bulkManager.initialize).not.toHaveBeenCalled();
expect(BulkContextMenu).not.toHaveBeenCalled();
expect(bulkManager.setBulkContextMenu).not.toHaveBeenCalled();
});
it('suppresses onboarding when version mismatch banner is visible', async () => {
bannerService.isBannerVisible.mockReturnValueOnce(true);
await appCore.initialize();
await vi.runAllTimersAsync();
expect(onboardingManager.start).not.toHaveBeenCalled();
});
});