1 import { MAX_ATTENDEES } from '@proton/shared/lib/calendar/constants';
2 import { ADDRESS_SEND } from '@proton/shared/lib/constants';
3 import { addressBuilder } from '@proton/testing/lib/builders';
6 getCanChangeCalendarOfEvent,
10 getCanEditSharedEventData,
13 getIsAvailableCalendar,
16 describe('getCannotSaveEvent()', () => {
17 test('Member cannot create invites in a shared calendar', () => {
18 const isOwnedCalendar = false;
19 const isOrganizer = true;
20 const numberOfAttendees = MAX_ATTENDEES - 1;
21 const canEditSharedEventData = true;
23 expect(getCannotSaveEvent({ isOwnedCalendar, isOrganizer, numberOfAttendees, canEditSharedEventData })).toEqual(
28 test('Owner can create invites in a personal calendar', () => {
29 const isOwnedCalendar = true;
30 const isOrganizer = true;
31 const numberOfAttendees = MAX_ATTENDEES - 1;
32 const canEditSharedEventData = true;
34 expect(getCannotSaveEvent({ isOwnedCalendar, isOrganizer, numberOfAttendees, canEditSharedEventData })).toEqual(
39 test('Owner cannot create invites with too many participants', () => {
40 const isOwnedCalendar = true;
41 const isOrganizer = true;
42 const numberOfAttendees = MAX_ATTENDEES + 1;
43 const canEditSharedEventData = true;
50 canEditSharedEventData,
51 maxAttendees: MAX_ATTENDEES,
56 test('Attendee can add notifications to invite in a personal calendar', () => {
57 const isOwnedCalendar = true;
58 const isOrganizer = false;
59 const numberOfAttendees = MAX_ATTENDEES - 1;
60 const canEditSharedEventData = false;
62 expect(getCannotSaveEvent({ isOwnedCalendar, isOrganizer, numberOfAttendees, canEditSharedEventData })).toEqual(
67 test('Attendee can add notifications to invite in a shared calendar', () => {
68 const isOwnedCalendar = false;
69 const isOrganizer = false;
70 const numberOfAttendees = MAX_ATTENDEES - 1;
71 const canEditSharedEventData = false;
73 expect(getCannotSaveEvent({ isOwnedCalendar, isOrganizer, numberOfAttendees, canEditSharedEventData })).toEqual(
78 test('Member can add notifications to an invite she organized in a shared calendar', () => {
79 const isOwnedCalendar = false;
80 const isOrganizer = true;
81 const numberOfAttendees = 10;
82 const canEditSharedEventData = false;
84 expect(getCannotSaveEvent({ isOwnedCalendar, isOrganizer, numberOfAttendees, canEditSharedEventData })).toEqual(
90 describe('getCanEditEvent()', () => {
91 test('User can edit events only if the calendar is of known type and is not disabled', () => {
92 const combinations = [];
93 for (let i = 0; i < 2 ** 2; i++) {
94 const isUnknownCalendar = !!(1 & i);
95 const isCalendarDisabled = !!(2 & i);
97 combinations.push({ isUnknownCalendar, isCalendarDisabled });
99 combinations.forEach(({ isUnknownCalendar, isCalendarDisabled }) => {
105 ).toEqual(!isCalendarDisabled && !isUnknownCalendar);
110 describe('getCanDeleteEvent()', () => {
111 test('User cannot delete events in subscribed or other read-only calendars', () => {
112 const combinations = [];
113 for (let i = 0; i < 2 ** 2; i++) {
114 const isOwnedCalendar = !!(1 & i);
115 const isInvitation = !!(2 & i);
117 combinations.push({ isOwnedCalendar, isInvitation });
119 combinations.forEach(({ isOwnedCalendar, isInvitation }) => {
123 isCalendarWritable: false,
130 test('Attendee can delete invites in her own calendar', () => {
131 const isOwnedCalendar = true;
132 const isCalendarWritable = true;
133 const isInvitation = true;
135 expect(getCanDeleteEvent({ isOwnedCalendar, isCalendarWritable, isInvitation })).toEqual(true);
138 test('Member cannot delete invites in a shared calendar with edit rights', () => {
139 const isOwnedCalendar = false;
140 const isCalendarWritable = true;
141 const isInvitation = true;
143 expect(getCanDeleteEvent({ isOwnedCalendar, isCalendarWritable, isInvitation })).toEqual(false);
146 test('Member cannot delete invites in a shared calendar with view-only rights', () => {
147 const isOwnedCalendar = false;
148 const isCalendarWritable = false;
149 const isInvitation = true;
151 expect(getCanDeleteEvent({ isOwnedCalendar, isCalendarWritable, isInvitation })).toEqual(false);
155 describe('getCanEditSharedEventData()', () => {
156 const activeAddress = addressBuilder();
157 const cannotSendAddress = {
159 Send: ADDRESS_SEND.SEND_NO,
162 test('Owner can edit shared event data of events which are not invitations', () => {
164 getCanEditSharedEventData({
165 isOwnedCalendar: true,
166 isCalendarWritable: true,
170 selfAddress: undefined,
175 test('Owner can edit shared event data of events she organizes if the address is active', () => {
177 getCanEditSharedEventData({
178 isOwnedCalendar: true,
179 isCalendarWritable: true,
183 selfAddress: activeAddress,
188 test('Owner cannot edit shared event data of events she organizes if the address cannot send', () => {
190 getCanEditSharedEventData({
191 isOwnedCalendar: true,
192 isCalendarWritable: true,
196 selfAddress: cannotSendAddress,
201 test('User cannot edit shared event data in subscribed calendars or other read-only calendars', () => {
202 const combinations = [];
203 for (let i = 0; i < 2 ** 3; i++) {
204 const isOrganizer = !!(1 & i);
205 const isAttendee = !!(2 & i);
206 const isInvitation = isOrganizer || isAttendee || !!(4 & i);
207 const selfAddress = isOrganizer || isAttendee ? activeAddress : undefined;
209 combinations.push({ isOrganizer, isAttendee, isInvitation, selfAddress });
211 combinations.forEach(({ isOrganizer, isAttendee, isInvitation, selfAddress }) => {
213 getCanEditSharedEventData({
214 isOwnedCalendar: true,
215 isCalendarWritable: false,
225 test('Member cannot edit shared event data in shared calendars with view-only rights', () => {
226 const combinations = [];
227 for (let i = 0; i < 2 ** 3; i++) {
228 const isOrganizer = !!(1 & i);
229 const isAttendee = !!(2 & i);
230 const isInvitation = isOrganizer || isAttendee || !!(4 & i);
231 const selfAddress = isOrganizer || isAttendee ? activeAddress : undefined;
233 combinations.push({ isOrganizer, isAttendee, isInvitation, selfAddress });
235 combinations.forEach(({ isOrganizer, isAttendee, isInvitation, selfAddress }) => {
237 getCanEditSharedEventData({
238 isOwnedCalendar: false,
239 isCalendarWritable: false,
249 test('Member with edit rights cannot edit shared event data of invitations', () => {
250 const combinations = [];
251 for (let i = 0; i < 2 ** 2; i++) {
252 const isOrganizer = !!(1 & i);
253 const isAttendee = !!(2 & i);
254 const selfAddress = isOrganizer || isAttendee ? activeAddress : undefined;
256 combinations.push({ isOrganizer, isAttendee, selfAddress });
258 combinations.forEach(({ isOrganizer, isAttendee, selfAddress }) => {
260 getCanEditSharedEventData({
261 isOwnedCalendar: false,
262 isCalendarWritable: true,
272 test('Member with view-only rights cannot edit invitations', () => {
273 const combinations = [];
274 for (let i = 0; i < 2 ** 2; i++) {
275 const isOrganizer = !!(1 & i);
276 const isAttendee = !!(2 & i);
277 const selfAddress = isOrganizer || isAttendee ? activeAddress : undefined;
279 combinations.push({ isOrganizer, isAttendee, selfAddress });
281 combinations.forEach(({ isOrganizer, isAttendee, selfAddress }) => {
283 getCanEditSharedEventData({
284 isOwnedCalendar: false,
285 isCalendarWritable: false,
295 test('User cannot edit invitations in owned calendars if she is not organizing or attending', () => {
297 getCanEditSharedEventData({
298 isOwnedCalendar: true,
299 isCalendarWritable: true,
303 selfAddress: undefined,
309 describe('getCanChangeCalendar()', () => {
310 test('User can change calendar of events that are not invitations', () => {
311 const combinations = [];
312 for (let i = 0; i < 2 ** 2; i++) {
313 const isOwnedCalendar = !!(1 & i);
314 const isSingleEdit = !!(2 & i);
316 combinations.push({ isOwnedCalendar, isSingleEdit });
318 combinations.forEach(({ isOwnedCalendar, isSingleEdit }) => {
320 getCanChangeCalendarOfEvent({
321 isCreateEvent: false,
323 isCalendarWritable: true,
333 test('User creating event can change calendar', () => {
334 const combinations = [];
335 for (let i = 0; i < 2 ** 2; i++) {
336 const isOwnedCalendar = !!(1 & i);
337 const isOrganizer = !!(2 & i);
338 const isInvitation = isOrganizer;
340 combinations.push({ isOwnedCalendar, isOrganizer, isInvitation });
342 combinations.forEach(({ isOwnedCalendar, isInvitation, isOrganizer }) => {
344 getCanChangeCalendarOfEvent({
347 isCalendarWritable: true,
357 test('User cannot change calendar of event in non-writable calendar', () => {
358 const combinations = [];
359 for (let i = 0; i < 2 ** 5; i++) {
360 const isOwnedCalendar = !!(1 & i);
361 const isSingleEdit = !!(2 & i);
362 const isOrganizer = !!(4 & i);
363 const isAttendee = isOrganizer ? false : !!(8 & i);
364 const isInvitation = isOrganizer || isAttendee ? true : !!(16 & i);
366 combinations.push({ isOwnedCalendar, isSingleEdit, isInvitation, isOrganizer, isAttendee });
368 combinations.forEach(({ isOwnedCalendar, isSingleEdit, isInvitation, isOrganizer, isAttendee }) => {
370 getCanChangeCalendarOfEvent({
371 isCreateEvent: false,
373 isCalendarWritable: false,
383 test('Member cannot change calendar of non-organized invitation in shared calendar', () => {
384 const combinations = [];
385 for (let i = 0; i < 2 ** 2; i++) {
386 const isSingleEdit = !!(1 & i);
387 const isAttendee = !!(2 & i);
389 combinations.push({ isSingleEdit, isAttendee });
391 combinations.forEach(({ isSingleEdit, isAttendee }) => {
393 getCanChangeCalendarOfEvent({
394 isCreateEvent: false,
395 isOwnedCalendar: false,
396 isCalendarWritable: true,
406 test('Organizer cannot change calendar existing invitation', () => {
407 const combinations = [];
408 for (let i = 0; i < 2 ** 3; i++) {
409 const isOwnedCalendar = !!(1 & i);
410 const isCalendarWritable = !!(2 & i);
411 const isSingleEdit = !!(4 & i);
413 combinations.push({ isOwnedCalendar, isCalendarWritable, isSingleEdit });
415 combinations.forEach(({ isOwnedCalendar, isCalendarWritable, isSingleEdit }) => {
417 getCanChangeCalendarOfEvent({
418 isCreateEvent: false,
430 test('Attendee can change calendar in owned calendars if the event is not a single edit', () => {
432 getCanChangeCalendarOfEvent({
433 isCreateEvent: false,
434 isOwnedCalendar: true,
435 isCalendarWritable: true,
443 getCanChangeCalendarOfEvent({
444 isCreateEvent: false,
445 isOwnedCalendar: true,
446 isCalendarWritable: true,
456 describe('getIsAvailableCalendar()', () => {
457 test('User cannot change calendar of events to subscribed or other read-only calendars', () => {
458 const combinations = [];
459 for (let i = 0; i < 2 ** 2; i++) {
460 const isOwnedCalendar = !!(1 & i);
461 const isInvitation = !!(2 & i);
463 combinations.push({ isOwnedCalendar, isInvitation });
465 combinations.forEach(({ isOwnedCalendar, isInvitation }) => {
467 getIsAvailableCalendar({
469 isCalendarWritable: false,
476 test('Invitations can only be changed to owned calendars', () => {
477 const combinations = [];
478 for (let i = 0; i < 2 ** 2; i++) {
479 const isOwnedCalendar = !!(1 & i);
480 const isCalendarWritable = isOwnedCalendar || !!(2 & i);
482 combinations.push({ isOwnedCalendar, isCalendarWritable });
484 combinations.forEach(({ isOwnedCalendar, isCalendarWritable }) => {
486 getIsAvailableCalendar({
491 ).toEqual(isOwnedCalendar);
495 test('Events that are not invitations can be changed to writable calendars', () => {
496 const combinations = [];
497 for (let i = 0; i < 2 ** 1; i++) {
498 const isOwnedCalendar = !!(1 & i);
499 const isCalendarWritable = isOwnedCalendar || !!(2 & i);
501 combinations.push({ isOwnedCalendar, isCalendarWritable });
503 combinations.forEach(({ isOwnedCalendar, isCalendarWritable }) => {
505 getIsAvailableCalendar({
510 ).toEqual(isCalendarWritable);
515 describe('getCanDuplicateEvent()', () => {
516 test('User cannot duplicate events in unknown calendars', () => {
517 const combinations = [];
518 for (let i = 0; i < 2 ** 4; i++) {
519 const isSubscribedCalendar = !!(1 & i);
520 const isOwnedCalendar = !!(2 & i);
521 const isOrganizer = !!(4 & i);
522 const isInvitation = !!(8 & i);
524 combinations.push({ isSubscribedCalendar, isOwnedCalendar, isOrganizer, isInvitation });
526 combinations.forEach(({ isSubscribedCalendar, isOwnedCalendar, isOrganizer, isInvitation }) => {
528 getCanDuplicateEvent({
529 isUnknownCalendar: true,
530 isSubscribedCalendar,
539 test('User cannot duplicate events in subscribed calendars', () => {
540 const combinations = [];
541 for (let i = 0; i < 2 ** 2; i++) {
542 const isOrganizer = !!(1 & i);
543 const isInvitation = isOrganizer || !!(2 & i);
545 combinations.push({ isOrganizer, isInvitation });
547 combinations.forEach(({ isOrganizer, isInvitation }) => {
549 getCanDuplicateEvent({
550 isUnknownCalendar: false,
551 isSubscribedCalendar: true,
552 isOwnedCalendar: true,
560 test('Owner can duplicate events that are not invitations', () => {
562 getCanDuplicateEvent({
563 isUnknownCalendar: false,
564 isSubscribedCalendar: false,
565 isOwnedCalendar: true,
572 test('Owner can duplicate invitations that she is organizing', () => {
574 getCanDuplicateEvent({
575 isUnknownCalendar: false,
576 isSubscribedCalendar: false,
577 isOwnedCalendar: true,
584 test('Owner cannot duplicate invitations if she is not the organizer', () => {
586 getCanDuplicateEvent({
587 isUnknownCalendar: false,
588 isSubscribedCalendar: false,
589 isOwnedCalendar: true,
596 test('Member can duplicate events that are not invitations', () => {
598 getCanDuplicateEvent({
599 isUnknownCalendar: false,
600 isSubscribedCalendar: false,
601 isOwnedCalendar: false,
608 test('Member cannot duplicate invitations', () => {
609 const combinations = [];
610 for (let i = 0; i < 2 ** 1; i++) {
611 const isOrganizer = !!(1 & i);
613 combinations.push({ isOrganizer });
615 combinations.forEach(({ isOrganizer }) => {
617 getCanDuplicateEvent({
618 isUnknownCalendar: false,
619 isSubscribedCalendar: false,
620 isOwnedCalendar: false,
629 describe('getCanReplyToEvent()', () => {
630 test('User can reply to events he is invited in one of his own personal calendars if and only if the event is not cancelled', () => {
631 const combinations = [];
632 for (let i = 0; i < 2 ** 1; i++) {
633 const isCancelled = !!(1 & i);
635 combinations.push({ isCancelled });
637 combinations.forEach(({ isCancelled }) => {
640 isOwnedCalendar: true,
641 isCalendarWritable: true,
645 ).toEqual(!isCancelled);
649 test('User cannot reply to events he is not attending', () => {
650 const combinations = [];
651 for (let i = 0; i < 2 ** 3; i++) {
652 const isOwnedCalendar = !!(1 & i);
653 const isCalendarWritable = isOwnedCalendar || !!(2 & i);
654 const isCancelled = !!(4 & i);
656 combinations.push({ isOwnedCalendar, isCalendarWritable, isCancelled });
658 combinations.forEach(({ isOwnedCalendar, isCalendarWritable, isCancelled }) => {
670 test('User cannot reply to invitations on subscribed calendars', () => {
671 const combinations = [];
672 for (let i = 0; i < 2 ** 1; i++) {
673 const isCancelled = !!(1 & i);
675 combinations.push({ isCancelled });
677 combinations.forEach(({ isCancelled }) => {
680 isOwnedCalendar: true,
681 isCalendarWritable: false,
689 test('User cannot reply to invitations on shared calendars, with or without edit rights', () => {
690 const combinations = [];
691 for (let i = 0; i < 2 ** 2; i++) {
692 const isCalendarWritable = !!(1 & i);
693 const isCancelled = !!(2 & i);
695 combinations.push({ isCalendarWritable, isCancelled });
697 combinations.forEach(({ isCalendarWritable, isCancelled }) => {
700 isOwnedCalendar: false,