From 8bc7da6c9a3223b3066c7b03779981dccba6ef8f Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Tue, 18 Jun 2024 16:01:58 +0100 Subject: [PATCH 1/6] feat: adds one signal plugin manager - adds code specific to outsystems lifecycle aka one signal plugin manager - adds the code that will be in outsystems' wrapper javascript nodes https://outsystemsrd.atlassian.net/browse/RMET-3477 --- .gitignore | 1 + jest.config.js | 14 +++++++ outsystems/definitions.d.ts | 1 + outsystems/index.d.ts | 31 ++++++++++++++ outsystems/initOneSignal.js | 13 ++++++ outsystems/manager.js | 69 ++++++++++++++++++++++++++++++++ outsystems/registerDispatcher.js | 32 +++++++++++++++ outsystems/unregisterPlugin.js | 1 + package.json | 20 ++++++++- src/outsystems/definitions.ts | 1 + src/outsystems/index.ts | 66 ++++++++++++++++++++++++++++++ tsconfig.json | 21 ++++++++++ vite.config.ts | 20 +++++++++ 13 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 jest.config.js create mode 100644 outsystems/definitions.d.ts create mode 100644 outsystems/index.d.ts create mode 100644 outsystems/initOneSignal.js create mode 100644 outsystems/manager.js create mode 100644 outsystems/registerDispatcher.js create mode 100644 outsystems/unregisterPlugin.js create mode 100644 src/outsystems/definitions.ts create mode 100644 src/outsystems/index.ts create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/.gitignore b/.gitignore index 3c3629e6..d5f19d89 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +package-lock.json diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..8a09803c --- /dev/null +++ b/jest.config.js @@ -0,0 +1,14 @@ +// jest.config.js + +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + moduleFileExtensions: ['ts', 'js'], + testMatch: ['**/*.spec.ts'], + transform: { + '^.+\\.tsx?$':['ts-jest', { + tsconfig: 'tsconfig.json', + }] + }, + }; + \ No newline at end of file diff --git a/outsystems/definitions.d.ts b/outsystems/definitions.d.ts new file mode 100644 index 00000000..712c66c5 --- /dev/null +++ b/outsystems/definitions.d.ts @@ -0,0 +1 @@ +export type OneSignalCallback = (...args: any[]) => void; diff --git a/outsystems/index.d.ts b/outsystems/index.d.ts new file mode 100644 index 00000000..f8ef235c --- /dev/null +++ b/outsystems/index.d.ts @@ -0,0 +1,31 @@ +import { OneSignalCallback } from './definitions'; + +declare class OneSignalManagerClass { + #private; + /** + * Public delegate for OneSignal's handleNotificationReceived + */ + notificationReceivedDelegate(jsonData: JSON): void; + /** + * Public delegate for OneSignal's handleNotificationOpened + */ + notificationOpenedDelegate(jsonData: JSON): void; + /** + * Sets the current callback for OneSignal's Notification Received events. + */ + setNotificationReceivedCallback(callback: OneSignalCallback): void; + /** + * Sets the current callback for OneSignal's Notification Opened events. + */ + setNotificationOpenedCallback(callback: OneSignalCallback): void; + /** + * Unregister the old callback of OneSignal's Notification Received + */ + unregisterReceivedCallback(callback: OneSignalCallback): void; + /** + * Unregister the old callback of OneSignal's Notification Opened + */ + unregisterOpenedCallback(callback: OneSignalCallback): void; +} +export declare const OneSignalPluginManager: OneSignalManagerClass; +export {}; diff --git a/outsystems/initOneSignal.js b/outsystems/initOneSignal.js new file mode 100644 index 00000000..cb540b9a --- /dev/null +++ b/outsystems/initOneSignal.js @@ -0,0 +1,13 @@ +var builder = window.plugins.OneSignal.startInit($parameters.ApiKey); +builder.handleNotificationReceived(OSOneSignal.Manager.notificationReceivedDelegate); +builder.handleNotificationOpened(OSOneSignal.Manager.notificationOpenedDelegate); +builder.inFocusDisplaying($parameters.InFocusDisplayOption); + +// Set your iOS Settings +var iosSettings = {}; +iosSettings["kOSSettingsKeyAutoPrompt"] = true; +iosSettings["kOSSettingsKeyInAppLaunchURL"] = false; + +builder.iOSSettings(iosSettings); + +builder.endInit(); \ No newline at end of file diff --git a/outsystems/manager.js b/outsystems/manager.js new file mode 100644 index 00000000..8855c0c9 --- /dev/null +++ b/outsystems/manager.js @@ -0,0 +1,69 @@ +(function(global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.OSOneSignal = {})); +})(this, function(exports2) { + "use strict";var __typeError = (msg) => { + throw TypeError(msg); +}; +var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); +var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); +var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); + + var _notificationReceivedCallback, _notificationOpenedCallback; + class OneSignalManagerClass { + constructor() { + __privateAdd(this, _notificationReceivedCallback, []); + __privateAdd(this, _notificationOpenedCallback, []); + } + /** + * Public delegate for OneSignal's handleNotificationReceived + */ + notificationReceivedDelegate(jsonData) { + __privateGet(this, _notificationReceivedCallback).forEach(function(callback) { + callback.call(void 0, jsonData); + }); + } + /** + * Public delegate for OneSignal's handleNotificationOpened + */ + notificationOpenedDelegate(jsonData) { + __privateGet(this, _notificationOpenedCallback).forEach(function(callback) { + callback.call(void 0, jsonData); + }); + } + /** + * Sets the current callback for OneSignal's Notification Received events. + */ + setNotificationReceivedCallback(callback) { + __privateGet(this, _notificationReceivedCallback).push(callback); + } + /** + * Sets the current callback for OneSignal's Notification Opened events. + */ + setNotificationOpenedCallback(callback) { + __privateGet(this, _notificationOpenedCallback).push(callback); + } + /** + * Unregister the old callback of OneSignal's Notification Received + */ + unregisterReceivedCallback(callback) { + var cbIndex = __privateGet(this, _notificationReceivedCallback).indexOf(callback); + if (cbIndex >= 0) { + delete __privateGet(this, _notificationReceivedCallback)[cbIndex]; + } + } + /** + * Unregister the old callback of OneSignal's Notification Opened + */ + unregisterOpenedCallback(callback) { + var cbIndex = __privateGet(this, _notificationOpenedCallback).indexOf(callback); + if (cbIndex >= 0) { + delete __privateGet(this, _notificationOpenedCallback)[cbIndex]; + } + } + } + _notificationReceivedCallback = new WeakMap(); + _notificationOpenedCallback = new WeakMap(); + const OneSignalPluginManager = new OneSignalManagerClass(); + exports2.OneSignalPluginManager = OneSignalPluginManager; + Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); +}); diff --git a/outsystems/registerDispatcher.js b/outsystems/registerDispatcher.js new file mode 100644 index 00000000..d8c4813e --- /dev/null +++ b/outsystems/registerDispatcher.js @@ -0,0 +1,32 @@ +var onReady = function(scope) { + console.log("onReady scope"); + scope.handleNotificationOpened = scope.newCallback(function(jsonData) { + try{ + console.log("handleNotificationOpened"); + window.oneSignalEvents.triggerOnDispatchNotificationOpened(jsonData); + } catch(err) { + console.error(err); + } + }); + + scope.handleNotificationReceived = scope.newCallback(function(jsonData) { + try{ + console.log("handleNotificationReceived"); + window.oneSignalEvents.triggerOnDispatchNotificationReceived(jsonData); + } catch(err) { + console.error(err); + } + }); + + OSOneSignal.Manager.setNotificationReceivedCallback(scope.handleNotificationReceived); + OSOneSignal.Manager.setNotificationOpenedCallback(scope.handleNotificationOpened); + +} + +var onDestroy = function(scope) { + console.log("onDestroy scope"); + OSOneSignal.Manager.unregisterReceivedCallback(scope.handleNotificationReceived); + OSOneSignal.Manager.unregisterOpenedCallback(scope.handleNotificationOpened); +} + +OSCommonPlugin.PluginManager.createScope(`OneSignalPlugin_${$parameters.Token}`, onReady, onDestroy); \ No newline at end of file diff --git a/outsystems/unregisterPlugin.js b/outsystems/unregisterPlugin.js new file mode 100644 index 00000000..74505f26 --- /dev/null +++ b/outsystems/unregisterPlugin.js @@ -0,0 +1 @@ +OSCommonPlugin.PluginManager.destroyScope(`OneSignalPlugin_${$parameters.Token}`); \ No newline at end of file diff --git a/package.json b/package.json index 516de784..9b995a31 100644 --- a/package.json +++ b/package.json @@ -64,5 +64,23 @@ "bugs": { "url": "https://github.com/onesignal/OneSignal-Cordova-SDK/issues" }, - "homepage": "https://github.com/onesignal/OneSignal-Cordova-SDK#readme" + "homepage": "https://github.com/onesignal/OneSignal-Cordova-SDK#readme", + "scripts": { + "build": "rimraf ./dist && vite build", + "test": "jest" + }, + "devDependencies": { + "jest": "^29.7.0", + "@types/jest": "^29.5.11", + "ts-jest": "^29.1.2", + "@rollup/plugin-typescript": "^11.1.6", + "@types/node": "^20.12.12", + "typescript": "~5.4.5", + "vite": "^5.2.11", + "vite-plugin-dts": "^3.9.1", + "rimraf": "4.3.1", + "eslint": "^7.11.0", + "prettier": "~2.3.0", + "@types/cordova": "^11.0.3" + } } diff --git a/src/outsystems/definitions.ts b/src/outsystems/definitions.ts new file mode 100644 index 00000000..f1fd4982 --- /dev/null +++ b/src/outsystems/definitions.ts @@ -0,0 +1 @@ +export type OneSignalCallback = (...args: any[]) => void; \ No newline at end of file diff --git a/src/outsystems/index.ts b/src/outsystems/index.ts new file mode 100644 index 00000000..ea6f5a4a --- /dev/null +++ b/src/outsystems/index.ts @@ -0,0 +1,66 @@ +import { OneSignalCallback } from "./definitions"; + +class OneSignalManagerClass { + + #notificationReceivedCallback: OneSignalCallback[] = []; + #notificationOpenedCallback: OneSignalCallback[] = []; + + /** + * Public delegate for OneSignal's handleNotificationReceived + */ + notificationReceivedDelegate(jsonData: JSON) { + this.#notificationReceivedCallback.forEach(function(callback:OneSignalCallback){ + callback.call(undefined, jsonData); + }); + } + + /** + * Public delegate for OneSignal's handleNotificationOpened + */ + notificationOpenedDelegate(jsonData: JSON) { + this.#notificationOpenedCallback.forEach(function(callback:OneSignalCallback){ + callback.call(undefined, jsonData); + }); + } + + /** + * Sets the current callback for OneSignal's Notification Received events. + */ + setNotificationReceivedCallback(callback:OneSignalCallback) { + this.#notificationReceivedCallback.push(callback); + } + + /** + * Sets the current callback for OneSignal's Notification Opened events. + */ + setNotificationOpenedCallback(callback:OneSignalCallback) { + this.#notificationOpenedCallback.push(callback); + } + + /** + * Unregister the old callback of OneSignal's Notification Received + */ + unregisterReceivedCallback(callback:OneSignalCallback) { + var cbIndex = this.#notificationReceivedCallback.indexOf(callback); + if(cbIndex >= 0) { + //this.#notificationReceivedCallback[cbIndex] = undefined; + delete this.#notificationReceivedCallback[cbIndex]; + } + } + + /** + * Unregister the old callback of OneSignal's Notification Opened + */ + unregisterOpenedCallback(callback:OneSignalCallback) { + var cbIndex = this.#notificationOpenedCallback.indexOf(callback); + if(cbIndex >= 0) { + //this.#notificationOpenedCallback[cbIndex] = undefined; + delete this.#notificationOpenedCallback[cbIndex]; + } + } + + + +} + +export const Manager = new OneSignalManagerClass(); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..97ff8325 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "allowUnreachableCode": false, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "pretty": true, + "strict": true, + "esModuleInterop": true, + "lib": ["dom", "es2020"], + "module": "esnext", + "moduleResolution": "node", + "target": "es2017" + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..330840c5 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vite'; +import dts from 'vite-plugin-dts'; + +export default defineConfig({ + plugins: [dts()], + build: { + minify: false, + outDir: 'outsystems', + target: 'es2020', + lib: { + entry: './src/outsystems/index.ts', + name: 'OSOneSignal', + fileName: (format) => `manager.${format === 'es' ? 'mjs' : format === 'cjs' ? 'cjs' : 'js'}`, + formats: ['umd'], + }, + rollupOptions: { + external: ['cordova'], + }, + }, +}); \ No newline at end of file From 3b985a836fdbd353dea3bedcf3a8ba24d62d7949 Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Tue, 18 Jun 2024 18:57:28 +0100 Subject: [PATCH 2/6] feat: adds unit testing using jest https://outsystemsrd.atlassian.net/browse/RMET-3477 --- outsystems/{ => nodes}/initOneSignal.js | 0 outsystems/{ => nodes}/registerDispatcher.js | 0 outsystems/{ => nodes}/unregisterPlugin.js | 0 outsystems/{ => scripts}/definitions.d.ts | 0 outsystems/{ => scripts}/index.d.ts | 6 +- outsystems/{ => scripts}/manager.js | 4 +- package.json | 2 +- src/outsystems/index.ts | 7 +- test/onesignalmanager.spec.ts | 184 +++++++++++++++++++ vite.config.ts | 7 +- 10 files changed, 194 insertions(+), 16 deletions(-) rename outsystems/{ => nodes}/initOneSignal.js (100%) rename outsystems/{ => nodes}/registerDispatcher.js (100%) rename outsystems/{ => nodes}/unregisterPlugin.js (100%) rename outsystems/{ => scripts}/definitions.d.ts (100%) rename outsystems/{ => scripts}/index.d.ts (83%) rename outsystems/{ => scripts}/manager.js (95%) create mode 100644 test/onesignalmanager.spec.ts diff --git a/outsystems/initOneSignal.js b/outsystems/nodes/initOneSignal.js similarity index 100% rename from outsystems/initOneSignal.js rename to outsystems/nodes/initOneSignal.js diff --git a/outsystems/registerDispatcher.js b/outsystems/nodes/registerDispatcher.js similarity index 100% rename from outsystems/registerDispatcher.js rename to outsystems/nodes/registerDispatcher.js diff --git a/outsystems/unregisterPlugin.js b/outsystems/nodes/unregisterPlugin.js similarity index 100% rename from outsystems/unregisterPlugin.js rename to outsystems/nodes/unregisterPlugin.js diff --git a/outsystems/definitions.d.ts b/outsystems/scripts/definitions.d.ts similarity index 100% rename from outsystems/definitions.d.ts rename to outsystems/scripts/definitions.d.ts diff --git a/outsystems/index.d.ts b/outsystems/scripts/index.d.ts similarity index 83% rename from outsystems/index.d.ts rename to outsystems/scripts/index.d.ts index f8ef235c..5530144b 100644 --- a/outsystems/index.d.ts +++ b/outsystems/scripts/index.d.ts @@ -5,11 +5,11 @@ declare class OneSignalManagerClass { /** * Public delegate for OneSignal's handleNotificationReceived */ - notificationReceivedDelegate(jsonData: JSON): void; + notificationReceivedDelegate(jsonData: any): void; /** * Public delegate for OneSignal's handleNotificationOpened */ - notificationOpenedDelegate(jsonData: JSON): void; + notificationOpenedDelegate(jsonData: any): void; /** * Sets the current callback for OneSignal's Notification Received events. */ @@ -27,5 +27,5 @@ declare class OneSignalManagerClass { */ unregisterOpenedCallback(callback: OneSignalCallback): void; } -export declare const OneSignalPluginManager: OneSignalManagerClass; +export declare const Manager: OneSignalManagerClass; export {}; diff --git a/outsystems/manager.js b/outsystems/scripts/manager.js similarity index 95% rename from outsystems/manager.js rename to outsystems/scripts/manager.js index 8855c0c9..3b559cde 100644 --- a/outsystems/manager.js +++ b/outsystems/scripts/manager.js @@ -63,7 +63,7 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot } _notificationReceivedCallback = new WeakMap(); _notificationOpenedCallback = new WeakMap(); - const OneSignalPluginManager = new OneSignalManagerClass(); - exports2.OneSignalPluginManager = OneSignalPluginManager; + const Manager = new OneSignalManagerClass(); + exports2.Manager = Manager; Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); }); diff --git a/package.json b/package.json index 9b995a31..c0b40829 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ }, "homepage": "https://github.com/onesignal/OneSignal-Cordova-SDK#readme", "scripts": { - "build": "rimraf ./dist && vite build", + "build": "rimraf ./outsystems/scripts && vite build", "test": "jest" }, "devDependencies": { diff --git a/src/outsystems/index.ts b/src/outsystems/index.ts index ea6f5a4a..c986baf5 100644 --- a/src/outsystems/index.ts +++ b/src/outsystems/index.ts @@ -8,7 +8,7 @@ class OneSignalManagerClass { /** * Public delegate for OneSignal's handleNotificationReceived */ - notificationReceivedDelegate(jsonData: JSON) { + notificationReceivedDelegate(jsonData: any) { this.#notificationReceivedCallback.forEach(function(callback:OneSignalCallback){ callback.call(undefined, jsonData); }); @@ -17,7 +17,7 @@ class OneSignalManagerClass { /** * Public delegate for OneSignal's handleNotificationOpened */ - notificationOpenedDelegate(jsonData: JSON) { + notificationOpenedDelegate(jsonData: any) { this.#notificationOpenedCallback.forEach(function(callback:OneSignalCallback){ callback.call(undefined, jsonData); }); @@ -58,9 +58,6 @@ class OneSignalManagerClass { delete this.#notificationOpenedCallback[cbIndex]; } } - - - } export const Manager = new OneSignalManagerClass(); \ No newline at end of file diff --git a/test/onesignalmanager.spec.ts b/test/onesignalmanager.spec.ts new file mode 100644 index 00000000..1a37e541 --- /dev/null +++ b/test/onesignalmanager.spec.ts @@ -0,0 +1,184 @@ + +import { Manager } from '../src/outsystems/index' + +describe("One Signal Manager: Notification Received Callback Tests", () => { + + it("if one received callback is registered, it should be called accordignly", () => { + + let mockCallback = jest.fn((num: number) => num++); + + Manager.setNotificationReceivedCallback(mockCallback); + expect(mockCallback.mock.calls.length).toBe(0); + + Manager.notificationReceivedDelegate(0); + + expect(mockCallback).toHaveBeenCalledWith(0); + expect(mockCallback.mock.calls.length).toBe(1); + }); + + it("if multiple received callback are registered, they should be called accordignly", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationReceivedCallback(mockCallback1); + Manager.setNotificationReceivedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.notificationReceivedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(1); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback1).toHaveBeenCalledWith(0); + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + + it("if multiple received callback are registered, but one is removed, only one should be called", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationReceivedCallback(mockCallback1); + Manager.setNotificationReceivedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.unregisterReceivedCallback(mockCallback1); + Manager.notificationReceivedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + +}); + +describe("One Signal Manager: Notification Opened Callback Tests", () => { + + it("if one opened callback is registered, it should be called accordignly", () => { + + let mockCallback = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(mockCallback); + expect(mockCallback.mock.calls.length).toBe(0); + + Manager.notificationOpenedDelegate(0); + + expect(mockCallback).toHaveBeenCalledWith(0); + expect(mockCallback.mock.calls.length).toBe(1); + }); + + it("if multiple Opened callback are registered, they should be called accordignly", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(mockCallback1); + Manager.setNotificationOpenedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.notificationOpenedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(1); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback1).toHaveBeenCalledWith(0); + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + + it("if multiple Opened callback are registered, but one is removed, only one should be called", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(mockCallback1); + Manager.setNotificationOpenedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.unregisterOpenedCallback(mockCallback1); + Manager.notificationOpenedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + +}); + +describe("One Signal Manager: Both Callback Tests", () => { + + it("if both callbacks are registered, and only one is called, then it should work as expected", () => { + + let openCallback = jest.fn((num: number) => num++); + let receivedCallback = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(openCallback); + Manager.setNotificationReceivedCallback(receivedCallback); + + expect(openCallback.mock.calls.length).toBe(0); + expect(receivedCallback.mock.calls.length).toBe(0); + + Manager.notificationOpenedDelegate(0); + + expect(openCallback).toHaveBeenCalledWith(0); + expect(openCallback.mock.calls.length).toBe(1); + expect(receivedCallback.mock.calls.length).toBe(0); + + Manager.notificationReceivedDelegate(1); + + expect(receivedCallback).toHaveBeenCalledWith(1); + expect(receivedCallback.mock.calls.length).toBe(1); + expect(openCallback.mock.calls.length).toBe(1); + }); + + it("if multiple Opened callback are registered, they should be called accordignly", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(mockCallback1); + Manager.setNotificationOpenedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.notificationOpenedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(1); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback1).toHaveBeenCalledWith(0); + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + + it("if multiple Opened callback are registered, but one is removed, only one should be called", () => { + + let mockCallback1 = jest.fn((num: number) => num++); + let mockCallback2 = jest.fn((num: number) => num++); + + Manager.setNotificationOpenedCallback(mockCallback1); + Manager.setNotificationOpenedCallback(mockCallback2); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(0); + + Manager.unregisterOpenedCallback(mockCallback1); + Manager.notificationOpenedDelegate(0); + + expect(mockCallback1.mock.calls.length).toBe(0); + expect(mockCallback2.mock.calls.length).toBe(1); + + expect(mockCallback2).toHaveBeenCalledWith(0); + }); + +}); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 330840c5..194573f4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,16 +5,13 @@ export default defineConfig({ plugins: [dts()], build: { minify: false, - outDir: 'outsystems', + outDir: 'outsystems/scripts', target: 'es2020', lib: { entry: './src/outsystems/index.ts', name: 'OSOneSignal', fileName: (format) => `manager.${format === 'es' ? 'mjs' : format === 'cjs' ? 'cjs' : 'js'}`, formats: ['umd'], - }, - rollupOptions: { - external: ['cordova'], - }, + } }, }); \ No newline at end of file From 93f0e972134063815d840015abf379ed462e6856 Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Wed, 19 Jun 2024 09:45:26 +0100 Subject: [PATCH 3/6] feat: add event scripts https://outsystemsrd.atlassian.net/browse/RMET-3477 --- outsystems/OneSignal_Events.js | 47 ++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 outsystems/OneSignal_Events.js diff --git a/outsystems/OneSignal_Events.js b/outsystems/OneSignal_Events.js new file mode 100644 index 00000000..cfb9a7e2 --- /dev/null +++ b/outsystems/OneSignal_Events.js @@ -0,0 +1,47 @@ +/** + * Due to the nature of OutSystems Screens' & Blocks' Lifecyle + * We keep track of the active callbacks (valid client actions) via this window object + */ +(function() { + + var callbacks = { + onDispatchNotificationOpened: null, + onDispatchNotificationReceived: null + } + + var token; + + var OneSignalEventsSync = { + registerCallbacks: function (onDispatchNotificationReceived, onDispatchNotificationOpened){ + token = (new Date()).getTime().toString(); + + callbacks.onDispatchNotificationReceived = onDispatchNotificationReceived; + callbacks.onDispatchNotificationOpened = onDispatchNotificationOpened; + + return token + }, + + unregisterCallbacks: function (previousToken){ + if(token === previousToken) { + callbacks = null; + } + }, + + triggerOnDispatchNotificationReceived: function (json){ + if(callbacks && callbacks.onDispatchNotificationReceived) { + callbacks.onDispatchNotificationReceived(JSON.stringify(json)); + } + }, + + triggerOnDispatchNotificationOpened: function (json){ + if(callbacks && callbacks.onDispatchNotificationOpened) { + callbacks.onDispatchNotificationOpened(JSON.stringify(json)); + } + } + + } + + if (!window.oneSignalEvents) { + window.oneSignalEvents = OneSignalEventsSync; + } +})(); diff --git a/package.json b/package.json index c0b40829..258dac8e 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ }, "homepage": "https://github.com/onesignal/OneSignal-Cordova-SDK#readme", "scripts": { - "build": "rimraf ./outsystems/scripts && vite build", + "build": "vite build", "test": "jest" }, "devDependencies": { From ee16feb5953dbef5ae268296c933fd8297ef1735 Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Wed, 19 Jun 2024 09:51:50 +0100 Subject: [PATCH 4/6] feat: adds o11 code https://outsystemsrd.atlassian.net/browse/RMET-3477 --- outsystems/CHANGELOG.md | 10 +++ outsystems/README.md | 19 ++++++ outsystems/nodes/O11/initOneSignal.js | 18 +++++ outsystems/nodes/O11/registerDispatcher.js | 37 ++++++++++ outsystems/nodes/O11/unregisterPlugin.js | 4 ++ outsystems/nodes/{ => ODC}/initOneSignal.js | 0 .../nodes/{ => ODC}/registerDispatcher.js | 0 .../nodes/{ => ODC}/unregisterPlugin.js | 0 outsystems/scripts/O11/manager.js | 68 +++++++++++++++++++ outsystems/scripts/{ => ODC}/definitions.d.ts | 0 outsystems/scripts/{ => ODC}/index.d.ts | 0 outsystems/scripts/{ => ODC}/manager.js | 0 outsystems/{ => scripts}/OneSignal_Events.js | 0 package.json | 2 +- vite.config.ts | 2 +- 15 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 outsystems/CHANGELOG.md create mode 100644 outsystems/README.md create mode 100644 outsystems/nodes/O11/initOneSignal.js create mode 100644 outsystems/nodes/O11/registerDispatcher.js create mode 100644 outsystems/nodes/O11/unregisterPlugin.js rename outsystems/nodes/{ => ODC}/initOneSignal.js (100%) rename outsystems/nodes/{ => ODC}/registerDispatcher.js (100%) rename outsystems/nodes/{ => ODC}/unregisterPlugin.js (100%) create mode 100644 outsystems/scripts/O11/manager.js rename outsystems/scripts/{ => ODC}/definitions.d.ts (100%) rename outsystems/scripts/{ => ODC}/index.d.ts (100%) rename outsystems/scripts/{ => ODC}/manager.js (100%) rename outsystems/{ => scripts}/OneSignal_Events.js (100%) diff --git a/outsystems/CHANGELOG.md b/outsystems/CHANGELOG.md new file mode 100644 index 00000000..cd47bc3d --- /dev/null +++ b/outsystems/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +### 2024-06-19 + +- Re-write `OneSignal_Manager` as an UMD module, [RMET-3477](https://outsystemsrd.atlassian.net/browse/RMET-3477) \ No newline at end of file diff --git a/outsystems/README.md b/outsystems/README.md new file mode 100644 index 00000000..0d141656 --- /dev/null +++ b/outsystems/README.md @@ -0,0 +1,19 @@ +# OutSystems Wrapper + + +Welcome! Here lies the code related to the OutSystems Wrapper *aka* the JavaScript code that is present on the OutSystems Plugin, downloadable from Forge. + +## Structure + +In an OutSystems Plugin, there's two ways to host JavaScript code: JavaScript Nodes and script files. + +* `nodes` holds the JavaScript code inside a OutSystems Javascript node, with the same name +* `scripts` JavaScript files that the plugin imports + +And lastly, but not least, the wrapper differs depending on the platform (ODC vs O11) and, as such, so does this folder. + +## How is it used + +This repository holds the code related to the OneSignal Plugin's module, `OneSignal_Manager`. Up until 2024, this manager was counting on the existence of RequireJS in an OutSystems' App Runtime to create this module. Since RequireJS will no longer be part of OutSystems' Runtime, `OneSignal_Manager` needed to be updated. The approach was to create an UMD module, available to any plugin/app that imports `OneSignal_Manager`. + +Additionally, this module assumes the Common Plugin's `PluginManager` is imported in the app. \ No newline at end of file diff --git a/outsystems/nodes/O11/initOneSignal.js b/outsystems/nodes/O11/initOneSignal.js new file mode 100644 index 00000000..bda72eb6 --- /dev/null +++ b/outsystems/nodes/O11/initOneSignal.js @@ -0,0 +1,18 @@ +require(["OneSignalPluginManager"], function(oneSignalMgr){ + var builder = window.plugins.OneSignal.startInit($parameters.ApiKey); + builder.handleNotificationReceived(oneSignalMgr.notificationReceivedDelegate); + builder.handleNotificationOpened(oneSignalMgr.notificationOpenedDelegate); + builder.inFocusDisplaying($parameters.InFocusDisplayOption); + + // Set your iOS Settings + var iosSettings = {}; + iosSettings["kOSSettingsKeyAutoPrompt"] = true; + iosSettings["kOSSettingsKeyInAppLaunchURL"] = false; + + builder.iOSSettings(iosSettings); + + builder.endInit(); + + $resolve(); + +}); \ No newline at end of file diff --git a/outsystems/nodes/O11/registerDispatcher.js b/outsystems/nodes/O11/registerDispatcher.js new file mode 100644 index 00000000..6dce4656 --- /dev/null +++ b/outsystems/nodes/O11/registerDispatcher.js @@ -0,0 +1,37 @@ +require(["PluginManager","OneSignalPluginManager"], function(module, oneSignalMgr){ + + var onReady = function(scope) { + console.log("onReady scope"); + scope.handleNotificationOpened = scope.newCallback(function(jsonData) { + try{ + console.log("handleNotificationOpened"); + window.oneSignalEvents.triggerOnDispatchNotificationOpened(jsonData); + } catch(err) { + console.error(err); + } + }); + + scope.handleNotificationReceived = scope.newCallback(function(jsonData) { + try{ + console.log("handleNotificationReceived"); + window.oneSignalEvents.triggerOnDispatchNotificationReceived(jsonData); + } catch(err) { + console.error(err); + } + }); + + oneSignalMgr.setNotificationReceivedCallback(scope.handleNotificationReceived); + oneSignalMgr.setNotificationOpenedCallback(scope.handleNotificationOpened); + + } + + var onDestroy = function(scope) { + console.log("onDestroy scope"); + oneSignalMgr.unregisterReceivedCallback(scope.handleNotificationReceived); + oneSignalMgr.unregisterOpenedCallback(scope.handleNotificationOpened); + } + + module.createScope(`OneSignalPlugin_${$parameters.Token}`, onReady, onDestroy); + + $resolve(); +}); \ No newline at end of file diff --git a/outsystems/nodes/O11/unregisterPlugin.js b/outsystems/nodes/O11/unregisterPlugin.js new file mode 100644 index 00000000..d63edfc4 --- /dev/null +++ b/outsystems/nodes/O11/unregisterPlugin.js @@ -0,0 +1,4 @@ +require(["PluginManager"], function(module){ + module.destroyScope(`OneSignalPlugin_${$parameters.Token}`); + $resolve(); +}); \ No newline at end of file diff --git a/outsystems/nodes/initOneSignal.js b/outsystems/nodes/ODC/initOneSignal.js similarity index 100% rename from outsystems/nodes/initOneSignal.js rename to outsystems/nodes/ODC/initOneSignal.js diff --git a/outsystems/nodes/registerDispatcher.js b/outsystems/nodes/ODC/registerDispatcher.js similarity index 100% rename from outsystems/nodes/registerDispatcher.js rename to outsystems/nodes/ODC/registerDispatcher.js diff --git a/outsystems/nodes/unregisterPlugin.js b/outsystems/nodes/ODC/unregisterPlugin.js similarity index 100% rename from outsystems/nodes/unregisterPlugin.js rename to outsystems/nodes/ODC/unregisterPlugin.js diff --git a/outsystems/scripts/O11/manager.js b/outsystems/scripts/O11/manager.js new file mode 100644 index 00000000..16ff3cfe --- /dev/null +++ b/outsystems/scripts/O11/manager.js @@ -0,0 +1,68 @@ +define("OneSignalPluginManager", ["exports"], function(exports) { + + var notificationReceivedCallback = []; + var notificationOpenedCallback = []; + + /** + * Public delegate for OneSignal's handleNotificationReceived + */ + function notificationReceivedDelegate(jsonData) { + notificationReceivedCallback.forEach(function(callback){ + callback.call(undefined, jsonData); + }); + } + + /** + * Public delegate for OneSignal's handleNotificationOpened + */ + function notificationOpenedDelegate(jsonData) { + notificationOpenedCallback.forEach(function(callback){ + callback.call(undefined, jsonData); + }); + } + + /** + * Sets the current callback for OneSignal's Notification Received events. + */ + function setNotificationReceivedCallback(callback) { + notificationReceivedCallback.push(callback); + } + + /** + * Sets the current callback for OneSignal's Notification Opened events. + */ + function setNotificationOpenedCallback(callback) { + notificationOpenedCallback.push(callback); + } + + /** + * Unregister the old callback of OneSignal's Notification Received + */ + function unregisterReceivedCallback(callback) { + var cbIndex = notificationReceivedCallback.indexOf(callback); + if(cbIndex >= 0) { + notificationReceivedCallback[cbIndex] = undefined; + delete notificationReceivedCallback[cbIndex]; + } + } + + /** + * Unregister the old callback of OneSignal's Notification Opened + */ + function unregisterOpenedCallback(callback) { + var cbIndex = notificationOpenedCallback.indexOf(callback); + if(cbIndex >= 0) { + notificationOpenedCallback[cbIndex] = undefined; + delete notificationOpenedCallback[cbIndex]; + } + } + + exports.notificationReceivedDelegate = notificationReceivedDelegate; + exports.notificationOpenedDelegate = notificationOpenedDelegate; + + exports.setNotificationReceivedCallback = setNotificationReceivedCallback; + exports.setNotificationOpenedCallback = setNotificationOpenedCallback; + + exports.unregisterReceivedCallback = unregisterReceivedCallback; + exports.unregisterOpenedCallback = unregisterOpenedCallback; +}); \ No newline at end of file diff --git a/outsystems/scripts/definitions.d.ts b/outsystems/scripts/ODC/definitions.d.ts similarity index 100% rename from outsystems/scripts/definitions.d.ts rename to outsystems/scripts/ODC/definitions.d.ts diff --git a/outsystems/scripts/index.d.ts b/outsystems/scripts/ODC/index.d.ts similarity index 100% rename from outsystems/scripts/index.d.ts rename to outsystems/scripts/ODC/index.d.ts diff --git a/outsystems/scripts/manager.js b/outsystems/scripts/ODC/manager.js similarity index 100% rename from outsystems/scripts/manager.js rename to outsystems/scripts/ODC/manager.js diff --git a/outsystems/OneSignal_Events.js b/outsystems/scripts/OneSignal_Events.js similarity index 100% rename from outsystems/OneSignal_Events.js rename to outsystems/scripts/OneSignal_Events.js diff --git a/package.json b/package.json index 258dac8e..e4a4609f 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "homepage": "https://github.com/onesignal/OneSignal-Cordova-SDK#readme", "scripts": { "build": "vite build", - "test": "jest" + "test": "jest --coverage --ci" }, "devDependencies": { "jest": "^29.7.0", diff --git a/vite.config.ts b/vite.config.ts index 194573f4..f6cad069 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ plugins: [dts()], build: { minify: false, - outDir: 'outsystems/scripts', + outDir: 'outsystems/scripts/ODC', target: 'es2020', lib: { entry: './src/outsystems/index.ts', From caf4d5ac61db151bc552eb00d82f8aec371970cc Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Thu, 20 Jun 2024 14:23:37 +0100 Subject: [PATCH 5/6] fix: rewrite module without class - having the object creation was leading to bugs on the OutSystems side, as it wasn't a singleton, new instances of the object kept being created - fixes unit tests accordingly https://outsystemsrd.atlassian.net/browse/RMET-3477 --- outsystems/nodes/ODC/initOneSignal.js | 4 +- outsystems/nodes/ODC/registerDispatcher.js | 8 +- outsystems/scripts/ODC/index.d.ts | 53 +++++------ outsystems/scripts/ODC/manager.js | 95 +++++++------------ src/outsystems/index.ts | 102 ++++++++++----------- test/onesignalmanager.spec.ts | 44 +-------- vite.config.ts | 2 +- 7 files changed, 116 insertions(+), 192 deletions(-) diff --git a/outsystems/nodes/ODC/initOneSignal.js b/outsystems/nodes/ODC/initOneSignal.js index cb540b9a..facec5d6 100644 --- a/outsystems/nodes/ODC/initOneSignal.js +++ b/outsystems/nodes/ODC/initOneSignal.js @@ -1,6 +1,6 @@ var builder = window.plugins.OneSignal.startInit($parameters.ApiKey); -builder.handleNotificationReceived(OSOneSignal.Manager.notificationReceivedDelegate); -builder.handleNotificationOpened(OSOneSignal.Manager.notificationOpenedDelegate); +builder.handleNotificationReceived(OSOneSignal.notificationReceivedDelegate); +builder.handleNotificationOpened(OSOneSignal.notificationOpenedDelegate); builder.inFocusDisplaying($parameters.InFocusDisplayOption); // Set your iOS Settings diff --git a/outsystems/nodes/ODC/registerDispatcher.js b/outsystems/nodes/ODC/registerDispatcher.js index d8c4813e..a419a0d0 100644 --- a/outsystems/nodes/ODC/registerDispatcher.js +++ b/outsystems/nodes/ODC/registerDispatcher.js @@ -18,15 +18,15 @@ var onReady = function(scope) { } }); - OSOneSignal.Manager.setNotificationReceivedCallback(scope.handleNotificationReceived); - OSOneSignal.Manager.setNotificationOpenedCallback(scope.handleNotificationOpened); + OSOneSignal.setNotificationReceivedCallback(scope.handleNotificationReceived); + OSOneSignal.setNotificationOpenedCallback(scope.handleNotificationOpened); } var onDestroy = function(scope) { console.log("onDestroy scope"); - OSOneSignal.Manager.unregisterReceivedCallback(scope.handleNotificationReceived); - OSOneSignal.Manager.unregisterOpenedCallback(scope.handleNotificationOpened); + OSOneSignal.unregisterReceivedCallback(scope.handleNotificationReceived); + OSOneSignal.unregisterOpenedCallback(scope.handleNotificationOpened); } OSCommonPlugin.PluginManager.createScope(`OneSignalPlugin_${$parameters.Token}`, onReady, onDestroy); \ No newline at end of file diff --git a/outsystems/scripts/ODC/index.d.ts b/outsystems/scripts/ODC/index.d.ts index 5530144b..c9c47d99 100644 --- a/outsystems/scripts/ODC/index.d.ts +++ b/outsystems/scripts/ODC/index.d.ts @@ -1,31 +1,26 @@ import { OneSignalCallback } from './definitions'; -declare class OneSignalManagerClass { - #private; - /** - * Public delegate for OneSignal's handleNotificationReceived - */ - notificationReceivedDelegate(jsonData: any): void; - /** - * Public delegate for OneSignal's handleNotificationOpened - */ - notificationOpenedDelegate(jsonData: any): void; - /** - * Sets the current callback for OneSignal's Notification Received events. - */ - setNotificationReceivedCallback(callback: OneSignalCallback): void; - /** - * Sets the current callback for OneSignal's Notification Opened events. - */ - setNotificationOpenedCallback(callback: OneSignalCallback): void; - /** - * Unregister the old callback of OneSignal's Notification Received - */ - unregisterReceivedCallback(callback: OneSignalCallback): void; - /** - * Unregister the old callback of OneSignal's Notification Opened - */ - unregisterOpenedCallback(callback: OneSignalCallback): void; -} -export declare const Manager: OneSignalManagerClass; -export {}; +/** + * Public delegate for OneSignal's handleNotificationReceived + */ +export declare function notificationReceivedDelegate(jsonData: any): void; +/** + * Public delegate for OneSignal's handleNotificationOpened + */ +export declare function notificationOpenedDelegate(jsonData: any): void; +/** + * Sets the current callback for OneSignal's Notification Received events. + */ +export declare function setNotificationReceivedCallback(callback: OneSignalCallback): void; +/** + * Sets the current callback for OneSignal's Notification Opened events. + */ +export declare function setNotificationOpenedCallback(callback: OneSignalCallback): void; +/** + * Unregister the old callback of OneSignal's Notification Received + */ +export declare function unregisterReceivedCallback(callback: OneSignalCallback): void; +/** + * Unregister the old callback of OneSignal's Notification Opened + */ +export declare function unregisterOpenedCallback(callback: OneSignalCallback): void; diff --git a/outsystems/scripts/ODC/manager.js b/outsystems/scripts/ODC/manager.js index 3b559cde..ca8bd001 100644 --- a/outsystems/scripts/ODC/manager.js +++ b/outsystems/scripts/ODC/manager.js @@ -1,69 +1,42 @@ (function(global, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.OSOneSignal = {})); })(this, function(exports2) { - "use strict";var __typeError = (msg) => { - throw TypeError(msg); -}; -var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); -var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); -var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); - - var _notificationReceivedCallback, _notificationOpenedCallback; - class OneSignalManagerClass { - constructor() { - __privateAdd(this, _notificationReceivedCallback, []); - __privateAdd(this, _notificationOpenedCallback, []); - } - /** - * Public delegate for OneSignal's handleNotificationReceived - */ - notificationReceivedDelegate(jsonData) { - __privateGet(this, _notificationReceivedCallback).forEach(function(callback) { - callback.call(void 0, jsonData); - }); - } - /** - * Public delegate for OneSignal's handleNotificationOpened - */ - notificationOpenedDelegate(jsonData) { - __privateGet(this, _notificationOpenedCallback).forEach(function(callback) { - callback.call(void 0, jsonData); - }); - } - /** - * Sets the current callback for OneSignal's Notification Received events. - */ - setNotificationReceivedCallback(callback) { - __privateGet(this, _notificationReceivedCallback).push(callback); - } - /** - * Sets the current callback for OneSignal's Notification Opened events. - */ - setNotificationOpenedCallback(callback) { - __privateGet(this, _notificationOpenedCallback).push(callback); - } - /** - * Unregister the old callback of OneSignal's Notification Received - */ - unregisterReceivedCallback(callback) { - var cbIndex = __privateGet(this, _notificationReceivedCallback).indexOf(callback); - if (cbIndex >= 0) { - delete __privateGet(this, _notificationReceivedCallback)[cbIndex]; - } + "use strict"; + var notificationReceivedCallback = []; + var notificationOpenedCallback = []; + function notificationReceivedDelegate(jsonData) { + notificationReceivedCallback.forEach(function(callback) { + callback(jsonData); + }); + } + function notificationOpenedDelegate(jsonData) { + notificationOpenedCallback.forEach(function(callback) { + callback(jsonData); + }); + } + function setNotificationReceivedCallback(callback) { + notificationReceivedCallback.push(callback); + } + function setNotificationOpenedCallback(callback) { + notificationOpenedCallback.push(callback); + } + function unregisterReceivedCallback(callback) { + var cbIndex = notificationReceivedCallback.indexOf(callback); + if (cbIndex >= 0) { + delete notificationReceivedCallback[cbIndex]; } - /** - * Unregister the old callback of OneSignal's Notification Opened - */ - unregisterOpenedCallback(callback) { - var cbIndex = __privateGet(this, _notificationOpenedCallback).indexOf(callback); - if (cbIndex >= 0) { - delete __privateGet(this, _notificationOpenedCallback)[cbIndex]; - } + } + function unregisterOpenedCallback(callback) { + var cbIndex = notificationOpenedCallback.indexOf(callback); + if (cbIndex >= 0) { + delete notificationOpenedCallback[cbIndex]; } } - _notificationReceivedCallback = new WeakMap(); - _notificationOpenedCallback = new WeakMap(); - const Manager = new OneSignalManagerClass(); - exports2.Manager = Manager; + exports2.notificationOpenedDelegate = notificationOpenedDelegate; + exports2.notificationReceivedDelegate = notificationReceivedDelegate; + exports2.setNotificationOpenedCallback = setNotificationOpenedCallback; + exports2.setNotificationReceivedCallback = setNotificationReceivedCallback; + exports2.unregisterOpenedCallback = unregisterOpenedCallback; + exports2.unregisterReceivedCallback = unregisterReceivedCallback; Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); }); diff --git a/src/outsystems/index.ts b/src/outsystems/index.ts index c986baf5..08431da6 100644 --- a/src/outsystems/index.ts +++ b/src/outsystems/index.ts @@ -1,63 +1,59 @@ import { OneSignalCallback } from "./definitions"; -class OneSignalManagerClass { - - #notificationReceivedCallback: OneSignalCallback[] = []; - #notificationOpenedCallback: OneSignalCallback[] = []; - - /** - * Public delegate for OneSignal's handleNotificationReceived - */ - notificationReceivedDelegate(jsonData: any) { - this.#notificationReceivedCallback.forEach(function(callback:OneSignalCallback){ - callback.call(undefined, jsonData); - }); - } +var notificationReceivedCallback: OneSignalCallback[] = []; +var notificationOpenedCallback: OneSignalCallback[] = []; + +/** + * Public delegate for OneSignal's handleNotificationReceived + */ +export function notificationReceivedDelegate(jsonData: any) { + notificationReceivedCallback.forEach(function(callback:OneSignalCallback){ + callback(jsonData); + }); +} - /** - * Public delegate for OneSignal's handleNotificationOpened - */ - notificationOpenedDelegate(jsonData: any) { - this.#notificationOpenedCallback.forEach(function(callback:OneSignalCallback){ - callback.call(undefined, jsonData); - }); - } +/** + * Public delegate for OneSignal's handleNotificationOpened + */ +export function notificationOpenedDelegate(jsonData: any) { + notificationOpenedCallback.forEach(function(callback:OneSignalCallback){ + callback(jsonData); + }); +} - /** - * Sets the current callback for OneSignal's Notification Received events. - */ - setNotificationReceivedCallback(callback:OneSignalCallback) { - this.#notificationReceivedCallback.push(callback); - } +/** + * Sets the current callback for OneSignal's Notification Received events. + */ +export function setNotificationReceivedCallback(callback:OneSignalCallback) { + notificationReceivedCallback.push(callback); +} - /** - * Sets the current callback for OneSignal's Notification Opened events. - */ - setNotificationOpenedCallback(callback:OneSignalCallback) { - this.#notificationOpenedCallback.push(callback); - } +/** + * Sets the current callback for OneSignal's Notification Opened events. + */ +export function setNotificationOpenedCallback(callback:OneSignalCallback) { + notificationOpenedCallback.push(callback); +} - /** - * Unregister the old callback of OneSignal's Notification Received - */ - unregisterReceivedCallback(callback:OneSignalCallback) { - var cbIndex = this.#notificationReceivedCallback.indexOf(callback); - if(cbIndex >= 0) { - //this.#notificationReceivedCallback[cbIndex] = undefined; - delete this.#notificationReceivedCallback[cbIndex]; - } +/** + * Unregister the old callback of OneSignal's Notification Received + */ +export function unregisterReceivedCallback(callback:OneSignalCallback) { + var cbIndex = notificationReceivedCallback.indexOf(callback); + if(cbIndex >= 0) { + //notificationReceivedCallback[cbIndex] = undefined; + delete notificationReceivedCallback[cbIndex]; } +} - /** - * Unregister the old callback of OneSignal's Notification Opened - */ - unregisterOpenedCallback(callback:OneSignalCallback) { - var cbIndex = this.#notificationOpenedCallback.indexOf(callback); - if(cbIndex >= 0) { - //this.#notificationOpenedCallback[cbIndex] = undefined; - delete this.#notificationOpenedCallback[cbIndex]; - } +/** + * Unregister the old callback of OneSignal's Notification Opened + */ +export function unregisterOpenedCallback(callback:OneSignalCallback) { + var cbIndex = notificationOpenedCallback.indexOf(callback); + if(cbIndex >= 0) { + //notificationOpenedCallback[cbIndex] = undefined; + delete notificationOpenedCallback[cbIndex]; } -} -export const Manager = new OneSignalManagerClass(); \ No newline at end of file +} \ No newline at end of file diff --git a/test/onesignalmanager.spec.ts b/test/onesignalmanager.spec.ts index 1a37e541..c16e04b9 100644 --- a/test/onesignalmanager.spec.ts +++ b/test/onesignalmanager.spec.ts @@ -1,5 +1,5 @@ -import { Manager } from '../src/outsystems/index' +import * as Manager from '../src/outsystems/index' describe("One Signal Manager: Notification Received Callback Tests", () => { @@ -135,50 +135,10 @@ describe("One Signal Manager: Both Callback Tests", () => { expect(receivedCallback.mock.calls.length).toBe(0); Manager.notificationReceivedDelegate(1); - + expect(receivedCallback).toHaveBeenCalledWith(1); expect(receivedCallback.mock.calls.length).toBe(1); expect(openCallback.mock.calls.length).toBe(1); }); - - it("if multiple Opened callback are registered, they should be called accordignly", () => { - - let mockCallback1 = jest.fn((num: number) => num++); - let mockCallback2 = jest.fn((num: number) => num++); - - Manager.setNotificationOpenedCallback(mockCallback1); - Manager.setNotificationOpenedCallback(mockCallback2); - - expect(mockCallback1.mock.calls.length).toBe(0); - expect(mockCallback2.mock.calls.length).toBe(0); - - Manager.notificationOpenedDelegate(0); - - expect(mockCallback1.mock.calls.length).toBe(1); - expect(mockCallback2.mock.calls.length).toBe(1); - - expect(mockCallback1).toHaveBeenCalledWith(0); - expect(mockCallback2).toHaveBeenCalledWith(0); - }); - - it("if multiple Opened callback are registered, but one is removed, only one should be called", () => { - - let mockCallback1 = jest.fn((num: number) => num++); - let mockCallback2 = jest.fn((num: number) => num++); - - Manager.setNotificationOpenedCallback(mockCallback1); - Manager.setNotificationOpenedCallback(mockCallback2); - - expect(mockCallback1.mock.calls.length).toBe(0); - expect(mockCallback2.mock.calls.length).toBe(0); - - Manager.unregisterOpenedCallback(mockCallback1); - Manager.notificationOpenedDelegate(0); - - expect(mockCallback1.mock.calls.length).toBe(0); - expect(mockCallback2.mock.calls.length).toBe(1); - - expect(mockCallback2).toHaveBeenCalledWith(0); - }); }); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index f6cad069..5370a15c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,7 +6,7 @@ export default defineConfig({ build: { minify: false, outDir: 'outsystems/scripts/ODC', - target: 'es2020', + target: 'modules', lib: { entry: './src/outsystems/index.ts', name: 'OSOneSignal', From 5d9efc845b08e48bec51e7780e83d102d36eb8ce Mon Sep 17 00:00:00 2001 From: Marta Carlos Date: Thu, 20 Jun 2024 17:29:52 +0100 Subject: [PATCH 6/6] feat: add sonar cloud integration --- .github/workflows/run_unit_tests_workflow.yml | 32 +++++++++++++++++++ .gitignore | 1 + outsystems/scripts/ODC/manager.js | 12 +++---- sonar-project.properties | 22 +++++++++++++ src/outsystems/index.ts | 14 ++++---- 5 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/run_unit_tests_workflow.yml create mode 100644 sonar-project.properties diff --git a/.github/workflows/run_unit_tests_workflow.yml b/.github/workflows/run_unit_tests_workflow.yml new file mode 100644 index 00000000..a8242161 --- /dev/null +++ b/.github/workflows/run_unit_tests_workflow.yml @@ -0,0 +1,32 @@ +name: Run Unit Tests + +on: + workflow_dispatch: + push: + branches: [ main, development ] + pull_request: + branches: [ main, development ] + +jobs: + test: + name: Unit-Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install dependencies + run: npm install + + - name: Run tests (with coverage) + run: npm test -- --coverage --ci + + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@master + env: + SONAR_TOKEN: ${{ secrets. SONAR_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index d5f19d89..b07ff2ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules package-lock.json +coverage diff --git a/outsystems/scripts/ODC/manager.js b/outsystems/scripts/ODC/manager.js index ca8bd001..7a3662ea 100644 --- a/outsystems/scripts/ODC/manager.js +++ b/outsystems/scripts/ODC/manager.js @@ -2,8 +2,8 @@ typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.OSOneSignal = {})); })(this, function(exports2) { "use strict"; - var notificationReceivedCallback = []; - var notificationOpenedCallback = []; + let notificationReceivedCallback = []; + let notificationOpenedCallback = []; function notificationReceivedDelegate(jsonData) { notificationReceivedCallback.forEach(function(callback) { callback(jsonData); @@ -21,15 +21,15 @@ notificationOpenedCallback.push(callback); } function unregisterReceivedCallback(callback) { - var cbIndex = notificationReceivedCallback.indexOf(callback); + let cbIndex = notificationReceivedCallback.indexOf(callback); if (cbIndex >= 0) { - delete notificationReceivedCallback[cbIndex]; + notificationReceivedCallback.splice(cbIndex, 1); } } function unregisterOpenedCallback(callback) { - var cbIndex = notificationOpenedCallback.indexOf(callback); + let cbIndex = notificationOpenedCallback.indexOf(callback); if (cbIndex >= 0) { - delete notificationOpenedCallback[cbIndex]; + notificationOpenedCallback.splice(cbIndex, 1); } } exports2.notificationOpenedDelegate = notificationOpenedDelegate; diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 00000000..0ac4819d --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,22 @@ +# Organization and project keys are displayed in the right sidebar of the project homepage +sonar.organization=outsystemsrd +sonar.projectKey=OutSystems_OneSignal-Cordova-SDK +sonar.host.url=https://sonarcloud.io + +sonar.language=ts + +# Path is relative to the sonar-project.properties file. Defaults to . +sonar.sources=src/outsystems +sonar.tests=test + +# Defining path to coverage file +sonar.javascript.lcov.reportPaths=./coverage/lcov.info + +# Specify the TypeScript file suffixes +sonar.typescript.file.suffixes=.ts,.tsx + +# Define TS lint +sonar.typescript.tslint.reportPaths=tslint-report.json + +# Exclude directories +sonar.exclusions=**/node_modules/**,**/*.spec.ts, **/*.java diff --git a/src/outsystems/index.ts b/src/outsystems/index.ts index 08431da6..71b7ce8e 100644 --- a/src/outsystems/index.ts +++ b/src/outsystems/index.ts @@ -1,7 +1,7 @@ import { OneSignalCallback } from "./definitions"; -var notificationReceivedCallback: OneSignalCallback[] = []; -var notificationOpenedCallback: OneSignalCallback[] = []; +let notificationReceivedCallback: OneSignalCallback[] = []; +let notificationOpenedCallback: OneSignalCallback[] = []; /** * Public delegate for OneSignal's handleNotificationReceived @@ -39,10 +39,9 @@ export function setNotificationOpenedCallback(callback:OneSignalCallback) { * Unregister the old callback of OneSignal's Notification Received */ export function unregisterReceivedCallback(callback:OneSignalCallback) { - var cbIndex = notificationReceivedCallback.indexOf(callback); + let cbIndex = notificationReceivedCallback.indexOf(callback); if(cbIndex >= 0) { - //notificationReceivedCallback[cbIndex] = undefined; - delete notificationReceivedCallback[cbIndex]; + notificationReceivedCallback.splice(cbIndex, 1); } } @@ -50,10 +49,9 @@ export function unregisterReceivedCallback(callback:OneSignalCallback) { * Unregister the old callback of OneSignal's Notification Opened */ export function unregisterOpenedCallback(callback:OneSignalCallback) { - var cbIndex = notificationOpenedCallback.indexOf(callback); + let cbIndex = notificationOpenedCallback.indexOf(callback); if(cbIndex >= 0) { - //notificationOpenedCallback[cbIndex] = undefined; - delete notificationOpenedCallback[cbIndex]; + notificationOpenedCallback.splice(cbIndex, 1); } } \ No newline at end of file