From 54c4a7f68c5f70152ef8e2e2c4b339f86e453c06 Mon Sep 17 00:00:00 2001 From: arc-alex Date: Sun, 26 Nov 2023 14:16:50 +0100 Subject: [PATCH] add test --- .../utils/__tests__/googleSheetUtils.test.ts | 330 ++++++++++++++++++ apps/server/src/utils/googleSheetUtils.ts | 21 +- 2 files changed, 343 insertions(+), 8 deletions(-) create mode 100644 apps/server/src/utils/__tests__/googleSheetUtils.test.ts diff --git a/apps/server/src/utils/__tests__/googleSheetUtils.test.ts b/apps/server/src/utils/__tests__/googleSheetUtils.test.ts new file mode 100644 index 000000000..84f4866a8 --- /dev/null +++ b/apps/server/src/utils/__tests__/googleSheetUtils.test.ts @@ -0,0 +1,330 @@ +import { millisToString } from 'ontime-utils'; +import { getA1Notation, cellRequenstFromEvent } from '../googleSheetUtils.js'; +import { EndAction, OntimeRundownEntry, SupportedEvent, TimerType } from 'ontime-types'; + +describe('getA1Notation()', () => { + test('A1', () => { + expect(getA1Notation(0, 0)).toStrictEqual('A1'); + }); + test('E3', () => { + expect(getA1Notation(2, 4)).toStrictEqual('E3'); + }); + test('AA100', () => { + expect(getA1Notation(99, 26)).toStrictEqual('AA100'); + }); + test('can not be negative', () => { + expect(() => getA1Notation(-1, 1)).toThrowError('Index can not be less than 0'); + }); +}); + +describe('cellRequenstFromEvent()', () => { + test('string to string', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: false, + skip: false, + colour: 'red', + user0: '', + user1: '', + user2: '', + user3: '', + user4: '', + user5: '', + user6: '', + user7: '', + user8: '', + user9: '', + revision: 0, + id: '1358', + }; + const metadata = { + type: { row: 1, col: 14 }, + cue: { row: 1, col: 15 }, + title: { row: 1, col: 16 }, + subtitle: { row: 1, col: 17 }, + presenter: { row: 1, col: 18 }, + note: { row: 1, col: 19 }, + timeStart: { row: 1, col: 20 }, + timeEnd: { row: 1, col: 21 }, + endAction: { row: 1, col: 22 }, + timerType: { row: 1, col: 23 }, + duration: { row: 1, col: 24 }, + isPublic: { row: 1, col: 25 }, + skip: { row: 1, col: 26 }, + colour: { row: 1, col: 27 }, + user0: { row: 1, col: 28 }, + user1: { row: 1, col: 29 }, + user2: { row: 1, col: 30 }, + user3: { row: 1, col: 31 }, + user4: { row: 1, col: 32 }, + user5: { row: 1, col: 33 }, + user6: { row: 1, col: 34 }, + user7: { row: 1, col: 35 }, + user8: { row: 1, col: 36 }, + user9: { row: 1, col: 37 }, + revision: { row: 1, col: 38 }, + id: { row: 1, col: 39 }, + }; + const result = cellRequenstFromEvent(event, 1, 1234, metadata); + expect(result.updateCells.rows[0].values[5].userEnteredValue.stringValue).toStrictEqual(event.note); + }); + + test('numer to timer', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: false, + skip: false, + colour: 'red', + user0: '', + user1: '', + user2: '', + user3: '', + user4: '', + user5: '', + user6: '', + user7: '', + user8: '', + user9: '', + revision: 0, + id: '1358', + }; + const metadata = { + type: { row: 1, col: 14 }, + cue: { row: 1, col: 15 }, + title: { row: 1, col: 16 }, + subtitle: { row: 1, col: 17 }, + presenter: { row: 1, col: 18 }, + note: { row: 1, col: 19 }, + timeStart: { row: 1, col: 20 }, + timeEnd: { row: 1, col: 21 }, + endAction: { row: 1, col: 22 }, + timerType: { row: 1, col: 23 }, + duration: { row: 1, col: 24 }, + isPublic: { row: 1, col: 25 }, + skip: { row: 1, col: 26 }, + colour: { row: 1, col: 27 }, + user0: { row: 1, col: 28 }, + user1: { row: 1, col: 29 }, + user2: { row: 1, col: 30 }, + user3: { row: 1, col: 31 }, + user4: { row: 1, col: 32 }, + user5: { row: 1, col: 33 }, + user6: { row: 1, col: 34 }, + user7: { row: 1, col: 35 }, + user8: { row: 1, col: 36 }, + user9: { row: 1, col: 37 }, + revision: { row: 1, col: 38 }, + id: { row: 1, col: 39 }, + }; + const result = cellRequenstFromEvent(event, 1, 1234, metadata).updateCells.rows[0].values[10].userEnteredValue + .stringValue; + expect(result).toStrictEqual(millisToString(event.duration)); + }); + + test('boolean to x', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: true, + skip: false, + colour: 'red', + user0: 'u', + user1: 'u', + user2: 'u', + user3: 'u', + user4: 'u', + user5: 'u', + user6: 'u', + user7: 'u', + user8: 'u', + user9: 'u', + revision: 0, + id: '1358', + }; + const metadata = { + type: { row: 1, col: 14 }, + cue: { row: 1, col: 15 }, + title: { row: 1, col: 16 }, + subtitle: { row: 1, col: 17 }, + presenter: { row: 1, col: 18 }, + note: { row: 1, col: 19 }, + timeStart: { row: 1, col: 20 }, + timeEnd: { row: 1, col: 21 }, + endAction: { row: 1, col: 22 }, + timerType: { row: 1, col: 23 }, + duration: { row: 1, col: 24 }, + isPublic: { row: 1, col: 25 }, + skip: { row: 1, col: 26 }, + colour: { row: 1, col: 27 }, + user0: { row: 1, col: 28 }, + user1: { row: 1, col: 29 }, + user2: { row: 1, col: 30 }, + user3: { row: 1, col: 31 }, + user4: { row: 1, col: 32 }, + user5: { row: 1, col: 33 }, + user6: { row: 1, col: 34 }, + user7: { row: 1, col: 35 }, + user8: { row: 1, col: 36 }, + user9: { row: 1, col: 37 }, + revision: { row: 1, col: 38 }, + id: { row: 1, col: 39 }, + }; + const result = cellRequenstFromEvent(event, 1, 1234, metadata); + expect(result.updateCells.rows[0].values[11].userEnteredValue.stringValue).toStrictEqual('x'); + expect(result.updateCells.rows[0].values[12].userEnteredValue.stringValue).toStrictEqual(''); + }); + + test('spacing in metadata', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: true, + skip: false, + colour: 'red', + user0: 'u', + user1: 'u', + user2: 'u', + user3: 'u', + user4: 'u', + user5: 'u', + user6: 'u', + user7: 'u', + user8: 'u', + user9: 'u', + revision: 0, + id: '1358', + }; + const metadata = { + cue: { row: 1, col: 0 }, + title: { row: 1, col: 6 }, + subtitle: { row: 1, col: 10 }, + user0: { row: 1, col: 16 }, + }; + const result = cellRequenstFromEvent(event, 1, 1234, metadata); + expect(result.updateCells.rows[0].values[0].userEnteredValue.stringValue).toStrictEqual(event.cue); + expect(result.updateCells.rows[0].values[6].userEnteredValue.stringValue).toStrictEqual(event.title); + expect(result.updateCells.rows[0].values[10].userEnteredValue.stringValue).toStrictEqual(event.subtitle); + }); + + test('metadata offset from zero', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: true, + skip: false, + colour: 'red', + user0: 'u', + user1: 'u', + user2: 'u', + user3: 'u', + user4: 'u', + user5: 'u', + user6: 'u', + user7: 'u', + user8: 'u', + user9: 'u', + revision: 0, + id: '1358', + }; + const metadata = { + cue: { row: 1, col: 5 }, + title: { row: 1, col: 6 }, + subtitle: { row: 1, col: 10 }, + user0: { row: 1, col: 16 }, + }; + const result = cellRequenstFromEvent(event, 1, 1234, metadata); + expect(result.updateCells.rows[0].values[0].userEnteredValue.stringValue).toStrictEqual(event.cue); + expect(result.updateCells.rows[0].values[1].userEnteredValue.stringValue).toStrictEqual(event.title); + expect(result.updateCells.rows[0].values[5].userEnteredValue.stringValue).toStrictEqual(event.subtitle); + }); + + test('sheet setup', () => { + const event: OntimeRundownEntry = { + type: SupportedEvent.Event, + cue: '1', + title: 'Fancy', + subtitle: 'Wow', + presenter: 'Mr. Presenter', + note: 'Blue button on the right', + timeStart: 46800000, + timeEnd: 57600000, + endAction: EndAction.None, + timerType: TimerType.CountDown, + duration: 10800000, + isPublic: true, + skip: false, + colour: 'red', + user0: 'u', + user1: 'u', + user2: 'u', + user3: 'u', + user4: 'u', + user5: 'u', + user6: 'u', + user7: 'u', + user8: 'u', + user9: 'u', + revision: 0, + id: '1358', + }; + const metadata = { + cue: { row: 10, col: 5 }, + title: { row: 10, col: 6 }, + subtitle: { row: 1, col: 10 }, + user0: { row: 10, col: 16 }, + }; + const result1 = cellRequenstFromEvent(event, 1, 1234, metadata); + expect(result1.updateCells.start.sheetId).toStrictEqual(1234); + const result2 = cellRequenstFromEvent(event, 10, 1234, metadata); + expect(result2.updateCells.start.rowIndex).toStrictEqual(21); + expect(result2.updateCells.start.columnIndex).toStrictEqual(5); + expect(result2.updateCells.fields).toStrictEqual('userEnteredValue'); + }); +}); diff --git a/apps/server/src/utils/googleSheetUtils.ts b/apps/server/src/utils/googleSheetUtils.ts index b0838dcac..159159fcd 100644 --- a/apps/server/src/utils/googleSheetUtils.ts +++ b/apps/server/src/utils/googleSheetUtils.ts @@ -11,7 +11,7 @@ import { OntimeRundownEntry, isOntimeEvent } from 'ontime-types'; * @example * * getA1Notation(2, 4) returns "E3" - * getA1Notation(26, 4) returns "AA3" + * getA1Notation(99, 26) returns "AA100" * */ export function getA1Notation(row: number, column: number): string { @@ -42,20 +42,25 @@ export function cellRequenstFromEvent( index: number, worksheetId: number, metadata, - titleCol: number, ): sheets_v4.Schema$Request { const r: sheets_v4.Schema$CellData[] = []; const tmp = Object.entries(metadata) .filter(([_, value]) => value !== undefined) - .sort(([_a, a], [_b, b]) => a['col'] - b['col']); + .sort(([_a, a], [_b, b]) => a['col'] - b['col']) as [string, { col: number; row: number }][]; - tmp.forEach(([_, value], index, arr) => { + const titleCol = tmp[0][1].col; + + for (const [index, e] of tmp.entries()) { if (index != 0) { - if (arr[index - 1][1]['col'] + 1 < value['col']) { - arr.splice(index, 0, ['blank', { col: arr[index - 1][1]['col'] + 1 }]); + const prevCol = tmp[index - 1][1].col; + const thisCol = e[1].col; + const diff = thisCol - prevCol; + if (diff > 1) { + const fillArr = new Array<(typeof tmp)[0]>(1).fill(['blank', { row: e[1].row, col: prevCol + 1 }]); + tmp.splice(index, 0, ...fillArr); } } - }); + } tmp.forEach(([key, _]) => { if (isOntimeEvent(event)) { @@ -86,7 +91,7 @@ export function cellRequenstFromEvent( updateCells: { start: { sheetId: worksheetId, - rowIndex: index + Object.values(metadata)[0]['row'] + 1, + rowIndex: index + tmp[0][1]['row'] + 1, columnIndex: titleCol, }, fields: 'userEnteredValue',