phase 13
All checks were successful
CI/CD Pipeline / VM Test - security (push) Successful in 7s
CI/CD Pipeline / Backend Linting (push) Successful in 4s
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 11s
CI/CD Pipeline / VM Test - full-stack (push) Successful in 8s
CI/CD Pipeline / VM Test - performance (push) Successful in 8s
CI/CD Pipeline / Nix Flake Check (push) Successful in 38s
CI/CD Pipeline / CI Summary (push) Successful in 0s
CI/CD Pipeline / Frontend Linting (push) Successful in 17s
All checks were successful
CI/CD Pipeline / VM Test - security (push) Successful in 7s
CI/CD Pipeline / Backend Linting (push) Successful in 4s
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 11s
CI/CD Pipeline / VM Test - full-stack (push) Successful in 8s
CI/CD Pipeline / VM Test - performance (push) Successful in 8s
CI/CD Pipeline / Nix Flake Check (push) Successful in 38s
CI/CD Pipeline / CI Summary (push) Successful in 0s
CI/CD Pipeline / Frontend Linting (push) Successful in 17s
This commit is contained in:
219
frontend/tests/canvas/groups.test.ts
Normal file
219
frontend/tests/canvas/groups.test.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Tests for grouping operations
|
||||
* Tests group creation, moving groups, ungrouping
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { get } from 'svelte/store';
|
||||
import type { Group } from '$lib/api/groups';
|
||||
import {
|
||||
createGroupFromSelection,
|
||||
canCreateGroup,
|
||||
getGroupColorSuggestions,
|
||||
generateDefaultGroupName,
|
||||
} from '$lib/canvas/operations/group';
|
||||
import { ungroupImages, removeImagesFromGroup } from '$lib/canvas/operations/ungroup';
|
||||
import { groups, groupsLoading, groupsError, groupCount } from '$lib/stores/groups';
|
||||
|
||||
// Mock API
|
||||
vi.mock('$lib/api/groups', () => ({
|
||||
createGroup: vi.fn().mockResolvedValue({
|
||||
id: 'group-1',
|
||||
board_id: 'board-1',
|
||||
name: 'Test Group',
|
||||
color: '#FF5733',
|
||||
annotation: 'Test',
|
||||
member_count: 2,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
}),
|
||||
listGroups: vi.fn().mockResolvedValue([]),
|
||||
updateGroup: vi.fn().mockResolvedValue({
|
||||
id: 'group-1',
|
||||
name: 'Updated',
|
||||
color: '#00FF00',
|
||||
}),
|
||||
deleteGroup: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
describe('Group Creation', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('can create group from selection', () => {
|
||||
const selectedIds = ['img1', 'img2'];
|
||||
expect(canCreateGroup(selectedIds)).toBe(true);
|
||||
});
|
||||
|
||||
it('cannot create group with no selection', () => {
|
||||
expect(canCreateGroup([])).toBe(false);
|
||||
});
|
||||
|
||||
it('creates group from selection', async () => {
|
||||
const selectedIds = ['img1', 'img2'];
|
||||
|
||||
const group = await createGroupFromSelection(selectedIds, 'board-1', {
|
||||
name: 'Test Group',
|
||||
color: '#FF5733',
|
||||
annotation: 'Test annotation',
|
||||
});
|
||||
|
||||
expect(group).not.toBeNull();
|
||||
expect(group?.name).toBe('Test Group');
|
||||
});
|
||||
|
||||
it('calls callback on group creation', async () => {
|
||||
const callback = vi.fn();
|
||||
|
||||
await createGroupFromSelection(['img1', 'img2'], 'board-1', {
|
||||
name: 'Test Group',
|
||||
color: '#FF5733',
|
||||
onGroupCreate: callback,
|
||||
});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('generates default group names', () => {
|
||||
const existingGroups: Group[] = [
|
||||
{
|
||||
id: '1',
|
||||
board_id: 'board-1',
|
||||
name: 'Group 1',
|
||||
color: '#FF5733',
|
||||
annotation: null,
|
||||
member_count: 2,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
board_id: 'board-1',
|
||||
name: 'Group 2',
|
||||
color: '#FF5733',
|
||||
annotation: null,
|
||||
member_count: 3,
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
},
|
||||
];
|
||||
|
||||
const newName = generateDefaultGroupName(existingGroups);
|
||||
expect(newName).toBe('Group 3');
|
||||
});
|
||||
|
||||
it('provides color suggestions', () => {
|
||||
const colors = getGroupColorSuggestions();
|
||||
|
||||
expect(colors).toBeInstanceOf(Array);
|
||||
expect(colors.length).toBeGreaterThan(0);
|
||||
expect(colors[0]).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Groups Store', () => {
|
||||
beforeEach(() => {
|
||||
groups.clear();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('starts with empty state', () => {
|
||||
const state = get(groups);
|
||||
|
||||
expect(state.groups).toEqual([]);
|
||||
expect(state.loading).toBe(false);
|
||||
expect(state.error).toBeNull();
|
||||
});
|
||||
|
||||
it('loads groups', async () => {
|
||||
await groups.load('board-1');
|
||||
|
||||
expect(get(groupsLoading)).toBe(false);
|
||||
});
|
||||
|
||||
it('creates group', async () => {
|
||||
const groupData = {
|
||||
name: 'New Group',
|
||||
color: '#FF5733',
|
||||
image_ids: ['img1', 'img2'],
|
||||
};
|
||||
|
||||
const group = await groups.create('board-1', groupData);
|
||||
|
||||
expect(group).not.toBeNull();
|
||||
expect(get(groupCount)).toBe(1);
|
||||
});
|
||||
|
||||
it('handles creation error', async () => {
|
||||
const { createGroup } = await import('$lib/api/groups');
|
||||
vi.mocked(createGroup).mockRejectedValueOnce(new Error('API Error'));
|
||||
|
||||
const group = await groups.create('board-1', {
|
||||
name: 'Test',
|
||||
color: '#FF5733',
|
||||
image_ids: ['img1'],
|
||||
});
|
||||
|
||||
expect(group).toBeNull();
|
||||
expect(get(groupsError)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('deletes group', async () => {
|
||||
// First create a group
|
||||
await groups.create('board-1', {
|
||||
name: 'Test',
|
||||
color: '#FF5733',
|
||||
image_ids: ['img1'],
|
||||
});
|
||||
|
||||
expect(get(groupCount)).toBe(1);
|
||||
|
||||
// Then delete it
|
||||
await groups.delete('board-1', 'group-1');
|
||||
|
||||
expect(get(groupCount)).toBe(0);
|
||||
});
|
||||
|
||||
it('clears all groups', () => {
|
||||
groups.clear();
|
||||
|
||||
const state = get(groups);
|
||||
expect(state.groups).toEqual([]);
|
||||
expect(state.loading).toBe(false);
|
||||
expect(state.error).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Ungroup Operations', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('ungroups images', async () => {
|
||||
const result = await ungroupImages('board-1', 'group-1');
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('handles ungroup error', async () => {
|
||||
const { deleteGroup } = await import('$lib/api/groups');
|
||||
vi.mocked(deleteGroup).mockRejectedValueOnce(new Error('API Error'));
|
||||
|
||||
const result = await ungroupImages('board-1', 'group-1');
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('removes specific images from group', async () => {
|
||||
vi.mock('$lib/api/client', () => ({
|
||||
apiClient: {
|
||||
patch: vi.fn().mockResolvedValue({}),
|
||||
},
|
||||
}));
|
||||
|
||||
const result = await removeImagesFromGroup('board-1', 'group-1', ['img1', 'img2']);
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user