Skip to content

Commit

Permalink
Merge branch 'diaryServices-rewrite' of https://github.com/the-bay-ka…
Browse files Browse the repository at this point in the history
…y/e-mission-phone into migration-wrapup
  • Loading branch information
JGreenlee committed Dec 4, 2023
2 parents f5dc166 + f80deb9 commit 76e6867
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 109 deletions.
31 changes: 24 additions & 7 deletions www/__mocks__/cordovaMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ export const mockFile = () => {
//for consent document
const _storage = {};

type MessageData = any;
type Message = { key: string; data: MessageData; metadata: { write_ts: number; [k: string]: any } };
export const mockBEMUserCache = (config?) => {
const _cache = {};
const messages: { key: string; value: any }[] = [];
const messages: Message[] = [];
const mockBEMUserCache = {
getLocalStorage: (key: string, isSecure: boolean) => {
return new Promise((rs, rj) =>
Expand Down Expand Up @@ -99,18 +101,36 @@ export const mockBEMUserCache = (config?) => {
putMessage: (key: string, value: any) => {
return new Promise<void>((rs, rj) =>
setTimeout(() => {
messages.push({ key, value });
messages.push({
key,
data: value,
// write_ts is epoch time in seconds
metadata: { write_ts: Math.floor(Date.now() / 1000) },
});
rs();
}, 100),
);
},
getAllMessages: (key: string, withMetadata?: boolean) => {
return new Promise<any[]>((rs, rj) =>
return new Promise<Message[] | MessageData[]>((rs, rj) =>
setTimeout(() => {
rs(messages.filter((m) => m.key == key).map((m) => m.value));
rs(messages.filter((m) => m.key == key).map((m) => (withMetadata ? m : m.data)));
}, 100),
);
},
getMessagesForInterval: (key: string, tq, withMetadata?: boolean) => {
return new Promise<Message[] | MessageData[]>((rs, rj) =>
setTimeout(() => {
rs(
messages
.filter((m) => m.key == key)
.filter((m) => m.metadata[tq.key] >= tq.startTs && m.metadata.write_ts <= tq.endTs)
.map((m) => (withMetadata ? m : m.data)),
);
}, 100),
);
// Used for getUnifiedDataForInterval
},
getDocument: (key: string, withMetadata?: boolean) => {
//returns the config provided as a paramenter to this mock!
if (key == 'config/app_ui_config') {
Expand Down Expand Up @@ -152,9 +172,6 @@ export const mockBEMUserCache = (config?) => {
return undefined;
}
},
getMessagesForInterval: () => {
// Used for getUnifiedDataForInterval
},
};
window['cordova'] ||= {};
window['cordova'].plugins ||= {};
Expand Down
52 changes: 5 additions & 47 deletions www/__mocks__/timelineHelperMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,20 +228,21 @@ export const mockFilterLocations: Array<ServerData<FilteredLocation>> = [
},
];

export const mockAppConfigOne = {
export const mockConfigEnketo = {
survey_info: {
'trip-labels': 'ENKETO',
surveys: { TripConfirmSurvey: { compatibleWith: 1.2 } },
},
};
export const mockAppConfigTwo = {
export const mockConfigModeOfStudy = {
survey_info: {
'trip-labels': 'Other',
'trip-labels': 'MULTILABEL',
},
intro: {
mode_studied: 'sample_study',
},
};
export const mockAppConfigThree = {
export const mockConfigNoModeOfStudy = {
survey_info: {
'trip-labels': 'Other',
},
Expand All @@ -250,49 +251,6 @@ export const mockAppConfigThree = {
},
};

export const mockLabelDataPromises = [
Promise.resolve([
// Mode
{
data: {
end_ts: 1681438322.981,
label: 'walk',
start_ts: 1681437527.4971218,
},
metadata: mockMetaData,
},
{
data: {
end_ts: 1681439339.983,
label: 'walk',
start_ts: 1681438918.6598706,
},
metadata: mockMetaDataTwo,
},
]),
Promise.resolve([
// Purpose
{
data: {
end_ts: 1681438322.981,
label: 'test',
start_ts: 1681437527.4971218,
},
metadata: mockMetaData,
},
{
data: {
end_ts: 1681438322.983,
label: 'testValue',
start_ts: 1681438918.6598706,
},
metadata: mockMetaDataTwo,
},
]),
Promise.resolve([]), // Replaced_Mode
];
//let mockLabelDataPromisesTwo = JSON.parse(JSON.stringify(mockLabelDataPromises));

// Used by jest.mocks() to return a various mocked objects.
export const fakeStartTsOne = -14576291;
export const fakeEndTsOne = -13885091;
Expand Down
4 changes: 2 additions & 2 deletions www/__tests__/diaryHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import initializedI18next from '../js/i18nextInit';
window['i18next'] = initializedI18next;

it('returns a formatted date', () => {
expect(getFormattedDate('2023-09-18T00:00:00-07:00')).toBe('Mon September 18, 2023');
expect(getFormattedDate('2023-09-18T00:00:00-07:00')).toBe('Mon, September 18, 2023');
expect(getFormattedDate('')).toBeUndefined();
expect(getFormattedDate('2023-09-18T00:00:00-07:00', '2023-09-21T00:00:00-07:00')).toBe(
'Mon September 18, 2023 - Thu September 21, 2023',
'Mon, September 18, 2023 - Thu, September 21, 2023',
);
});

Expand Down
6 changes: 3 additions & 3 deletions www/__tests__/enketoHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ it('loads the previous response to a given survey', () => {
*/
it('filters the survey responses by their name and version', () => {
//no response -> no filtered responses
expect(filterByNameAndVersion('TimeUseSurvey', [])).resolves.toStrictEqual([]);
expect(filterByNameAndVersion('TimeUseSurvey', [], fakeConfig)).toStrictEqual([]);

const response = [
{
Expand All @@ -296,7 +296,7 @@ it('filters the survey responses by their name and version', () => {
];

//one response -> that response
expect(filterByNameAndVersion('TimeUseSurvey', response)).resolves.toStrictEqual(response);
expect(filterByNameAndVersion('TimeUseSurvey', response, fakeConfig)).toStrictEqual(response);

const responses = [
{
Expand Down Expand Up @@ -338,5 +338,5 @@ it('filters the survey responses by their name and version', () => {
];

//several responses -> only the one that has a name match
expect(filterByNameAndVersion('TimeUseSurvey', responses)).resolves.toStrictEqual(response);
expect(filterByNameAndVersion('TimeUseSurvey', responses, fakeConfig)).toStrictEqual(response);
});
121 changes: 107 additions & 14 deletions www/__tests__/timelineHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
compositeTrips2TimelineMap,
updateUnprocessedInputs,
keysForLabelInputs,
updateLocalUnprocessedInputs,
} from '../js/diary/timelineHelper';
import { mockBEMUserCache } from '../__mocks__/cordovaMocks';
import * as mockTLH from '../__mocks__/timelineHelperMocks';
Expand Down Expand Up @@ -94,8 +95,8 @@ describe('compositeTrips2TimelineMap', () => {
});

it('use an appConfig to get labelInputKeys', () => {
expect(keysForLabelInputs(mockTLH.mockAppConfigOne)).toEqual(['manual/trip_user_input']);
expect(keysForLabelInputs(mockTLH.mockAppConfigTwo).length).toEqual(3);
expect(keysForLabelInputs(mockTLH.mockConfigEnketo)).toEqual(['manual/trip_user_input']);
expect(keysForLabelInputs(mockTLH.mockConfigModeOfStudy).length).toEqual(3);
});

// updateUnprocessedInputs Tests
Expand All @@ -105,22 +106,114 @@ jest.mock('../js/survey/multilabel/confirmHelper', () => ({
}));

it('processed empty labels', async () => {
await updateUnprocessedInputs([], [], mockTLH.mockAppConfigThree);
await updateUnprocessedInputs([], [], mockTLH.mockConfigNoModeOfStudy);
expect(unprocessedLabels).toEqual({});
});

it('updates unprocessed labels', async () => {
await updateUnprocessedInputs(mockTLH.mockLabelDataPromises, [], mockTLH.mockAppConfigThree);
expect(unprocessedLabels).toEqual(
expect.objectContaining({
MODE: expect.any(Array<UserInputEntry>),
PURPOSE: expect.any(Array<UserInputEntry>),
REPLACED_MODE: expect.any(Array<UserInputEntry>),
}),
it('processes some mode and purpose labels after they were just recorded', async () => {
// record some labels
await window['cordova'].plugins.BEMUserCache.putMessage('manual/mode_confirm', {
start_ts: 2,
end_ts: 3,
label: 'tricycle',
});
await window['cordova'].plugins.BEMUserCache.putMessage('manual/purpose_confirm', {
start_ts: 2,
end_ts: 3,
label: 'shopping',
});

// update unprocessed inputs and check that the new labels show up in unprocessedLabels
await updateLocalUnprocessedInputs({ start_ts: 2, end_ts: 3 }, mockTLH.mockConfigNoModeOfStudy);
expect(unprocessedLabels['MODE'].length).toEqual(1);
expect(unprocessedLabels['MODE'][0].data.label).toEqual('tricycle');
expect(unprocessedLabels['PURPOSE'].length).toEqual(1);
expect(unprocessedLabels['PURPOSE'][0].data.label).toEqual('shopping');
});

it('processes trip- and place- survey responses after they were just recorded', async () => {
// record two survey responses, one for trip_user_input and one for place_user_input
const tripSurveyResponse = {
start_ts: 4,
end_ts: 5,
name: 'TripConfirmSurvey', // for now, the name of this survey must be hardcoded (see note in UserInputButton.tsx)
version: 1.2,
label: '1 foobar',
match_id: 'd263935e-9163-4072-9909-9d3e1edb31be',
key: 'manual/trip_user_input',
xmlResponse: `<data xmlns:jr="http://openrosa.org/javarosa" xmlns:odk="http://www.opendatakit.org/xforms" xmlns:orx="http://openrosa.org/xforms" id="snapshot_xml"> <start>2023-12-04T12:12:38.968-05:00</start> <end>2023-12-04T12:12:38.970-05:00</end> <foo>bar</foo> <meta><instanceID>uuid:75dc7b18-2a9d-4356-b66e-d63dfa7568ca</instanceID></meta> </data>`,
};
const placeSurveyResponse = {
...tripSurveyResponse,
start_ts: 5,
end_ts: 6,
key: 'manual/place_user_input',
};
await window['cordova'].plugins.BEMUserCache.putMessage(
'manual/trip_user_input',
tripSurveyResponse,
);
expect(unprocessedLabels.MODE.length).toEqual(2);
expect(unprocessedLabels.PURPOSE.length).toEqual(2);
expect(unprocessedLabels.REPLACED_MODE.length).toEqual(0);
await window['cordova'].plugins.BEMUserCache.putMessage(
'manual/place_user_input',
placeSurveyResponse,
);

// update unprocessed inputs and check that the trip survey response shows up in unprocessedLabels
await updateLocalUnprocessedInputs({ start_ts: 4, end_ts: 6 }, mockTLH.mockConfigEnketo);
expect(unprocessedLabels['SURVEY'][0].data).toEqual(tripSurveyResponse);
// the second response is ignored for now because we haven't enabled place_user_input yet
// so the length is only 1
expect(unprocessedLabels['SURVEY'].length).toEqual(1);
});

it('processes some trip- and place- level additions after they were just recorded', async () => {
// record two additions, one for trip_addition_input and one for place_addition_input
const tripAdditionOne = {
start_ts: 6,
end_ts: 7,
key: 'manual/trip_addition_input',
data: { foo: 'bar' },
};
const tripAdditionTwo = {
...tripAdditionOne,
data: { foo: 'baz' },
};
const placeAdditionOne = {
...tripAdditionOne,
start_ts: 7,
end_ts: 8,
key: 'manual/place_addition_input',
};
const placeAdditionTwo = {
...placeAdditionOne,
data: { foo: 'baz' },
};
Promise.all([
window['cordova'].plugins.BEMUserCache.putMessage(
'manual/trip_addition_input',
tripAdditionOne,
),
window['cordova'].plugins.BEMUserCache.putMessage(
'manual/place_addition_input',
tripAdditionTwo,
),
window['cordova'].plugins.BEMUserCache.putMessage(
'manual/trip_addition_input',
placeAdditionOne,
),
window['cordova'].plugins.BEMUserCache.putMessage(
'manual/place_addition_input',
placeAdditionTwo,
),
]).then(() => {
// update unprocessed inputs and check that all additions show up in unprocessedNotes
updateLocalUnprocessedInputs({ start_ts: 6, end_ts: 8 }, mockTLH.mockConfigEnketo);
expect(unprocessedLabels['NOTES'].length).toEqual(4);
expect(unprocessedLabels['NOTES'][0].data).toEqual(tripAdditionOne);
expect(unprocessedLabels['NOTES'][1].data).toEqual(tripAdditionTwo);
expect(unprocessedLabels['NOTES'][2].data).toEqual(placeAdditionOne);
expect(unprocessedLabels['NOTES'][3].data).toEqual(placeAdditionTwo);
});
});

// Tests for readAllCompositeTrips
Expand Down
10 changes: 4 additions & 6 deletions www/js/diary/diaryHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { DateTime } from 'luxon';
import { CompositeTrip } from '../types/diaryTypes';
import { LabelOptions } from '../types/labelTypes';
import { LocalDt } from '../types/serverData';

const humanizeDuration = require('humanize-duration');
import humanizeDuration from 'humanize-duration';

export const modeColors = {
pink: '#c32e85', // oklch(56% 0.2 350) // e-car
Expand Down Expand Up @@ -125,7 +124,7 @@ export function getFormattedDate(beginFmtTime?: string, endFmtTime?: string) {
day: '2-digit',
year: 'numeric',
});
return tConversion.replace(',', '');
return tConversion;
}

/**
Expand Down Expand Up @@ -153,10 +152,9 @@ export function getFormattedTimeRange(beginFmtTime: string, endFmtTime: string)
const beginTime = DateTime.fromISO(beginFmtTime, { setZone: true });
const endTime = DateTime.fromISO(endFmtTime, { setZone: true });
const range = endTime.diff(beginTime, ['hours', 'minutes']);
const unitsToDisplay = range.hours < 1 ? ['m'] : ['h'];
return humanizeDuration(range.as('milliseconds'), {
language: i18next.language,
units: unitsToDisplay,
largest: 1,
round: true,
});
}
Expand Down Expand Up @@ -197,5 +195,5 @@ export function getLocalTimeString(dt?: LocalDt) {
hour: dt.hour,
minute: dt.minute,
});
return dateTime.toFormat('h:mm a');
return dateTime.toLocaleString(DateTime.TIME_SIMPLE);
}
Loading

0 comments on commit 76e6867

Please sign in to comment.