diff --git a/www/__mocks__/cordovaMocks.ts b/www/__mocks__/cordovaMocks.ts index 62aa9be1a..f8d7ae74f 100644 --- a/www/__mocks__/cordovaMocks.ts +++ b/www/__mocks__/cordovaMocks.ts @@ -1,5 +1,4 @@ import packageJsonBuild from '../../package.cordovabuild.json'; - export const mockCordova = () => { window['cordova'] ||= {}; window['cordova'].platformId ||= 'ios'; @@ -116,6 +115,9 @@ export const mockBEMUserCache = () => { return false; } }, + getMessagesForInterval: () => { + // Used for getUnifiedDataForInterval + }, }; window['cordova'] ||= {}; window['cordova'].plugins ||= {}; diff --git a/www/__tests__/timelineHelper.test.ts b/www/__tests__/timelineHelper.test.ts new file mode 100644 index 000000000..c6a4bcd67 --- /dev/null +++ b/www/__tests__/timelineHelper.test.ts @@ -0,0 +1,121 @@ +import { mockLogger } from '../__mocks__/globalMocks'; +import { readAllCompositeTrips, readUnprocessedTrips } from '../js/diary/timelineHelper'; +import { mockBEMUserCache } from '../__mocks__/cordovaMocks'; + +import { MetaData, ServerResponse } from '../js/types/serverData'; +import { CompositeTrip } from '../js/types/diaryTypes'; + +mockLogger(); +mockBEMUserCache(); +const mockMetaData: MetaData = { + write_ts: -13885091, + key: 'test/value', + platform: 'test', + time_zone: 'America/Los_Angeles', + write_fmt_time: '1969-07-16T07:01:49.000Z', + write_local_dt: null, + origin_key: '12345', +}; +const mockData: ServerResponse = { + phone_data: [ + { + data: { + _id: null, + additions: [], + cleaned_section_summary: null, // TODO + cleaned_trip: null, //ObjId; + confidence_threshold: -1, + confirmed_trip: null, //ObjId; + distance: 777, + duration: 777, + end_confirmed_place: { + data: null, + metadata: JSON.parse(JSON.stringify(mockMetaData)), + }, + end_fmt_time: '2023-11-01T17:55:20.999397-07:00', + end_loc: { + type: 'Point', + coordinates: [-1, -1], + }, + end_local_dt: null, //LocalDt; + end_place: null, //ObjId; + end_ts: -1, + expectation: null, // TODO "{to_label: boolean}" + expected_trip: null, //ObjId; + inferred_labels: [], // TODO + inferred_section_summary: { + count: { + CAR: 1, + WALKING: 1, + }, + distance: { + CAR: 222, + WALKING: 222, + }, + duration: { + CAR: 333, + WALKING: 333, + }, + }, + inferred_trip: null, + key: '12345', + locations: [ + { + metadata: JSON.parse(JSON.stringify(mockMetaData)), + data: null, + }, + ], // LocationType + origin_key: '', + raw_trip: null, + sections: [ + { + metadata: JSON.parse(JSON.stringify(mockMetaData)), + data: null, + }, + ], // TODO + source: 'DwellSegmentationDistFilter', + start_confirmed_place: { + data: null, + metadata: JSON.parse(JSON.stringify(mockMetaData)), + }, + start_fmt_time: '2023-11-01T17:55:20.999397-07:00', + start_loc: { + type: 'Point', + coordinates: [-1, -1], + }, + start_local_dt: null, + start_place: null, + start_ts: null, + user_input: null, + }, + metadata: JSON.parse(JSON.stringify(mockMetaData)), + }, + ], +}; + +const testStart = -14576291; +const testEnd = -13885091; + +jest.mock('../js/commHelper', () => ({ + getRawEntries: jest.fn(() => mockData), +})); + +it('fetches a composite trip object and collapses it', async () => { + // When we have End-to-End testing, we can properly test with getRawEnteries + console.log(JSON.stringify(mockData, null, 2)); + expect(readAllCompositeTrips(testStart, testEnd)).resolves.not.toThrow(); +}); + +jest.mock('../js/unifiedDataLoader', () => ({ + getUnifiedDataForInterval: jest.fn(() => { + return Promise.resolve([]); + }), +})); + +it('works when there are no unprocessed trips...', async () => { + expect(readUnprocessedTrips(testStart, testEnd, null)).resolves.not.toThrow(); +}); + +it('works when there are no unprocessed trips...', async () => { + expect(readUnprocessedTrips(testStart, testEnd, null)).resolves.not.toThrow(); +}); diff --git a/www/js/diary/timelineHelper.ts b/www/js/diary/timelineHelper.ts index 07cdb6dc8..83d9cbf1c 100644 --- a/www/js/diary/timelineHelper.ts +++ b/www/js/diary/timelineHelper.ts @@ -1,4 +1,3 @@ -import { getAngularService } from '../angular-react-helper'; import { displayError, logDebug } from '../plugin/logger'; import { getBaseModeByKey, getBaseModeOfLabeledTrip } from './diaryHelper'; import { getUnifiedDataForInterval } from '../unifiedDataLoader'; @@ -7,7 +6,7 @@ import { ServerResponse, ServerData } from '../types/serverData'; import L from 'leaflet'; import i18next from 'i18next'; import { DateTime } from 'luxon'; -import { CompositeTrip } from '../types/diaryTypes'; +import { CompositeTrip, TripTransition, SectionData, Trip } from '../types/diaryTypes'; import { LabelOptions } from '../types/labelTypes'; const cachedGeojsons = new Map(); @@ -235,7 +234,7 @@ const unpackServerData = (obj: ServerData) => ({ export const readAllCompositeTrips = function (startTs: number, endTs: number) { const readPromises = [getRawEntries(['analysis/composite_trip'], startTs, endTs, 'data.end_ts')]; return Promise.all(readPromises) - .then(([ctList]: [ServerResponse]) => { + .then(([ctList]: [ServerResponse]) => { return ctList.phone_data.map((ct) => { const unpackedCt = unpackServerData(ct); return { @@ -439,7 +438,7 @@ const isEndingTransition = function (transWrapper) { * * Let's abstract this out into our own minor state machine. */ -const transitions2Trips = function (transitionList) { +const transitions2Trips = function (transitionList: Array) { var inTrip = false; var tripList = []; var currStartTransitionIndex = -1; @@ -517,9 +516,11 @@ export const readUnprocessedTrips = function (startTs, endTs, lastProcessedTrip) DateTime.fromSeconds(tq.endTs).toLocaleString(DateTime.DATETIME_MED), ); + console.log('Testing...'); const getMessageMethod = window['cordova'].plugins.BEMUserCache.getMessagesForInterval; + console.log('Entering...'); return getUnifiedDataForInterval('statemachine/transition', tq, getMessageMethod).then(function ( - transitionList: Array, + transitionList: Array, ) { if (transitionList.length == 0) { logDebug('No unprocessed trips. yay!'); @@ -529,7 +530,7 @@ export const readUnprocessedTrips = function (startTs, endTs, lastProcessedTrip) const tripsList = transitions2Trips(transitionList); logDebug(`Mapped into ${tripsList.length} trips. yay!`); tripsList.forEach(function (trip) { - logDebug(JSON.stringify(trip)); + logDebug(JSON.stringify(trip, null, 2)); }); var tripFillPromises = tripsList.map(transitionTrip2TripObj); return Promise.all(tripFillPromises).then(function (raw_trip_gj_list) { diff --git a/www/js/types/diaryTypes.ts b/www/js/types/diaryTypes.ts index 4f10fb50f..933e2db68 100644 --- a/www/js/types/diaryTypes.ts +++ b/www/js/types/diaryTypes.ts @@ -55,7 +55,7 @@ export type CompositeTrip = { confirmed_trip: ObjId; distance: number; duration: number; - end_confirmed_place: ConfirmedPlace; + end_confirmed_place: ServerData; end_fmt_time: string; end_loc: { type: string; coordinates: number[] }; end_local_dt: LocalDt; @@ -72,7 +72,7 @@ export type CompositeTrip = { raw_trip: ObjId; sections: any[]; // TODO source: string; - start_confirmed_place: ConfirmedPlace; + start_confirmed_place: ServerData; start_fmt_time: string; start_loc: { type: string; coordinates: number[] }; start_local_dt: LocalDt;