Unit tests

Signed-off-by: Georg Ehrke <developer@georgehrke.com>
This commit is contained in:
Georg Ehrke 2019-11-07 16:02:25 +01:00
parent 1576d29eff
commit a6c64c7989
No known key found for this signature in database
GPG Key ID: 9D98FD9380A1CB43
52 changed files with 3411 additions and 409 deletions

View File

@ -1,7 +0,0 @@
export function translate(app, str) {
return 'TRANSLATED:' + str
}
export function translatePlural(app, singularStr, pluralStr) {
return 'TRANSLATED:' + pluralStr
}

View File

@ -0,0 +1,41 @@
/**
* @returns {String}
*/
export function getLocale() {
return 'en'
}
/**
* @returns {String[]}
*/
export function getDayNames() {
return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
}
/**
* @returns {String[]}
*/
export function getDayNamesShort() {
return ['Sun.', 'Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.', 'Sat.']
}
/**
* @returns {String[]}
*/
export function getDayNamesMin() {
return ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
}
/**
* @returns {String[]}
*/
export function getMonthNames() {
return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
}
/**
* @returns {String[]}
*/
export function getMonthNamesShort() {
return ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May.', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.']
}

View File

@ -56,7 +56,6 @@
"jstz": "^2.1.1",
"md5": "^2.2.1",
"p-limit": "^2.2.1",
"p-queue": "^6.2.1",
"uuid": "^3.3.3",
"v-autosize": "^1.0.3",
"v-tooltip": "^2.0.2",
@ -78,6 +77,7 @@
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.7.1",
"@vue/test-utils": "^1.0.0-beta.29",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
"babel-loader": "^8.0.6",
@ -99,6 +99,7 @@
"jest-serializer-vue": "^2.0.2",
"node-sass": "^4.13.0",
"prettier-eslint": "^9.0.0",
"regenerator-runtime": "^0.13.3",
"sass-loader": "^7.3.1",
"stylelint": "^11.1.1",
"stylelint-bare-webpack-plugin": "^1.1.3",
@ -124,17 +125,30 @@
"^@/(.*)$": "<rootDir>/src/$1"
},
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.vue$": "vue-jest"
".*\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
],
"globals": {
"t": true,
"n": true,
"OC": true,
"OCA": true
}
"coverageDirectory": "./coverage/",
"collectCoverage": true,
"collectCoverageFrom": [
"<rootDir>/src/**/*.{js,vue}",
"!**/node_modules/**"
],
"coverageReporters": [
"json",
"text",
"html",
"lcov",
"clover"
],
"transformIgnorePatterns": [
"/node_modules/(?!calendar-js).+\\.js$"
],
"setupFilesAfterEnv": [
"./tests/javascript/jest.setup.js"
]
}
}

View File

@ -20,7 +20,7 @@
*
*/
export default function getDefaultAlarms(allDay = false) {
export function getDefaultAlarms(allDay = false) {
if (allDay) {
return [
9 * 60 * 60, // On the day of the event at 9am
@ -42,3 +42,5 @@ export default function getDefaultAlarms(allDay = false) {
]
}
}
export default getDefaultAlarms

View File

@ -21,7 +21,7 @@
*/
import { translate as t } from '@nextcloud/l10n'
export default () => {
export function getDefaultCategories() {
// This list was taken from https://tools.ietf.org/html/rfc5545#section-5
return [
t('calendar', 'Anniversary'),
@ -41,3 +41,5 @@ export default () => {
t('calendar', 'Vacation'),
]
}
export default getDefaultCategories

View File

@ -24,22 +24,24 @@ import { translate as t, translatePlural as n } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
/**
* Formats an alarm
*
* @param {Object} alarm The alarm object to format
* @param {Boolean} isAllDay Whether or not the event is all-day
* @param {String} currentUserTimezone The current timezone of the user
* @param {String} locale The locale to format it in
* @returns {String}
*/
export default (alarm, isAllDay, currentUserTimezone) => {
export default (alarm, isAllDay, currentUserTimezone, locale) => {
if (alarm.relativeTrigger !== null) {
// relative trigger
const time = moment.duration(Math.abs(alarm.relativeTrigger), 'seconds').humanize()
const time = moment.duration(Math.abs(alarm.relativeTrigger), 'seconds').locale(locale).humanize()
if (isAllDay && alarm.relativeIsRelatedToStart && alarm.relativeTrigger < 86400) {
const date = new Date()
date.setHours(alarm.relativeHoursAllDay)
date.setMinutes(alarm.relativeMinutesAllDay)
const formattedHourMinute = moment(date).format('LT')
const formattedHourMinute = moment(date).locale(locale).format('LT')
if (alarm.relativeTrigger === 0) {
return t('calendar', 'Midnight on the day the event starts')
@ -93,11 +95,11 @@ export default (alarm, isAllDay, currentUserTimezone) => {
// absolute trigger
if (currentUserTimezone === alarm.absoluteTimezoneId) {
return t('calendar', 'on {time}', {
time: moment(alarm.absoluteDate).format('LLLL'),
time: moment(alarm.absoluteDate).locale(locale).format('LLLL'),
})
} else {
return t('calendar', 'on {time} {timezoneId}', {
time: moment(alarm.absoluteDate).format('LLLL'),
time: moment(alarm.absoluteDate).locale(locale).format('LLLL'),
timezoneId: alarm.absoluteTimezoneId,
})
}

View File

@ -26,15 +26,13 @@ import moment from '@nextcloud/moment'
*
* @param {Date} value The date object to format
* @param {Boolean} isAllDay Whether or not to display only the date part
* @param {String} locale The locale to format it in
* @returns {string}
*/
export default (value, isAllDay) => {
if (!value) {
return ''
}
export default (value, isAllDay, locale) => {
if (isAllDay) {
return moment(value).format('ll')
return moment(value).locale(locale).format('ll')
} else {
return moment(value).format('lll')
return moment(value).locale(locale).format('lll')
}
}

View File

@ -22,19 +22,27 @@
import moment from '@nextcloud/moment'
import { translate as t } from '@nextcloud/l10n'
export default (value, view) => {
/**
* Formats a date-range depending on the user's current view
*
* @param {String|Date} value The date to format
* @param {String} view The current view of the user
* @param {String} locale Which locale to format it in
* @returns {string}
*/
export default (value, view, locale) => {
switch (view) {
case 'timeGridDay':
return moment(value).format('ll')
return moment(value).locale(locale).format('ll')
case 'timeGridWeek':
return t('calendar', 'Week {number} of {year}', {
number: moment(value).week(),
year: moment(value).year(),
number: moment(value).locale(locale).week(),
year: moment(value).locale(locale).weekYear(),
})
case 'dayGridMonth':
default:
return moment(value).format('MMMM YYYY')
return moment(value).locale(locale).format('MMMM YYYY')
}
}

View File

@ -0,0 +1,231 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { translate as t, translatePlural as n, getDayNames, getMonthNames } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
/**
* Formats a recurrence-rule
*
* @param {Object} recurrenceRule The recurrence-rule to format
* @param {String} locale The locale to format it into
* @returns {String}
*/
export default (recurrenceRule, locale) => {
if (recurrenceRule.frequency === 'NONE') {
return t('calendar', 'Does not repeat')
}
let freqPart = ''
if (recurrenceRule.interval === 1) {
switch (recurrenceRule.frequency) {
case 'DAILY':
freqPart = t('calendar', 'Daily')
break
case 'WEEKLY':
freqPart = t('calendar', 'Weekly')
break
case 'MONTHLY':
freqPart = t('calendar', 'Monthly')
break
case 'YEARLY':
freqPart = t('calendar', 'Yearly')
break
}
} else {
switch (recurrenceRule.frequency) {
case 'DAILY':
freqPart = n('calendar', 'Every %n day', 'Every %n days', recurrenceRule.interval)
break
case 'WEEKLY':
freqPart = n('calendar', 'Every %n week', 'Every %n weeks', recurrenceRule.interval)
break
case 'MONTHLY':
freqPart = n('calendar', 'Every %n month', 'Every %n months', recurrenceRule.interval)
break
case 'YEARLY':
freqPart = n('calendar', 'Every %n year', 'Every %n years', recurrenceRule.interval)
break
}
}
let limitPart = ''
if (recurrenceRule.frequency === 'WEEKLY' && recurrenceRule.byDay.length !== 0) {
const formattedDays = getTranslatedByDaySet(recurrenceRule.byDay)
limitPart = n('calendar', 'on {weekday}', 'on {weekdays}', recurrenceRule.byDay.length, {
weekday: formattedDays,
weekdays: formattedDays,
})
} else if (recurrenceRule.frequency === 'MONTHLY') {
if (recurrenceRule.byMonthDay.length !== 0) {
const dayOfMonthList = recurrenceRule.byMonthDay.join(', ')
limitPart = n('calendar', 'on day {dayOfMonthList}', 'on days {dayOfMonthList}', recurrenceRule.byMonthDay.length, {
dayOfMonthList,
})
} else {
const ordinalNumber = getTranslatedOrdinalNumber(recurrenceRule.bySetPosition)
const byDaySet = getTranslatedByDaySet(recurrenceRule.byDay)
limitPart = t('calendar', 'on the {ordinalNumber} {byDaySet}', {
ordinalNumber,
byDaySet,
})
}
} else if (recurrenceRule.frequency === 'YEARLY') {
const monthNames = getTranslatedMonths(recurrenceRule.byMonth)
if (recurrenceRule.byDay.length === 0) {
limitPart = t('calendar', 'in {monthNames}', {
monthNames,
})
} else {
const ordinalNumber = getTranslatedOrdinalNumber(recurrenceRule.bySetPosition)
const byDaySet = getTranslatedByDaySet(recurrenceRule.byDay)
limitPart = t('calendar', 'in {monthNames} on the {ordinalNumber} {byDaySet}', {
monthNames,
ordinalNumber,
byDaySet,
})
}
}
let endPart = ''
if (recurrenceRule.until !== null) {
const untilDate = moment(recurrenceRule.until).locale(locale).format('L')
endPart = t('calendar', 'until {untilDate}', {
untilDate,
})
} else if (recurrenceRule.count !== null) {
endPart = n('calendar', '%n time', '%n times', recurrenceRule.count)
}
return [
freqPart,
limitPart,
endPart,
].join(' ').replace(/\s{2,}/g, ' ').trim()
}
/**
* Gets the byDay list as formatted list of translated weekdays
*
* @param {string[]} byDayList The by-day-list to get formatted
* @returns {string}
*/
function getTranslatedByDaySet(byDayList) {
const byDayNames = []
const allByDayNames = getDayNames()
// TODO: This should be sorted by first day of week
// TODO: This should summarise:
// - SA, SU to weekend
// - MO, TU, WE, TH, FR to weekday
// - MO, TU, WE, TH, FR, SA, SU to day
if (byDayList.includes('MO')) {
byDayNames.push(allByDayNames[1])
}
if (byDayList.includes('TU')) {
byDayNames.push(allByDayNames[2])
}
if (byDayList.includes('WE')) {
byDayNames.push(allByDayNames[3])
}
if (byDayList.includes('TH')) {
byDayNames.push(allByDayNames[4])
}
if (byDayList.includes('FR')) {
byDayNames.push(allByDayNames[5])
}
if (byDayList.includes('SA')) {
byDayNames.push(allByDayNames[6])
}
if (byDayList.includes('SU')) {
byDayNames.push(allByDayNames[0])
}
return byDayNames.join(', ')
}
/**
* Gets the byMonth list as formatted list of translated month-names
*
*
* @param {string[]} byMonthList The by-month list to get formatted
* @returns {string}
*/
function getTranslatedMonths(byMonthList) {
const sortedByMonth = byMonthList.slice().map((n) => parseInt(n, 10))
sortedByMonth.sort((a, b) => a - b)
const monthNames = []
const allMonthNames = getMonthNames()
for (const month of sortedByMonth) {
monthNames.push(allMonthNames[month - 1])
}
return monthNames.join(', ')
}
/**
* Gets the translated ordinal number for by-set-position
*
* @param {Number} bySetPositionNum The by-set-position number to get the translation of
* @returns {string}
*/
function getTranslatedOrdinalNumber(bySetPositionNum) {
switch (bySetPositionNum) {
case 1:
return t('calendar', 'first')
case 2:
return t('calendar', 'second')
case 3:
return t('calendar', 'third')
case 4:
return t('calendar', 'fourth')
case 5:
return t('calendar', 'fifth')
case -2:
return t('calendar', 'second to last')
case -1:
return t('calendar', 'last')
default:
return ''
}
}

View File

@ -42,15 +42,15 @@ export default function(store, router, route, window) {
}
const name = getPrefixedRoute(route.name, desiredRoute)
const params = Object.assign({}, store.state.route.params, {
const params = Object.assign({}, route.params, {
object: event.extendedProps.objectId,
recurrenceId: String(event.extendedProps.recurrenceId),
})
// Don't push new route when day didn't change
if (name === store.state.route.name
&& params.object === store.state.route.params.object
&& params.recurrenceId === store.state.route.params.recurrenceId) {
if ((getPrefixedRoute(route.name, 'EditPopoverView') === route.name || getPrefixedRoute(route.name, 'EditSidebarView') === route.name)
&& params.object === route.params.object
&& params.recurrenceId === route.params.recurrenceId) {
return
}

View File

@ -30,7 +30,7 @@ import getTimezoneManager from '../services/timezoneDataProviderService'
* @returns {Function}
*/
export default function(store, fcAPI) {
return async function({ event, oldEvent, delta, revert }) {
return async function({ event, delta, revert }) {
const deltaDuration = getDurationValueFromFullCalendarDuration(delta)
const defaultAllDayDuration = getDurationValueFromFullCalendarDuration(fcAPI.getOption('defaultAllDayEventDuration'))
const defaultTimedDuration = getDurationValueFromFullCalendarDuration(fcAPI.getOption('defaultTimedEventDuration'))
@ -46,30 +46,44 @@ export default function(store, fcAPI) {
const recurrenceId = event.extendedProps.recurrenceId
const recurrenceIdDate = new Date(recurrenceId * 1000)
let calendarObject
try {
await store.dispatch('getEventByObjectId', { objectId })
calendarObject = await store.dispatch('getEventByObjectId', { objectId })
} catch (error) {
console.debug(error)
revert()
return
}
const calendarObject = store.getters.getCalendarObjectById(objectId)
const eventComponent = calendarObject.getObjectAtRecurrenceId(recurrenceIdDate)
if (!eventComponent) {
console.debug('Recurrence-id not found')
revert()
return
}
eventComponent.shiftByDuration(deltaDuration, event.allDay, timezone, defaultAllDayDuration, defaultTimedDuration)
try {
// shiftByDuration may throw exceptions in certain cases
eventComponent.shiftByDuration(deltaDuration, event.allDay, timezone, defaultAllDayDuration, defaultTimedDuration)
} catch (error) {
calendarObject.resetToDav()
console.debug(error)
revert()
return
}
if (eventComponent.canCreateRecurrenceExceptions()) {
eventComponent.createRecurrenceException()
}
await store.dispatch('updateCalendarObject', {
calendarObject,
})
try {
await store.dispatch('updateCalendarObject', {
calendarObject,
})
} catch (error) {
calendarObject.resetToDav()
console.debug(error)
revert()
}
}
}

View File

@ -21,6 +21,8 @@
*/
/**
* Adds data to the html element representing the event in the fullcalendar grid.
* This is used to later on position the popover
*
* @param {Object} data The destructuring object
* @param {EventApi} event The fullcalendar event object

View File

@ -28,7 +28,7 @@ import { getDurationValueFromFullCalendarDuration } from './duration'
* @returns {Function}
*/
export default function(store) {
return async function({ event, prevEvent, startDelta, endDelta, revert }) {
return async function({ event, startDelta, endDelta, revert }) {
const startDeltaDuration = getDurationValueFromFullCalendarDuration(startDelta)
const endDeltaDuration = getDurationValueFromFullCalendarDuration(endDelta)
@ -41,17 +41,16 @@ export default function(store) {
const recurrenceId = event.extendedProps.recurrenceId
const recurrenceIdDate = new Date(recurrenceId * 1000)
let calendarObject
try {
await store.dispatch('getEventByObjectId', { objectId })
calendarObject = await store.dispatch('getEventByObjectId', { objectId })
} catch (error) {
console.debug(error)
revert()
return
}
const calendarObject = store.getters.getCalendarObjectById(objectId)
const eventComponent = calendarObject.getObjectAtRecurrenceId(recurrenceIdDate)
if (!eventComponent) {
console.debug('Recurrence-id not found')
revert()
@ -69,8 +68,14 @@ export default function(store) {
eventComponent.createRecurrenceException()
}
await store.dispatch('updateCalendarObject', {
calendarObject,
})
try {
await store.dispatch('updateCalendarObject', {
calendarObject,
})
} catch (error) {
calendarObject.resetToDav()
console.debug(error)
revert()
}
}
}

View File

@ -45,14 +45,19 @@ export default function(store) {
const timezoneObject = getTimezoneManager().getTimezoneForId(timeZone)
const timeRange = store.getters.getTimeRangeForCalendarCoveringRange(calendar.id, getUnixTimestampFromDate(start), getUnixTimestampFromDate(end))
if (!timeRange) {
await store.dispatch('getEventsFromCalendarInTimeRange', {
calendar: calendar,
from: start,
to: end,
})
let timeRangeId
try {
timeRangeId = await store.dispatch('getEventsFromCalendarInTimeRange', {
calendar: calendar,
from: start,
to: end,
})
} catch (error) {
failureCallback(error)
return
}
const timeRange = store.getters.getTimeRangeForCalendarCoveringRange(calendar.id, getUnixTimestampFromDate(start), getUnixTimestampFromDate(end))
const calendarObjects = store.getters.getCalendarObjectsByTimeRangeId(timeRange.id)
const calendarObjects = store.getters.getCalendarObjectsByTimeRangeId(timeRangeId)
successCallback(eventSourceFunction(calendarObjects, start, end, timezoneObject))
} else {
const calendarObjects = store.getters.getCalendarObjectsByTimeRangeId(timeRange.id)

View File

@ -19,10 +19,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import {
generateTextColorForRGBString,
} from '../utils/color.js'
import { translate as t } from '@nextcloud/l10n'
import logger from '../utils/logger.js'
/**
* convert an array of calendar-objects to events
@ -36,7 +34,14 @@ import { translate as t } from '@nextcloud/l10n'
export function eventSourceFunction(calendarObjects, start, end, timezone) {
const fcEvents = []
for (const calendarObject of calendarObjects) {
const allObjectsInTimeRange = calendarObject.getAllObjectsInTimeRange(start, end)
let allObjectsInTimeRange
try {
allObjectsInTimeRange = calendarObject.getAllObjectsInTimeRange(start, end)
} catch (error) {
logger.error(error.message)
continue
}
for (const object of allObjectsInTimeRange) {
const classNames = []
@ -60,10 +65,10 @@ export function eventSourceFunction(calendarObjects, start, end, timezone) {
},
}
if (calendarObject.color) {
fcEvent.backgroundColor = calendarObject.color
fcEvent.textColor = generateTextColorForRGBString(calendarObject.color)
}
// if (object.color) {
// fcEvent.backgroundColor = object.color
// fcEvent.textColor = generateTextColorForRGBString(object.color)
// }
fcEvents.push(fcEvent)
}

View File

@ -27,10 +27,11 @@
*
* @param {Object} store The Vuex store
* @param {Object} router The Vue router
* @param {Object} route The Vue route
* @param {Window} window The window object
* @returns {Function}
*/
export default function(store, router, window) {
export default function(store, router, route, window) {
return function({ start, end, allDay }) {
let name = store.state.settings.skipPopover
? 'NewSidebarView'
@ -40,17 +41,20 @@ export default function(store, router, window) {
name = 'NewSidebarView'
}
const params = Object.assign({}, store.state.route.params, {
// If we are already in a new event view, don't change it
if (['NewSidebarView', 'NewPopoverView'].includes(route.name)) {
name = route.name
}
const params = Object.assign({}, route.params, {
allDay: allDay ? '1' : '0',
dtstart: String(Math.floor(start.getTime() / 1000)),
dtend: String(Math.floor(end.getTime() / 1000)),
})
// Don't push new route when day didn't change
if (name === store.state.route.name
&& params.allDay === store.state.route.params.allDay
&& params.dtstart === store.state.route.params.dtstart
&& params.dtend === store.state.route.params.dtend) {
if (name === route.name && params.allDay === route.params.allDay
&& params.dtstart === route.params.dtstart && params.dtend === route.params.dtend) {
return
}

View File

@ -48,7 +48,7 @@ class VTimezoneNamedTimezone extends NamedTimeZoneImpl {
/**
* returns parameters for Date object in this timezone based on given timestamp
*
* @param {Number[]} ms Timestamp in milliseconds
* @param {Number} ms Timestamp in milliseconds
* @returns {Number[]}
*/
timestampToArray(ms) {

View File

@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import rfcProps from '../models/rfcProps'
import { getRFCProperties } from '../models/rfcProps'
import logger from '../utils/logger.js'
import { getIllustrationForTitle } from '../utils/illustration.js'
import { getPrefixedRoute } from '../utils/router.js'
@ -301,7 +301,7 @@ export default {
* @returns {{geo, color, timeTransparency, description, resources, location, categories, accessClass, priority, status}}
*/
rfcProps() {
return rfcProps
return getRFCProperties()
},
/**
* Returns whether or not this event can be downloaded from the server

View File

@ -172,14 +172,12 @@ export function mapDavShareeToSharee(sharee) {
let displayName
if (sharee['common-name']) {
displayName = sharee['common-name']
} else if (sharee.href.startsWith('principal:principals/groups/')) {
displayName = sharee.href.substr(28)
} else if (sharee.href.startsWith('principal:principals/users/')) {
displayName = sharee.href.substr(27)
} else {
if (sharee.href.startsWith('principal:principals/groups/')) {
displayName = sharee.href.substr(28)
} else if (sharee.href.startsWith('principal:principals/users/')) {
displayName = sharee.href.substr(27)
} else {
displayName = sharee.href
}
displayName = sharee.href
}
const writeable = sharee.access[0].endsWith('read-write')

View File

@ -20,13 +20,15 @@
*
*/
import PQueue from 'p-queue'
import { getParserManager } from 'calendar-js'
import DateTimeValue from 'calendar-js/src/values/dateTimeValue'
import CalendarComponent from 'calendar-js/src/components/calendarComponent'
/**
* This model represents exactly
*
* TODO: this should not be a class, but a simple object
* TODO: all methods should be converted to vuex commits
*/
export default class CalendarObject {
@ -59,14 +61,6 @@ export default class CalendarObject {
*/
this.dav = dav
/**
* A queue for sending updates to the server
* aiming to prevent race-conditions
*
* @type {Object}
*/
this.updateQueue = new PQueue({ concurrency: 1 })
/**
* parsed calendar-js object
* @type {CalendarComponent}

View File

@ -72,7 +72,7 @@ export const getDefaultCalendarObjectInstanceObject = (props = {}) => Object.ass
organizer: {
// name of the organizer
name: null,
// email of the organzier:
// email of the organizer
uri: null,
},
// Alarm of the event
@ -81,7 +81,7 @@ export const getDefaultCalendarObjectInstanceObject = (props = {}) => Object.ass
customColor: null,
// Categories
categories: [],
// Wether or not the user is allowed to toggle the all-day checkbox
// Whether or not the user is allowed to toggle the all-day checkbox
canModifyAllDay: true,
// The real event-component coming from calendar-js
eventComponent: null,

View File

@ -20,89 +20,98 @@
*
*/
import { translate as t } from '@nextcloud/l10n'
import getDefaultCategories from '../defaults/defaultCategories.js'
import { getDefaultCategories } from '../defaults/defaultCategories.js'
export default {
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.3
*/
accessClass: {
readableName: t('calendar', 'When shared show'),
icon: 'icon-eye',
options: [
{ value: 'PUBLIC', label: t('calendar', 'When shared show full event') },
{ value: 'CONFIDENTIAL', label: t('calendar', 'When shared show only busy') },
{ value: 'PRIVATE', label: t('calendar', 'When shared hide this event') },
],
multiple: false,
info: t('calendar', 'The visibility of this event in shared calendars.'),
defaultValue: 'PUBLIC',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.7
*/
location: {
readableName: t('calendar', 'Location'),
placeholder: t('calendar', 'Add a location'),
icon: 'icon-address',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.5
*/
description: {
readableName: t('calendar', 'Description'),
placeholder: t('calendar', 'Add a description'),
icon: 'icon-menu',
defaultNumberOfRows: 2,
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.11
*/
status: {
readableName: t('calendar', 'Status'),
icon: 'icon-checkmark',
options: [
{ value: 'CONFIRMED', label: t('calendar', 'Confirmed') },
{ value: 'TENTATIVE', label: t('calendar', 'Tentative') },
{ value: 'CANCELLED', label: t('calendar', 'Cancelled') },
],
multiple: false,
info: t('calendar', 'Confirmation about the overall status of the event.'),
defaultValue: 'CONFIRMED',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.2.7
*/
timeTransparency: {
readableName: t('calendar', 'Show as'),
icon: 'icon-briefcase',
multiple: false,
info: t('calendar', 'Take this event into account when calculating free-busy information.'),
options: [
{ value: 'TRANSPARENT', label: t('calendar', 'Free') },
{ value: 'OPAQUE', label: t('calendar', 'Busy') },
],
defaultValue: 'TRANSPARENT',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.2
*/
categories: {
readableName: t('calendar', 'Categories'),
icon: 'icon-tag',
multiple: true,
info: t('calendar', 'Categories help you to structure and organize your events.'),
placeholder: t('calendar', 'Search or add categories'),
tagPlaceholder: t('calendar', 'Add this as a new category'),
options: getDefaultCategories(),
},
/**
* https://tools.ietf.org/html/rfc7986#section-5.9
*/
color: {
readableName: t('calendar', 'Custom color'),
icon: 'icon-color-picker',
multiple: false,
info: t('calendar', 'Special color of this event. Overrides the calendar-color.'),
},
/**
* Gets all supported RFC properties
*
* @returns {{color: {readableName: *, icon: string, multiple: boolean, info: *}, timeTransparency: {readableName: *, defaultValue: string, icon: string, multiple: boolean, options: *[], info: *}, description: {readableName: *, icon: string, placeholder: *, defaultNumberOfRows: number}, location: {readableName: *, icon: string, placeholder: *}, categories: {readableName: *, icon: string, multiple: boolean, options: *, tagPlaceholder: *, placeholder: *, info: *}, accessClass: {readableName: *, defaultValue: string, icon: string, options: *[], multiple: boolean, info: *}, status: {readableName: *, defaultValue: string, icon: string, options: *[], multiple: boolean, info: *}}}
*/
export function getRFCProperties() {
return {
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.3
*/
accessClass: {
readableName: t('calendar', 'When shared show'),
icon: 'icon-eye',
options: [
{ value: 'PUBLIC', label: t('calendar', 'When shared show full event') },
{ value: 'CONFIDENTIAL', label: t('calendar', 'When shared show only busy') },
{ value: 'PRIVATE', label: t('calendar', 'When shared hide this event') },
],
multiple: false,
info: t('calendar', 'The visibility of this event in shared calendars.'),
defaultValue: 'PUBLIC',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.7
*/
location: {
readableName: t('calendar', 'Location'),
placeholder: t('calendar', 'Add a location'),
icon: 'icon-address',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.5
*/
description: {
readableName: t('calendar', 'Description'),
placeholder: t('calendar', 'Add a description'),
icon: 'icon-menu',
defaultNumberOfRows: 2,
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.11
*/
status: {
readableName: t('calendar', 'Status'),
icon: 'icon-checkmark',
options: [
{ value: 'CONFIRMED', label: t('calendar', 'Confirmed') },
{ value: 'TENTATIVE', label: t('calendar', 'Tentative') },
{ value: 'CANCELLED', label: t('calendar', 'Cancelled') },
],
multiple: false,
info: t('calendar', 'Confirmation about the overall status of the event.'),
defaultValue: 'CONFIRMED',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.2.7
*/
timeTransparency: {
readableName: t('calendar', 'Show as'),
icon: 'icon-briefcase',
multiple: false,
info: t('calendar', 'Take this event into account when calculating free-busy information.'),
options: [
{ value: 'TRANSPARENT', label: t('calendar', 'Free') },
{ value: 'OPAQUE', label: t('calendar', 'Busy') },
],
defaultValue: 'TRANSPARENT',
},
/**
* https://tools.ietf.org/html/rfc5545#section-3.8.1.2
*/
categories: {
readableName: t('calendar', 'Categories'),
icon: 'icon-tag',
multiple: true,
info: t('calendar', 'Categories help you to structure and organize your events.'),
placeholder: t('calendar', 'Search or add categories'),
tagPlaceholder: t('calendar', 'Add this as a new category'),
options: getDefaultCategories(),
},
/**
* https://tools.ietf.org/html/rfc7986#section-5.9
*/
color: {
readableName: t('calendar', 'Custom color'),
icon: 'icon-color-picker',
multiple: false,
info: t('calendar', 'Special color of this event. Overrides the calendar-color.'),
},
}
}
export default getRFCProperties

View File

@ -0,0 +1,2 @@
import 'core-js/stable';
import 'regenerator-runtime/runtime';

View File

@ -20,27 +20,54 @@
*
*/
import defaultCategories from '../../../../src/defaults/defaultCategories.js'
import { translate } from '@nextcloud/l10n'
jest.mock('@nextcloud/l10n')
describe('defaults/defaultCategories test suite', () => {
beforeEach(() => {
translate.mockClear()
})
it('should provide a default set of categories', () => {
translate
.mockImplementation((app, str) => str)
expect(defaultCategories()).toEqual([
'TRANSLATED:Anniversary',
'TRANSLATED:Appointment',
'TRANSLATED:Business',
'TRANSLATED:Education',
'TRANSLATED:Holiday',
'TRANSLATED:Meeting',
'TRANSLATED:Miscellaneous',
'TRANSLATED:Non-working hours',
'TRANSLATED:Not in office',
'TRANSLATED:Personal',
'TRANSLATED:Phone call',
'TRANSLATED:Sick day',
'TRANSLATED:Special occasion',
'TRANSLATED:Travel',
'TRANSLATED:Vacation',
'Anniversary',
'Appointment',
'Business',
'Education',
'Holiday',
'Meeting',
'Miscellaneous',
'Non-working hours',
'Not in office',
'Personal',
'Phone call',
'Sick day',
'Special occasion',
'Travel',
'Vacation',
])
expect(translate).toHaveBeenCalledTimes(15)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Anniversary')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'Appointment')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'Business')
expect(translate).toHaveBeenNthCalledWith(4, 'calendar', 'Education')
expect(translate).toHaveBeenNthCalledWith(5, 'calendar', 'Holiday')
expect(translate).toHaveBeenNthCalledWith(6, 'calendar', 'Meeting')
expect(translate).toHaveBeenNthCalledWith(7, 'calendar', 'Miscellaneous')
expect(translate).toHaveBeenNthCalledWith(8, 'calendar', 'Non-working hours')
expect(translate).toHaveBeenNthCalledWith(9, 'calendar', 'Not in office')
expect(translate).toHaveBeenNthCalledWith(10, 'calendar', 'Personal')
expect(translate).toHaveBeenNthCalledWith(11, 'calendar', 'Phone call')
expect(translate).toHaveBeenNthCalledWith(12, 'calendar', 'Sick day')
expect(translate).toHaveBeenNthCalledWith(13, 'calendar', 'Special occasion')
expect(translate).toHaveBeenNthCalledWith(14, 'calendar', 'Travel')
expect(translate).toHaveBeenNthCalledWith(15, 'calendar', 'Vacation')
})
})

View File

@ -0,0 +1,77 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('format/alarmFormat test suite', () => {
it('should format an alarm for an all-day event at midnight', () => {
})
it('should format an alarm for an all-day event days before', () => {
})
it('should format an alarm for an all-day event weeks weeks before', () => {
})
it('should format an alarm for an all-day event on the same day at a certain time', () => {
})
it('should format an alarm for an all-day event not supported in the default range', () => {
// Bigger than one day or not related to start
})
it('should format a relative trigger at the events start', () => {
})
it('should format a relative trigger at the events end', () => {
})
it('should format a relative trigger before the event starts', () => {
})
it('should format a relative trigger before the event ends', () => {
})
it('should format a relative trigger after the event starts', () => {
})
it('should format a relative trigger after the event ends', () => {
})
it('should format an absolute alarm in the user\'s timezone', () => {
})
it('should format an absolute alarm in a different timezone', () => {
})
})

View File

@ -0,0 +1,73 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import dateFormat from "../../../../src/filters/dateFormat.js";
import moment from '@nextcloud/moment'
jest.mock('@nextcloud/moment')
describe('format/dateFormat test suite', () => {
beforeEach(() => {
moment.mockClear()
})
it('should format an all-day date', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-date')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(dateFormat(date, true, 'de')).toEqual('formatted-allday-date')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'll')
})
it('should format a timed date', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-date')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(dateFormat(date, false, 'de')).toEqual('formatted-allday-date')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'lll')
})
})

View File

@ -0,0 +1,138 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import moment from '@nextcloud/moment'
import dateRangeFormat from "../../../../src/filters/dateRangeFormat.js";
import { translate } from '@nextcloud/l10n'
jest.mock('@nextcloud/moment')
jest.mock('@nextcloud/l10n')
describe('format/dateRangeFormat test suite', () => {
beforeEach(() => {
moment.mockClear()
translate.mockClear()
})
it('should provide a format for day view', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-date')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(dateRangeFormat(date, 'timeGridDay', 'de')).toEqual('formatted-allday-date')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'll')
expect(translate).toHaveBeenCalledTimes(0)
})
it('should provide a format for week view', () => {
translate
.mockImplementation((app, str) => str)
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const week = jest.fn()
.mockReturnValue('week-no')
const weekYear = jest.fn()
.mockReturnValue('week-year')
const locale = jest.fn()
.mockReturnValue({ week, weekYear })
moment
.mockReturnValue({ locale })
expect(dateRangeFormat(date, 'timeGridWeek', 'de')).toEqual('Week {number} of {year}')
expect(moment).toHaveBeenCalledTimes(2)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(moment).toHaveBeenNthCalledWith(2, date)
expect(locale).toHaveBeenCalledTimes(2)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(locale).toHaveBeenNthCalledWith(2, 'de')
expect(week).toHaveBeenCalledTimes(1)
expect(week).toHaveBeenNthCalledWith(1)
expect(weekYear).toHaveBeenCalledTimes(1)
expect(weekYear).toHaveBeenNthCalledWith(1)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Week {number} of {year}', {
number: 'week-no',
year: 'week-year',
})
})
it('should provide a format for month view', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-month-year')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(dateRangeFormat(date, 'dayGridMonth', 'de')).toEqual('formatted-allday-month-year')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'MMMM YYYY')
expect(translate).toHaveBeenCalledTimes(0)
})
it('should provide month as fallback for unknown view', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-month-year')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(dateRangeFormat(date, 'fooBarUnknownView', 'de')).toEqual('formatted-allday-month-year')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'MMMM YYYY')
expect(translate).toHaveBeenCalledTimes(0)
})
})

View File

@ -0,0 +1,353 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import recurrenceRuleFormat from '../../../../src/filters/recurrenceRuleFormat.js'
import moment from '@nextcloud/moment'
import { translate, translatePlural, getDayNames, getMonthNames } from '@nextcloud/l10n'
jest.mock('@nextcloud/moment')
jest.mock('@nextcloud/l10n')
describe('format/recurrenceRuleFormat test suite', () => {
beforeEach(() => {
moment.mockClear()
translate.mockClear()
translatePlural.mockClear()
translate
.mockImplementation((app, str) => str)
translatePlural
.mockImplementation((app, sinStr, pluStr) => pluStr)
getDayNames
.mockReturnValue(['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'])
getMonthNames
.mockReturnValue(['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'])
})
it('should format a recurrence-rule that is non-recurring', () => {
expect(recurrenceRuleFormat({
frequency: 'NONE',
interval: 1,
count: null,
until: null,
byDay: [],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Does not repeat')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Does not repeat')
})
it('should format a recurrence-rule that is recurring infinitely every day', () => {
expect(recurrenceRuleFormat({
frequency: 'DAILY',
interval: 1,
count: null,
until: null,
byDay: [],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Daily')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Daily')
})
it('should format a recurrence-rule that is recurring infinitely every week on Tuesday', () => {
expect(recurrenceRuleFormat({
frequency: 'WEEKLY',
interval: 1,
count: null,
until: null,
byDay: ['TU'],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Weekly on {weekdays}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Weekly')
expect(translatePlural).toHaveBeenCalledTimes(1)
expect(translatePlural).toHaveBeenNthCalledWith(1, 'calendar', 'on {weekday}', 'on {weekdays}', 1, {
weekday: 'Tuesday',
weekdays: 'Tuesday',
})
})
it('should format a recurrence-rule that is recurring infinitely every third week on Tuesday and Thursday', () => {
expect(recurrenceRuleFormat({
frequency: 'WEEKLY',
interval: 3,
count: null,
until: null,
byDay: ['TU', 'TH'],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Every %n weeks on {weekdays}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(0)
expect(translatePlural).toHaveBeenCalledTimes(2)
expect(translatePlural).toHaveBeenNthCalledWith(1, 'calendar', 'Every %n week', 'Every %n weeks', 3)
expect(translatePlural).toHaveBeenNthCalledWith(2, 'calendar', 'on {weekday}', 'on {weekdays}', 2, {
weekday: 'Tuesday, Thursday',
weekdays: 'Tuesday, Thursday',
})
})
it('should format a recurrence-rule that is recurring infinitely every other month on 15th', () => {
expect(recurrenceRuleFormat({
frequency: 'MONTHLY',
interval: 2,
count: null,
until: null,
byDay: [],
byMonth: [],
byMonthDay: ['15'],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Every %n months on days {dayOfMonthList}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(0)
expect(translatePlural).toHaveBeenCalledTimes(2)
expect(translatePlural).toHaveBeenNthCalledWith(1, 'calendar', 'Every %n month', 'Every %n months', 2)
expect(translatePlural).toHaveBeenNthCalledWith(2, 'calendar', 'on day {dayOfMonthList}', 'on days {dayOfMonthList}', 1, {
dayOfMonthList: '15',
})
})
it('should format a recurrence-rule that is recurring infinitely every month on 15th, 16th, 17th, 18th', () => {
expect(recurrenceRuleFormat({
frequency: 'MONTHLY',
interval: 1,
count: null,
until: null,
byDay: [],
byMonth: [],
byMonthDay: ['15', '16', '17', '18'],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Monthly on days {dayOfMonthList}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Monthly')
expect(translatePlural).toHaveBeenCalledTimes(1)
expect(translatePlural).toHaveBeenNthCalledWith(1, 'calendar', 'on day {dayOfMonthList}', 'on days {dayOfMonthList}', 4, {
dayOfMonthList: '15, 16, 17, 18',
})
})
it('should format a recurrence-rule that is recurring infinitely every month on last weekday', () => {
expect(recurrenceRuleFormat({
frequency: 'MONTHLY',
interval: 1,
count: null,
until: null,
byDay: ['MO', 'TU', 'WE', 'TH', 'FR'],
byMonth: [],
byMonthDay: [],
bySetPosition: -1,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Monthly on the {ordinalNumber} {byDaySet}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(3)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Monthly')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'last')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'on the {ordinalNumber} {byDaySet}', {
ordinalNumber: 'last',
byDaySet: 'Monday, Tuesday, Wednesday, Thursday, Friday',
})
})
it('should format a recurrence-rule that is recurring infinitely every month second Wednesday', () => {
expect(recurrenceRuleFormat({
frequency: 'MONTHLY',
interval: 1,
count: null,
until: null,
byDay: ['WE'],
byMonth: [],
byMonthDay: [],
bySetPosition: 2,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Monthly on the {ordinalNumber} {byDaySet}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(3)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Monthly')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'second')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'on the {ordinalNumber} {byDaySet}', {
ordinalNumber: 'second',
byDaySet: 'Wednesday',
})
})
it('should format a recurrence-rule that is recurring infinitely every year in May', () => {
expect(recurrenceRuleFormat({
frequency: 'YEARLY',
interval: 1,
count: null,
until: null,
byDay: [],
byMonth: ['5'],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Yearly in {monthNames}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(2)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Yearly')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'in {monthNames}', {
monthNames: 'May'
})
})
it('should format a recurrence-rule that is recurring infinitely every year in May, July, October', () => {
expect(recurrenceRuleFormat({
frequency: 'YEARLY',
interval: 1,
count: null,
until: null,
byDay: [],
byMonth: ['5', '7', '10'],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Yearly in {monthNames}')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(2)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Yearly')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'in {monthNames}', {
monthNames: 'May, July, October'
})
})
it('should format a recurrence-rule that is recurring infinitely every year in May, July, October on third Thursday', () => {
expect(recurrenceRuleFormat({
frequency: 'YEARLY',
interval: 1,
count: null,
until: null,
byDay: ['TH'],
byMonth: ['5', '7', '10'],
byMonthDay: [],
bySetPosition: 3,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Yearly in {monthNames} on the {ordinalNumber} {byDaySet}')
expect(moment).toHaveBeenCalledTimes(0)
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(3)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Yearly')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'third')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'in {monthNames} on the {ordinalNumber} {byDaySet}', {
monthNames: 'May, July, October',
ordinalNumber: 'third',
byDaySet: 'Thursday'
})
})
it('should format a recurrence-rule that is recurring every day until a certain date', () => {
const date = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const format = jest.fn()
.mockReturnValue('formatted-allday-date')
const locale = jest.fn()
.mockReturnValue({ format })
moment
.mockReturnValue({ locale })
expect(recurrenceRuleFormat({
frequency: 'DAILY',
interval: 1,
count: null,
until: date,
byDay: [],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Daily until {untilDate}')
expect(moment).toHaveBeenCalledTimes(1)
expect(moment).toHaveBeenNthCalledWith(1, date)
expect(locale).toHaveBeenCalledTimes(1)
expect(locale).toHaveBeenNthCalledWith(1, 'de')
expect(format).toHaveBeenCalledTimes(1)
expect(format).toHaveBeenNthCalledWith(1, 'L')
expect(translate).toHaveBeenCalledTimes(2)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Daily')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'until {untilDate}', {
untilDate: 'formatted-allday-date'
})
})
it('should format a recurrence-rule that is recurring every day exactly 10 times', () => {
expect(recurrenceRuleFormat({
frequency: 'DAILY',
interval: 1,
count: 42,
until: null,
byDay: [],
byMonth: [],
byMonthDay: [],
bySetPosition: null,
isUnsupported: false,
recurrenceRuleValue: null,
}, 'de')).toEqual('Daily %n times')
expect(moment).toHaveBeenCalledTimes(0)
expect(translate).toHaveBeenCalledTimes(1)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Daily')
expect(translatePlural).toHaveBeenCalledTimes(1)
expect(translatePlural).toHaveBeenNthCalledWith(1, 'calendar', '%n time', '%n times', 42)
})
})

View File

@ -19,11 +19,59 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { getDurationValueFromFullCalendarDuration, getFullCalendarDurationFromDurationValue } from '../../../../src/fullcalendar/duration.js'
describe('fullcalendar/duration test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
it('should get the calendar-js duration from a fullcalendar duration object - object', () => {
expect(getDurationValueFromFullCalendarDuration({
year: 99,
days: 2,
})).toEqual(null)
expect(getDurationValueFromFullCalendarDuration({
days: 2,
minutes: 50,
seconds: 2
}).totalSeconds).toEqual(175802)
expect(getDurationValueFromFullCalendarDuration({
day: 2,
minute: 50,
second: 2
}).totalSeconds).toEqual(175802)
expect(getDurationValueFromFullCalendarDuration({
days: 1,
day: 1,
minutes: 25,
minute: 25,
seconds: 1,
second: 1,
milliseconds: 5555,
millisecond: 6666,
ms: 7777
}).totalSeconds).toEqual(175820)
})
it('should get the calendar-js duration from a fullcalendar duration object - string', () => {
expect(getDurationValueFromFullCalendarDuration('05:00').totalSeconds).toEqual(18000)
expect(getDurationValueFromFullCalendarDuration('05:21').totalSeconds).toEqual(19260)
expect(getDurationValueFromFullCalendarDuration('05:21:50').totalSeconds).toEqual(19310)
expect(getDurationValueFromFullCalendarDuration('05:21:23.678').totalSeconds).toEqual(19283)
expect(getDurationValueFromFullCalendarDuration('FOO')).toEqual(null)
})
it('should get the calendar-js duration from a fullcalendar duration object - number', () => {
expect(getDurationValueFromFullCalendarDuration(5000).totalSeconds).toEqual(5)
expect(getDurationValueFromFullCalendarDuration(5555).totalSeconds).toEqual(5)
})
it('should get the calendar-js duration from a fullcalendar duration object - other', () => {
expect(getDurationValueFromFullCalendarDuration(false)).toEqual(null)
})
it('should get the fullcalendar duration from a calendar-js duration object', () => {
expect(getFullCalendarDurationFromDurationValue({ totalSeconds: 500 })).toEqual({ seconds: 500 })
})
})

View File

@ -19,11 +19,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventAllow from "../../../../src/fullcalendar/eventAllow.js";
describe('fullcalendar/eventAllow test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
it('should always allow to drop an event that does allow modifying all-days', () => {
expect(eventAllow({ allDay: true }, { allDay: true, extendedProps: { canModifyAllDay: true }})).toEqual(true)
expect(eventAllow({ allDay: true }, { allDay: false, extendedProps: { canModifyAllDay: true }})).toEqual(true)
expect(eventAllow({ allDay: false }, { allDay: true, extendedProps: { canModifyAllDay: true }})).toEqual(true)
expect(eventAllow({ allDay: false }, { allDay: false, extendedProps: { canModifyAllDay: true }})).toEqual(true)
})
it('should disallow changing the allday state when prohibited', () => {
expect(eventAllow({ allDay: true }, { allDay: true, extendedProps: { canModifyAllDay: false }})).toEqual(true)
expect(eventAllow({ allDay: true }, { allDay: false, extendedProps: { canModifyAllDay: false }})).toEqual(false)
expect(eventAllow({ allDay: false }, { allDay: true, extendedProps: { canModifyAllDay: false }})).toEqual(false)
expect(eventAllow({ allDay: false }, { allDay: false, extendedProps: { canModifyAllDay: false }})).toEqual(true)
})
})

View File

@ -19,11 +19,250 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventClick from "../../../../src/fullcalendar/eventClick.js";
import { getPrefixedRoute } from "../../../../src/utils/router.js";
jest.mock("../../../../src/utils/router.js");
describe('fullcalendar/eventClick test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
getPrefixedRoute.mockClear()
})
it('should open the Popover on big screens', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'CalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'CalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'CalendarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(1)
expect(router.push.mock.calls[0][0]).toEqual({
name: 'EditPopoverView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
})
})
it('should open the Sidebar on big screens if the user wishes so', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('EditSidebarView')
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'CalendarView', 'EditSidebarView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'CalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'CalendarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(1)
expect(router.push.mock.calls[0][0]).toEqual({
name: 'EditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
})
})
it('should open the Sidebar on smaller screens', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 760 }
getPrefixedRoute
.mockReturnValueOnce('EditSidebarView')
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'CalendarView', 'EditSidebarView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'CalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'CalendarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(1)
expect(router.push.mock.calls[0][0]).toEqual({
name: 'EditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
})
})
it('should keep the public prefix when viewed in public mode', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = { name: 'PublicCalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('PublicEditSidebarView')
.mockReturnValueOnce('PublicEditPopoverView')
.mockReturnValueOnce('PublicEditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'PublicCalendarView', 'EditSidebarView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'PublicCalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'PublicCalendarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(1)
expect(router.push.mock.calls[0][0]).toEqual({
name: 'PublicEditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
})
})
it('should keep the embed prefix when viewed in embedded mode', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = { name: 'EmbedCalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('EmbedEditSidebarView')
.mockReturnValueOnce('EmbedEditPopoverView')
.mockReturnValueOnce('EmbedEditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'EmbedCalendarView', 'EditSidebarView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'EmbedCalendarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'EmbedCalendarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(1)
expect(router.push.mock.calls[0][0]).toEqual({
name: 'EmbedEditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
})
})
it('should not update the route when the same event and same occurrence is already viewed - same route', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = {
name: 'EditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
}
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('EditSidebarView')
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'EditSidebarView', 'EditSidebarView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'EditSidebarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'EditSidebarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(0)
})
it('should not update the route when the same event and same occurrence is already viewed - Sidebar Route', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = {
name: 'EditSidebarView',
params: {
object: 'object123',
otherParam: '456',
recurrenceId: 'recurrence456',
}
}
const window = { innerWidth: 1920 }
getPrefixedRoute
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditPopoverView')
.mockReturnValueOnce('EditSidebarView')
const eventClickFunction = eventClick(store, router, route, window)
eventClickFunction({ event: {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
}
}})
expect(getPrefixedRoute).toHaveBeenNthCalledWith(1, 'EditSidebarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(2, 'EditSidebarView', 'EditPopoverView')
expect(getPrefixedRoute).toHaveBeenNthCalledWith(3, 'EditSidebarView', 'EditSidebarView')
expect(router.push.mock.calls.length).toEqual(0)
})
})

View File

@ -19,11 +19,668 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventDrop from "../../../../src/fullcalendar/eventDrop.js";
import { getDurationValueFromFullCalendarDuration} from "../../../../src/fullcalendar/duration.js";
import getTimezoneManager from '../../../../src/services/timezoneDataProviderService.js'
jest.mock("../../../../src/fullcalendar/duration.js")
jest.mock('../../../../src/services/timezoneDataProviderService.js')
describe('fullcalendar/eventDrop test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
getDurationValueFromFullCalendarDuration.mockClear()
getTimezoneManager.mockClear()
})
it('should properly drop a non-recurring event', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(1)
expect(eventComponent.shiftByDuration).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 }, false, { calendarJsTimezone: true, tzid: 'America/New_York' }, { calendarJsDurationValue: true, days: 1 }, { calendarJsDurationValue: true, hours: 2 })
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(0)
})
it('should properly drop a recurring event', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(true),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(1)
expect(eventComponent.shiftByDuration).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 }, false, { calendarJsTimezone: true, tzid: 'America/New_York' }, { calendarJsDurationValue: true, days: 1 }, { calendarJsDurationValue: true, hours: 2 })
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenNthCalledWith(1)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(0)
})
it('should revert if delta duration could not be parsed', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce(false)
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(0)
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert if default allday duration could not be parsed', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce(false)
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(0)
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert if default timed duration could not be parsed', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce(false)
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(0)
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when the object was not found', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockRejectedValueOnce({ message: 'error message' }) // getEventByObjectId
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when the recurrence was not found', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(null),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when shiftByDuration throws an exception', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn().mockImplementation(() => {
throw new Error();
}),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockResolvedValueOnce() // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(1)
expect(eventComponent.shiftByDuration).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 }, false, { calendarJsTimezone: true, tzid: 'America/New_York' }, { calendarJsDurationValue: true, days: 1 }, { calendarJsDurationValue: true, hours: 2 })
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(1)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when there was an error updating the event', async () => {
const store = {
dispatch: jest.fn()
}
const fcAPI = {
getOption: jest.fn()
.mockReturnValueOnce({ days: 1 })
.mockReturnValueOnce({ hours: 2 })
.mockReturnValueOnce('America/New_York'),
}
const event = {
allDay: false,
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const delta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce({ calendarJsDurationValue: true, days: 1 })
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 2 })
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const eventComponent = {
shiftByDuration: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch.mockResolvedValueOnce(calendarObject) // getEventByObjectId
store.dispatch.mockImplementationOnce(() => {
throw new Error()
}) // updateCalendarObject
const eventDropFunction = eventDrop(store, fcAPI)
await eventDropFunction({ event, delta, revert })
expect(fcAPI.getOption).toHaveBeenCalledTimes(3)
expect(fcAPI.getOption).toHaveBeenNthCalledWith(1, 'defaultAllDayEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(2, 'defaultTimedEventDuration')
expect(fcAPI.getOption).toHaveBeenNthCalledWith(3, 'timeZone')
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(3)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, delta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, { days: 1})
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(3, { hours: 2 })
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.shiftByDuration).toHaveBeenCalledTimes(1)
expect(eventComponent.shiftByDuration).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 }, false, { calendarJsTimezone: true, tzid: 'America/New_York' }, { calendarJsDurationValue: true, days: 1 }, { calendarJsDurationValue: true, hours: 2 })
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(1)
expect(revert).toHaveBeenCalledTimes(1)
})
})

View File

@ -19,11 +19,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventRender from "../../../../src/fullcalendar/eventRender.js";
describe('services/illustrationProviderService test suite', () => {
describe('fullcalendar/eventRender test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
it('should add extended properties from the event to the dataset of the dom element', () => {
const el = document.createElement('div')
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: 'recurrence456',
},
}
eventRender({ event, el })
expect(el.dataset.objectId).toEqual('object123')
expect(el.dataset.recurrenceId).toEqual('recurrence456')
})
})

View File

@ -19,11 +19,355 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventResize from "../../../../src/fullcalendar/eventResize.js";
import { getDurationValueFromFullCalendarDuration} from '../../../../src/fullcalendar/duration.js'
jest.mock('../../../../src/fullcalendar/duration.js')
describe('fullcalendar/eventResize test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
getDurationValueFromFullCalendarDuration.mockClear()
})
it('should properly resize a non-recurring event', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {
hours: 5
}
const endDelta = {}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce(false)
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch
.mockResolvedValueOnce(calendarObject) // getEventByObjectId
.mockResolvedValueOnce() // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(1)
expect(eventComponent.addDurationToStart).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 })
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(0)
})
it('should properly resize a recurring event', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {}
const endDelta = {
hours: 5
}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce(false)
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(true),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch
.mockResolvedValueOnce(calendarObject) // getEventByObjectId
.mockResolvedValueOnce() // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(0)
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(1)
expect(eventComponent.addDurationToEnd).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 })
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(1)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(0)
})
it('should revert the action when neither a valid start nor end resize was given', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {}
const endDelta = {}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce(false)
.mockReturnValueOnce(false)
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(true),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch
.mockResolvedValueOnce(calendarObject) // getEventByObjectId
.mockResolvedValueOnce() // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(0)
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(0)
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when the object was not found', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {
hours: 5
}
const endDelta = {}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce(false)
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch
.mockImplementationOnce(() => {
throw new Error()
}) // getEventByObjectId
.mockResolvedValueOnce() // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(0)
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when the recurrence was not found', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {
hours: 5
}
const endDelta = {}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce(false)
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(null),
resetToDav: jest.fn()
}
store.dispatch
.mockResolvedValueOnce(calendarObject) // getEventByObjectId
.mockResolvedValueOnce() // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(0)
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(0)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(0)
expect(revert).toHaveBeenCalledTimes(1)
})
it('should revert the action when there was an error updating the event', async () => {
const store = {
dispatch: jest.fn()
}
const event = {
extendedProps: {
objectId: 'object123',
recurrenceId: '1573554842'
}
}
const startDelta = {
hours: 5
}
const endDelta = {}
const revert = jest.fn()
getDurationValueFromFullCalendarDuration
.mockReturnValueOnce({ calendarJsDurationValue: true, hours: 5 })
.mockReturnValueOnce(false)
const eventComponent = {
addDurationToStart: jest.fn(),
addDurationToEnd: jest.fn(),
canCreateRecurrenceExceptions: jest.fn().mockReturnValue(false),
createRecurrenceException: jest.fn(),
}
const calendarObject = {
getObjectAtRecurrenceId: jest.fn().mockReturnValueOnce(eventComponent),
resetToDav: jest.fn()
}
store.dispatch
.mockResolvedValueOnce(calendarObject) // getEventByObjectId
.mockImplementationOnce(() => {
throw new Error()
}) // updateCalendarObject
const eventResizeFunction = eventResize(store)
await eventResizeFunction({ event, startDelta, endDelta, revert })
expect(getDurationValueFromFullCalendarDuration).toHaveBeenCalledTimes(2)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(1, startDelta)
expect(getDurationValueFromFullCalendarDuration).toHaveBeenNthCalledWith(2, endDelta)
expect(store.dispatch).toHaveBeenCalledTimes(2)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventByObjectId', { objectId: 'object123' })
expect(store.dispatch).toHaveBeenNthCalledWith(2, 'updateCalendarObject', { calendarObject })
expect(eventComponent.addDurationToStart).toHaveBeenCalledTimes(1)
expect(eventComponent.addDurationToStart).toHaveBeenNthCalledWith(1, { calendarJsDurationValue: true, hours: 5 })
expect(eventComponent.addDurationToEnd).toHaveBeenCalledTimes(0)
expect(eventComponent.canCreateRecurrenceExceptions).toHaveBeenCalledTimes(1)
expect(eventComponent.createRecurrenceException).toHaveBeenCalledTimes(0)
expect(calendarObject.resetToDav).toHaveBeenCalledTimes(1)
expect(revert).toHaveBeenCalledTimes(1)
})
})

View File

@ -19,11 +19,272 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import eventSource from "../../../../src/fullcalendar/eventSource.js";
import { generateTextColorForRGBString } from '../../../../src/utils/color.js'
import getTimezoneManager from '../../../../src/services/timezoneDataProviderService'
import { getUnixTimestampFromDate } from '../../../../src/utils/date.js'
import { eventSourceFunction } from '../../../../src/fullcalendar/eventSourceFunction.js'
jest.mock('../../../../src/utils/color.js')
jest.mock('../../../../src/services/timezoneDataProviderService')
jest.mock('../../../../src/utils/date.js')
jest.mock('../../../../src/fullcalendar/eventSourceFunction.js')
describe('fullcalendar/eventSource test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
generateTextColorForRGBString.mockClear()
getTimezoneManager.mockClear()
getUnixTimestampFromDate.mockClear()
eventSourceFunction.mockClear()
})
it('should provide an eventSource for a given calendar', () => {
const store = {}
const calendar = {
id: 'calendar-id-123',
color: '#ff00ff',
isReadOnly: false
}
generateTextColorForRGBString
.mockReturnValue('#00ff00')
const eventSourceFunction = eventSource(store)
expect(eventSourceFunction(calendar)).toEqual({
id: 'calendar-id-123',
backgroundColor: '#ff00ff',
borderColor: '#ff00ff',
textColor: '#00ff00',
events: expect.any(Function)
})
expect(generateTextColorForRGBString).toHaveBeenCalledTimes(1)
expect(generateTextColorForRGBString).toHaveBeenNthCalledWith(1, '#ff00ff')
})
it('should provide an eventSource for a given read-only calendar', () => {
const store = {}
const calendar = {
id: 'calendar-id-123',
color: '#ff00ff',
isReadOnly: true
}
generateTextColorForRGBString
.mockReturnValue('#00ff00')
const eventSourceFunction = eventSource(store)
expect(eventSourceFunction(calendar)).toEqual({
id: 'calendar-id-123',
backgroundColor: '#ff00ff',
borderColor: '#ff00ff',
textColor: '#00ff00',
events: expect.any(Function),
editable: false
})
expect(generateTextColorForRGBString).toHaveBeenCalledTimes(1)
expect(generateTextColorForRGBString).toHaveBeenNthCalledWith(1, '#ff00ff')
})
it('should provide an eventSource function to provide events - fetch new timerange', async () => {
const store = {
dispatch: jest.fn()
.mockReturnValueOnce(42),
getters: {
getTimeRangeForCalendarCoveringRange: jest.fn()
.mockReturnValueOnce(false),
getCalendarObjectsByTimeRangeId: jest.fn()
.mockReturnValueOnce([{ calendarObjectId: 1 }, { calendarObjectId: 2 }])
}
}
const calendar = {
id: 'calendar-id-123',
color: '#ff00ff',
isReadOnly: true
}
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
getUnixTimestampFromDate
.mockReturnValueOnce(1234)
.mockReturnValueOnce(5678)
generateTextColorForRGBString
.mockReturnValue('#00ff00')
eventSourceFunction
.mockReturnValueOnce([{ fcEventId: 1 }, { fcEventId: 2 }])
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 31, 59, 59, 59, 999))
const timeZone = 'America/New_York'
const successCallback = jest.fn()
const failureCallback = jest.fn()
const eventSourceFn = eventSource(store)
const { events } = eventSourceFn(calendar)
await events({ start, end, timeZone }, successCallback, failureCallback)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenCalledTimes(1)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenNthCalledWith(1, 'calendar-id-123', 1234, 5678)
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventsFromCalendarInTimeRange', {
calendar,
from: start,
to: end
})
expect(store.getters.getCalendarObjectsByTimeRangeId).toHaveBeenCalledTimes(1)
expect(store.getters.getCalendarObjectsByTimeRangeId).toHaveBeenNthCalledWith(1, 42)
expect(eventSourceFunction).toHaveBeenCalledTimes(1)
expect(eventSourceFunction).toHaveBeenNthCalledWith(1, [{ calendarObjectId: 1 }, { calendarObjectId: 2 }], start, end, { calendarJsTimezone: true, tzid: 'America/New_York' })
expect(successCallback).toHaveBeenCalledTimes(1)
expect(successCallback).toHaveBeenNthCalledWith(1, [{ fcEventId: 1 }, { fcEventId: 2 }])
expect(failureCallback).toHaveBeenCalledTimes(0)
})
it('should provide an eventSource function to provide events - existing timerange', async () => {
const store = {
dispatch: jest.fn()
.mockReturnValueOnce(42),
getters: {
getTimeRangeForCalendarCoveringRange: jest.fn()
.mockReturnValueOnce({
id: 42
}),
getCalendarObjectsByTimeRangeId: jest.fn()
.mockReturnValueOnce([{ calendarObjectId: 1 }, { calendarObjectId: 2 }])
}
}
const calendar = {
id: 'calendar-id-123',
color: '#ff00ff',
isReadOnly: true
}
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
getUnixTimestampFromDate
.mockReturnValueOnce(1234)
.mockReturnValueOnce(5678)
generateTextColorForRGBString
.mockReturnValue('#00ff00')
eventSourceFunction
.mockReturnValueOnce([{ fcEventId: 1 }, { fcEventId: 2 }])
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 31, 59, 59, 59, 999))
const timeZone = 'America/New_York'
const successCallback = jest.fn()
const failureCallback = jest.fn()
const eventSourceFn = eventSource(store)
const { events } = eventSourceFn(calendar)
await events({ start, end, timeZone }, successCallback, failureCallback)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenCalledTimes(1)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenNthCalledWith(1, 'calendar-id-123', 1234, 5678)
expect(store.dispatch).toHaveBeenCalledTimes(0)
expect(store.getters.getCalendarObjectsByTimeRangeId).toHaveBeenCalledTimes(1)
expect(store.getters.getCalendarObjectsByTimeRangeId).toHaveBeenNthCalledWith(1, 42)
expect(eventSourceFunction).toHaveBeenCalledTimes(1)
expect(eventSourceFunction).toHaveBeenNthCalledWith(1, [{ calendarObjectId: 1 }, { calendarObjectId: 2 }], start, end, { calendarJsTimezone: true, tzid: 'America/New_York' })
expect(successCallback).toHaveBeenCalledTimes(1)
expect(successCallback).toHaveBeenNthCalledWith(1, [{ fcEventId: 1 }, { fcEventId: 2 }])
expect(failureCallback).toHaveBeenCalledTimes(0)
})
it('should provide an eventSource function that catches errors while fetching', async () => {
const store = {
dispatch: jest.fn()
.mockImplementationOnce(() => {
throw new Error()
}),
getters: {
getTimeRangeForCalendarCoveringRange: jest.fn()
.mockReturnValueOnce(false),
getCalendarObjectsByTimeRangeId: jest.fn()
.mockReturnValueOnce([{ calendarObjectId: 1 }, { calendarObjectId: 2 }])
}
}
const calendar = {
id: 'calendar-id-123',
color: '#ff00ff',
isReadOnly: true
}
const getTimezoneForId = jest.fn()
.mockReturnValueOnce({ calendarJsTimezone: true, tzid: 'America/New_York' })
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
getUnixTimestampFromDate
.mockReturnValueOnce(1234)
.mockReturnValueOnce(5678)
generateTextColorForRGBString
.mockReturnValue('#00ff00')
eventSourceFunction
.mockReturnValueOnce([{ fcEventId: 1 }, { fcEventId: 2 }])
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 31, 59, 59, 59, 999))
const timeZone = 'America/New_York'
const successCallback = jest.fn()
const failureCallback = jest.fn()
const eventSourceFn = eventSource(store)
const { events } = eventSourceFn(calendar)
await events({ start, end, timeZone }, successCallback, failureCallback)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenCalledTimes(1)
expect(store.getters.getTimeRangeForCalendarCoveringRange).toHaveBeenNthCalledWith(1, 'calendar-id-123', 1234, 5678)
expect(store.dispatch).toHaveBeenCalledTimes(1)
expect(store.dispatch).toHaveBeenNthCalledWith(1, 'getEventsFromCalendarInTimeRange', {
calendar,
from: start,
to: end
})
expect(store.getters.getCalendarObjectsByTimeRangeId).toHaveBeenCalledTimes(0)
expect(eventSourceFunction).toHaveBeenCalledTimes(0)
expect(successCallback).toHaveBeenCalledTimes(0)
expect(failureCallback).toHaveBeenCalledTimes(1)
})
})

View File

@ -19,11 +19,211 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { eventSourceFunction } from '../../../../src/fullcalendar/eventSourceFunction.js'
import { translate } from '@nextcloud/l10n'
jest.mock('@nextcloud/l10n')
describe('fullcalendar/eventSourceFunction test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
translate.mockClear()
})
it('should provide fc-events', () => {
translate
.mockImplementation((app, str) => str)
const eventComponentSet1 = [{
id: '1-1',
// To title on purpose
isAllDay: jest.fn().mockReturnValue(false),
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 123 }),
canModifyAllDay: jest.fn().mockReturnValue(false),
startDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-1-start'
})
},
endDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-1-end'
})
},
}, {
id: '1-2',
status: 'CANCELLED',
isAllDay: jest.fn().mockReturnValue(false),
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 456 }),
canModifyAllDay: jest.fn().mockReturnValue(false),
startDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-2-start'
})
},
endDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-2-end'
})
},
}, {
id: '1-3',
status: 'TENTATIVE',
isAllDay: jest.fn().mockReturnValue(false),
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 789 }),
canModifyAllDay: jest.fn().mockReturnValue(false),
startDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-3-start'
})
},
endDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-1-3-end'
})
},
}]
const eventComponentSet2 = [{
id: '2-1',
status: 'CONFIRMED',
isAllDay: jest.fn().mockReturnValue(true),
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 101 }),
canModifyAllDay: jest.fn().mockReturnValue(true),
startDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-2-1-start'
})
},
endDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-2-1-end'
})
},
}]
const eventComponentSet4 = [{
id: '3-1',
status: 'CONFIRMED',
isAllDay: jest.fn().mockReturnValue(false),
getReferenceRecurrenceId: jest.fn().mockReturnValue({ unixTime: 303 }),
canModifyAllDay: jest.fn().mockReturnValue(true),
startDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-3-1-start'
})
},
endDate: {
getInTimezone: jest.fn().mockReturnValue({
jsDate: 'js-date-3-1-end'
})
},
}]
const calendarObjects = [{
calendarObject: true,
id: '1',
getAllObjectsInTimeRange: jest.fn()
.mockReturnValueOnce(eventComponentSet1),
}, {
calendarObject: true,
id: '2',
getAllObjectsInTimeRange: jest.fn()
.mockReturnValueOnce(eventComponentSet2),
}, {
calendarObject: true,
id: '3',
getAllObjectsInTimeRange: jest.fn()
.mockImplementationOnce(() => {
throw new Error('Error while getting all objects in time-range')
})
}, {
calendarObject: true,
id: '4',
getAllObjectsInTimeRange: jest.fn()
.mockReturnValueOnce(eventComponentSet4),
}]
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 31, 59, 59, 59, 999))
const timezone = { calendarJsTimezone: true, tzid: 'America/New_York' }
const result = eventSourceFunction(calendarObjects, start, end, timezone)
expect(result).toEqual([
{
id: '1###1-1',
title: 'Untitled event',
allDay: false,
start: 'js-date-1-1-start',
end: 'js-date-1-1-end',
classNames: [],
extendedProps: { objectId: '1', recurrenceId: 123, canModifyAllDay: false }
},
{
id: '1###1-2',
title: 'Untitled event',
allDay: false,
start: 'js-date-1-2-start',
end: 'js-date-1-2-end',
classNames: [ 'fc-event-nc-cancelled' ],
extendedProps: { objectId: '1', recurrenceId: 456, canModifyAllDay: false }
},
{
id: '1###1-3',
title: 'Untitled event',
allDay: false,
start: 'js-date-1-3-start',
end: 'js-date-1-3-end',
classNames: [ 'fc-event-nc-tentative' ],
extendedProps: { objectId: '1', recurrenceId: 789, canModifyAllDay: false }
},
{
id: '2###2-1',
title: 'Untitled event',
allDay: true,
start: 'js-date-2-1-start',
end: 'js-date-2-1-end',
classNames: [],
extendedProps: { objectId: '2', recurrenceId: 101, canModifyAllDay: true }
},
{
id: '4###3-1',
title: 'Untitled event',
allDay: false,
start: 'js-date-3-1-start',
end: 'js-date-3-1-end',
classNames: [],
extendedProps: { objectId: '4', recurrenceId: 303, canModifyAllDay: true }
}
])
expect(eventComponentSet1[0].startDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[0].startDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet1[0].endDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[0].endDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet1[1].startDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[1].startDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet1[1].endDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[1].endDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet1[2].startDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[2].startDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet1[2].endDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet1[2].endDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet2[0].startDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet2[0].startDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet2[0].endDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet2[0].endDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet4[0].startDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet4[0].startDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(eventComponentSet4[0].endDate.getInTimezone).toHaveBeenCalledTimes(1)
expect(eventComponentSet4[0].endDate.getInTimezone).toHaveBeenNthCalledWith(1, timezone)
expect(translate).toHaveBeenCalledTimes(5)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Untitled event')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'Untitled event')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'Untitled event')
expect(translate).toHaveBeenNthCalledWith(4, 'calendar', 'Untitled event')
expect(translate).toHaveBeenNthCalledWith(5, 'calendar', 'Untitled event')
})
})

View File

@ -19,11 +19,244 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import select from "../../../../src/fullcalendar/select.js";
describe('fullcalendar/select test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
it('should open the Popover on big screens', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenNthCalledWith(1, {
name: 'NewPopoverView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
})
})
it('should open the Sidebar on big screens if the user wishes so', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenNthCalledWith(1, {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
})
})
it('should open the Sidebar on smaller screens', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = { name: 'CalendarView', params: { otherParam: '456' } }
const window = { innerWidth: 760 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenNthCalledWith(1, {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
})
})
it('should not update the route if the exact time-range is already open - Popover to Popover', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = {
name: 'NewPopoverView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(0)
})
it('should not update the route if the exact time-range is already open - Sidebar to Popover', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(0)
})
it('should not update the route if the exact time-range is already open - Sidebar to Sidebar', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(0)
})
it('should not update the route if the exact time-range is already open - Popover to Sidebar', () => {
const store = { state: { settings: { skipPopover: true } } }
const router = { push: jest.fn() }
const route = {
name: 'NewPopoverView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 0, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 0, 2, 0, 0, 0, 0))
const allDay = true
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(0)
})
it('should not the popover when a new event sidebar is already open - Popover', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = {
name: 'NewPopoverView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 3, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 3, 2, 0, 0, 0, 0))
const allDay = false
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenNthCalledWith(1, {
name: 'NewPopoverView',
params: {
otherParam: '456',
allDay: '0',
dtstart: '1554076800',
dtend: '1554163200',
},
})
})
it('should not the popover when a new event sidebar is already open - Sidebar', () => {
const store = { state: { settings: { skipPopover: false } } }
const router = { push: jest.fn() }
const route = {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '1',
dtstart: '1546300800',
dtend: '1546387200',
},
}
const window = { innerWidth: 1920 }
const start = new Date(Date.UTC(2019, 3, 1, 0, 0, 0, 0))
const end = new Date(Date.UTC(2019, 3, 2, 0, 0, 0, 0))
const allDay = false
const selectFunction = select(store, router, route, window)
selectFunction({ start, end, allDay })
expect(router.push).toHaveBeenCalledTimes(1)
expect(router.push).toHaveBeenNthCalledWith(1, {
name: 'NewSidebarView',
params: {
otherParam: '456',
allDay: '0',
dtstart: '1554076800',
dtend: '1554163200',
},
})
})
})

View File

@ -20,10 +20,80 @@
*
*/
import {
createPlugin,
} from '@fullcalendar/core'
import getTimezoneManager from '../../../../src/services/timezoneDataProviderService.js'
jest.mock('../../../../src/services/timezoneDataProviderService.js')
jest.mock('@fullcalendar/core')
import vtimezoneNamedTimezoneImpl from "../../../../src/fullcalendar/vtimezoneNamedTimezoneImpl.js";
describe('fullcalendar/vtimezoneNamedTimezoneImpl test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
beforeEach(() => {
getTimezoneManager.mockClear()
})
it('should properly register a plugin for full-calendar', () => {
expect(createPlugin).toHaveBeenCalledTimes(1)
expect(createPlugin).toHaveBeenNthCalledWith(1, {
namedTimeZonedImpl: expect.any(Function)
})
})
it('should properly implement the offsetForArray method', () => {
const timezone = {
calendarJsTimezone: true,
tzid: 'America/New_York',
offsetForArray: jest.fn().mockReturnValue(1337 * 60)
}
const getTimezoneForId = jest.fn()
.mockReturnValue(timezone)
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const VTimezoneNamedTimezone = createPlugin.mock.calls[0][0].namedTimeZonedImpl
const instance = new VTimezoneNamedTimezone('America/New_York')
const result = instance.offsetForArray([2019, 0, 1, 14, 30, 0])
expect(result).toEqual(1337)
expect(getTimezoneForId).toHaveBeenCalledTimes(1)
expect(timezone.offsetForArray).toHaveBeenCalledTimes(1)
expect(timezone.offsetForArray).toHaveBeenNthCalledWith(1, 2019, 1, 1, 14, 30, 0)
})
it('should properly implement the timestampToArray method', () => {
const timezone = {
calendarJsTimezone: true,
tzid: 'America/New_York',
timestampToArray: jest.fn().mockReturnValue([2019, 1, 1, 14, 30, 0])
}
const getTimezoneForId = jest.fn()
.mockReturnValue(timezone)
getTimezoneManager
.mockReturnValue({
getTimezoneForId
})
const VTimezoneNamedTimezone = createPlugin.mock.calls[0][0].namedTimeZonedImpl
const instance = new VTimezoneNamedTimezone('America/New_York')
const result = instance.timestampToArray(1337)
expect(result).toEqual([2019, 0, 1, 14, 30, 0])
expect(getTimezoneForId).toHaveBeenCalledTimes(1)
expect(timezone.timestampToArray).toHaveBeenCalledTimes(1)
expect(timezone.timestampToArray).toHaveBeenNthCalledWith(1, 1337)
})
})

View File

@ -20,7 +20,7 @@
*
*/
describe('services/datew test suite', () => {
describe('models/calendarOje test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)

View File

@ -19,78 +19,120 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import rfcProps from '../../../../src/models/rfcProps.js'
import { getRFCProperties } from '../../../../src/models/rfcProps.js'
import { translate } from '@nextcloud/l10n'
import { getDefaultCategories } from '../../../../src/defaults/defaultCategories.js'
jest.mock('@nextcloud/l10n')
jest.mock('../../../../src/defaults/defaultCategories.js')
describe('models/rfcProps test suite', () => {
it('should provide property info for access class', () => {
expect(rfcProps.accessClass).toEqual(expect.any(Object))
beforeEach(() => {
translate.mockClear()
getDefaultCategories.mockClear()
expect(rfcProps.accessClass.readableName).toEqual('TRANSLATED:When shared show')
translate
.mockImplementation((app, str) => str)
getDefaultCategories
.mockReturnValue(['Category 1', 'Category 2', 'Category 3'])
})
it('should provide property info for rfc properties', () => {
const rfcProps = getRFCProperties()
expect(rfcProps.accessClass).toEqual(expect.any(Object))
expect(rfcProps.accessClass.readableName).toEqual('When shared show')
expect(rfcProps.accessClass.icon).toEqual('icon-eye')
expect(rfcProps.accessClass.multiple).toEqual(false)
expect(rfcProps.accessClass.info).toEqual('TRANSLATED:The visibility of this event in shared calendars.')
expect(rfcProps.accessClass.info).toEqual('The visibility of this event in shared calendars.')
expect(rfcProps.accessClass.defaultValue).toEqual('PUBLIC')
})
expect(rfcProps.accessClass.options).toEqual([
{value: 'PUBLIC', label: 'When shared show full event'},
{value: 'CONFIDENTIAL', label: 'When shared show only busy'},
{value: 'PRIVATE', label: 'When shared hide this event'},
])
it('should provide property info for location', () => {
expect(rfcProps.location).toEqual(expect.any(Object))
expect(rfcProps.location.readableName).toEqual('TRANSLATED:Location')
expect(rfcProps.location.placeholder).toEqual('TRANSLATED:Add a location')
expect(rfcProps.location.readableName).toEqual('Location')
expect(rfcProps.location.placeholder).toEqual('Add a location')
expect(rfcProps.location.icon).toEqual('icon-address')
expect(rfcProps.location.defaultNumberOfRows).toEqual(undefined)
})
it('should provide property info for description', () => {
expect(rfcProps.description).toEqual(expect.any(Object))
expect(rfcProps.description.readableName).toEqual('TRANSLATED:Description')
expect(rfcProps.description.placeholder).toEqual('TRANSLATED:Add a description')
expect(rfcProps.description.readableName).toEqual('Description')
expect(rfcProps.description.placeholder).toEqual('Add a description')
expect(rfcProps.description.icon).toEqual('icon-menu')
expect(rfcProps.description.defaultNumberOfRows).toEqual(2)
})
it('should provide property info for status', () => {
expect(rfcProps.status).toEqual(expect.any(Object))
expect(rfcProps.status.readableName).toEqual('TRANSLATED:Status')
expect(rfcProps.status.readableName).toEqual('Status')
expect(rfcProps.status.icon).toEqual('icon-checkmark')
expect(rfcProps.status.multiple).toEqual(false)
expect(rfcProps.status.info).toEqual('TRANSLATED:Confirmation about the overall status of the event.')
expect(rfcProps.status.info).toEqual('Confirmation about the overall status of the event.')
expect(rfcProps.status.defaultValue).toEqual('CONFIRMED')
})
expect(rfcProps.status.options).toEqual([
{ value: 'CONFIRMED', label: 'Confirmed' },
{ value: 'TENTATIVE', label: 'Tentative' },
{ value: 'CANCELLED', label: 'Cancelled' },
])
it('should provide property info for timeTransparency', () => {
expect(rfcProps.timeTransparency).toEqual(expect.any(Object))
expect(rfcProps.timeTransparency.readableName).toEqual('TRANSLATED:Show as')
expect(rfcProps.timeTransparency.readableName).toEqual('Show as')
expect(rfcProps.timeTransparency.icon).toEqual('icon-briefcase')
expect(rfcProps.timeTransparency.multiple).toEqual(false)
expect(rfcProps.timeTransparency.info).toEqual('TRANSLATED:Take this event into account when calculating free-busy information.')
expect(rfcProps.timeTransparency.info).toEqual('Take this event into account when calculating free-busy information.')
expect(rfcProps.timeTransparency.defaultValue).toEqual('TRANSPARENT')
})
expect(rfcProps.timeTransparency.options).toEqual([
{ value: 'TRANSPARENT', label: 'Free' },
{ value: 'OPAQUE', label: 'Busy' },
])
it('should provide property info for categories', () => {
expect(rfcProps.categories).toEqual(expect.any(Object))
expect(rfcProps.categories.readableName).toEqual('TRANSLATED:Categories')
expect(rfcProps.categories.readableName).toEqual('Categories')
expect(rfcProps.categories.icon).toEqual('icon-tag')
expect(rfcProps.categories.multiple).toEqual(true)
expect(rfcProps.categories.info).toEqual('TRANSLATED:Categories help you to structure and organize your events.')
expect(rfcProps.categories.placeholder).toEqual('TRANSLATED:Search or add categories')
expect(rfcProps.categories.tagPlaceholder).toEqual('TRANSLATED:Add this as a new category')
})
expect(rfcProps.categories.info).toEqual('Categories help you to structure and organize your events.')
expect(rfcProps.categories.placeholder).toEqual('Search or add categories')
expect(rfcProps.categories.tagPlaceholder).toEqual('Add this as a new category')
expect(rfcProps.categories.options).toEqual(['Category 1', 'Category 2', 'Category 3'])
it('should provide property info for color', () => {
expect(rfcProps.color).toEqual(expect.any(Object))
expect(rfcProps.color.readableName).toEqual('TRANSLATED:Custom color')
expect(rfcProps.color.readableName).toEqual('Custom color')
expect(rfcProps.color.multiple).toEqual(false)
expect(rfcProps.color.icon).toEqual('icon-color-picker')
expect(rfcProps.color.info).toEqual('TRANSLATED:Special color of this event. Overrides the calendar-color.')
expect(rfcProps.color.info).toEqual('Special color of this event. Overrides the calendar-color.')
// expect(translate).toHaveBeenCalledTimes(10)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'When shared show')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'When shared show full event')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'When shared show only busy')
expect(translate).toHaveBeenNthCalledWith(4, 'calendar', 'When shared hide this event')
expect(translate).toHaveBeenNthCalledWith(5, 'calendar', 'The visibility of this event in shared calendars.')
expect(translate).toHaveBeenNthCalledWith(6, 'calendar', 'Location')
expect(translate).toHaveBeenNthCalledWith(7, 'calendar', 'Add a location')
expect(translate).toHaveBeenNthCalledWith(8, 'calendar', 'Description')
expect(translate).toHaveBeenNthCalledWith(9, 'calendar', 'Add a description')
expect(translate).toHaveBeenNthCalledWith(10, 'calendar', 'Status')
expect(translate).toHaveBeenNthCalledWith(11, 'calendar', 'Confirmed')
expect(translate).toHaveBeenNthCalledWith(12, 'calendar', 'Tentative')
expect(translate).toHaveBeenNthCalledWith(13, 'calendar', 'Cancelled')
expect(translate).toHaveBeenNthCalledWith(14, 'calendar', 'Confirmation about the overall status of the event.')
expect(translate).toHaveBeenNthCalledWith(15, 'calendar', 'Show as')
expect(translate).toHaveBeenNthCalledWith(16, 'calendar', 'Take this event into account when calculating free-busy information.')
expect(translate).toHaveBeenNthCalledWith(17, 'calendar', 'Free')
expect(translate).toHaveBeenNthCalledWith(18, 'calendar', 'Busy')
expect(translate).toHaveBeenNthCalledWith(19, 'calendar', 'Categories')
expect(translate).toHaveBeenNthCalledWith(20, 'calendar', 'Categories help you to structure and organize your events.')
expect(translate).toHaveBeenNthCalledWith(21, 'calendar', 'Search or add categories')
expect(translate).toHaveBeenNthCalledWith(22, 'calendar', 'Add this as a new category')
expect(translate).toHaveBeenNthCalledWith(23, 'calendar', 'Custom color')
expect(translate).toHaveBeenNthCalledWith(24, 'calendar', 'Special color of this event. Overrides the calendar-color.')
})
})

View File

@ -1,29 +0,0 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('services/colorService test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
})
})

View File

@ -1,29 +0,0 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('services/defaultColor test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
})
})

View File

@ -1,29 +0,0 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('services/loggerService test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
})
})

View File

@ -1,29 +0,0 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('services/productInformationProvider test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
})
})

View File

@ -1,29 +0,0 @@
/**
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke <oc.list@georgehrke.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
describe('services/settingsService test suite', () => {
it('should be true', () => {
expect(true).toEqual(true)
})
})

View File

@ -20,14 +20,28 @@
*
*/
import getIllustrationForTitle from "../../../../src/utils/illustration.js";
import { imagePath } from '@nextcloud/router'
jest.mock('@nextcloud/router')
describe('utils/illustration test suite', () => {
beforeEach(() => {
imagePath.mockClear()
})
it('should return a matching illustration', () => {
imagePath.mockImplementation((app, image) => 'imagePath###' + app + '###' + image)
expect(getIllustrationForTitle('Watch movie with Jane')).toEqual('imagePath###calendar###illustrations/movie_night')
expect(getIllustrationForTitle('Take time to relax')).toEqual('imagePath###calendar###illustrations/relaxation')
expect(getIllustrationForTitle('Give presentation about calendar')).toEqual('imagePath###calendar###illustrations/presentation')
expect(getIllustrationForTitle('ABC', ['Watch', 'movie'])).toEqual('imagePath###calendar###illustrations/movie_night')
expect(imagePath).toHaveBeenCalledTimes(4)
expect(imagePath).toHaveBeenNthCalledWith(1, 'calendar', 'illustrations/movie_night')
expect(imagePath).toHaveBeenNthCalledWith(2, 'calendar', 'illustrations/relaxation')
expect(imagePath).toHaveBeenNthCalledWith(3, 'calendar', 'illustrations/presentation')
expect(imagePath).toHaveBeenNthCalledWith(4, 'calendar', 'illustrations/movie_night')
})
})

View File

@ -19,15 +19,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import {
getConfigValueFromHiddenInput,
getLinkToConfig
} from '../../../../src/utils/settings.js'
import { getConfigValueFromHiddenInput, getLinkToConfig } from '../../../../src/utils/settings.js'
import { linkTo } from '@nextcloud/router'
jest.mock('@nextcloud/router')
describe('utils/settings test suite', () => {
beforeEach(() => {
linkTo.mockClear()
})
it('should read a config value from DOM', () => {
document.body.innerHTML = `
<input id="config-first-day" value="1" />
@ -40,7 +41,13 @@ describe('utils/settings test suite', () => {
})
it('should generate a link to the config api', () => {
expect(getLinkToConfig('view')).toEqual('linkTo###calendar###index.php/v1/config/view')
expect(getLinkToConfig('weekends')).toEqual('linkTo###calendar###index.php/v1/config/weekends')
linkTo.mockImplementation(() => 'baseurl:')
expect(getLinkToConfig('view')).toEqual('baseurl:/v1/config/view')
expect(getLinkToConfig('weekends')).toEqual('baseurl:/v1/config/weekends')
expect(linkTo).toHaveBeenCalledTimes(2)
expect(linkTo).toHaveBeenNthCalledWith(1, 'calendar', 'index.php')
expect(linkTo).toHaveBeenNthCalledWith(2, 'calendar', 'index.php')
})
})

View File

@ -23,12 +23,20 @@ import {
getSortedTimezoneList,
getReadableTimezoneName
} from '../../../../src/utils/timezone.js'
import { translate } from '@nextcloud/l10n'
jest.mock('@nextcloud/l10n')
describe('utils/timezone test suite', () => {
beforeEach(() => {
translate.mockClear()
})
it('should sort a timezone list', () => {
translate
.mockImplementation((app, str) => str)
const sorted = getSortedTimezoneList([
'Europe/Berlin',
'Europe/Amsterdam',
@ -43,7 +51,7 @@ describe('utils/timezone test suite', () => {
label: 'ABC',
timezoneId: 'id123'
}, {
continent: 'TRANSLATED:Global',
continent: 'Global',
label: 'DEF',
timezoneId: 'id456'
}])
@ -82,7 +90,7 @@ describe('utils/timezone test suite', () => {
timezoneId: 'id123'
}])
expect(sorted[3].continent).toEqual('TRANSLATED:Global')
expect(sorted[3].continent).toEqual('Global')
expect(sorted[3].regions).toEqual([{
cities: [],
label: 'DEF',
@ -100,6 +108,11 @@ describe('utils/timezone test suite', () => {
label: 'Z',
timezoneId: 'Z'
}])
expect(translate).toHaveBeenCalledTimes(3)
expect(translate).toHaveBeenNthCalledWith(1, 'calendar', 'Global')
expect(translate).toHaveBeenNthCalledWith(2, 'calendar', 'Global')
expect(translate).toHaveBeenNthCalledWith(3, 'calendar', 'Global')
})
it ('should get a readable timezone name', () => {

View File

@ -42,7 +42,7 @@ module.exports = {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules\/(?!(p-limit|p-defer|p-queue|p-try|cdav-library))/
exclude: /node_modules\/(?!(p-limit|p-defer|p-queue|p-try|cdav-library|calendar-js))/
},
{
test: /\.(png|jpg|gif|svg)$/,