Files
chore/frontend/src/components/routine/__tests__/RoutineComponents.spec.ts
T
ryanandCopilot 5392e5af70
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m8s
Add routine management features for child and parent views
- Implemented routine child-mode flow tests to ensure proper functionality of routine assignment and task completion.
- Created notification tests for parent view to verify routine completion notifications for children.
- Developed ChildRoutineOverlay component for displaying routine tasks and handling user interactions.
- Added RoutineApproveDialog component for approving or rejecting completed routines.
- Created unit tests for ChildRoutineOverlay and RoutineEditView components to ensure correct behavior and rendering.
- Enhanced RoutineEditView with proper handling of task addition and form submission.

Co-authored-by: Copilot <copilot@github.com>
2026-05-17 23:47:12 -04:00

184 lines
5.5 KiB
TypeScript

// Unit tests for routine components.
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount } from '@vue/test-utils'
import RoutineEditView from '@/components/routine/RoutineEditView.vue'
import RoutineConfirmDialog from '@/components/child/RoutineConfirmDialog.vue'
import ModalDialog from '@/components/shared/ModalDialog.vue'
// Mock fetch globally
global.fetch = vi.fn()
describe('RoutineEditView.vue', () => {
beforeEach(() => {
vi.clearAllMocks()
;(global.fetch as ReturnType<typeof vi.fn>).mockClear()
})
it('renders create form heading when no id prop provided', async () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
expect(wrapper.text()).toContain('Create Routine')
})
it('renders name and points inputs', () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
// EntityEditForm renders inputs with id matching field.name
expect(wrapper.find('input[id="name"]').exists()).toBe(true)
expect(wrapper.find('input[id="points"]').exists()).toBe(true)
})
it('shows Routine Tasks section', () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
expect(wrapper.text()).toContain('Routine Tasks')
})
it('shows empty state message when no tasks added', () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
expect(wrapper.text()).toContain('Add at least one task')
})
it('shows Add Task button by default', () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
expect(wrapper.text()).toContain('Add Task')
})
it('opens item form when Add Task button clicked', async () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
const addBtn = wrapper.find('.add-task-trigger')
expect(addBtn.exists()).toBe(true)
await addBtn.trigger('click')
// Item form should appear with a task name input
expect(wrapper.find('input[id="item-name"]').exists()).toBe(true)
})
it('allows typing a task name in the add form', async () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
await wrapper.find('.add-task-trigger').trigger('click')
const itemInput = wrapper.find('input[id="item-name"]')
await itemInput.setValue('Make Bed')
expect((itemInput.element as HTMLInputElement).value).toBe('Make Bed')
})
it('adds item to list when Add button clicked with valid name', async () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
await wrapper.find('.add-task-trigger').trigger('click')
await wrapper.find('input[id="item-name"]').setValue('Make Bed')
await wrapper.find('.item-form-actions .btn-primary').trigger('click')
await wrapper.vm.$nextTick()
// The item name should now appear in the list
expect(wrapper.text()).toContain('Make Bed')
})
it('renders Cancel and Create buttons', () => {
const wrapper = mount(RoutineEditView, {
props: { id: undefined },
})
const text = wrapper.text()
expect(text).toContain('Cancel')
expect(text).toContain('Create')
})
it('renders edit heading when id prop provided', async () => {
;(global.fetch as ReturnType<typeof vi.fn>)
.mockResolvedValueOnce({
ok: true,
json: async () => ({
id: 'r1',
name: 'Morning Routine',
points: 50,
image_id: null,
image_url: null,
}),
})
.mockResolvedValueOnce({
ok: true,
json: async () => ({ items: [] }),
})
const wrapper = mount(RoutineEditView, {
props: { id: 'r1' },
})
await wrapper.vm.$nextTick()
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Edit Routine')
})
})
describe('RoutineConfirmDialog.vue', () => {
const routine = {
id: 'r1',
name: 'Morning Routine',
points: 20,
custom_value: null,
image_id: null,
image_url: null,
pending_status: null,
pending_confirmation_id: null,
schedule: null,
items: [],
}
it('displays routine name', () => {
const wrapper = mount(RoutineConfirmDialog, {
props: { routine, childName: 'Timmy' },
global: { components: { ModalDialog } },
})
expect(wrapper.text()).toContain('Morning Routine')
})
it('displays child name', () => {
const wrapper = mount(RoutineConfirmDialog, {
props: { routine, childName: 'Timmy' },
global: { components: { ModalDialog } },
})
expect(wrapper.text()).toContain('Timmy')
})
it('emits confirm event when Yes button clicked', async () => {
const wrapper = mount(RoutineConfirmDialog, {
props: { routine, childName: 'Timmy' },
global: { components: { ModalDialog } },
})
const buttons = wrapper.findAll('button')
const confirmBtn = buttons.find((b) => b.text().toLowerCase().includes('yes'))
if (confirmBtn) {
await confirmBtn.trigger('click')
expect(wrapper.emitted('confirm')).toBeTruthy()
}
})
it('emits cancel event when Cancel button clicked', async () => {
const wrapper = mount(RoutineConfirmDialog, {
props: { routine, childName: 'Timmy' },
global: { components: { ModalDialog } },
})
const buttons = wrapper.findAll('button')
const cancelBtn = buttons.find((b) => b.text().toLowerCase().includes('cancel'))
if (cancelBtn) {
await cancelBtn.trigger('click')
expect(wrapper.emitted('cancel')).toBeTruthy()
}
})
})