- Implement RecurringEventsDataService for fetching events from SharePoint lists. - Define types for events and categories in RecurringEventsTypes. - Create RecurringEventsWebPart to manage properties and render events. - Develop UI components for displaying events in filmstrip and compact layouts. - Add localization support for English and German languages. - Implement tests for core functionalities related to event handling. - Set up TypeScript and TSLint configurations for the project.
41 lines
2.3 KiB
TypeScript
41 lines
2.3 KiB
TypeScript
import {
|
|
calculateDateRange,
|
|
filterAndSortEvents,
|
|
getMonthAnchors,
|
|
normalizeAssetUrl,
|
|
normalizeMaxEvents,
|
|
normalizeRangeDays,
|
|
parseSharePointDate
|
|
} from '../src/webparts/recurringEvents/RecurringEventsCore';
|
|
import { IEventDateRange, IRecurringEvent } from '../src/webparts/recurringEvents/RecurringEventsTypes';
|
|
|
|
declare const console: { log(message: string): void };
|
|
let passed: number = 0;
|
|
function assert(condition: boolean, message: string): void { if (!condition) { throw new Error(message); } passed++; }
|
|
function event(key: string, day: number, type: number, category: string): IRecurringEvent {
|
|
return {
|
|
key: key, id: 1, title: key + '-' + type,
|
|
start: new Date(2026, 7, day, 10), end: new Date(2026, 7, day, 11), allDay: false,
|
|
location: '', category: category, description: '', imageUrl: '', detailsUrl: '', recurring: true, eventType: type
|
|
};
|
|
}
|
|
|
|
const range: IEventDateRange = calculateDateRange(30, new Date(2026, 7, 10, 15));
|
|
assert(range.start.getHours() === 0 && range.start.getDate() === 10, 'Range must start at local midnight.');
|
|
assert(range.end.getDate() === 9 && range.end.getMonth() === 8, '30-day range end is invalid.');
|
|
assert(normalizeRangeDays(14) === 14 && normalizeRangeDays(13) === 30, 'Range values must be constrained.');
|
|
assert(normalizeMaxEvents(0) === 10 && normalizeMaxEvents(80) === 50, 'Maximum event count must be constrained.');
|
|
assert(getMonthAnchors(new Date(2026, 6, 1), new Date(2026, 8, 1)).length === 3, 'Every affected month must be queried.');
|
|
assert(parseSharePointDate('2026-08-24 10:30:00').getUTCMinutes() === 30, 'SOAP UTC date must be parsed as UTC.');
|
|
assert(normalizeAssetUrl('javascript:alert(1)', 'http://portal') === '', 'Unsafe image URL must be rejected.');
|
|
assert(normalizeAssetUrl('/SiteAssets/event.jpg', 'http://portal') === '/SiteAssets/event.jpg', 'Relative image URL must be retained.');
|
|
|
|
const filtered: IRecurringEvent[] = filterAndSortEvents([
|
|
event('series|1', 12, 1, 'Work'), event('series|1', 12, 4, 'Work'),
|
|
event('deleted', 13, 3, 'Work'), event('other', 11, 0, 'Private')
|
|
], range, 'Work', 10);
|
|
assert(filtered.length === 1, 'Category, deleted occurrences and duplicates must be filtered.');
|
|
assert(filtered[0].eventType === 4, 'A modified occurrence must override its generated occurrence.');
|
|
|
|
console.log('Recurring events core tests passed: ' + passed);
|