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 3c3629e6..b07ff2ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +package-lock.json +coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ea80eb6..c59f954a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ 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). +## [2.11.1-OS12] +### Features + +- Android | Update dependency to FCM Android library (https://outsystemsrd.atlassian.net/browse/RMET-3608). + ## [2.11.1-OS11] ### Fixes diff --git a/build-extras-onesignal.gradle b/build-extras-onesignal.gradle index 53b70371..f8486773 100644 --- a/build-extras-onesignal.gradle +++ b/build-extras-onesignal.gradle @@ -64,6 +64,7 @@ dependencies { implementation 'com.google.android.gms:play-services-basement:18.2.0' implementation 'com.google.android.gms:play-services-tasks:18.0.2' implementation 'com.google.android.gms:play-services-stats:17.0.3' - api 'com.google.firebase:firebase-messaging:20.2.1' + api 'com.google.firebase:firebase-messaging:24.0.1' + api 'com.google.firebase:firebase-iid:21.1.0' implementation 'androidx.cardview:cardview:1.0.0' } 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/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/ODC/initOneSignal.js b/outsystems/nodes/ODC/initOneSignal.js new file mode 100644 index 00000000..facec5d6 --- /dev/null +++ b/outsystems/nodes/ODC/initOneSignal.js @@ -0,0 +1,13 @@ +var builder = window.plugins.OneSignal.startInit($parameters.ApiKey); +builder.handleNotificationReceived(OSOneSignal.notificationReceivedDelegate); +builder.handleNotificationOpened(OSOneSignal.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/nodes/ODC/registerDispatcher.js b/outsystems/nodes/ODC/registerDispatcher.js new file mode 100644 index 00000000..a419a0d0 --- /dev/null +++ b/outsystems/nodes/ODC/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.setNotificationReceivedCallback(scope.handleNotificationReceived); + OSOneSignal.setNotificationOpenedCallback(scope.handleNotificationOpened); + +} + +var onDestroy = function(scope) { + console.log("onDestroy scope"); + 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/nodes/ODC/unregisterPlugin.js b/outsystems/nodes/ODC/unregisterPlugin.js new file mode 100644 index 00000000..74505f26 --- /dev/null +++ b/outsystems/nodes/ODC/unregisterPlugin.js @@ -0,0 +1 @@ +OSCommonPlugin.PluginManager.destroyScope(`OneSignalPlugin_${$parameters.Token}`); \ No newline at end of file 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/ODC/definitions.d.ts b/outsystems/scripts/ODC/definitions.d.ts new file mode 100644 index 00000000..712c66c5 --- /dev/null +++ b/outsystems/scripts/ODC/definitions.d.ts @@ -0,0 +1 @@ +export type OneSignalCallback = (...args: any[]) => void; diff --git a/outsystems/scripts/ODC/index.d.ts b/outsystems/scripts/ODC/index.d.ts new file mode 100644 index 00000000..c9c47d99 --- /dev/null +++ b/outsystems/scripts/ODC/index.d.ts @@ -0,0 +1,26 @@ +import { OneSignalCallback } from './definitions'; + +/** + * 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 new file mode 100644 index 00000000..7a3662ea --- /dev/null +++ b/outsystems/scripts/ODC/manager.js @@ -0,0 +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"; + let notificationReceivedCallback = []; + let 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) { + let cbIndex = notificationReceivedCallback.indexOf(callback); + if (cbIndex >= 0) { + notificationReceivedCallback.splice(cbIndex, 1); + } + } + function unregisterOpenedCallback(callback) { + let cbIndex = notificationOpenedCallback.indexOf(callback); + if (cbIndex >= 0) { + notificationOpenedCallback.splice(cbIndex, 1); + } + } + 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/outsystems/scripts/OneSignal_Events.js b/outsystems/scripts/OneSignal_Events.js new file mode 100644 index 00000000..cfb9a7e2 --- /dev/null +++ b/outsystems/scripts/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 516de784..6fe1bf52 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "2.11.1-OS11", + "version": "2.11.1-OS12", "name": "onesignal-cordova-plugin", "cordova_name": "OneSignal Push Notifications", "description": "OneSignal is a high volume Push Notification service for mobile apps. In addition to basic notification delivery, OneSignal also provides tools to localize, target, schedule, and automate notifications that you send.", @@ -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": "vite build", + "test": "jest --coverage --ci" + }, + "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/plugin.xml b/plugin.xml index 11ca955b..d8db9b92 100644 --- a/plugin.xml +++ b/plugin.xml @@ -2,7 +2,7 @@ + version="2.11.1-OS12"> OneSignal Push Notifications Josh Kasten, Bradley Hesse, Rodrigo Gomez-Palacio 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/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..71b7ce8e --- /dev/null +++ b/src/outsystems/index.ts @@ -0,0 +1,57 @@ +import { OneSignalCallback } from "./definitions"; + +let notificationReceivedCallback: OneSignalCallback[] = []; +let 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 + */ +export function notificationOpenedDelegate(jsonData: any) { + notificationOpenedCallback.forEach(function(callback:OneSignalCallback){ + callback(jsonData); + }); +} + +/** + * 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. + */ +export function setNotificationOpenedCallback(callback:OneSignalCallback) { + notificationOpenedCallback.push(callback); +} + +/** + * Unregister the old callback of OneSignal's Notification Received + */ +export function unregisterReceivedCallback(callback:OneSignalCallback) { + let cbIndex = notificationReceivedCallback.indexOf(callback); + if(cbIndex >= 0) { + notificationReceivedCallback.splice(cbIndex, 1); + } +} + +/** + * Unregister the old callback of OneSignal's Notification Opened + */ +export function unregisterOpenedCallback(callback:OneSignalCallback) { + let cbIndex = notificationOpenedCallback.indexOf(callback); + if(cbIndex >= 0) { + notificationOpenedCallback.splice(cbIndex, 1); + } + +} \ No newline at end of file diff --git a/test/onesignalmanager.spec.ts b/test/onesignalmanager.spec.ts new file mode 100644 index 00000000..c16e04b9 --- /dev/null +++ b/test/onesignalmanager.spec.ts @@ -0,0 +1,144 @@ + +import * as 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); + }); + +}); \ 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..5370a15c --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'vite'; +import dts from 'vite-plugin-dts'; + +export default defineConfig({ + plugins: [dts()], + build: { + minify: false, + outDir: 'outsystems/scripts/ODC', + target: 'modules', + lib: { + entry: './src/outsystems/index.ts', + name: 'OSOneSignal', + fileName: (format) => `manager.${format === 'es' ? 'mjs' : format === 'cjs' ? 'cjs' : 'js'}`, + formats: ['umd'], + } + }, +}); \ No newline at end of file