fix tax log
This commit is contained in:
8
frontend/src/lib/stores/__tests__/mocks/environment.js
Normal file
8
frontend/src/lib/stores/__tests__/mocks/environment.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// [DEF:environment:Mock]
|
||||
// @PURPOSE: Mock for $app/environment in tests
|
||||
|
||||
export const browser = true;
|
||||
export const dev = true;
|
||||
export const building = false;
|
||||
|
||||
// [/DEF:environment:Mock]
|
||||
10
frontend/src/lib/stores/__tests__/mocks/navigation.js
Normal file
10
frontend/src/lib/stores/__tests__/mocks/navigation.js
Normal file
@@ -0,0 +1,10 @@
|
||||
// [DEF:navigation:Mock]
|
||||
// @PURPOSE: Mock for $app/navigation in tests
|
||||
|
||||
export const goto = () => Promise.resolve();
|
||||
export const push = () => Promise.resolve();
|
||||
export const replace = () => Promise.resolve();
|
||||
export const prefetch = () => Promise.resolve();
|
||||
export const prefetchRoutes = () => Promise.resolve();
|
||||
|
||||
// [/DEF:navigation:Mock]
|
||||
23
frontend/src/lib/stores/__tests__/mocks/stores.js
Normal file
23
frontend/src/lib/stores/__tests__/mocks/stores.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// [DEF:stores:Mock]
|
||||
// @PURPOSE: Mock for $app/stores in tests
|
||||
|
||||
import { writable, readable } from 'svelte/store';
|
||||
|
||||
export const page = readable({
|
||||
url: new URL('http://localhost'),
|
||||
params: {},
|
||||
route: { id: 'test' },
|
||||
status: 200,
|
||||
error: null,
|
||||
data: {},
|
||||
form: null
|
||||
});
|
||||
|
||||
export const navigating = writable(null);
|
||||
|
||||
export const updated = {
|
||||
check: () => Promise.resolve(false),
|
||||
subscribe: writable(false).subscribe
|
||||
};
|
||||
|
||||
// [/DEF:stores:Mock]
|
||||
63
frontend/src/lib/stores/__tests__/setupTests.js
Normal file
63
frontend/src/lib/stores/__tests__/setupTests.js
Normal file
@@ -0,0 +1,63 @@
|
||||
// [DEF:setupTests:Module]
|
||||
// @TIER: STANDARD
|
||||
// @PURPOSE: Global test setup with mocks for SvelteKit modules
|
||||
// @LAYER: UI
|
||||
|
||||
import { vi } from 'vitest';
|
||||
|
||||
// Mock $app/environment
|
||||
vi.mock('$app/environment', () => ({
|
||||
browser: true,
|
||||
dev: true,
|
||||
building: false
|
||||
}));
|
||||
|
||||
// Mock $app/stores
|
||||
vi.mock('$app/stores', () => {
|
||||
const { writable } = require('svelte/store');
|
||||
return {
|
||||
page: writable({ url: new URL('http://localhost'), params: {}, route: { id: 'test' } }),
|
||||
navigating: writable(null),
|
||||
updated: { check: vi.fn(), subscribe: writable(false).subscribe }
|
||||
};
|
||||
});
|
||||
|
||||
// Mock $app/navigation
|
||||
vi.mock('$app/navigation', () => ({
|
||||
goto: vi.fn(),
|
||||
push: vi.fn(),
|
||||
replace: vi.fn(),
|
||||
prefetch: vi.fn(),
|
||||
prefetchRoutes: vi.fn()
|
||||
}));
|
||||
|
||||
// Mock localStorage
|
||||
const localStorageMock = (() => {
|
||||
let store = {};
|
||||
return {
|
||||
getItem: vi.fn((key) => store[key] || null),
|
||||
setItem: vi.fn((key, value) => { store[key] = value; }),
|
||||
removeItem: vi.fn((key) => { delete store[key]; }),
|
||||
clear: () => { store = {}; },
|
||||
get length() { return Object.keys(store).length; },
|
||||
key: vi.fn((i) => Object.keys(store)[i] || null)
|
||||
};
|
||||
})();
|
||||
|
||||
Object.defineProperty(global, 'localStorage', { value: localStorageMock });
|
||||
Object.defineProperty(global, 'sessionStorage', { value: localStorageMock });
|
||||
|
||||
// Mock console.log to reduce noise in tests
|
||||
const originalLog = console.log;
|
||||
console.log = vi.fn((...args) => {
|
||||
// Keep activity store and task drawer logs for test output
|
||||
const firstArg = args[0];
|
||||
if (typeof firstArg === 'string' &&
|
||||
(firstArg.includes('[activityStore]') ||
|
||||
firstArg.includes('[taskDrawer]') ||
|
||||
firstArg.includes('[SidebarStore]'))) {
|
||||
originalLog.apply(console, args);
|
||||
}
|
||||
});
|
||||
|
||||
// [/DEF:setupTests:Module]
|
||||
115
frontend/src/lib/stores/__tests__/sidebar.test.js
Normal file
115
frontend/src/lib/stores/__tests__/sidebar.test.js
Normal file
@@ -0,0 +1,115 @@
|
||||
// @RELATION: VERIFIES -> frontend/src/lib/stores/sidebar.js
|
||||
// [DEF:frontend.src.lib.stores.__tests__.sidebar:Module]
|
||||
// @TIER: STANDARD
|
||||
// @PURPOSE: Unit tests for sidebar store
|
||||
// @LAYER: Domain (Tests)
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { get } from 'svelte/store';
|
||||
import { sidebarStore, toggleSidebar, setActiveItem, setMobileOpen, closeMobile, toggleMobileSidebar } from '../sidebar.js';
|
||||
|
||||
// Mock the $app/environment module
|
||||
vi.mock('$app/environment', () => ({
|
||||
browser: false
|
||||
}));
|
||||
|
||||
describe('SidebarStore', () => {
|
||||
// [DEF:test_sidebar_initial_state:Function]
|
||||
// @TEST: Store initializes with default values
|
||||
// @PRE: No localStorage state
|
||||
// @POST: Default state is { isExpanded: true, activeCategory: 'dashboards', activeItem: '/dashboards', isMobileOpen: false }
|
||||
describe('initial state', () => {
|
||||
it('should have default values when no localStorage', () => {
|
||||
const state = get(sidebarStore);
|
||||
|
||||
expect(state.isExpanded).toBe(true);
|
||||
expect(state.activeCategory).toBe('dashboards');
|
||||
expect(state.activeItem).toBe('/dashboards');
|
||||
expect(state.isMobileOpen).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
// [DEF:test_toggleSidebar:Function]
|
||||
// @TEST: toggleSidebar toggles isExpanded state
|
||||
// @PRE: Store is initialized
|
||||
// @POST: isExpanded is toggled from previous value
|
||||
describe('toggleSidebar', () => {
|
||||
it('should toggle isExpanded from true to false', () => {
|
||||
const initialState = get(sidebarStore);
|
||||
expect(initialState.isExpanded).toBe(true);
|
||||
|
||||
toggleSidebar();
|
||||
|
||||
const newState = get(sidebarStore);
|
||||
expect(newState.isExpanded).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle isExpanded from false to true', () => {
|
||||
toggleSidebar(); // Now false
|
||||
toggleSidebar(); // Should be true again
|
||||
|
||||
const state = get(sidebarStore);
|
||||
expect(state.isExpanded).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// [DEF:test_setActiveItem:Function]
|
||||
// @TEST: setActiveItem updates activeCategory and activeItem
|
||||
// @PRE: Store is initialized
|
||||
// @POST: activeCategory and activeItem are updated
|
||||
describe('setActiveItem', () => {
|
||||
it('should update activeCategory and activeItem', () => {
|
||||
setActiveItem('datasets', '/datasets');
|
||||
|
||||
const state = get(sidebarStore);
|
||||
expect(state.activeCategory).toBe('datasets');
|
||||
expect(state.activeItem).toBe('/datasets');
|
||||
});
|
||||
|
||||
it('should update to admin category', () => {
|
||||
setActiveItem('admin', '/settings');
|
||||
|
||||
const state = get(sidebarStore);
|
||||
expect(state.activeCategory).toBe('admin');
|
||||
expect(state.activeItem).toBe('/settings');
|
||||
});
|
||||
});
|
||||
|
||||
// [DEF:test_mobile_functions:Function]
|
||||
// @TEST: Mobile functions correctly update isMobileOpen
|
||||
// @PRE: Store is initialized
|
||||
// @POST: isMobileOpen is correctly updated
|
||||
describe('mobile functions', () => {
|
||||
it('should set isMobileOpen to true with setMobileOpen', () => {
|
||||
setMobileOpen(true);
|
||||
|
||||
const state = get(sidebarStore);
|
||||
expect(state.isMobileOpen).toBe(true);
|
||||
});
|
||||
|
||||
it('should set isMobileOpen to false with closeMobile', () => {
|
||||
setMobileOpen(true);
|
||||
closeMobile();
|
||||
|
||||
const state = get(sidebarStore);
|
||||
expect(state.isMobileOpen).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle isMobileOpen with toggleMobileSidebar', () => {
|
||||
const initialState = get(sidebarStore);
|
||||
const initialMobileOpen = initialState.isMobileOpen;
|
||||
|
||||
toggleMobileSidebar();
|
||||
|
||||
const state1 = get(sidebarStore);
|
||||
expect(state1.isMobileOpen).toBe(!initialMobileOpen);
|
||||
|
||||
toggleMobileSidebar();
|
||||
|
||||
const state2 = get(sidebarStore);
|
||||
expect(state2.isMobileOpen).toBe(initialMobileOpen);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// [/DEF:frontend.src.lib.stores.__tests__.sidebar:Module]
|
||||
48
frontend/src/lib/stores/__tests__/taskDrawer.test.js
Normal file
48
frontend/src/lib/stores/__tests__/taskDrawer.test.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { get } from 'svelte/store';
|
||||
import { taskDrawerStore, openDrawerForTask, closeDrawer, updateResourceTask } from '../taskDrawer.js';
|
||||
|
||||
describe('taskDrawerStore', () => {
|
||||
beforeEach(() => {
|
||||
taskDrawerStore.set({
|
||||
isOpen: false,
|
||||
activeTaskId: null,
|
||||
resourceTaskMap: {}
|
||||
});
|
||||
});
|
||||
|
||||
it('should open drawer for a specific task', () => {
|
||||
openDrawerForTask('task-123');
|
||||
const state = get(taskDrawerStore);
|
||||
expect(state.isOpen).toBe(true);
|
||||
expect(state.activeTaskId).toBe('task-123');
|
||||
});
|
||||
|
||||
it('should close drawer and clear active task', () => {
|
||||
openDrawerForTask('task-123');
|
||||
closeDrawer();
|
||||
const state = get(taskDrawerStore);
|
||||
expect(state.isOpen).toBe(false);
|
||||
expect(state.activeTaskId).toBe(null);
|
||||
});
|
||||
|
||||
it('should update resource task mapping for running task', () => {
|
||||
updateResourceTask('dash-1', 'task-1', 'RUNNING');
|
||||
const state = get(taskDrawerStore);
|
||||
expect(state.resourceTaskMap['dash-1']).toEqual({ taskId: 'task-1', status: 'RUNNING' });
|
||||
});
|
||||
|
||||
it('should remove mapping when task completes (SUCCESS)', () => {
|
||||
updateResourceTask('dash-1', 'task-1', 'RUNNING');
|
||||
updateResourceTask('dash-1', 'task-1', 'SUCCESS');
|
||||
const state = get(taskDrawerStore);
|
||||
expect(state.resourceTaskMap['dash-1']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should remove mapping when task fails (ERROR)', () => {
|
||||
updateResourceTask('dash-1', 'task-1', 'RUNNING');
|
||||
updateResourceTask('dash-1', 'task-1', 'ERROR');
|
||||
const state = get(taskDrawerStore);
|
||||
expect(state.resourceTaskMap['dash-1']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
119
frontend/src/lib/stores/__tests__/test_activity.js
Normal file
119
frontend/src/lib/stores/__tests__/test_activity.js
Normal file
@@ -0,0 +1,119 @@
|
||||
// [DEF:frontend.src.lib.stores.__tests__.test_activity:Module]
|
||||
// @TIER: STANDARD
|
||||
// @PURPOSE: Unit tests for activity store
|
||||
// @LAYER: UI
|
||||
// @RELATION: VERIFIES -> frontend.src.lib.stores.activity
|
||||
// @RELATION: DEPENDS_ON -> frontend.src.lib.stores.taskDrawer
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
describe('activity store', () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it('should have zero active count initially', async () => {
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(0);
|
||||
expect(state.recentTasks).toEqual([]);
|
||||
});
|
||||
|
||||
it('should count RUNNING tasks as active', async () => {
|
||||
const { taskDrawerStore, updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add a running task
|
||||
updateResourceTask('dashboard-1', 'task-1', 'RUNNING');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should not count SUCCESS tasks as active', async () => {
|
||||
const { updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add a success task
|
||||
updateResourceTask('dashboard-1', 'task-1', 'SUCCESS');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should not count ERROR tasks as active', async () => {
|
||||
const { updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add an error task
|
||||
updateResourceTask('dashboard-1', 'task-1', 'ERROR');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should not count WAITING_INPUT as active', async () => {
|
||||
const { updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add a waiting input task - should NOT be counted as active per contract
|
||||
// Only RUNNING tasks count as active
|
||||
updateResourceTask('dashboard-1', 'task-1', 'WAITING_INPUT');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should track multiple running tasks', async () => {
|
||||
const { updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add multiple running tasks
|
||||
updateResourceTask('dashboard-1', 'task-1', 'RUNNING');
|
||||
updateResourceTask('dashboard-2', 'task-2', 'RUNNING');
|
||||
updateResourceTask('dataset-1', 'task-3', 'RUNNING');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.activeCount).toBe(3);
|
||||
});
|
||||
|
||||
it('should return recent tasks', async () => {
|
||||
const { updateResourceTask } = await import('../taskDrawer.js');
|
||||
const { activityStore } = await import('../activity.js');
|
||||
|
||||
// Add multiple tasks
|
||||
updateResourceTask('dashboard-1', 'task-1', 'RUNNING');
|
||||
updateResourceTask('dataset-1', 'task-2', 'SUCCESS');
|
||||
updateResourceTask('storage-1', 'task-3', 'ERROR');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = activityStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.recentTasks.length).toBeGreaterThan(0);
|
||||
expect(state.recentTasks[0]).toHaveProperty('taskId');
|
||||
expect(state.recentTasks[0]).toHaveProperty('resourceId');
|
||||
expect(state.recentTasks[0]).toHaveProperty('status');
|
||||
});
|
||||
});
|
||||
|
||||
// [/DEF:frontend.src.lib.stores.__tests__.test_activity:Module]
|
||||
142
frontend/src/lib/stores/__tests__/test_sidebar.js
Normal file
142
frontend/src/lib/stores/__tests__/test_sidebar.js
Normal file
@@ -0,0 +1,142 @@
|
||||
// [DEF:frontend.src.lib.stores.__tests__.test_sidebar:Module]
|
||||
// @TIER: STANDARD
|
||||
// @PURPOSE: Unit tests for sidebar store
|
||||
// @LAYER: UI
|
||||
// @RELATION: VERIFIES -> frontend.src.lib.stores.sidebar
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
// Mock browser environment
|
||||
vi.mock('$app/environment', () => ({
|
||||
browser: true
|
||||
}));
|
||||
|
||||
// Mock localStorage
|
||||
const localStorageMock = (() => {
|
||||
let store = {};
|
||||
return {
|
||||
getItem: vi.fn((key) => store[key] || null),
|
||||
setItem: vi.fn((key, value) => { store[key] = value; }),
|
||||
clear: () => { store = {}; }
|
||||
};
|
||||
})();
|
||||
|
||||
Object.defineProperty(global, 'localStorage', { value: localStorageMock });
|
||||
|
||||
describe('sidebar store', () => {
|
||||
// Reset modules to get fresh store
|
||||
beforeEach(async () => {
|
||||
localStorageMock.clear();
|
||||
vi.clearAllMocks();
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it('should have correct initial state', async () => {
|
||||
const { sidebarStore } = await import('../sidebar.js');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = sidebarStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.isExpanded).toBe(true);
|
||||
expect(state.activeCategory).toBe('dashboards');
|
||||
expect(state.activeItem).toBe('/dashboards');
|
||||
expect(state.isMobileOpen).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle sidebar expansion', async () => {
|
||||
const { sidebarStore, toggleSidebar } = await import('../sidebar.js');
|
||||
|
||||
let state = null;
|
||||
const unsub1 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.isExpanded).toBe(true);
|
||||
|
||||
toggleSidebar();
|
||||
|
||||
const unsub2 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.isExpanded).toBe(false);
|
||||
expect(localStorageMock.setItem).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set active category and item', async () => {
|
||||
const { sidebarStore, setActiveItem } = await import('../sidebar.js');
|
||||
|
||||
setActiveItem('datasets', '/datasets');
|
||||
|
||||
let state = null;
|
||||
const unsub = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub();
|
||||
expect(state.activeCategory).toBe('datasets');
|
||||
expect(state.activeItem).toBe('/datasets');
|
||||
expect(localStorageMock.setItem).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set mobile open state', async () => {
|
||||
const { sidebarStore, setMobileOpen } = await import('../sidebar.js');
|
||||
|
||||
setMobileOpen(true);
|
||||
|
||||
let state = null;
|
||||
const unsub = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub();
|
||||
expect(state.isMobileOpen).toBe(true);
|
||||
});
|
||||
|
||||
it('should close mobile sidebar', async () => {
|
||||
const { sidebarStore, closeMobile } = await import('../sidebar.js');
|
||||
|
||||
// First open mobile
|
||||
let state = null;
|
||||
sidebarStore.update(s => ({ ...s, isMobileOpen: true }));
|
||||
const unsub1 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.isMobileOpen).toBe(true);
|
||||
|
||||
closeMobile();
|
||||
|
||||
const unsub2 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.isMobileOpen).toBe(false);
|
||||
});
|
||||
|
||||
it('should toggle mobile sidebar', async () => {
|
||||
const { sidebarStore, toggleMobileSidebar } = await import('../sidebar.js');
|
||||
|
||||
toggleMobileSidebar();
|
||||
|
||||
let state = null;
|
||||
const unsub1 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.isMobileOpen).toBe(true);
|
||||
|
||||
toggleMobileSidebar();
|
||||
|
||||
const unsub2 = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.isMobileOpen).toBe(false);
|
||||
});
|
||||
|
||||
it('should load state from localStorage', async () => {
|
||||
localStorageMock.getItem.mockReturnValue(JSON.stringify({
|
||||
isExpanded: false,
|
||||
activeCategory: 'storage',
|
||||
activeItem: '/storage',
|
||||
isMobileOpen: true
|
||||
}));
|
||||
|
||||
// Re-import with localStorage populated
|
||||
vi.resetModules();
|
||||
const { sidebarStore } = await import('../sidebar.js');
|
||||
|
||||
let state = null;
|
||||
const unsub = sidebarStore.subscribe(s => { state = s; });
|
||||
unsub();
|
||||
expect(state.isExpanded).toBe(false);
|
||||
expect(state.activeCategory).toBe('storage');
|
||||
expect(state.isMobileOpen).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// [/DEF:frontend.src.lib.stores.__tests__.test_sidebar:Module]
|
||||
158
frontend/src/lib/stores/__tests__/test_taskDrawer.js
Normal file
158
frontend/src/lib/stores/__tests__/test_taskDrawer.js
Normal file
@@ -0,0 +1,158 @@
|
||||
// [DEF:frontend.src.lib.stores.__tests__.test_taskDrawer:Module]
|
||||
// @TIER: CRITICAL
|
||||
// @PURPOSE: Unit tests for task drawer store
|
||||
// @LAYER: UI
|
||||
// @RELATION: VERIFIES -> frontend.src.lib.stores.taskDrawer
|
||||
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
|
||||
describe('taskDrawer store', () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it('should have correct initial state', async () => {
|
||||
const { taskDrawerStore } = await import('../taskDrawer.js');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.isOpen).toBe(false);
|
||||
expect(state.activeTaskId).toBeNull();
|
||||
expect(state.resourceTaskMap).toEqual({});
|
||||
});
|
||||
|
||||
it('should open drawer for specific task', async () => {
|
||||
const { taskDrawerStore, openDrawerForTask } = await import('../taskDrawer.js');
|
||||
|
||||
openDrawerForTask('task-123');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.isOpen).toBe(true);
|
||||
expect(state.activeTaskId).toBe('task-123');
|
||||
});
|
||||
|
||||
it('should open drawer in list mode', async () => {
|
||||
const { taskDrawerStore, openDrawer } = await import('../taskDrawer.js');
|
||||
|
||||
openDrawer();
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.isOpen).toBe(true);
|
||||
expect(state.activeTaskId).toBeNull();
|
||||
});
|
||||
|
||||
it('should close drawer', async () => {
|
||||
const { taskDrawerStore, openDrawerForTask, closeDrawer } = await import('../taskDrawer.js');
|
||||
|
||||
// First open drawer
|
||||
openDrawerForTask('task-123');
|
||||
|
||||
let state = null;
|
||||
const unsub1 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.isOpen).toBe(true);
|
||||
|
||||
closeDrawer();
|
||||
|
||||
const unsub2 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.isOpen).toBe(false);
|
||||
expect(state.activeTaskId).toBeNull();
|
||||
});
|
||||
|
||||
it('should update resource-task mapping', async () => {
|
||||
const { taskDrawerStore, updateResourceTask } = await import('../taskDrawer.js');
|
||||
|
||||
updateResourceTask('dashboard-1', 'task-123', 'RUNNING');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.resourceTaskMap['dashboard-1']).toEqual({
|
||||
taskId: 'task-123',
|
||||
status: 'RUNNING'
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove mapping on task completion (SUCCESS)', async () => {
|
||||
const { taskDrawerStore, updateResourceTask } = await import('../taskDrawer.js');
|
||||
|
||||
// First add a running task
|
||||
updateResourceTask('dashboard-1', 'task-123', 'RUNNING');
|
||||
|
||||
let state = null;
|
||||
const unsub1 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.resourceTaskMap['dashboard-1']).toBeDefined();
|
||||
|
||||
// Complete the task
|
||||
updateResourceTask('dashboard-1', 'task-123', 'SUCCESS');
|
||||
|
||||
const unsub2 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.resourceTaskMap['dashboard-1']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should remove mapping on task error', async () => {
|
||||
const { taskDrawerStore, updateResourceTask } = await import('../taskDrawer.js');
|
||||
|
||||
updateResourceTask('dataset-1', 'task-456', 'RUNNING');
|
||||
|
||||
let state = null;
|
||||
const unsub1 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub1();
|
||||
expect(state.resourceTaskMap['dataset-1']).toBeDefined();
|
||||
|
||||
// Error the task
|
||||
updateResourceTask('dataset-1', 'task-456', 'ERROR');
|
||||
|
||||
const unsub2 = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsub2();
|
||||
expect(state.resourceTaskMap['dataset-1']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should keep mapping for WAITING_INPUT status', async () => {
|
||||
const { taskDrawerStore, updateResourceTask } = await import('../taskDrawer.js');
|
||||
|
||||
updateResourceTask('dashboard-1', 'task-789', 'WAITING_INPUT');
|
||||
|
||||
let state = null;
|
||||
const unsubscribe = taskDrawerStore.subscribe(s => { state = s; });
|
||||
unsubscribe();
|
||||
|
||||
expect(state.resourceTaskMap['dashboard-1']).toEqual({
|
||||
taskId: 'task-789',
|
||||
status: 'WAITING_INPUT'
|
||||
});
|
||||
});
|
||||
|
||||
it('should get task for resource', async () => {
|
||||
const { updateResourceTask, getTaskForResource } = await import('../taskDrawer.js');
|
||||
|
||||
updateResourceTask('dashboard-1', 'task-123', 'RUNNING');
|
||||
|
||||
const taskInfo = getTaskForResource('dashboard-1');
|
||||
expect(taskInfo).toEqual({
|
||||
taskId: 'task-123',
|
||||
status: 'RUNNING'
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null for resource without task', async () => {
|
||||
const { getTaskForResource } = await import('../taskDrawer.js');
|
||||
|
||||
const taskInfo = getTaskForResource('non-existent');
|
||||
expect(taskInfo).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
// [/DEF:frontend.src.lib.stores.__tests__.test_taskDrawer:Module]
|
||||
Reference in New Issue
Block a user