UNPKG

@shopware-ag/meteor-admin-sdk

Version:

The Meteor SDK for the Shopware Administration.

606 lines 34.2 kB
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../../ui/modal", "../../location", "../../context", "../../data", "jwt-decode", "./index"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const modal = __importStar(require("../../ui/modal")); const location = __importStar(require("../../location")); const context = __importStar(require("../../context")); const data = __importStar(require("../../data")); const jwt_decode_1 = require("jwt-decode"); /* Mock dependencies */ jest.mock('../../ui/modal'); jest.mock('../../location'); jest.mock('../../context'); jest.mock('../../data', () => ({ repository: jest.fn(), Classes: { Criteria: jest.fn().mockImplementation(function () { this.addFilter = jest.fn(); return this; }), }, })); jest.mock('jwt-decode', () => ({ jwtDecode: jest.fn(), })); /* Set up BroadcastChannel mock before importing the module */ const mockBroadcastChannelInstance = { addEventListener: jest.fn(), removeEventListener: jest.fn(), postMessage: jest.fn(), close: jest.fn(), }; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any global.BroadcastChannel = jest.fn().mockImplementation(() => { return mockBroadcastChannelInstance; }); const index_1 = require("./index"); describe('Private Service Payment', () => { let mockModalClose; let mockLocationStartAutoResizer; let mockGetAppInformation; let mockGetShopId; let eventListeners; let mockModalOpen; beforeEach(() => { mockModalOpen = jest.fn().mockResolvedValue(undefined); modal.open = mockModalOpen; /* Track event listeners for testing */ eventListeners = new Map(); const originalAddEventListener = window.addEventListener.bind(window); const originalRemoveEventListener = window.removeEventListener.bind(window); /* Mock window.addEventListener for testing */ jest.spyOn(window, 'addEventListener').mockImplementation((type, listener) => { if (!eventListeners.has(type)) { eventListeners.set(type, new Set()); } const listenerSet = eventListeners.get(type); if (listenerSet) { listenerSet.add(listener); } originalAddEventListener(type, listener); }); /* Mock window.removeEventListener for testing */ jest.spyOn(window, 'removeEventListener').mockImplementation((type, listener) => { var _a; (_a = eventListeners.get(type)) === null || _a === void 0 ? void 0 : _a.delete(listener); originalRemoveEventListener(type, listener); }); // Mock modal functions mockModalClose = jest.fn().mockResolvedValue(undefined); modal.close = mockModalClose; // Mock location functions mockLocationStartAutoResizer = jest.fn(); location.startAutoResizer = mockLocationStartAutoResizer; // Mock context functions mockGetAppInformation = jest.fn().mockResolvedValue({ name: 'test-app', version: '1.0.0', }); context.getAppInformation = mockGetAppInformation; // Mock context.getShopId mockGetShopId = jest.fn().mockResolvedValue('shop-id-123'); context.getShopId = mockGetShopId; // Clear all mocks jest.clearAllMocks(); mockBroadcastChannelInstance.addEventListener.mockClear(); mockBroadcastChannelInstance.removeEventListener.mockClear(); mockBroadcastChannelInstance.postMessage.mockClear(); mockBroadcastChannelInstance.close.mockClear(); }); afterEach(() => { // Clean up event listeners eventListeners.clear(); jest.restoreAllMocks(); }); describe('addPaymentIframe', () => { describe('iframe creation', () => { let container; const baseUrl = 'https://example.com'; const options = { shopUrl: 'https://shop.example.com', swVersion: '6.5.0', swUserLanguage: 'en-GB', shopPlan: 'beyond', }; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { if (container.parentNode) { document.body.removeChild(container); } }); it('should create an iframe with correct attributes and URL when no valid license', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); expect(mockGetAppInformation).toHaveBeenCalledTimes(1); expect(result.iframeEl).toBeInstanceOf(HTMLIFrameElement); expect(result.iframeEl.src).toBe('https://example.com/payment?service-name=test-app&service-version=1.0.0&shop-url=https://shop.example.com&sw-version=6.5.0&sw-user-language=en-GB&shop-plan=beyond&shop-id=shop-id-123'); expect(container.contains(result.iframeEl)).toBe(true); })); it('should create an iframe with shop-url and shop-plan from license when license is valid', () => __awaiter(void 0, void 0, void 0, function* () { const futureExp = Math.floor(Date.now() / 1000) + 3600; const mockSearch = jest.fn().mockResolvedValue({ first: () => ({ configurationValue: 'valid-jwt-token' }), }); data.repository.mockReturnValue({ search: mockSearch }); jwt_decode_1.jwtDecode.mockReturnValue({ aud: 'https://license-aud.shop.example.com', 'plan-name': 'premium', exp: futureExp, iat: 1000000000, iss: 'shopware', nbf: 1000000000, 'license-toggles': {}, 'plan-usage': 'commercial', 'plan-variant': 'default', swemp: 'example', }); const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); expect(result.iframeEl.src).toBe('https://example.com/payment?service-name=test-app&service-version=1.0.0&shop-url=https://license-aud.shop.example.com&sw-version=6.5.0&sw-user-language=en-GB&shop-plan=premium&shop-id=shop-id-123'); })); it('should default shop-id to an empty value when getShopId returns null', () => __awaiter(void 0, void 0, void 0, function* () { mockGetShopId.mockResolvedValue(null); const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); expect(mockGetShopId).toHaveBeenCalledTimes(1); expect(result.iframeEl.src.endsWith('&shop-id=')).toBe(true); })); it('should append iframe to the provided element', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); expect(container.contains(result.iframeEl)).toBe(true); expect(container.children.length).toBe(1); expect(container.children[0]).toBe(result.iframeEl); })); it('should add event listener for message events', () => __awaiter(void 0, void 0, void 0, function* () { var _a; yield (0, index_1.addPaymentIframe)(container, baseUrl, options); expect(window.addEventListener).toHaveBeenCalledWith('message', expect.any(Function)); expect((_a = eventListeners.get('message')) === null || _a === void 0 ? void 0 : _a.size).toBeGreaterThan(0); })); }); describe('event handling', () => { let container; const baseUrl = 'https://example.com'; const options = { shopUrl: 'https://shop.example.com', swVersion: '6.5.0', swUserLanguage: 'en-GB', }; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { if (container.parentNode) { document.body.removeChild(container); } }); it('should handle SYNC_HEIGHT event and update iframe height', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); expect(messageListeners === null || messageListeners === void 0 ? void 0 : messageListeners.size).toBeGreaterThan(0); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const mockEvent = new MessageEvent('message', { data: { type: index_1.MESSAGE_EVENT_TYPE.SYNC_HEIGHT, payload: 500, }, }); handleEvent(mockEvent); expect(result.iframeEl.style.height).toBe('500px'); expect(mockLocationStartAutoResizer).toHaveBeenCalledTimes(1); })); it('should handle PAYMENT_CLOSE event and close modal', () => __awaiter(void 0, void 0, void 0, function* () { yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const mockEvent = new MessageEvent('message', { data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_CLOSE, payload: null, }, }); handleEvent(mockEvent); expect(window.removeEventListener).toHaveBeenCalledWith('message', handleEvent); expect(mockModalClose).toHaveBeenCalledWith({ locationId: 'sw-service-payment-modal', }); })); it('should handle PAYMENT_SUCCESS event and post to BroadcastChannel', () => __awaiter(void 0, void 0, void 0, function* () { yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const eventData = { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, payload: { transactionId: '123' }, }; const mockEvent = new MessageEvent('message', { data: eventData, }); handleEvent(mockEvent); expect(mockBroadcastChannelInstance.postMessage).toHaveBeenCalledWith(eventData); })); it('should not handle unknown event types', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const mockEvent = new MessageEvent('message', { data: { type: 'unknown_event', payload: null, }, }); const initialHeight = result.iframeEl.style.height; handleEvent(mockEvent); expect(result.iframeEl.style.height).toBe(initialHeight); expect(mockModalClose).not.toHaveBeenCalled(); expect(mockBroadcastChannelInstance.postMessage).not.toHaveBeenCalled(); })); it('should handle PAYMENT_ERROR event (no special handling)', () => __awaiter(void 0, void 0, void 0, function* () { yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const mockEvent = new MessageEvent('message', { data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_ERROR, payload: { error: 'Payment failed' }, }, }); // Should not throw and should not call any special handlers expect(() => handleEvent(mockEvent)).not.toThrow(); expect(mockModalClose).not.toHaveBeenCalled(); expect(mockBroadcastChannelInstance.postMessage).not.toHaveBeenCalled(); })); it('should handle multiple SYNC_HEIGHT events and update height each time', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; const firstEvent = new MessageEvent('message', { data: { type: index_1.MESSAGE_EVENT_TYPE.SYNC_HEIGHT, payload: 300, }, }); const secondEvent = new MessageEvent('message', { data: { type: index_1.MESSAGE_EVENT_TYPE.SYNC_HEIGHT, payload: 600, }, }); handleEvent(firstEvent); expect(result.iframeEl.style.height).toBe('300px'); handleEvent(secondEvent); expect(result.iframeEl.style.height).toBe('600px'); })); }); describe('unmount function', () => { let container; const baseUrl = 'https://example.com'; const options = { shopUrl: 'https://shop.example.com', swVersion: '6.5.0', swUserLanguage: 'en-GB', }; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { if (container.parentNode) { document.body.removeChild(container); } }); it('should provide unmount function that cleans up', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const messageListeners = eventListeners.get('message'); const messageListenersArray = messageListeners ? Array.from(messageListeners) : []; const handleEvent = messageListenersArray[0]; result.unmount(); expect(window.removeEventListener).toHaveBeenCalledWith('message', handleEvent); expect(mockBroadcastChannelInstance.close).toHaveBeenCalledTimes(1); })); it('should remove event listener when unmount is called', () => __awaiter(void 0, void 0, void 0, function* () { var _a, _b; const result = yield (0, index_1.addPaymentIframe)(container, baseUrl, options); const initialListenerCount = ((_a = eventListeners.get('message')) === null || _a === void 0 ? void 0 : _a.size) || 0; result.unmount(); expect((_b = eventListeners.get('message')) === null || _b === void 0 ? void 0 : _b.size).toBeLessThan(initialListenerCount); })); }); }); describe('startPaymentFlow', () => { it('should open modal with correct options and return flow', () => __awaiter(void 0, void 0, void 0, function* () { const flow = yield (0, index_1.startPaymentFlow)(); expect(mockModalOpen).toHaveBeenCalledWith({ locationId: 'sw-service-payment-modal', variant: 'small', showHeader: false, showFooter: false, closable: false, }); expect(flow).toBeDefined(); expect(flow.subscribe).toBeInstanceOf(Function); })); it('should return a flow with subscribe method', () => __awaiter(void 0, void 0, void 0, function* () { const flow = yield (0, index_1.startPaymentFlow)(); expect(typeof flow.subscribe).toBe('function'); })); describe('Flow subscribe', () => { let flow; let mockModalOpen; beforeEach(() => __awaiter(void 0, void 0, void 0, function* () { mockModalOpen = jest.fn().mockResolvedValue(undefined); modal.open = mockModalOpen; flow = yield (0, index_1.startPaymentFlow)(); })); it('should subscribe to events and call callback when event matches', () => { const callback = jest.fn(); const { unsubscribe } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback); expect(mockBroadcastChannelInstance.addEventListener).toHaveBeenCalledWith('message', expect.any(Function)); // Simulate message event const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[0] || !mockCalls[0][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler = mockCalls[0][1]; const mockEvent = { data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, payload: null, }, }; eventHandler(mockEvent); expect(callback).toHaveBeenCalledTimes(1); unsubscribe(); }); it('should not call callback when event type does not match', () => { const callback = jest.fn(); const { unsubscribe } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback); const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[0] || !mockCalls[0][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler = mockCalls[0][1]; const mockEvent = { data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_ERROR, payload: null, }, }; eventHandler(mockEvent); expect(callback).not.toHaveBeenCalled(); unsubscribe(); }); it('should unsubscribe from events correctly', () => { const callback = jest.fn(); const { unsubscribe } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback); const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[0] || !mockCalls[0][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler = mockCalls[0][1]; unsubscribe(); expect(mockBroadcastChannelInstance.removeEventListener).toHaveBeenCalledWith('message', eventHandler); }); it('should handle multiple subscriptions independently', () => { const callback1 = jest.fn(); const callback2 = jest.fn(); const { unsubscribe: unsubscribe1 } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback1); const { unsubscribe: unsubscribe2 } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_ERROR, callback2); expect(mockBroadcastChannelInstance.addEventListener).toHaveBeenCalledTimes(2); // Trigger first subscription const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[0] || !mockCalls[0][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler1 = mockCalls[0][1]; eventHandler1({ data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, payload: null, }, }); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).not.toHaveBeenCalled(); // Trigger second subscription // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[1] || !mockCalls[1][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler2 = mockCalls[1][1]; eventHandler2({ data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_ERROR, payload: null, }, }); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(1); unsubscribe1(); unsubscribe2(); }); it('should handle all event types correctly', () => { const eventTypes = [ index_1.MESSAGE_EVENT_TYPE.PAYMENT_CLOSE, index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, index_1.MESSAGE_EVENT_TYPE.PAYMENT_ERROR, index_1.MESSAGE_EVENT_TYPE.SYNC_HEIGHT, ]; eventTypes.forEach((eventType) => { const callback = jest.fn(); const { unsubscribe } = flow.subscribe(eventType, callback); const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; const lastCallIndex = mockCalls.length - 1; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[lastCallIndex] || !mockCalls[lastCallIndex][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler = mockCalls[lastCallIndex][1]; eventHandler({ data: { type: eventType, payload: null, }, }); expect(callback).toHaveBeenCalledTimes(1); unsubscribe(); }); }); it('should allow multiple subscriptions to the same event type', () => { const callback1 = jest.fn(); const callback2 = jest.fn(); const { unsubscribe: unsubscribe1 } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback1); const { unsubscribe: unsubscribe2 } = flow.subscribe(index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, callback2); const mockCalls = mockBroadcastChannelInstance.addEventListener.mock.calls; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[0] || !mockCalls[0][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler1 = mockCalls[0][1]; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (!mockCalls[1] || !mockCalls[1][1]) { throw new Error('Event handler not found'); } // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const eventHandler2 = mockCalls[1][1]; const mockEvent = { data: { type: index_1.MESSAGE_EVENT_TYPE.PAYMENT_SUCCESS, payload: null, }, }; eventHandler1(mockEvent); eventHandler2(mockEvent); expect(callback1).toHaveBeenCalledTimes(1); expect(callback2).toHaveBeenCalledTimes(1); unsubscribe1(); unsubscribe2(); }); }); }); describe('decodeLicense', () => { const mockTokenPayload = { 'license-toggles': { 'feature-a': true }, 'plan-name': 'beyond', 'plan-usage': 'commercial', 'plan-variant': 'default', aud: 'https://shop.example.com', exp: 9999999999, iat: 1000000000, iss: 'shopware', nbf: 1000000000, swemp: 'example', }; beforeEach(() => { const mockSearch = jest.fn().mockResolvedValue({ first: () => ({ configurationValue: 'valid-jwt-token' }), }); const mockRepository = { search: mockSearch }; data.repository.mockReturnValue(mockRepository); jwt_decode_1.jwtDecode.mockReturnValue(mockTokenPayload); }); it('should return decoded token when system config has license key and token is valid', () => __awaiter(void 0, void 0, void 0, function* () { const result = yield (0, index_1.decodeLicense)(); expect(data.repository).toHaveBeenCalledWith('system_config'); expect(result).toEqual(mockTokenPayload); expect(jwt_decode_1.jwtDecode).toHaveBeenCalledWith('valid-jwt-token'); })); it('should return null when no license key in system config (empty token)', () => __awaiter(void 0, void 0, void 0, function* () { const mockSearch = jest.fn().mockResolvedValue({ first: () => ({ configurationValue: '' }), }); data.repository.mockReturnValue({ search: mockSearch }); jwt_decode_1.jwtDecode.mockImplementation(() => { throw new Error('Invalid token'); }); const result = yield (0, index_1.decodeLicense)(); expect(jwt_decode_1.jwtDecode).toHaveBeenCalledWith(''); expect(result).toBeNull(); })); it('should return null when repository search throws', () => __awaiter(void 0, void 0, void 0, function* () { const mockSearch = jest.fn().mockRejectedValue(new Error('Network error')); data.repository.mockReturnValue({ search: mockSearch }); const result = yield (0, index_1.decodeLicense)(); expect(result).toBeNull(); expect(jwt_decode_1.jwtDecode).not.toHaveBeenCalled(); })); it('should return null when res.first() returns undefined (no config found)', () => __awaiter(void 0, void 0, void 0, function* () { const mockSearch = jest.fn().mockResolvedValue({ first: () => undefined, }); data.repository.mockReturnValue({ search: mockSearch }); jwt_decode_1.jwtDecode.mockImplementation(() => { throw new Error('Invalid token'); }); const result = yield (0, index_1.decodeLicense)(); expect(jwt_decode_1.jwtDecode).toHaveBeenCalledWith(''); expect(result).toBeNull(); })); it('should return null when jwtDecode throws (invalid token)', () => __awaiter(void 0, void 0, void 0, function* () { jwt_decode_1.jwtDecode.mockImplementation(() => { throw new Error('Invalid token'); }); const result = yield (0, index_1.decodeLicense)(); expect(result).toBeNull(); })); }); }); }); //# sourceMappingURL=index.spec.js.map