opsdash-app/opsdash/test/useWidgetLayoutManager.test.ts
blade34242 6055062138
All checks were successful
Nextcloud Server Tests / version-consistency (push) Successful in 38s
Nextcloud Server Tests / matrix-config (push) Successful in 33s
Nextcloud Server Tests / Nextcloud stable31 / PHP 8.2 (stable31, 8.2) (push) Successful in 18m59s
Nextcloud Server Tests / Nextcloud stable31 / PHP 8.3 (stable31, 8.3) (push) Successful in 17m21s
Nextcloud Server Tests / Nextcloud stable32 / PHP 8.2 (stable32, 8.2) (push) Successful in 17m53s
Nextcloud Server Tests / Nextcloud stable32 / PHP 8.3 (stable32, 8.3) (push) Successful in 18m31s
Nextcloud Server Tests / Nextcloud stable33 / PHP 8.2 (stable33, 8.2) (push) Successful in 22m56s
Nextcloud Server Tests / Nextcloud stable33 / PHP 8.3 (stable33, 8.3) (push) Successful in 19m17s
Nextcloud Server Tests / Nextcloud stable34 / PHP 8.2 (stable34, 8.2) (push) Successful in 24m2s
Nextcloud Server Tests / Nextcloud stable34 / PHP 8.3 (stable34, 8.3) (push) Successful in 22m38s
Add calendar stats workspace widget
2026-07-17 17:02:43 +07:00

215 lines
7.7 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest'
import { nextTick, ref } from 'vue'
import { useWidgetLayoutManager } from '../composables/useWidgetLayoutManager'
describe('useWidgetLayoutManager', () => {
const registry = {
test_widget: {
label: 'Test Widget',
defaultLayout: { width: 'half', height: 'm', order: 10 },
},
}
function makeManager() {
return useWidgetLayoutManager({
storageKey: 'opsdash.widgets.test',
widgetsRegistry: registry,
createDefaultTabs: () => ({
tabs: [{ id: 'tab-1', label: 'Overview', widgets: [] }],
defaultTabId: 'tab-1',
}),
normalizeWidgetTabs: (input, fallback) => (input ? input : fallback),
dashboardMode: ref('standard'),
deckEnabled: ref(true),
hasInitialLoad: ref(true),
queueSaveRef: ref(vi.fn()),
})
}
it('persists dirty widgets after initial load completes', async () => {
const queueSave = vi.fn()
const hasInitialLoad = ref(false)
const manager = useWidgetLayoutManager({
storageKey: 'opsdash.widgets.test',
widgetsRegistry: {
test_widget: {
label: 'Test Widget',
defaultLayout: { width: 'half', height: 'm', order: 10 },
},
},
createDefaultTabs: () => ({
tabs: [{ id: 'tab-1', label: 'Overview', widgets: [] }],
defaultTabId: 'tab-1',
}),
normalizeWidgetTabs: (input, fallback) => (input ? input : fallback),
dashboardMode: ref('standard'),
deckEnabled: ref(true),
hasInitialLoad,
queueSaveRef: ref(queueSave),
})
manager.addWidget('test_widget')
expect(queueSave).not.toHaveBeenCalled()
hasInitialLoad.value = true
await nextTick()
expect(queueSave).toHaveBeenCalledWith(false)
})
it('adds and renames tabs without mutating other tabs', () => {
const manager = makeManager()
manager.addTab('Reports')
expect(manager.layoutTabs.value).toHaveLength(2)
expect(manager.activeTabId.value).toBe(manager.layoutTabs.value[1].id)
manager.renameTab(manager.layoutTabs.value[1].id, 'Weekly')
expect(manager.layoutTabs.value[1].label).toBe('Weekly')
expect(manager.layoutTabs.value[0].label).toBe('Overview')
})
it('applies the complete dashboard template, including Workspace widgets', () => {
const dashboardMode = ref<'quick' | 'standard' | 'pro'>('standard')
const manager = useWidgetLayoutManager({
storageKey: 'opsdash.widgets.test',
widgetsRegistry: registry,
createDefaultTabs: () => dashboardMode.value === 'pro'
? {
tabs: [
{ id: 'tab-1', label: 'Overview', widgets: [
{ id: 'legacy-deck-stats', type: 'deck_stats', options: {}, layout: { width: 'half', height: 'm', order: 30 }, version: 1 },
] },
{ id: 'workspace', label: 'Workspace', widgets: [
{ id: 'deck-cards', type: 'deck_cards', options: {}, layout: { width: 'half', height: 'xl', order: 89 }, version: 1 },
{ id: 'calendar-stats', type: 'calendar_stats', options: {}, layout: { width: 'quarter', height: 'xl', order: 99 }, version: 1 },
] },
],
defaultTabId: 'tab-1',
}
: { tabs: [{ id: 'tab-1', label: 'Overview', widgets: [] }], defaultTabId: 'tab-1' },
normalizeWidgetTabs: (input, fallback) => (input ? input : fallback),
dashboardMode,
deckEnabled: ref(true),
hasInitialLoad: ref(true),
queueSaveRef: ref(vi.fn()),
})
manager.applyDashboardPreset('pro')
expect(manager.layoutTabs.value.map((tab) => tab.label)).toEqual(['Overview', 'Workspace'])
expect(manager.layoutTabs.value[0].widgets).toEqual([])
expect(manager.layoutTabs.value[1].widgets.map((widget) => widget.type)).toEqual(['deck_cards', 'calendar_stats'])
expect(manager.defaultTabId.value).toBe('tab-1')
expect(manager.activeTabId.value).toBe('tab-1')
})
it('switches active widgets per tab', () => {
const manager = makeManager()
manager.addWidget('test_widget')
const firstTabId = manager.activeTabId.value
const firstTabWidgets = manager.widgets.value
expect(firstTabWidgets).toHaveLength(1)
manager.addTab('Secondary')
expect(manager.widgets.value).toHaveLength(0)
manager.setActiveTab(firstTabId)
expect(manager.widgets.value).toHaveLength(1)
})
it('removes tabs and keeps a valid default', () => {
const manager = makeManager()
manager.addTab('Secondary')
const firstTabId = manager.layoutTabs.value[0].id
const secondTabId = manager.layoutTabs.value[1].id
manager.setDefaultTab(secondTabId)
expect(manager.defaultTabId.value).toBe(secondTabId)
manager.removeTab(secondTabId)
expect(manager.layoutTabs.value).toHaveLength(1)
expect(manager.defaultTabId.value).toBe(firstTabId)
expect(manager.activeTabId.value).toBe(firstTabId)
})
it('moves widgets to another tab and activates the destination tab', () => {
const manager = makeManager()
manager.addWidget('test_widget')
manager.addTab('Secondary')
const sourceTabId = manager.layoutTabs.value[0].id
const targetTabId = manager.layoutTabs.value[1].id
const widgetId = manager.layoutTabs.value[0].widgets[0].id
manager.setActiveTab(sourceTabId)
const moved = manager.moveWidgetToTab(widgetId, targetTabId)
expect(moved).toBe(true)
expect(manager.activeTabId.value).toBe(targetTabId)
expect(manager.layoutTabs.value[0].widgets).toHaveLength(0)
expect(manager.layoutTabs.value[1].widgets).toHaveLength(1)
expect(manager.layoutTabs.value[1].widgets[0].id).toBe(widgetId)
})
it('duplicates widgets into another tab without removing the source widget', () => {
const manager = makeManager()
manager.addWidget('test_widget')
manager.addTab('Secondary')
const sourceTabId = manager.layoutTabs.value[0].id
const targetTabId = manager.layoutTabs.value[1].id
const widgetId = manager.layoutTabs.value[0].widgets[0].id
manager.setActiveTab(sourceTabId)
const duplicateId = manager.duplicateWidgetToTab(widgetId, targetTabId)
expect(duplicateId).toBeTruthy()
expect(manager.layoutTabs.value[0].widgets).toHaveLength(1)
expect(manager.layoutTabs.value[1].widgets).toHaveLength(1)
expect(manager.layoutTabs.value[1].widgets[0].id).not.toBe(widgetId)
expect(manager.layoutTabs.value[1].widgets[0].type).toBe('test_widget')
})
it('hides deck widget types when Deck is disabled', () => {
const deckEnabled = ref(false)
const manager = useWidgetLayoutManager({
storageKey: 'opsdash.widgets.test',
widgetsRegistry: {
deck_cards: {
label: 'Deck cards',
defaultLayout: { width: 'half', height: 'm', order: 10 },
},
deck_stats: {
label: 'Deck stats',
defaultLayout: { width: 'half', height: 'm', order: 20 },
},
},
createDefaultTabs: () => ({
tabs: [{
id: 'tab-1',
label: 'Overview',
widgets: [
{ id: 'deck-cards', type: 'deck_cards', options: {}, layout: { width: 'half', height: 'm', order: 10 }, version: 1 },
{ id: 'deck-stats', type: 'deck_stats', options: {}, layout: { width: 'half', height: 'm', order: 20 }, version: 1 },
],
}],
defaultTabId: 'tab-1',
}),
normalizeWidgetTabs: (input, fallback) => (input ? input : fallback),
dashboardMode: ref('standard'),
deckEnabled,
hasInitialLoad: ref(true),
queueSaveRef: ref(vi.fn()),
})
expect(manager.widgets.value).toEqual([])
deckEnabled.value = true
expect(manager.widgets.value.map((widget) => widget.type)).toEqual(['deck_cards', 'deck_stats'])
})
})