Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m8s
- 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>
184 lines
5.5 KiB
TypeScript
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()
|
|
}
|
|
})
|
|
})
|