Files
workavia-calendar-front/__test__/features/Events/updateEventHelpers/updateAttendeesAfterTimeChange.test.ts
T
lethemanh cadfa70e60 #708 apply strictier linting rules (#717)
* #708 apply strictier linting rules and fix simple eslint bugs

* #708 fix eslint errors relate to promise

* #708 fix eslint import/no-extraneous-dependencies

* #708 fix eslint errors of react-hook

* #708 enable eslint check for typescript

---------

Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
2026-04-01 17:15:10 +02:00

214 lines
7.3 KiB
TypeScript

import { CalendarEvent } from '@/features/Events/EventsTypes'
import { updateAttendeesAfterTimeChange } from '@/features/Events/updateEventHelpers/updateAttendeesAfterTimeChange'
import { userAttendee } from '@/features/User/models/attendee'
import { userOrganiser } from '@/features/User/userDataTypes'
describe('updateAttendeesAfterTimeChange', () => {
const mockAttendee: userAttendee = {
cal_address: 'attendee@example.com',
partstat: 'ACCEPTED',
rsvp: 'FALSE',
role: 'REQ-PARTICIPANT',
cutype: 'INDIVIDUAL',
cn: 'attendee'
}
const mockOrganizer: userOrganiser = {
cn: 'Organizer',
cal_address: 'organizer@example.com'
}
const organizerAttendee: userAttendee = {
cal_address: 'organizer@example.com',
partstat: 'ACCEPTED',
rsvp: 'FALSE',
role: 'CHAIR',
cutype: 'INDIVIDUAL',
cn: 'organizer'
}
const baseEvent: CalendarEvent = {
uid: 'test-event',
URL: '/calendar/667037022b752d0026472254/cal1/test-event.ics',
title: 'Test Event',
calId: '667037022b752d0026472254/cal1',
start: '2025-01-15T07:00:00.000Z',
end: '2025-01-15T08:00:00.000Z',
allday: false,
organizer: mockOrganizer,
attendee: [mockAttendee, organizerAttendee],
timezone: 'ETC/UTC'
}
describe('early returns', () => {
it('should return the event unchanged when attendee list is undefined', () => {
const event = { ...baseEvent, attendee: undefined }
const result = updateAttendeesAfterTimeChange(
event as unknown as CalendarEvent
)
expect(result).toBe(event)
})
it('should NOT bail out early when organizer is undefined', () => {
const event = { ...baseEvent, organizer: undefined }
const result = updateAttendeesAfterTimeChange(event)
expect(result.attendee).toBeDefined()
expect(result.attendee).toHaveLength(2)
})
})
describe('without provided attendees list', () => {
it('should return attendees unchanged when timeChanged is false', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, false)
expect(result.attendee?.[0].partstat).toBe('ACCEPTED')
expect(result.attendee?.[0].rsvp).toBe('FALSE')
})
it('should mark non-organizer attendees as NEEDS-ACTION when timeChanged is true', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, true)
const attendee = result.attendee?.find(
a => a.cal_address === 'attendee@example.com'
)
expect(attendee?.partstat).toBe('NEEDS-ACTION')
expect(attendee?.rsvp).toBe('TRUE')
})
it('should NOT mark the organizer as NEEDS-ACTION when timeChanged is true', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, true)
const organizer = result.attendee?.find(
a => a.cal_address === 'organizer@example.com'
)
expect(organizer?.partstat).toBe('ACCEPTED')
expect(organizer?.rsvp).toBe('FALSE')
})
it('should return attendees unchanged when timeChanged is undefined', () => {
const result = updateAttendeesAfterTimeChange(baseEvent)
expect(result.attendee?.[0].partstat).toBe('ACCEPTED')
})
})
describe('with provided attendees list', () => {
const newAttendee: userAttendee = {
cal_address: 'new@example.com',
partstat: 'ACCEPTED',
rsvp: 'FALSE',
role: 'REQ-PARTICIPANT',
cutype: 'INDIVIDUAL',
cn: 'new'
}
it('should use existing attendee data when the address already exists in the event', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, false, [
mockAttendee
])
const attendee = result.attendee?.find(
a => a.cal_address === 'attendee@example.com'
)
expect(attendee?.partstat).toBe('ACCEPTED')
})
it('should mark new attendee as NEEDS-ACTION when not found in existing list', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, false, [
newAttendee
])
const attendee = result.attendee?.find(
a => a.cal_address === 'new@example.com'
)
expect(attendee?.partstat).toBe('NEEDS-ACTION')
expect(attendee?.rsvp).toBe('TRUE')
})
it('should mark all attendees as NEEDS-ACTION when timeChanged is true', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, true, [
mockAttendee,
newAttendee
])
const nonOrganizerAttendees = result.attendee?.filter(
a => a.cal_address !== 'organizer@example.com'
)
nonOrganizerAttendees?.forEach(a => {
expect(a.partstat).toBe('NEEDS-ACTION')
expect(a.rsvp).toBe('TRUE')
})
})
it('should append organizer entry at the end of the attendee list', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, false, [
mockAttendee
])
const last = result.attendee?.[result.attendee.length - 1]
expect(last?.cal_address).toBe('organizer@example.com')
})
it('should use existing organizer attendee data when found in event attendees', () => {
const result = updateAttendeesAfterTimeChange(baseEvent, false, [
mockAttendee
])
const organizer = result.attendee?.find(
a => a.cal_address === 'organizer@example.com'
)
expect(organizer?.partstat).toBe('ACCEPTED')
})
it('should fall back to organizer defaults when organizer is not in existing attendees', () => {
const eventWithoutOrganizerInAttendees: CalendarEvent = {
...baseEvent,
attendee: [mockAttendee] // organizer not in attendee list
}
const result = updateAttendeesAfterTimeChange(
eventWithoutOrganizerInAttendees,
false,
[mockAttendee]
)
const organizer = result.attendee?.find(
a => a.cal_address === 'organizer@example.com'
)
expect(organizer?.role).toBe('CHAIR')
expect(organizer?.partstat).toBe('NEEDS-ACTION')
})
})
describe('organizer undefined', () => {
const eventNoOrganizer: CalendarEvent = {
...baseEvent,
organizer: undefined
}
it('should return attendees without bailing out', () => {
const result = updateAttendeesAfterTimeChange(eventNoOrganizer)
expect(result.attendee).toHaveLength(2)
})
it('should mark attendees as NEEDS-ACTION when timeChanged is true', () => {
const result = updateAttendeesAfterTimeChange(eventNoOrganizer, true)
result.attendee?.forEach(a => {
expect(a.partstat).toBe('NEEDS-ACTION')
expect(a.rsvp).toBe('TRUE')
})
})
it('should not mutate attendees when timeChanged is false', () => {
const result = updateAttendeesAfterTimeChange(eventNoOrganizer, false)
expect(result.attendee?.[0].partstat).toBe('ACCEPTED')
expect(result.attendee?.[0].rsvp).toBe('FALSE')
})
it('should not append an organizer entry when organizer is undefined and attendees list is provided', () => {
const newAttendee: userAttendee = {
cal_address: 'new@example.com',
partstat: 'ACCEPTED',
rsvp: 'FALSE',
role: 'REQ-PARTICIPANT',
cutype: 'INDIVIDUAL',
cn: 'new'
}
const result = updateAttendeesAfterTimeChange(eventNoOrganizer, false, [
newAttendee
])
expect(result.attendee).toHaveLength(1)
expect(result.attendee?.[0].cal_address).toBe('new@example.com')
})
})
})