Files
MajoorWaldi-ComfyUI-Majoor-…/js/tests/grid_selection_manager.vitest.mjs
T
MajoorWaldi b0070544d0 feat: implement request deduplication in API client
- Added deduplication logic to prevent multiple simultaneous requests for the same asset metadata.
- Introduced a pending requests cache to manage in-flight promises.
- Updated `getAssetMetadata` and `vectorFindSimilar` functions to utilize the deduplication feature.
- Enhanced error handling to clear pending entries on request failures.

feat: add MediaBlobCache for media asset error tracking

- Created MediaBlobCache to manage blob URLs and track loading errors for media assets.
- Implemented methods to mark URLs as errored and acquire blob URLs with ref-counting.
- Integrated MediaBlobCache into the Card component to handle broken image URLs.

feat: reconcile selection IDs in grid management

- Added `reconcileSelectionIds` function to synchronize selected asset IDs with visible assets.
- Updated grid selection management to prune selections based on visibility.
- Enhanced the AssetsManagerPanel to trigger selection reconciliation on filter changes.

style: improve loading overlay and skeleton loaders

- Refined loading overlay styles for better user experience.
- Added CSS for skeleton loaders to provide visual feedback during asset loading.

test: add unit tests for API client deduplication and grid selection

- Implemented tests for deduplication logic in the API client.
- Added tests for the new `reconcileSelectionIds` function in the grid selection manager.
2026-03-30 17:04:33 +02:00

119 lines
3.6 KiB
JavaScript

import { describe, expect, it } from "vitest";
import {
getSelectedIdSet,
reconcileSelectionIds,
safeEscapeId,
setSelectionIds,
syncSelectionClasses,
} from "../features/grid/GridSelectionManager.js";
function makeCard(id) {
const classSet = new Set();
const attrs = new Map();
return {
dataset: { mjrAssetId: String(id) },
classList: {
add(v) {
classSet.add(v);
},
remove(v) {
classSet.delete(v);
},
has(v) {
return classSet.has(v);
},
},
setAttribute(k, v) {
attrs.set(k, v);
},
getAttribute(k) {
return attrs.get(k);
},
};
}
describe("GridSelectionManager", () => {
it("supports single and multi selection dataset keys", () => {
const g1 = { dataset: { mjrSelectedAssetIds: JSON.stringify([1, "2"]) } };
expect(Array.from(getSelectedIdSet(g1)).sort()).toEqual(["1", "2"]);
const g2 = { dataset: { mjrSelectedAssetId: "9" } };
expect(Array.from(getSelectedIdSet(g2))).toEqual(["9"]);
});
it("updates cards and emits event when selection changes", () => {
const cards = [makeCard(1), makeCard(2), makeCard(3)];
const events = [];
globalThis.CustomEvent = class {
constructor(type, init) {
this.type = type;
this.detail = init?.detail;
}
};
globalThis.window = {
dispatchEvent(evt) {
events.push(evt);
},
};
const grid = {
dataset: {},
dispatchEvent(evt) {
events.push(evt);
},
};
syncSelectionClasses(grid, new Set(["2"]), () => cards);
expect(cards[1].classList.has("is-selected")).toBe(true);
expect(cards[0].getAttribute("aria-selected")).toBe("false");
const selected = setSelectionIds(grid, ["1", 3, "3"], { activeId: "3" }, () => cards);
expect(selected.sort()).toEqual(["1", "3"]);
expect(grid.dataset.mjrSelectedAssetId).toBe("3");
expect(events.length).toBeGreaterThanOrEqual(1);
});
it("falls back when CSS.escape is unavailable", () => {
globalThis.CSS = undefined;
expect(safeEscapeId('a"b\\c')).toBe('a\\"b\\\\c');
});
it("reconciles selection against visible assets and reports pruned items", () => {
const cards = [makeCard(1), makeCard(2), makeCard(3)];
const events = [];
globalThis.CustomEvent = class {
constructor(type, init) {
this.type = type;
this.detail = init?.detail;
}
};
globalThis.window = {
dispatchEvent(evt) {
events.push(evt);
},
};
const grid = {
dataset: {
mjrSelectedAssetIds: JSON.stringify(["1", "2", "9"]),
mjrSelectedAssetId: "2",
},
dispatchEvent(evt) {
events.push(evt);
},
};
const result = reconcileSelectionIds(
grid,
["2", "3"],
{ activeId: "2" },
() => cards,
);
expect(result.pruned).toBe(2);
expect(result.selectedIds).toEqual(["2"]);
expect(grid.dataset.mjrSelectedAssetIds).toBe(JSON.stringify(["2"]));
expect(grid.dataset.mjrSelectedAssetId).toBe("2");
expect(events.some((evt) => evt.type === "mjr:selection-changed")).toBe(true);
});
});