diff --git a/package.json b/package.json index 8633df7..3e8a189 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "devDependencies": { "eslint": "^8.38.0", "jest": "^29.7.0", + "jest-environment-jsdom": "^30.0.0-beta.3", "nodemon": "^2.0.22", "supertest": "^6.3.3" }, diff --git a/public/js/vivid-market.js b/public/js/vivid-market.js index fc4980a..cc8696e 100644 --- a/public/js/vivid-market.js +++ b/public/js/vivid-market.js @@ -1,9 +1,15 @@ /** - * Placeholder function for initializing notifications. - * TODO: Implement actual notification initialization logic. + * Initialize the notification system by creating a toast container + * if it doesn't already exist. This container will hold all + * notification elements. */ function initializeNotifications() { - console.warn('initializeNotifications function called, but not implemented.'); + let container = document.querySelector('.notification-container'); + if (!container) { + container = document.createElement('div'); + container.className = 'notification-container'; + document.body.appendChild(container); + } } /** * Vivid Market JavaScript @@ -217,26 +223,31 @@ function initializeItemPreviews() { * @param {string} type - Notification type (success, error, info) */ function showNotification(message, type = 'info') { - // Create notification element if it doesn't exist - let notification = document.querySelector('.notification'); - if (!notification) { - notification = document.createElement('div'); - notification.className = 'notification'; - document.body.appendChild(notification); - } + // Ensure container exists + initializeNotifications(); - // Set notification content and type - notification.textContent = message; + const container = document.querySelector('.notification-container'); + + // Create individual toast element + const notification = document.createElement('div'); notification.className = `notification ${type}`; + notification.textContent = message; + + container.appendChild(notification); - // Show notification + // Trigger show animation setTimeout(() => { notification.classList.add('show'); }, 10); - // Hide notification after 3 seconds + // Hide and remove after 3 seconds setTimeout(() => { notification.classList.remove('show'); + notification.addEventListener( + 'transitionend', + () => notification.remove(), + { once: true } + ); }, 3000); } @@ -377,3 +388,12 @@ function initializePurchaseFlow() { function isUserLoggedIn() { return document.body.classList.contains('user-logged-in'); } + +// Export functions for testing in Node environments +if (typeof module !== 'undefined') { + module.exports = { + initializeNotifications, + showNotification, + isUserLoggedIn + }; +} diff --git a/tests/vivid-market-notifications.test.js b/tests/vivid-market-notifications.test.js new file mode 100644 index 0000000..eec88a3 --- /dev/null +++ b/tests/vivid-market-notifications.test.js @@ -0,0 +1,34 @@ +/** + * @jest-environment jsdom + */ +const { initializeNotifications, showNotification } = require('../public/js/vivid-market'); + +describe('Vivid Market Notifications', () => { + beforeEach(() => { + document.body.innerHTML = ''; + }); + + test('initializeNotifications creates a container', () => { + initializeNotifications(); + const container = document.querySelector('.notification-container'); + expect(container).not.toBeNull(); + }); + + test('showNotification appends a toast', () => { + jest.useFakeTimers(); + initializeNotifications(); + showNotification('Test', 'success'); + + const container = document.querySelector('.notification-container'); + expect(container.children.length).toBe(1); + + const toast = container.firstElementChild; + expect(toast.textContent).toBe('Test'); + expect(toast.classList.contains('success')).toBe(true); + + jest.advanceTimersByTime(20); + expect(toast.classList.contains('show')).toBe(true); + + jest.useRealTimers(); + }); +});