Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎟️ πŸ”” πŸ“± Custom Events + pushNotify + storeDeviceSettings + remoteNotify rewrites #1093

Merged
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ea3fb10
create event handler
Oct 31, 2023
d267fcf
change file name
Oct 31, 2023
7d69847
rewrite pushNotify in react
Oct 31, 2023
56156a0
remove references to old file
Oct 31, 2023
332bfbe
centralize the event names
Oct 31, 2023
a991814
emit AND publish events
Oct 31, 2023
a90af2f
add function descriptions
Oct 31, 2023
09cbaa1
ensure proper initialization
Oct 31, 2023
b1838aa
add tests for customEventHandler
Oct 31, 2023
a6bf881
Merge remote-tracking branch 'origin/startprefs-rewrite' into event-n…
Oct 31, 2023
2dca41e
finish resolving merge conflicts
Oct 31, 2023
bb8f1ec
add rough tests, correct data access
Nov 1, 2023
5fbeac2
increase tests
Nov 1, 2023
c406988
pushnotify relies on events now
Nov 1, 2023
d27aedd
update tests
Nov 1, 2023
82e864b
add docstrings to customEventHandler
Nov 1, 2023
0eb7b4b
test cloud event
Nov 1, 2023
24784db
add timeout to config mock
Nov 1, 2023
46d5ed8
update tests
Nov 1, 2023
4f5e853
sync up test runs
Nov 1, 2023
38c64c4
Merge remote-tracking branch 'upstream/service_rewrite_2023' into eve…
Nov 2, 2023
e1999fd
rename file
Nov 2, 2023
ede2347
rewrite service to typscript
Nov 2, 2023
cd6dc05
remove / update references
Nov 2, 2023
7b7efc8
add initStoreDeviceSettings call
Nov 2, 2023
78eb704
add more docstrings
Nov 2, 2023
72a76fa
add server comm mock
Nov 2, 2023
188d478
start tests
Nov 2, 2023
395940f
resolve prettier merge conflicts
Nov 2, 2023
5e04536
re-prettify merge conflicted files
Nov 2, 2023
8764701
Merge remote-tracking branch 'upstream/service_rewrite_2023' into eve…
Nov 2, 2023
4393362
prettify recent changes
Nov 2, 2023
bc5c589
update tests so they pass
Nov 3, 2023
1aceb94
complete tests
Nov 3, 2023
9581ca2
remove unused mock code
Nov 3, 2023
9aa89d5
rename remotenotify file
Nov 3, 2023
16c87f0
typescript migration
Nov 3, 2023
68e0701
formatting changes to controller.js
Nov 3, 2023
84064bb
remove angular.isDefined calls
Nov 3, 2023
b58ee5c
clean up comments and docstrings
Nov 3, 2023
87de6c2
first two tests function
Nov 3, 2023
dcf35fa
complete writing testing
Nov 3, 2023
9b1665a
simplify event name storage
Nov 6, 2023
c25ebb6
directly use alert, for now
Nov 6, 2023
ad68e1b
remove old alerts
Nov 6, 2023
85d2884
swap var for const
Nov 6, 2023
29f44e7
update test
Nov 6, 2023
77d2ad1
Merge branch 'service_rewrite_2023' into event-notif-rewrite
shankari Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions www/__mocks__/cordovaMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const mockBEMUserCache = () => {
return new Promise<void>((rs, rj) =>
setTimeout(() => {
for (let p in _cache) delete _cache[p];
for (let doc in _storage) delete _storage[doc];
rs();
}, 100),
);
Expand Down Expand Up @@ -129,7 +130,59 @@ export const mockBEMDataCollection = () => {
_storage['config/consent'] = consentDoc;
}, 100);
},
getConfig: () => {
return new Promise<any>((rs, rj) => {
setTimeout(() => {
rs({ ios_use_remote_push_for_sync: true });
}, 100);
});
},
handleSilentPush: () => {
return new Promise<void>((rs, rj) =>
setTimeout(() => {
rs();
}, 100),
);
},
};
window['cordova'] ||= {};
window['cordova'].plugins.BEMDataCollection = mockBEMDataCollection;
};

export const mockBEMServerCom = () => {
const mockBEMServerCom = {
postUserPersonalData: (actionString, typeString, updateDoc, rs, rj) => {
setTimeout(() => {
console.log('set in mock', updateDoc);
_storage['user_data'] = updateDoc;
rs();
}, 100);
},

getUserPersonalData: (actionString, rs, rj) => {
setTimeout(() => {
rs(_storage['user_data']);
}, 100);
},
};
window['cordova'].plugins.BEMServerComm = mockBEMServerCom;
};

let _url_stash = '';

export const mockInAppBrowser = () => {
const mockInAppBrowser = {
open: (url: string, mode: string, options: {}) => {
_url_stash = url;
},
};
window['cordova'].InAppBrowser = mockInAppBrowser;
};

export const getURL = () => {
return _url_stash;
};

export const clearURL = () => {
_url_stash = '';
};
16 changes: 16 additions & 0 deletions www/__mocks__/globalMocks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
export const mockLogger = () => {
window['Logger'] = { log: console.log };
};

let alerts = [];

export const mockAlert = () => {
window['alert'] = (message) => {
alerts.push(message);
};
};

export const clearAlerts = () => {
alerts = [];
};

export const getAlerts = () => {
return alerts;
};
33 changes: 33 additions & 0 deletions www/__mocks__/pushNotificationMocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
let notifSettings;
let onList: any = {};
let called = null;

export const mockPushNotification = () => {
window['PushNotification'] = {
init: (settings: Object) => {
notifSettings = settings;
return {
on: (event: string, callback: Function) => {
onList[event] = callback;
},
finish: (content: any, errorFcn: Function, notID: any) => {
called = notID;
},
};
},
};
};

export const clearNotifMock = function () {
notifSettings = {};
onList = {};
called = null;
};

export const getOnList = function () {
return onList;
};

export const getCalled = function () {
return called;
};
24 changes: 24 additions & 0 deletions www/__tests__/customEventHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { publish, subscribe, unsubscribe } from '../js/customEventHandler';
import { mockLogger } from '../__mocks__/globalMocks';

mockLogger();

it('subscribes and publishes to an event', () => {
const listener = jest.fn();
subscribe('test', listener);
publish('test', 'test data');
expect(listener).toHaveBeenCalledWith(
expect.objectContaining({
type: 'test',
detail: 'test data',
}),
);
});

it('can unsubscribe', () => {
const listener = jest.fn();
subscribe('test', listener);
unsubscribe('test', listener);
publish('test', 'test data');
expect(listener).not.toHaveBeenCalled();
});
119 changes: 119 additions & 0 deletions www/__tests__/pushNotifySettings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { DateTime } from 'luxon';
import { EVENT_NAMES, publish } from '../js/customEventHandler';
import { INTRO_DONE_KEY, readIntroDone } from '../js/onboarding/onboardingHelper';
import { storageSet } from '../js/plugin/storage';
import { initPushNotify } from '../js/splash/pushNotifySettings';
import { mockCordova, mockBEMUserCache, mockBEMDataCollection } from '../__mocks__/cordovaMocks';
import { mockLogger } from '../__mocks__/globalMocks';
import {
clearNotifMock,
getOnList,
mockPushNotification,
getCalled,
} from '../__mocks__/pushNotificationMocks';

mockCordova();
mockLogger();
mockPushNotification();
mockBEMUserCache();
mockBEMDataCollection();

global.fetch = (url: string) =>
new Promise((rs, rj) => {
setTimeout(() =>
rs({
json: () =>
new Promise((rs, rj) => {
let myJSON = {
emSensorDataCollectionProtocol: {
protocol_id: '2014-04-6267',
approval_date: '2016-07-14',
},
};
setTimeout(() => rs(myJSON), 100);
}),
}),
);
}) as any;

afterEach(() => {
clearNotifMock();
});

it('intro done does nothing if not registered', () => {
expect(getOnList()).toStrictEqual({});
publish(EVENT_NAMES.INTRO_DONE_EVENT, 'test data');
expect(getOnList()).toStrictEqual({});
});

it('intro done initializes the push notifications', () => {
expect(getOnList()).toStrictEqual({});

initPushNotify();
publish(EVENT_NAMES.INTRO_DONE_EVENT, 'test data');
expect(getOnList()).toStrictEqual(
expect.objectContaining({
notification: expect.any(Function),
error: expect.any(Function),
registration: expect.any(Function),
}),
);
});

it('cloud event does nothing if not registered', () => {
expect(window['cordova'].platformId).toEqual('ios');
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, {
additionalData: { 'content-available': 1, payload: { notId: 3 } },
});
expect(getCalled()).toBeNull();
});

it('cloud event handles notification if registered', async () => {
expect(window['cordova'].platformId).toEqual('ios');
initPushNotify();
publish(EVENT_NAMES.INTRO_DONE_EVENT, 'intro done');
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, {
additionalData: { 'content-available': 1, payload: { notId: 3 } },
});
await new Promise((r) => setTimeout(r, 1000));
expect(getCalled()).toEqual(3);
});

it('consent event does nothing if not registered', () => {
expect(getOnList()).toStrictEqual({});
publish(EVENT_NAMES.CONSENTED_EVENT, 'test data');
expect(getOnList()).toStrictEqual({});
});

it('consent event registers if intro done', async () => {
//make sure the mock is clear
expect(getOnList()).toStrictEqual({});

//initialize the pushNotify, to subscribe to events
initPushNotify();

//mark the intro as done
const currDateTime = DateTime.now().toISO();
let marked = await storageSet(INTRO_DONE_KEY, currDateTime);
let introDone = await readIntroDone();
expect(introDone).toBeTruthy();

//publish consent event and check results
publish(EVENT_NAMES.CONSENTED_EVENT, 'test data');
//have to wait a beat since event response is async
await new Promise((r) => setTimeout(r, 1000));
expect(getOnList()).toStrictEqual(
expect.objectContaining({
notification: expect.any(Function),
error: expect.any(Function),
registration: expect.any(Function),
}),
);
});

it('consent event does not register if intro not done', () => {
expect(getOnList()).toStrictEqual({});
initPushNotify();
publish(EVENT_NAMES.CONSENTED_EVENT, 'test data');
expect(getOnList()).toStrictEqual({}); //nothing, intro not done
});
76 changes: 76 additions & 0 deletions www/__tests__/remoteNotifyHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { EVENT_NAMES, publish } from '../js/customEventHandler';
import { initRemoteNotifyHandler } from '../js/splash/remoteNotifyHandler';
import {
clearURL,
getURL,
mockBEMUserCache,
mockDevice,
mockGetAppVersion,
mockInAppBrowser,
} from '../__mocks__/cordovaMocks';
import { clearAlerts, getAlerts, mockAlert, mockLogger } from '../__mocks__/globalMocks';

mockLogger();
mockDevice();
mockBEMUserCache();
mockGetAppVersion();
mockInAppBrowser();
mockAlert();

const db = window['cordova']?.plugins?.BEMUserCache;

beforeEach(() => {
clearURL();
clearAlerts();
});

it('does not adds a statEvent if not subscribed', async () => {
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, 'test data');
const storedMessages = await db.getAllMessages('stats/client_nav_event', false);
expect(storedMessages).toEqual([]);
});

it('adds a statEvent if subscribed', async () => {
initRemoteNotifyHandler();
await new Promise((r) => setTimeout(r, 500)); //wait for subscription
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, 'test data');
await new Promise((r) => setTimeout(r, 500)); //wait for event handling
const storedMessages = await db.getAllMessages('stats/client_nav_event', false);
expect(storedMessages).toContainEqual({
name: 'notification_open',
ts: expect.any(Number),
reading: null,
client_app_version: '1.2.3',
client_os_version: '14.0.0',
});
});

it('handles the url if subscribed', () => {
initRemoteNotifyHandler();
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, {
additionalData: {
payload: { alert_type: 'website', spec: { url: 'https://this_is_a_test.com' } },
},
});
expect(getURL()).toBe('https://this_is_a_test.com');
});

it('handles the popup if subscribed', () => {
initRemoteNotifyHandler();
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, {
additionalData: {
payload: {
alert_type: 'popup',
spec: { title: 'Hello', text: 'World' },
},
},
});
expect(getAlerts()).toEqual(expect.arrayContaining(['━━━━\nHello\n━━━━\nWorld']));
});

it('does nothing if subscribed and no data', () => {
initRemoteNotifyHandler();
publish(EVENT_NAMES.CLOUD_NOTIFICATION_EVENT, {});
expect(getURL()).toEqual('');
expect(getAlerts()).toEqual([]);
});
Loading
Loading