Update frontend test for ci
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { setActivePinia, createPinia } from 'pinia'
|
||||
import { useAlertQualityStore } from './alertQuality'
|
||||
import { useAlertQualityStore } from '@/stores/alertQuality'
|
||||
|
||||
vi.mock('@/api/alertQuality', () => ({
|
||||
submitAlertFeedback: vi.fn().mockResolvedValue({ id: 'fb-1', createdAt: '2026-06-23T00:00:00Z' }),
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { useFeedbackStore } from '@/stores/feedback'
|
||||
|
||||
describe('useFeedbackStore', () => {
|
||||
const { submitAlertFeedback, fetchQualityMetricsSummary, fetchQualityMetrics } = vi.hoisted(() => ({
|
||||
submitAlertFeedback: vi.fn().mockResolvedValue({
|
||||
id: 'fb-1',
|
||||
createdAt: '2026-06-23T00:00:00Z',
|
||||
feedbackType: 'Useful',
|
||||
}),
|
||||
fetchQualityMetricsSummary: vi.fn().mockResolvedValue({
|
||||
totalAlerts: 10,
|
||||
totalFeedback: 4,
|
||||
acknowledgementRate: 0.8,
|
||||
usefulRate: 0.75,
|
||||
falsePositiveRate: 0.1,
|
||||
wouldActRate: 0.6,
|
||||
avgSecondsToAcknowledge: 300,
|
||||
avgSecondsToResolution: 1200,
|
||||
}),
|
||||
fetchQualityMetrics: vi.fn().mockResolvedValue({
|
||||
items: [
|
||||
{ alertType: 'SEPSIS_WARNING', usefulRate: 0.75, falsePositiveRate: 0.1, acknowledgementRate: 0.8, totalAlerts: 5 },
|
||||
{ alertType: 'WARNING_HEART_RATE', usefulRate: 0.5, falsePositiveRate: 0.2, acknowledgementRate: 0.7, totalAlerts: 5 },
|
||||
],
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/api/alertQuality', () => ({
|
||||
submitAlertFeedback,
|
||||
fetchQualityMetricsSummary,
|
||||
fetchQualityMetrics,
|
||||
FEEDBACK_TYPE_MAP: {
|
||||
useful: 'Useful',
|
||||
'false-positive': 'FalsePositive',
|
||||
'would-act': 'WouldAct',
|
||||
'too-early': 'TooEarly',
|
||||
},
|
||||
}))
|
||||
|
||||
describe('useFeedbackStore (compat shim)', () => {
|
||||
beforeEach(() => {
|
||||
localStorage.clear()
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createPinia())
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
it('addFeedback_delegatesToAlertQualityAndCaches', async () => {
|
||||
const store = useFeedbackStore()
|
||||
await store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
|
||||
expect(submitAlertFeedback).toHaveBeenCalledWith('a1', 'useful', '')
|
||||
expect(store.getFeedback('a1').rating).toBe('useful')
|
||||
})
|
||||
|
||||
it('addFeedback_createsEntry', () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
it('addFeedback_updatesCachedRating', async () => {
|
||||
submitAlertFeedback
|
||||
.mockResolvedValueOnce({ id: 'fb-1', createdAt: '2026-06-23T00:00:00Z', feedbackType: 'Useful' })
|
||||
.mockResolvedValueOnce({ id: 'fb-2', createdAt: '2026-06-23T00:01:00Z', feedbackType: 'FalsePositive' })
|
||||
|
||||
expect(store.entries).toHaveLength(1)
|
||||
expect(store.entries[0].alertId).toBe('a1')
|
||||
expect(store.entries[0].rating).toBe('useful')
|
||||
const store = useFeedbackStore()
|
||||
await store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
await store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'false-positive')
|
||||
|
||||
expect(store.getFeedback('a1').rating).toBe('false-positive')
|
||||
})
|
||||
|
||||
it('addFeedback_updatesExisting', () => {
|
||||
it('stats_mapsFromQualitySummary', async () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'false-positive')
|
||||
const { useAlertQualityStore } = await import('@/stores/alertQuality')
|
||||
await useAlertQualityStore().loadDashboard()
|
||||
|
||||
expect(store.entries).toHaveLength(1)
|
||||
expect(store.entries[0].rating).toBe('false-positive')
|
||||
expect(store.stats.value.total).toBe(4)
|
||||
expect(store.stats.value.usefulPct).toBe(75)
|
||||
expect(store.stats.value.fpPct).toBe(10)
|
||||
})
|
||||
|
||||
it('stats_computesCorrectly', () => {
|
||||
it('byAlertType_groupsSnapshots', async () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
store.addFeedback('a2', 'SEPSIS_WARNING', 'CRITICAL', 'would-act')
|
||||
store.addFeedback('a3', 'WARNING_HEART_RATE', 'WARNING', 'false-positive')
|
||||
store.addFeedback('a4', 'WARNING_HEART_RATE', 'WARNING', 'too-early')
|
||||
const { useAlertQualityStore } = await import('@/stores/alertQuality')
|
||||
await useAlertQualityStore().loadDashboard()
|
||||
|
||||
expect(store.stats.total).toBe(4)
|
||||
expect(store.stats.useful).toBe(2)
|
||||
expect(store.stats.falsePositive).toBe(1)
|
||||
expect(store.stats.usefulPct).toBe(50)
|
||||
expect(store.stats.fpPct).toBe(25)
|
||||
expect(Object.keys(store.byAlertType.value)).toHaveLength(2)
|
||||
expect(store.byAlertType.value.SEPSIS_WARNING).toHaveLength(1)
|
||||
expect(store.byAlertType.value.WARNING_HEART_RATE).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('byAlertType_groupsCorrectly', () => {
|
||||
it('entries_isEmptyCompatStub', () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
store.addFeedback('a2', 'WARNING_HEART_RATE', 'WARNING', 'false-positive')
|
||||
store.addFeedback('a3', 'SEPSIS_WARNING', 'CRITICAL', 'too-early')
|
||||
|
||||
expect(Object.keys(store.byAlertType)).toHaveLength(2)
|
||||
expect(store.byAlertType.SEPSIS_WARNING).toHaveLength(2)
|
||||
expect(store.byAlertType.WARNING_HEART_RATE).toHaveLength(1)
|
||||
expect(store.entries.value).toEqual([])
|
||||
})
|
||||
|
||||
it('exportAsJson_generatesValidJson', () => {
|
||||
it('exportAndClearAreNoOps', () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
|
||||
let capturedBlob = null
|
||||
const click = vi.fn()
|
||||
const originalCreateElement = document.createElement.bind(document)
|
||||
|
||||
URL.createObjectURL = vi.fn((blob) => {
|
||||
capturedBlob = blob
|
||||
return 'blob:url'
|
||||
})
|
||||
URL.revokeObjectURL = vi.fn()
|
||||
vi.spyOn(document, 'createElement').mockImplementation((tag) => {
|
||||
if (tag === 'a') return { href: '', download: '', click }
|
||||
return originalCreateElement(tag)
|
||||
})
|
||||
|
||||
expect(() => store.exportAsJson()).not.toThrow()
|
||||
expect(capturedBlob).toBeInstanceOf(Blob)
|
||||
expect(capturedBlob.type).toBe('application/json')
|
||||
expect(click).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('clearAll_emptiesEntries', () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
store.clearAll()
|
||||
|
||||
expect(store.entries).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('persistsToLocalStorage', () => {
|
||||
const store = useFeedbackStore()
|
||||
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem('vigilcare-feedback'))
|
||||
expect(stored).toHaveLength(1)
|
||||
expect(stored[0].rating).toBe('useful')
|
||||
expect(() => store.exportAsCsv()).not.toThrow()
|
||||
expect(() => store.clearAll()).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { computed } from 'vue'
|
||||
import { useAlertQualityStore } from './alertQuality'
|
||||
|
||||
/**
|
||||
* Compatibility shim for pre–Phase 33 feedback consumers.
|
||||
* Feedback submission and analytics now live in useAlertQualityStore;
|
||||
* /feedback redirects to /analytics/alerts.
|
||||
*/
|
||||
export function useFeedbackStore() {
|
||||
const store = useAlertQualityStore()
|
||||
return {
|
||||
@@ -10,7 +15,7 @@ export function useFeedbackStore() {
|
||||
usefulPct: store.summaryStats.usefulRate,
|
||||
fpPct: store.summaryStats.falsePositiveRate,
|
||||
})),
|
||||
byAlertType: store.byAlertType,
|
||||
byAlertType: computed(() => store.byAlertType),
|
||||
addFeedback: (alertId, _type, _severity, rating, notes) =>
|
||||
store.submitFeedback(alertId, rating, notes),
|
||||
getFeedback: store.getFeedback,
|
||||
|
||||
Reference in New Issue
Block a user