Files
ontime/apps/client/src/features/rundown/__tests__/rundown.utils.test.ts
T
Carlos Valente ae15f3cdc5 Alpha 5 (#1741)
* refactor: align header columns

* refactor: improve scrollbar visibility

* refactor: center align table elements

* refactor: make param elements stateful

* fix: issue with collapsed elements not loosing value

* fix: prevent search params containing multiple alias references

* fix: the issue where a file disappears if it is both migrated and recovered in the same load operation (#1744)

* refactor: disable group action for elements in groups

* refactor: move context menu items into the event element (#1747)

* feat: sheet import new features for v4 (#1730)

* import milestone

* fixup! import milestone

* test: milestone import

* add entries to group

stop on new group or on group-end type

* fixup! add entries to group

* cleanup

* add event target duration

* link start if undefined

* add skip import type

* extract some to the excel paresing functions

* tweaks to presentation

* move file

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* fix: notify runtimeStore of events bieng groupd

* fix: improve authentication and stage detection in demo

* chore: ship logo with project

* fix: client is referenced by name

* fix: prevent reflow in event editor

* fix: stale render on selected event due to ref mismatch

* Create/Load/Delete multiple rundowns (#1696)

* refactor: restore last loaded rundown

* refactor: initialise rundown in ProjectService

* feat: allow switching rundowns

ensure on coordination between the db object and the working object

server provide list of rundowns

implement switch in the UI

implement delete

implement new rundown button

* fix: render order for floating button

* refactor: appropriate names to service

* refactor: rundown endpoints

* refactor: save last loaded rundown ID

* refactor: rundown management UI

* refactor: emit refetch all on project load

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* feat: recover single event subscription

* fixup! feat: sheet import new features for v4 (#1730)

* fix: prevent dropping a group inside another

* fixup! refactor: move context menu items into the event element (#1747)

* fix: prevent stale references to custom fields

* fix: propagate updates to all rundowns

* refactor: client rundown metadata (#1728)

* generate metadata in the hook

* move test

* ensure there is always a last element

* use for-loop

* update metadata in useEfect

* fully extract metadata generation

* use direct assignment

* cleanup

---------

Co-authored-by: Carlos Valente <carlosvalente@pm.me>

* refactor: small imporvement and tests for coerce functions (#1752)

* refactor: small imporvement and tests for coerce functions

add test `coerceString`

add test `coerceBoolean`

add test `coerceColour`

* remove old todo

* fix: consistent quick add behaviour

* refactor: create flat rundown with metadata

* fix: show add buttons on top

* feat: allow editing milestones

* refactor: style tweaks to rundown elements

refactor: milestones are full width

refactor: cuesheet header alignment

fix: editor styling in cuesheet

* refactor: virtualise table

* refactor: improve overscan (#1758)

* bump version to 4.0.0-alpha.5

---------

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
2025-09-03 15:50:20 +02:00

287 lines
9.8 KiB
TypeScript

import { EntryId, OntimeEvent, OntimeGroup, RundownEntries, SupportedEntry } from 'ontime-types';
import { makeSortableList, moveDown, moveUp, orderEntries } from '../rundown.utils';
describe('makeSortableList()', () => {
it('generates a list with group ends', () => {
const order = ['group-1', '2', 'group-3', 'group-4'];
const entries: RundownEntries = {
'group-1': { type: SupportedEntry.Group, id: 'group-1', entries: ['11'] } as OntimeGroup,
'11': { type: SupportedEntry.Event, id: '11', parent: 'group-1' } as OntimeEvent,
'2': { type: SupportedEntry.Event, id: '2', parent: null } as OntimeEvent,
'group-3': { type: SupportedEntry.Group, id: 'group-3', entries: ['31'] } as OntimeGroup,
'31': { type: SupportedEntry.Event, id: '31', parent: 'group-3' } as OntimeEvent,
'group-4': { type: SupportedEntry.Group, id: 'group-4', entries: [] as string[] } as OntimeGroup,
};
const sortableList = makeSortableList(order, entries);
expect(sortableList).toStrictEqual([
'group-1',
'11',
'end-group-1',
'2',
'group-3',
'31',
'end-group-3',
'group-4',
'end-group-4',
]);
});
it('closes dangling group', () => {
const order = ['group'];
const entries: RundownEntries = {
group: { type: SupportedEntry.Group, id: 'group-1', entries: ['11', '12'] } as OntimeGroup,
'11': { type: SupportedEntry.Event, id: '11', parent: 'group-1' } as OntimeEvent,
'12': { type: SupportedEntry.Event, id: '12', parent: 'group-1' } as OntimeEvent,
};
const sortableList = makeSortableList(order, entries);
expect(sortableList).toStrictEqual(['group-1', '11', '12', 'end-group-1']);
});
it('handles a list with just groups', () => {
const order = ['group-1', 'group-2'];
const entries: RundownEntries = {
'group-1': { type: SupportedEntry.Group, id: 'group-1', entries: [] as string[] } as OntimeGroup,
'group-2': { type: SupportedEntry.Group, id: 'group-2', entries: [] as string[] } as OntimeGroup,
};
const sortableList = makeSortableList(order, entries);
expect(sortableList).toStrictEqual(['group-1', 'end-group-1', 'group-2', 'end-group-2']);
});
});
describe('moveUp()', () => {
const rundown = {
entries: {
'1': { id: '1', type: 'event', parent: null } as OntimeEvent,
'2': { id: '2', type: 'event', parent: null } as OntimeEvent,
'3': { id: '3', type: 'event', parent: null } as OntimeEvent,
group: { id: 'group', type: 'group', entries: ['11', '12'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
'12': { id: '12', type: 'event', parent: 'group' } as OntimeEvent,
'4': { id: '4', type: 'event', parent: null } as OntimeEvent,
group2: { id: 'group2', type: 'group', entries: [] as EntryId[] } as OntimeGroup,
'5': { id: '5', type: 'event', parent: null } as OntimeEvent,
},
order: ['1', '2', '3', 'group', '4', 'group2', '5'],
flatOrder: ['1', '2', '3', 'group', '11', '12', '4', 'group2', '5'],
};
it('moving the first event is a noop', () => {
expect(moveUp('1', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: null,
order: 'before',
});
});
it('moves an entry up in the rundown', () => {
expect(moveUp('2', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '1',
order: 'before',
});
});
it('moves an entry up inside a group', () => {
expect(moveUp('12', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '11',
order: 'before',
});
});
it('moves an entry up into an empty group', () => {
expect(moveUp('5', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group2',
order: 'insert',
});
});
it('moves an entry up into a group', () => {
expect(moveUp('4', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '12',
order: 'after',
});
});
it('moves an entry up out of a group', () => {
expect(moveUp('11', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group',
order: 'before',
});
});
it('moves a group in the rundown', () => {
expect(moveUp('group', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '3',
order: 'before',
});
});
it('swaps two groups', () => {
const rundown = {
entries: {
group: { id: 'group', type: 'group', entries: ['11'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
group2: { id: 'group2', type: 'group', entries: [] as EntryId[] } as OntimeGroup,
},
order: ['group', 'group2'],
flatOrder: ['group', '11', 'group2'],
};
expect(moveUp('group2', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group',
order: 'before',
});
});
it('moves before a group', () => {
const rundown = {
entries: {
group: { id: 'group', type: 'group', entries: ['11'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
},
order: ['group'],
flatOrder: ['group', '11'],
};
expect(moveUp('11', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group',
order: 'before',
});
});
});
describe('moveDown()', () => {
const rundown = {
entries: {
'1': { id: '1', type: 'event', parent: null } as OntimeEvent,
'2': { id: '2', type: 'event', parent: null } as OntimeEvent,
'3': { id: '3', type: 'event', parent: null } as OntimeEvent,
group: { id: 'group', type: 'group', entries: ['11', '12'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
'12': { id: '12', type: 'event', parent: 'group' } as OntimeEvent,
'4': { id: '4', type: 'event', parent: null } as OntimeEvent,
group2: { id: 'group2', type: 'group', entries: [] as EntryId[] } as OntimeGroup,
'5': { id: '5', type: 'event', parent: null } as OntimeEvent,
},
order: ['1', '2', '3', 'group', '4', 'group2', '5'],
flatOrder: ['1', '2', '3', 'group', '11', '12', '4', 'group2', '5'],
};
it('moving the last event is a noop', () => {
expect(moveDown('5', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: null,
order: 'after',
});
});
it('moves an entry down in the rundown', () => {
expect(moveDown('2', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '3',
order: 'after',
});
});
it('moves an entry down inside a group', () => {
expect(moveDown('11', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '12',
order: 'after',
});
});
it('moves an entry down into an empty group', () => {
expect(moveDown('4', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group2',
order: 'insert',
});
});
it('moves an entry down out of a group', () => {
expect(moveDown('12', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group',
order: 'after',
});
});
it('moves an entry down into a group', () => {
expect(moveDown('3', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '11',
order: 'before',
});
});
it('moves a group in the rundown', () => {
expect(moveDown('group', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: '4',
order: 'after',
});
});
it('swaps two groups', () => {
const rundown = {
entries: {
group: { id: 'group', type: 'group', entries: ['11'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
group2: { id: 'group2', type: 'group', entries: [] as EntryId[] } as OntimeGroup,
},
order: ['group', 'group2'],
flatOrder: ['group', '11', 'group2'],
};
expect(moveDown('group', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group2',
order: 'after',
});
});
it('moves after a group', () => {
const rundown = {
entries: {
group: { id: 'group', type: 'group', entries: ['11'] } as OntimeGroup,
'11': { id: '11', type: 'event', parent: 'group' } as OntimeEvent,
},
order: ['group'],
flatOrder: ['group', '11'],
};
expect(moveDown('11', rundown.flatOrder, rundown.entries)).toStrictEqual({
destinationId: 'group',
order: 'after',
});
});
});
describe('orderEntries()', () => {
it('should return an empty array when both inputs are empty', () => {
const unorderedArray: string[] = [];
const flatOrder: string[] = [];
const result = orderEntries(unorderedArray, flatOrder);
expect(result).toEqual([]);
});
it('should return an ordered array based on flatOrder', () => {
const unorderedArray = ['b', 'a', 'c'];
const flatOrder = ['a', 'b', 'c'];
const result = orderEntries(unorderedArray, flatOrder);
expect(result).toEqual(['a', 'b', 'c']);
});
it('should ignore elements in unorderedArray not present in flatOrder', () => {
const unorderedArray = ['b', 'a', 'c', 'd'];
const flatOrder = ['a', 'b', 'c'];
const result = orderEntries(unorderedArray, flatOrder);
expect(result).toEqual(['a', 'b', 'c']);
});
it('should handle cases where flatOrder has elements not in unorderedArray', () => {
const unorderedArray = ['b', 'a'];
const flatOrder = ['a', 'b', 'c'];
const result = orderEntries(unorderedArray, flatOrder);
expect(result).toEqual(['a', 'b']);
});
it('should return an empty array if unorderedArray has no matching elements in flatOrder', () => {
const unorderedArray = ['x', 'y', 'z'];
const flatOrder = ['a', 'b', 'c'];
const result = orderEntries(unorderedArray, flatOrder);
expect(result).toEqual([]);
});
});