188 lines
5.3 KiB
TypeScript
188 lines
5.3 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import type {
|
|
EditorAsset,
|
|
EditorAssetFolder,
|
|
} from './ImageCanvasEditorTypes';
|
|
import {
|
|
areAllSelectableAssetsSelected,
|
|
createLocalAssetFolder,
|
|
deleteAssetFolderLocally,
|
|
getSelectableAssets,
|
|
groupAssetsByFolder,
|
|
moveAssetToFolderLocally,
|
|
removeAssetById,
|
|
removeSelectedAssets,
|
|
renameAssetById,
|
|
renameAssetFolderById,
|
|
replaceLocalAssetFolder,
|
|
resolveAllAssetSelection,
|
|
resolveDefaultAssetFolder,
|
|
toggleAssetFolderCollapsed,
|
|
toggleAssetSelection,
|
|
} from './ImageCanvasAssetLibraryModel';
|
|
|
|
function createFolder(
|
|
overrides: Partial<EditorAssetFolder> = {},
|
|
): EditorAssetFolder {
|
|
return {
|
|
id: 'project',
|
|
label: '项目素材',
|
|
collapsed: false,
|
|
systemDefault: true,
|
|
persisted: true,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function createAsset(overrides: Partial<EditorAsset> = {}): EditorAsset {
|
|
return {
|
|
id: 'asset-a',
|
|
label: '素材A',
|
|
src: 'data:image/png;base64,YQ==',
|
|
width: 320,
|
|
height: 240,
|
|
folderId: 'project',
|
|
sourceKind: 'uploaded',
|
|
sourceType: 'uploaded',
|
|
persisted: true,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('ImageCanvasAssetLibraryModel', () => {
|
|
it('groups assets by folder and resolves selectable uploaded assets', () => {
|
|
const folders = [
|
|
createFolder(),
|
|
createFolder({ id: 'folder-role', label: '角色素材' }),
|
|
];
|
|
const assets = [
|
|
createAsset({ id: 'asset-a', folderId: 'project' }),
|
|
createAsset({
|
|
id: 'asset-b',
|
|
label: '素材B',
|
|
folderId: 'folder-role',
|
|
}),
|
|
createAsset({
|
|
id: 'built-in',
|
|
label: '内置素材',
|
|
sourceKind: 'built-in',
|
|
}),
|
|
];
|
|
|
|
expect(groupAssetsByFolder(folders, assets)).toMatchObject([
|
|
{ id: 'project', assets: [{ id: 'asset-a' }, { id: 'built-in' }] },
|
|
{ id: 'folder-role', assets: [{ id: 'asset-b' }] },
|
|
]);
|
|
expect(getSelectableAssets(assets).map((asset) => asset.id)).toEqual([
|
|
'asset-a',
|
|
'asset-b',
|
|
]);
|
|
});
|
|
|
|
it('renames assets, toggles folders and creates local folders', () => {
|
|
expect(renameAssetById([createAsset()], 'asset-a', '新名字')[0]).toMatchObject(
|
|
{ label: '新名字' },
|
|
);
|
|
expect(
|
|
renameAssetFolderById([createFolder()], 'project', '默认素材')[0],
|
|
).toMatchObject({ label: '默认素材' });
|
|
expect(toggleAssetFolderCollapsed([createFolder()], 'project')[0]).toMatchObject(
|
|
{ collapsed: true },
|
|
);
|
|
expect(
|
|
createLocalAssetFolder({
|
|
folderId: 'folder-local',
|
|
label: '角色素材',
|
|
}),
|
|
).toEqual({
|
|
id: 'folder-local',
|
|
label: '角色素材',
|
|
collapsed: false,
|
|
systemDefault: false,
|
|
persisted: false,
|
|
});
|
|
});
|
|
|
|
it('replaces local folder ids in folders and contained assets', () => {
|
|
const result = replaceLocalAssetFolder({
|
|
folders: [createFolder(), createFolder({ id: 'folder-local' })],
|
|
assets: [createAsset({ folderId: 'folder-local' })],
|
|
localFolderId: 'folder-local',
|
|
persistedFolder: {
|
|
folderId: 'folder-role',
|
|
label: '角色素材',
|
|
collapsed: false,
|
|
systemDefault: false,
|
|
},
|
|
});
|
|
|
|
expect(result.folders[1]).toEqual({
|
|
id: 'folder-role',
|
|
label: '角色素材',
|
|
collapsed: false,
|
|
systemDefault: false,
|
|
persisted: true,
|
|
});
|
|
expect(result.assets[0]).toMatchObject({ folderId: 'folder-role' });
|
|
});
|
|
|
|
it('deletes assets and moves deleted folder contents to the default folder', () => {
|
|
const folders = [
|
|
createFolder(),
|
|
createFolder({ id: 'folder-role', systemDefault: false }),
|
|
];
|
|
const assets = [
|
|
createAsset({ id: 'asset-a', folderId: 'folder-role' }),
|
|
createAsset({ id: 'asset-b', folderId: 'project' }),
|
|
];
|
|
|
|
expect(removeAssetById(assets, 'asset-a').map((asset) => asset.id)).toEqual([
|
|
'asset-b',
|
|
]);
|
|
expect(resolveDefaultAssetFolder(folders)?.id).toBe('project');
|
|
expect(
|
|
deleteAssetFolderLocally({
|
|
folders,
|
|
assets,
|
|
folderId: 'folder-role',
|
|
defaultFolderId: 'project',
|
|
}),
|
|
).toMatchObject({
|
|
folders: [{ id: 'project' }],
|
|
assets: [
|
|
{ id: 'asset-a', folderId: 'project' },
|
|
{ id: 'asset-b', folderId: 'project' },
|
|
],
|
|
});
|
|
});
|
|
|
|
it('toggles selection, selects all uploaded assets and removes selected assets', () => {
|
|
const assets = [
|
|
createAsset({ id: 'asset-a' }),
|
|
createAsset({ id: 'asset-b' }),
|
|
];
|
|
const selected = toggleAssetSelection(new Set<string>(), 'asset-a');
|
|
|
|
expect([...selected]).toEqual(['asset-a']);
|
|
expect([...toggleAssetSelection(selected, 'asset-a')]).toEqual([]);
|
|
expect(areAllSelectableAssetsSelected(assets, new Set(['asset-a']))).toBe(
|
|
false,
|
|
);
|
|
const allSelected = resolveAllAssetSelection({
|
|
allSelectableAssetsSelected: false,
|
|
selectableAssets: assets,
|
|
});
|
|
expect([...allSelected]).toEqual(['asset-a', 'asset-b']);
|
|
const removal = removeSelectedAssets(assets, new Set(['asset-b']));
|
|
expect(removal.assets.map((asset) => asset.id)).toEqual(['asset-a']);
|
|
expect(removal.deletedAssets.map((asset) => asset.id)).toEqual(['asset-b']);
|
|
});
|
|
|
|
it('moves assets between folders locally', () => {
|
|
expect(
|
|
moveAssetToFolderLocally([createAsset()], 'asset-a', 'folder-role')[0],
|
|
).toMatchObject({ folderId: 'folder-role' });
|
|
});
|
|
});
|