fix: update ParentView tests to use mount options and improve mock implementations
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m18s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m18s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||||
import { mount, VueWrapper } from '@vue/test-utils'
|
import { mount, VueWrapper } from '@vue/test-utils'
|
||||||
import { nextTick } from 'vue'
|
import { nextTick, defineComponent } from 'vue'
|
||||||
import ParentView from '../ParentView.vue'
|
import ParentView from '../ParentView.vue'
|
||||||
import { eventBus } from '@/common/eventBus'
|
import { eventBus } from '@/common/eventBus'
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ import { eventBus } from '@/common/eventBus'
|
|||||||
vi.mock('vue-router', () => ({
|
vi.mock('vue-router', () => ({
|
||||||
useRoute: vi.fn(() => ({
|
useRoute: vi.fn(() => ({
|
||||||
params: { id: 'child-123' },
|
params: { id: 'child-123' },
|
||||||
|
query: {},
|
||||||
})),
|
})),
|
||||||
useRouter: vi.fn(() => ({
|
useRouter: vi.fn(() => ({
|
||||||
push: vi.fn(),
|
push: vi.fn(),
|
||||||
@@ -17,6 +18,15 @@ vi.mock('vue-router', () => ({
|
|||||||
vi.mock('@/common/api', () => ({
|
vi.mock('@/common/api', () => ({
|
||||||
setChildOverride: vi.fn(),
|
setChildOverride: vi.fn(),
|
||||||
parseErrorResponse: vi.fn(() => ({ msg: 'Test error', code: 'TEST_ERROR' })),
|
parseErrorResponse: vi.fn(() => ({ msg: 'Test error', code: 'TEST_ERROR' })),
|
||||||
|
extendChoreTime: vi.fn(),
|
||||||
|
approveChore: vi.fn(),
|
||||||
|
rejectChore: vi.fn(),
|
||||||
|
resetChore: vi.fn(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
vi.mock('@/common/imageCache', () => ({
|
||||||
|
getCachedImageUrl: vi.fn(() => Promise.resolve('/mock-image.png')),
|
||||||
|
revokeAllImageUrls: vi.fn(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
global.fetch = vi.fn()
|
global.fetch = vi.fn()
|
||||||
@@ -24,6 +34,51 @@ global.alert = vi.fn()
|
|||||||
|
|
||||||
import { setChildOverride, parseErrorResponse } from '@/common/api'
|
import { setChildOverride, parseErrorResponse } from '@/common/api'
|
||||||
|
|
||||||
|
// Stub for ScrollingList that exposes the same interface
|
||||||
|
const ScrollingListStub = defineComponent({
|
||||||
|
name: 'ScrollingList',
|
||||||
|
props: [
|
||||||
|
'title',
|
||||||
|
'fetchBaseUrl',
|
||||||
|
'ids',
|
||||||
|
'itemKey',
|
||||||
|
'imageField',
|
||||||
|
'imageFields',
|
||||||
|
'enableEdit',
|
||||||
|
'childId',
|
||||||
|
'readyItemId',
|
||||||
|
'isParentAuthenticated',
|
||||||
|
'filterFn',
|
||||||
|
'sortFn',
|
||||||
|
'getItemClass',
|
||||||
|
],
|
||||||
|
emits: ['trigger-item', 'edit-item', 'item-ready'],
|
||||||
|
setup(_, { expose }) {
|
||||||
|
const refresh = vi.fn()
|
||||||
|
const scrollToItem = vi.fn()
|
||||||
|
const centerItem = vi.fn()
|
||||||
|
expose({ refresh, items: [], centerItem, scrollToItem })
|
||||||
|
return { refresh, scrollToItem, centerItem }
|
||||||
|
},
|
||||||
|
template: '<div class="scrolling-list-stub"><slot /></div>',
|
||||||
|
})
|
||||||
|
|
||||||
|
const mountOptions = {
|
||||||
|
global: {
|
||||||
|
stubs: {
|
||||||
|
ScrollingList: ScrollingListStub,
|
||||||
|
ChildDetailCard: { template: '<div class="child-detail-stub" />' },
|
||||||
|
StatusMessage: { template: '<div class="status-stub" />' },
|
||||||
|
ModalDialog: { template: '<div class="modal-stub"><slot /></div>' },
|
||||||
|
ScheduleModal: { template: '<div class="schedule-stub" />' },
|
||||||
|
PendingRewardDialog: { template: '<div class="pending-reward-stub" />' },
|
||||||
|
TaskConfirmDialog: { template: '<div class="task-confirm-stub" />' },
|
||||||
|
RewardConfirmDialog: { template: '<div class="reward-confirm-stub" />' },
|
||||||
|
ChoreApproveDialog: { template: '<div class="chore-approve-stub" />' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
describe('ParentView', () => {
|
describe('ParentView', () => {
|
||||||
let wrapper: VueWrapper<any>
|
let wrapper: VueWrapper<any>
|
||||||
|
|
||||||
@@ -91,7 +146,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Component Mounting', () => {
|
describe('Component Mounting', () => {
|
||||||
it('loads and displays child data on mount', async () => {
|
it('loads and displays child data on mount', async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
|
|
||||||
@@ -100,7 +155,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
it('registers SSE event listeners on mount', async () => {
|
it('registers SSE event listeners on mount', async () => {
|
||||||
const onSpy = vi.spyOn(eventBus, 'on')
|
const onSpy = vi.spyOn(eventBus, 'on')
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
expect(onSpy).toHaveBeenCalledWith('child_task_triggered', expect.any(Function))
|
expect(onSpy).toHaveBeenCalledWith('child_task_triggered', expect.any(Function))
|
||||||
@@ -111,7 +166,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
it('unregisters SSE event listeners on unmount', async () => {
|
it('unregisters SSE event listeners on unmount', async () => {
|
||||||
const offSpy = vi.spyOn(eventBus, 'off')
|
const offSpy = vi.spyOn(eventBus, 'off')
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
wrapper.unmount()
|
wrapper.unmount()
|
||||||
@@ -123,7 +178,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Override Modal', () => {
|
describe('Override Modal', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
@@ -184,7 +239,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Save Override', () => {
|
describe('Save Override', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
@@ -229,7 +284,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('SSE Event Handlers', () => {
|
describe('SSE Event Handlers', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
@@ -248,13 +303,15 @@ describe('ParentView', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('handles child_override_set event and refreshes appropriate lists', async () => {
|
it('handles child_override_set event and refreshes appropriate lists', async () => {
|
||||||
const mockChoreRefresh = vi.fn()
|
const mockChoreRefresh = vi.fn().mockResolvedValue(undefined)
|
||||||
const mockPenaltyRefresh = vi.fn()
|
const mockPenaltyRefresh = vi.fn().mockResolvedValue(undefined)
|
||||||
const mockRewardRefresh = vi.fn()
|
const mockRewardRefresh = vi.fn().mockResolvedValue(undefined)
|
||||||
|
const mockKindnessRefresh = vi.fn().mockResolvedValue(undefined)
|
||||||
|
|
||||||
wrapper.vm.childChoreListRef = { refresh: mockChoreRefresh }
|
wrapper.vm.childChoreListRef = { refresh: mockChoreRefresh, scrollToItem: vi.fn() }
|
||||||
wrapper.vm.childPenaltyListRef = { refresh: mockPenaltyRefresh }
|
wrapper.vm.childKindnessListRef = { refresh: mockKindnessRefresh, scrollToItem: vi.fn() }
|
||||||
wrapper.vm.childRewardListRef = { refresh: mockRewardRefresh }
|
wrapper.vm.childPenaltyListRef = { refresh: mockPenaltyRefresh, scrollToItem: vi.fn() }
|
||||||
|
wrapper.vm.childRewardListRef = { refresh: mockRewardRefresh, scrollToItem: vi.fn() }
|
||||||
|
|
||||||
// Test task override
|
// Test task override
|
||||||
wrapper.vm.handleOverrideSet({
|
wrapper.vm.handleOverrideSet({
|
||||||
@@ -318,7 +375,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Ready Item State Management', () => {
|
describe('Ready Item State Management', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
@@ -339,7 +396,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Penalty Display', () => {
|
describe('Penalty Display', () => {
|
||||||
it('displays penalty values as negative in template', async () => {
|
it('displays penalty values as negative in template', async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
// The template should show -custom_value or -points for penalties
|
// The template should show -custom_value or -points for penalties
|
||||||
@@ -361,7 +418,7 @@ describe('ParentView', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
@@ -453,7 +510,7 @@ describe('ParentView', () => {
|
|||||||
|
|
||||||
describe('Chore Card Selection (selectedChoreId)', () => {
|
describe('Chore Card Selection (selectedChoreId)', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
wrapper = mount(ParentView)
|
wrapper = mount(ParentView, mountOptions)
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await new Promise((resolve) => setTimeout(resolve, 50))
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -89,13 +89,6 @@ async function refresh() {
|
|||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
refresh,
|
|
||||||
items,
|
|
||||||
centerItem,
|
|
||||||
scrollToItem,
|
|
||||||
})
|
|
||||||
|
|
||||||
const scrollToItem = async (itemId: string) => {
|
const scrollToItem = async (itemId: string) => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const card = itemRefs.value[itemId]
|
const card = itemRefs.value[itemId]
|
||||||
@@ -123,6 +116,13 @@ const centerItem = async (itemId: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
refresh,
|
||||||
|
items,
|
||||||
|
centerItem,
|
||||||
|
scrollToItem,
|
||||||
|
})
|
||||||
|
|
||||||
const handleClicked = async (item: any) => {
|
const handleClicked = async (item: any) => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
const wrapper = scrollWrapper.value
|
const wrapper = scrollWrapper.value
|
||||||
|
|||||||
Reference in New Issue
Block a user