mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 07:05:43 -03:00
Merge pull request #471 from willmiao/codex/organize-frontend-tests-into-new-directories
test(frontend): document dom fixture workflow
This commit is contained in:
51
docs/frontend-dom-fixtures.md
Normal file
51
docs/frontend-dom-fixtures.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Frontend DOM Fixture Strategy
|
||||||
|
|
||||||
|
This guide outlines how to reproduce the markup emitted by the Django templates while running Vitest in jsdom. The aim is to make it straightforward to write integration-style unit tests for managers and UI helpers without having to duplicate template fragments inline.
|
||||||
|
|
||||||
|
## Loading Template Markup
|
||||||
|
|
||||||
|
Vitest executes inside Node, so we can read the same HTML templates that ship with the extension:
|
||||||
|
|
||||||
|
1. Use the helper utilities from `tests/frontend/utils/domFixtures.js` to read files under the `templates/` directory.
|
||||||
|
2. Mount the returned markup into `document.body` (or any custom container) before importing the module under test so its query selectors resolve correctly.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { renderTemplate } from '../utils/domFixtures.js'; // adjust the relative path to your spec
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
renderTemplate('loras.html', {
|
||||||
|
dataset: { page: 'loras' }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The helper ensures the dataset is applied to the container, which mirrors how Django sets `data-page` in production.
|
||||||
|
|
||||||
|
## Working with Partial Components
|
||||||
|
|
||||||
|
Many features are implemented as template partials located under `templates/components/`. When a test only needs a fragment (for example, the progress panel or context menu markup), load the component file directly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const container = renderTemplate('components/progress_panel.html');
|
||||||
|
|
||||||
|
const progressPanel = container.querySelector('#progress-panel');
|
||||||
|
```
|
||||||
|
|
||||||
|
This pattern avoids hand-written fixture strings and keeps the tests aligned with the actual markup.
|
||||||
|
|
||||||
|
## Resetting Between Tests
|
||||||
|
|
||||||
|
The shared Vitest setup clears `document.body` and storage APIs before each test. If a suite adds additional DOM nodes outside of the body or needs to reset custom attributes mid-test, use `resetDom()` exported from `domFixtures.js`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { resetDom } from '../utils/domFixtures.js';
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
resetDom();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
- Provide typed helpers for injecting mock script tags (e.g., replicating ComfyUI globals).
|
||||||
|
- Compose higher-level fixtures that mimic specific pages (loras, checkpoints, recipes) once those managers receive dedicated suites.
|
||||||
@@ -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 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 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; expand to additional page wiring and scroll hooks |
|
| Phase 2 | Test AppCore orchestration | Simulate page bootstrapping, infinite scroll hooks, and manager registration using JSDOM DOM fixtures | 🟡 In Progress | AppCore initialization specs landed; documented DOM fixture workflow and plan to expand to additional page wiring and scroll hooks |
|
||||||
| 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 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 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 |
|
| 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 |
|
||||||
@@ -16,8 +16,9 @@ This roadmap tracks the planned rollout of automated testing for the ComfyUI LoR
|
|||||||
## Next Steps Checklist
|
## Next Steps Checklist
|
||||||
|
|
||||||
- [x] Expand unit tests for `storageHelpers` covering migrations and namespace behavior.
|
- [x] Expand unit tests for `storageHelpers` covering migrations and namespace behavior.
|
||||||
- [ ] Document DOM fixture strategy for reproducing template structures in tests.
|
- [x] Document DOM fixture strategy for reproducing template structures in tests.
|
||||||
- [x] Prototype AppCore initialization test that verifies manager bootstrapping with stubbed dependencies.
|
- [x] Prototype AppCore initialization test that verifies manager bootstrapping with stubbed dependencies.
|
||||||
- [ ] Evaluate integrating coverage reporting once test surface grows (> 20 specs).
|
- [ ] 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.
|
||||||
|
|
||||||
Maintaining this roadmap alongside code changes will make it easier to append new automated test tasks and update their progress.
|
Maintaining this roadmap alongside code changes will make it easier to append new automated test tasks and update their progress.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { afterEach, beforeEach } from 'vitest';
|
import { afterEach, beforeEach } from 'vitest';
|
||||||
|
import { resetDom } from './utils/domFixtures.js';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Ensure storage is clean before each test to avoid cross-test pollution
|
// Ensure storage is clean before each test to avoid cross-test pollution
|
||||||
@@ -6,11 +7,10 @@ beforeEach(() => {
|
|||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
|
|
||||||
// Reset DOM state for modules that rely on body attributes
|
// Reset DOM state for modules that rely on body attributes
|
||||||
document.body.innerHTML = '';
|
resetDom();
|
||||||
document.body.dataset.page = '';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
// Clean any dynamically attached globals by tests
|
// Clean any dynamically attached globals by tests
|
||||||
delete document.body.dataset.page;
|
resetDom();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
import { createDefaultSettings, getCurrentPageState, initPageState, setCurrentPageType, state } from './index.js';
|
import { createDefaultSettings, getCurrentPageState, initPageState, setCurrentPageType, state } from '../../../static/js/state/index.js';
|
||||||
import { MODEL_TYPES } from '../api/apiConfig.js';
|
import { MODEL_TYPES } from '../../../static/js/api/apiConfig.js';
|
||||||
import { DEFAULT_PATH_TEMPLATES } from '../utils/constants.js';
|
import { DEFAULT_PATH_TEMPLATES } from '../../../static/js/utils/constants.js';
|
||||||
|
|
||||||
describe('state module', () => {
|
describe('state module', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
68
tests/frontend/utils/domFixtures.js
Normal file
68
tests/frontend/utils/domFixtures.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
const TEMPLATE_ROOT = path.resolve(process.cwd(), 'templates');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an HTML template from the templates directory and returns its markup.
|
||||||
|
* @param {string} relativePath - Path relative to the templates directory.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function readTemplate(relativePath) {
|
||||||
|
const filePath = path.join(TEMPLATE_ROOT, relativePath);
|
||||||
|
return fs.readFileSync(filePath, 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injects the provided HTML markup into the supplied container (defaults to document.body).
|
||||||
|
* @param {string} html
|
||||||
|
* @param {Element} [container=document.body]
|
||||||
|
* @returns {Element}
|
||||||
|
*/
|
||||||
|
export function mountMarkup(html, container = document.body) {
|
||||||
|
container.innerHTML = html;
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a template file and mounts it into the DOM, returning the container used.
|
||||||
|
* @param {string} relativePath - Template path relative to templates directory.
|
||||||
|
* @param {{
|
||||||
|
* container?: Element,
|
||||||
|
* dataset?: Record<string, string>,
|
||||||
|
* beforeMount?: (options: { container: Element }) => void,
|
||||||
|
* afterMount?: (options: { container: Element }) => void
|
||||||
|
* }} [options]
|
||||||
|
* @returns {Element}
|
||||||
|
*/
|
||||||
|
export function renderTemplate(relativePath, options = {}) {
|
||||||
|
const { container = document.body, dataset = {}, beforeMount, afterMount } = options;
|
||||||
|
if (beforeMount) {
|
||||||
|
beforeMount({ container });
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = readTemplate(relativePath);
|
||||||
|
const target = mountMarkup(html, container);
|
||||||
|
|
||||||
|
Object.entries(dataset).forEach(([key, value]) => {
|
||||||
|
target.dataset[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (afterMount) {
|
||||||
|
afterMount({ container: target });
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility to reset the DOM to a clean state. Useful when tests modify the structure
|
||||||
|
* beyond what the shared Vitest setup clears.
|
||||||
|
* @param {Element} [container=document.body]
|
||||||
|
*/
|
||||||
|
export function resetDom(container = document.body) {
|
||||||
|
container.innerHTML = '';
|
||||||
|
if (container === document.body) {
|
||||||
|
document.body.removeAttribute('data-page');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||||
import * as storageHelpers from './storageHelpers.js';
|
import * as storageHelpers from '../../../static/js/utils/storageHelpers.js';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getStorageItem,
|
getStorageItem,
|
||||||
@@ -6,7 +6,6 @@ export default defineConfig({
|
|||||||
globals: true,
|
globals: true,
|
||||||
setupFiles: ['tests/frontend/setup.js'],
|
setupFiles: ['tests/frontend/setup.js'],
|
||||||
include: [
|
include: [
|
||||||
'static/js/**/*.test.js',
|
|
||||||
'tests/frontend/**/*.test.js'
|
'tests/frontend/**/*.test.js'
|
||||||
],
|
],
|
||||||
coverage: {
|
coverage: {
|
||||||
|
|||||||
Reference in New Issue
Block a user