From d66ea9580c85d68e1d16f53802cf6562d88f6104 Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Fri, 24 Dec 2021 01:09:13 +0000 Subject: [PATCH 1/5] Add off method and refactor on --- src/api/messaging.js | 2 +- src/api/webpage/eventRegistring.js | 43 ++++++++++++++++++++++++++++++ src/api/webpage/index.js | 32 ++-------------------- src/pages/Content/injected.js | 1 - 4 files changed, 46 insertions(+), 32 deletions(-) create mode 100644 src/api/webpage/eventRegistring.js diff --git a/src/api/messaging.js b/src/api/messaging.js index f8d6e8b4..51f96b44 100644 --- a/src/api/messaging.js +++ b/src/api/messaging.js @@ -171,7 +171,7 @@ export const Messaging = { // protect background by not allowing not whitelisted if (!whitelisted || whitelisted.error) return; - const event = new CustomEvent(TARGET + response.event, { + const event = new CustomEvent(`${TARGET}${response.event}`, { detail: response.data, }); diff --git a/src/api/webpage/eventRegistring.js b/src/api/webpage/eventRegistring.js new file mode 100644 index 00000000..45038904 --- /dev/null +++ b/src/api/webpage/eventRegistring.js @@ -0,0 +1,43 @@ +import { TARGET } from '../../config/config'; + +/** + * @param {string} eventName + * @param {Function} callback + */ +export const on = (eventName, callback) => { + const handler = (event) => callback(event.detail); + + const events = window.cardano._events[eventName] || []; + + window.cardano._events[eventName] = [ + ...events, + [ callback, handler ], + ]; + + window.addEventListener(`${TARGET}${eventName}`, handler); +}; + +/** + * @param {string} eventName + * @param {Function} callback + */ +export const off = (eventName, callback) => { + const filterHandlersBy = (predicate) => (handlers) => handlers.filter( + ([ savedCallback ]) => predicate(savedCallback) + ); + + const filterByMatchingHandlers = filterHandlersBy((cb) => cb === callback); + const filterByNonMatchingHandlers = filterHandlersBy((cb) => cb !== callback); + + const eventHandlers = window.cardano._events[eventName]; + + if (typeof eventHandlers !== 'undefined') { + const matchingHandlers = filterByMatchingHandlers(eventHandlers); + + for (const [, handler] of matchingHandlers) { + window.removeEventListener(`${TARGET}${eventName}`, handler); + } + + window.cardano._events[eventName] = filterByNonMatchingHandlers(eventHandlers); + } +}; diff --git a/src/api/webpage/index.js b/src/api/webpage/index.js index 49c08390..29ff1940 100644 --- a/src/api/webpage/index.js +++ b/src/api/webpage/index.js @@ -1,4 +1,4 @@ -import { EVENT, METHOD, SENDER, TARGET } from '../../config/config'; +import { METHOD } from '../../config/config'; import { Messaging } from '../messaging'; export const getBalance = async () => { @@ -76,32 +76,4 @@ export const submitTx = async (tx) => { return result.data; }; -export const on = (eventName, callback) => { - const fn = (e) => callback(e.detail); - Object.defineProperty(fn, 'name', { value: callback.name }); - window.cardano._events[eventName] = [ - ...(window.cardano._events[eventName] || []), - fn, - ]; - window.addEventListener( - TARGET + eventName, - window.cardano._events[eventName][ - window.cardano._events[eventName].length - 1 - ] - ); -}; - -export const removeListener = (eventName, callback) => { - const fn = window.cardano._events[eventName].find( - (f) => f.name == callback.name - ); - if (!fn) return; - const index = window.cardano._events[eventName].indexOf(fn); - window.removeEventListener( - TARGET + eventName, - window.cardano._events[eventName][index] - ); - window.cardano._events[eventName].splice(index, 1); - if (window.cardano._events[eventName].length <= 0) - delete window.cardano._events[eventName]; -}; +export { on, off } from './eventRegistring'; diff --git a/src/pages/Content/injected.js b/src/pages/Content/injected.js index ba7caffb..d887b1a2 100644 --- a/src/pages/Content/injected.js +++ b/src/pages/Content/injected.js @@ -8,7 +8,6 @@ import { getUtxos, isEnabled, on, - removeListener, signData, signTx, submitTx, From 490bb0a658c2239a6f4192ff7dcd3a743fce2364 Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Fri, 24 Dec 2021 01:09:32 +0000 Subject: [PATCH 2/5] Add tests for on/off methods --- jest.config.js | 1 + .../unit/api/webpage/eventRegistring.test.js | 92 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/test/unit/api/webpage/eventRegistring.test.js diff --git a/jest.config.js b/jest.config.js index 7726b093..921a64c0 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,4 +14,5 @@ module.exports = { }, transformIgnorePatterns: [`/node_modules/(?!crypto-random-string)`], setupFilesAfterEnv: ['./jest.setup.js'], + testEnvironment: 'jsdom' }; diff --git a/src/test/unit/api/webpage/eventRegistring.test.js b/src/test/unit/api/webpage/eventRegistring.test.js new file mode 100644 index 00000000..784abfe3 --- /dev/null +++ b/src/test/unit/api/webpage/eventRegistring.test.js @@ -0,0 +1,92 @@ +import { on, off } from '../../../../api/webpage/eventRegistring'; +import { TARGET } from '../../../../config/config'; + +describe('webpage/eventRegistring', () => { + const makeEvent = (eventType, detail) => (new CustomEvent(`${TARGET}${eventType}`, { detail })); + + describe('on', () => { + + beforeEach(() => { + window.cardano = { + _events: {}, + }; + }); + + test('invokes the callback when a the target event is triggered', () => { + const eventType = 'mock-event'; + const mockPayload = 'mock-payload'; + const event = makeEvent(eventType, mockPayload); + const mockFn = jest.fn(); + + on(eventType, mockFn); + + window.dispatchEvent(event); + + expect(mockFn).toHaveBeenCalledTimes(1); + expect(mockFn).toHaveBeenCalledWith(mockPayload); + }); + + test('does not invoke the callback when a different event is triggered', () => { + const mockFn = jest.fn(); + + on('event-A', mockFn); + + const mockPayload = 'mock-payload'; + const event = makeEvent('event-B', mockPayload); + + window.dispatchEvent(event); + + expect(mockFn).not.toHaveBeenCalled(); + }); + }); + + describe('of', () => { + const mockEventType = 'mock-event'; + const mockCallback = jest.fn(); + const mockHandler = jest.fn().mockImplementation(() => mockCallback()); + + beforeEach(() => { + jest.resetAllMocks(); + + window.cardano = { + _events: { + [mockEventType]: [[mockCallback, mockHandler]] + }, + }; + }); + + test('clean out matching callbacks fom the given event', () => { + off(mockEventType, mockCallback); + + expect(window.cardano._events).toEqual({ + [mockEventType]: [] + }) + }); + + test('stops the given callback from being invoked when cleaned out', () => { + off(mockEventType, mockCallback); + + console.log(window.cardano._events); + + const event = makeEvent(mockEventType); + + window.dispatchEvent(event); + + expect(mockCallback).not.toHaveBeenCalled() + }); + + test('does not stop other callbacks from being invoked after cleaned one out', () => { + const mockFn = jest.fn(); + + on('event-A', mockFn); + + off('mockEventType', mockCallback); + + const event = makeEvent('event-A'); + + window.dispatchEvent(event); + + expect(mockFn).toHaveBeenCalledTimes(1) + }); + }); +}); From 1695056d7f886eb3ca70969551b61e10e040065b Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Fri, 24 Dec 2021 01:10:02 +0000 Subject: [PATCH 3/5] Fix issue with 'react-icons/go' import --- src/ui/app/components/transactionBuilder.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/app/components/transactionBuilder.jsx b/src/ui/app/components/transactionBuilder.jsx index e25cb331..55357aac 100644 --- a/src/ui/app/components/transactionBuilder.jsx +++ b/src/ui/app/components/transactionBuilder.jsx @@ -26,7 +26,7 @@ import { UnorderedList, ListItem, } from '@chakra-ui/react'; -import { GoStop } from 'react-icons/Go'; +import { GoStop } from 'react-icons/go'; // Assets import Berry from '../../../assets/img/berry.svg'; import { ERROR } from '../../../config/config'; From 7adb56eaaf5516fa20a6c81ae89059ddb50da8ba Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Fri, 24 Dec 2021 01:10:44 +0000 Subject: [PATCH 4/5] Remove console.log --- src/test/unit/api/webpage/eventRegistring.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/unit/api/webpage/eventRegistring.test.js b/src/test/unit/api/webpage/eventRegistring.test.js index 784abfe3..1317a6e7 100644 --- a/src/test/unit/api/webpage/eventRegistring.test.js +++ b/src/test/unit/api/webpage/eventRegistring.test.js @@ -66,8 +66,6 @@ describe('webpage/eventRegistring', () => { test('stops the given callback from being invoked when cleaned out', () => { off(mockEventType, mockCallback); - console.log(window.cardano._events); - const event = makeEvent(mockEventType); window.dispatchEvent(event); From ac470b8c67a19e6697673300fe898baf15d3bf9d Mon Sep 17 00:00:00 2001 From: Luis Silva Date: Fri, 24 Dec 2021 01:33:05 +0000 Subject: [PATCH 5/5] add remove method --- src/api/webpage/eventRegistring.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/api/webpage/eventRegistring.js b/src/api/webpage/eventRegistring.js index 45038904..35c912cf 100644 --- a/src/api/webpage/eventRegistring.js +++ b/src/api/webpage/eventRegistring.js @@ -15,6 +15,8 @@ export const on = (eventName, callback) => { ]; window.addEventListener(`${TARGET}${eventName}`, handler); + + return { remove: () => off(eventName, callback) }; }; /**