mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 18:33:53 +00:00
Prefeat/skip (#188)
* refactor: refactor size of event list * refactor: optimise event mutations * refactor: prepare skip feature * refactor: update tests * refactor: simplify type assertion
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import { getPreviousPlayable } from '../eventUtils.js';
|
||||
|
||||
describe('getPreviousPlayable()', () => {
|
||||
describe('given a list of events', () => {
|
||||
it('finds the previous playable event', () => {
|
||||
const events = [
|
||||
{ id: 100, type: 'delay' },
|
||||
{ id: 101, type: 'event', skip: true },
|
||||
{ id: 102, type: 'event', skip: true },
|
||||
{ id: 103, type: 'event', skip: false },
|
||||
{ id: 'not-this', type: 'block' },
|
||||
{ id: 104, type: 'event' },
|
||||
];
|
||||
const { index, id } = getPreviousPlayable(events, events[4].id);
|
||||
expect(index).toBe(3);
|
||||
expect(id).toBe(103);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handles common errors', () => {
|
||||
it('returns null if id not found in list', () => {
|
||||
const events = [
|
||||
{ id: 0, type: 'delay' },
|
||||
{ id: 1, type: 'event', skip: true },
|
||||
{ id: 2, type: 'event', skip: true },
|
||||
{ id: 3, type: 'event', skip: false },
|
||||
{ id: 4, type: 'event' },
|
||||
];
|
||||
const { index, id } = getPreviousPlayable(events, 'no-valid-id');
|
||||
expect(index).toBe(null);
|
||||
expect(id).toBe(null);
|
||||
});
|
||||
|
||||
it('returns null if there are no previous events to play', () => {
|
||||
const events = [
|
||||
{ id: 0, type: 'delay' },
|
||||
{ id: 1, type: 'event', skip: true },
|
||||
{ id: 2, type: 'event', skip: true },
|
||||
{ id: 3, type: 'event', skip: true },
|
||||
{ id: 4, type: 'event' },
|
||||
];
|
||||
const { index, id } = getPreviousPlayable(events, events[4].id);
|
||||
expect(index).toBe(null);
|
||||
expect(id).toBe(null);
|
||||
});
|
||||
|
||||
it('returns null if list is empty', () => {
|
||||
const events = [];
|
||||
const { index, id } = getPreviousPlayable(events, 'made-up');
|
||||
expect(index).toBe(null);
|
||||
expect(id).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import jest from 'jest-mock';
|
||||
import { dbModelv1, dbModelv1 as dbModel } from '../../models/dataModel.js';
|
||||
import { parseExcel_v1, parseJson_v1, validateEvent_v1 } from '../parser.js';
|
||||
import { isStringEmpty, parseExcel_v1, parseJson_v1, validateEvent_v1 } from '../parser.js';
|
||||
import { makeString, validateDuration } from '../parserUtils.js';
|
||||
import { parseAliases_v1, parseUserFields_v1 } from '../parserUtils_v1.js';
|
||||
|
||||
@@ -42,7 +42,8 @@ describe('test json parser with valid def', () => {
|
||||
timeType: 'start-end',
|
||||
duration: 36000000 - 32400000,
|
||||
isPublic: true,
|
||||
colour: '',
|
||||
skip: true,
|
||||
colour: 'red',
|
||||
type: 'event',
|
||||
revision: 0,
|
||||
id: 'f24d',
|
||||
@@ -92,6 +93,7 @@ describe('test json parser with valid def', () => {
|
||||
timeType: 'start-end',
|
||||
duration: 39000000 - 37200000,
|
||||
isPublic: true,
|
||||
skip: false,
|
||||
colour: '',
|
||||
type: 'event',
|
||||
revision: 0,
|
||||
@@ -208,6 +210,7 @@ describe('test json parser with valid def', () => {
|
||||
timeType: 'start-end',
|
||||
duration: 32400000 - 31500000,
|
||||
isPublic: false,
|
||||
skip: false,
|
||||
colour: '',
|
||||
type: 'event',
|
||||
revision: 0,
|
||||
@@ -226,6 +229,37 @@ describe('test json parser with valid def', () => {
|
||||
expect(first).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('second event is as a match', () => {
|
||||
const second = parseResponse?.events[1];
|
||||
const expected = {
|
||||
title: 'Good Morning',
|
||||
subtitle: 'Days schedule',
|
||||
presenter: 'Carlos Valente',
|
||||
note: '',
|
||||
timeStart: 32400000,
|
||||
timeEnd: 36000000,
|
||||
timeType: 'start-end',
|
||||
duration: 36000000 - 32400000,
|
||||
isPublic: true,
|
||||
skip: true,
|
||||
colour: 'red',
|
||||
type: 'event',
|
||||
revision: 0,
|
||||
id: 'f24d',
|
||||
user0: '',
|
||||
user1: '',
|
||||
user2: '',
|
||||
user3: '',
|
||||
user4: '',
|
||||
user5: '',
|
||||
user6: '',
|
||||
user7: '',
|
||||
user8: '',
|
||||
user9: '',
|
||||
};
|
||||
expect(second).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
it('loaded event settings', () => {
|
||||
const eventTitle = parseResponse?.event?.title;
|
||||
expect(eventTitle).toBe('This is a test definition');
|
||||
@@ -436,6 +470,7 @@ describe('test event validator', () => {
|
||||
timeStart: expect.any(Number),
|
||||
timeEnd: expect.any(Number),
|
||||
isPublic: expect.any(Boolean),
|
||||
skip: expect.any(Boolean),
|
||||
revision: expect.any(Number),
|
||||
type: expect.any(String),
|
||||
id: expect.any(String),
|
||||
@@ -534,6 +569,7 @@ describe('test parseExcel function', () => {
|
||||
'Presenter Name',
|
||||
'Event Subtitle',
|
||||
'Is Public? (x)',
|
||||
'Skip? (x)',
|
||||
'Notes',
|
||||
'User0:test0',
|
||||
'User1:test1',
|
||||
@@ -554,6 +590,7 @@ describe('test parseExcel function', () => {
|
||||
'Carlos',
|
||||
'Getting things started',
|
||||
'x',
|
||||
'',
|
||||
'Ballyhoo',
|
||||
'',
|
||||
'',
|
||||
@@ -578,6 +615,7 @@ describe('test parseExcel function', () => {
|
||||
'Still Carlos',
|
||||
'Derailing early',
|
||||
'',
|
||||
'',
|
||||
'Rainbow chase',
|
||||
'',
|
||||
'',
|
||||
@@ -606,6 +644,7 @@ describe('test parseExcel function', () => {
|
||||
presenter: 'Carlos',
|
||||
subtitle: 'Getting things started',
|
||||
isPublic: true,
|
||||
skip: false,
|
||||
note: 'Ballyhoo',
|
||||
user0: 'a0',
|
||||
user1: 'a1',
|
||||
@@ -627,6 +666,7 @@ describe('test parseExcel function', () => {
|
||||
presenter: 'Still Carlos',
|
||||
subtitle: 'Derailing early',
|
||||
isPublic: false,
|
||||
skip: true,
|
||||
note: 'Rainbow chase',
|
||||
user0: 'b0',
|
||||
user5: 'b5',
|
||||
@@ -642,6 +682,7 @@ describe('test parseExcel function', () => {
|
||||
expect(parsedData.events.presenter).toBe(expectedParsedEvents.presenter);
|
||||
expect(parsedData.events.subtitle).toBe(expectedParsedEvents.subtitle);
|
||||
expect(parsedData.events.isPublic).toBe(expectedParsedEvents.isPublic);
|
||||
expect(parsedData.events.skip).toBe(expectedParsedEvents.skip);
|
||||
expect(parsedData.events.note).toBe(expectedParsedEvents.note);
|
||||
expect(parsedData.events.type).toBe(expectedParsedEvents.type);
|
||||
});
|
||||
@@ -790,3 +831,24 @@ describe('test validateDuration()', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isStringEmpty() function', () => {
|
||||
describe('returns true with any non empty', () => {
|
||||
const notEmpty = ['test', 'thisalso', '123', '#'];
|
||||
for (const testValue of notEmpty) {
|
||||
it(testValue, () => {
|
||||
const isEmpty = isStringEmpty(testValue);
|
||||
expect(isEmpty).toBe(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
describe('returns true empty string or undefined', () => {
|
||||
const empty = ['', ' ', undefined, null];
|
||||
for (const testValue of empty) {
|
||||
it(`handles ${testValue}`, () => {
|
||||
const isEmpty = isStringEmpty(testValue);
|
||||
expect(isEmpty).toBe(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @description Returns id of previous played event
|
||||
* @param {array} events
|
||||
* @param {string} eventId
|
||||
* @return {object}
|
||||
*/
|
||||
export function getPreviousPlayable(events, eventId) {
|
||||
// find current index
|
||||
const current = events.findIndex((event) => event.id === eventId);
|
||||
|
||||
if (current === -1) {
|
||||
return { index: null, id: null };
|
||||
}
|
||||
|
||||
let index = current - 1;
|
||||
while (index >= 0) {
|
||||
const event = events[index];
|
||||
if (event.type === 'event' && !event.skip) {
|
||||
return { index, id: event.id };
|
||||
}
|
||||
index--;
|
||||
}
|
||||
|
||||
return { index: null, id: null };
|
||||
}
|
||||
@@ -18,6 +18,19 @@ import { generateId } from './generate_id.js';
|
||||
export const EXCEL_MIME = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
||||
export const JSON_MIME = 'application/json';
|
||||
|
||||
/**
|
||||
* @description Whether a string is considered empty
|
||||
* @param value
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isStringEmpty = (value) => {
|
||||
let v = value;
|
||||
if (typeof value === 'string') {
|
||||
v = value.replace(/\s+/g, '');
|
||||
}
|
||||
return v === '' || !v;
|
||||
};
|
||||
|
||||
/**
|
||||
* @description Excel array parser
|
||||
* @param {array} excelData - array with excel sheet
|
||||
@@ -36,6 +49,7 @@ export const parseExcel_v1 = async (excelData) => {
|
||||
let presenterIndex = null;
|
||||
let subtitleIndex = null;
|
||||
let isPublicIndex = null;
|
||||
let skipIndex = null;
|
||||
let notesIndex = null;
|
||||
let colourIndex = null;
|
||||
let user0Index = null;
|
||||
@@ -75,12 +89,9 @@ export const parseExcel_v1 = async (excelData) => {
|
||||
} else if (j === subtitleIndex) {
|
||||
event.subtitle = column;
|
||||
} else if (j === isPublicIndex) {
|
||||
// whether column is not empty
|
||||
let c = column;
|
||||
if (typeof column === 'string') {
|
||||
c = column.replace(/\s+/g, '');
|
||||
}
|
||||
event.isPublic = c !== '';
|
||||
event.isPublic = isStringEmpty(column);
|
||||
} else if (j === skipIndex) {
|
||||
event.skip = isStringEmpty(column);
|
||||
} else if (j === notesIndex) {
|
||||
event.note = column;
|
||||
} else if (j === colourIndex) {
|
||||
@@ -144,6 +155,11 @@ export const parseExcel_v1 = async (excelData) => {
|
||||
case 'public':
|
||||
isPublicIndex = j;
|
||||
break;
|
||||
case 'skip? (x)':
|
||||
case 'skip?':
|
||||
case 'skip':
|
||||
skipIndex = j;
|
||||
break;
|
||||
case 'notes':
|
||||
notesIndex = j;
|
||||
break;
|
||||
@@ -278,7 +294,8 @@ export const validateEvent_v1 = (eventArgs) => {
|
||||
timeEnd: end,
|
||||
timeType: 'start-end',
|
||||
duration: validateDuration(start, end),
|
||||
isPublic: e.isPublic != null && typeof e.isPublic === 'boolean' ? e.isPublic : d.isPublic,
|
||||
isPublic: typeof e.isPublic === 'boolean' ? e.isPublic : d.isPublic,
|
||||
skip: typeof e.skip === 'boolean' ? e.skip : d.skip,
|
||||
note: makeString(e.note, d.note),
|
||||
user0: makeString(e.user0, d.user0),
|
||||
user1: makeString(e.user1, d.user1),
|
||||
|
||||
Reference in New Issue
Block a user