diff --git a/tests/constructor.test.js b/tests/constructor.test.js index b7ed365d..4b295050 100644 --- a/tests/constructor.test.js +++ b/tests/constructor.test.js @@ -1,78 +1,85 @@ const VideoModal = require('../scripts/videopage'); -// Globally mock fetch -global.fetch = jest.fn(); +global.fetch = jest.fn(() => Promise.resolve({ + ok: true, + json: () => Promise.resolve({ liked: true, likes: 10 }) +})); describe('VideoModal', () => { beforeEach(() => { - // Reset fetch mocks before each test - fetch.mockReset(); - - // Mock DOM elements + // Reset all mocks between tests + fetch.mockClear(); + document.getElementById.mockClear(); + document.getElementsByClassName.mockClear(); + document.querySelectorAll.mockClear(); + + // Set up mocks for document methods used in VideoModal document.getElementById = jest.fn().mockImplementation(id => { - if (id === 'modal') { - return { style: {} }; // Mock modal element - } - if (id === 'videoFrame') { - return { src: '' }; // Mock videoFrame element - } + if (id === 'modal') return { style: { display: 'none' } }; + if (id === 'videoFrame') return { src: '' }; + return null; }); document.getElementsByClassName = jest.fn().mockReturnValue([{ - onclick: jest.fn() - }]); // Mock for className 'close' - - document.querySelectorAll = jest.fn().mockReturnValue([{ - getAttribute: jest.fn(name => { - if (name === 'data-video-id') { - return '123'; - } - return null; - }), + addEventListener: jest.fn() + }]); + + document.querySelectorAll = jest.fn().mockReturnValue([...new Array(5)].map(() => ({ + getAttribute: jest.fn().mockReturnValue('123'), addEventListener: jest.fn(), querySelector: jest.fn().mockReturnValue({ textContent: '', - classList: { toggle: jest.fn() }, + classList: { + toggle: jest.fn() + }, innerHTML: '' }) - }]); // Mock for selector '.video-card' + }))); }); - it('initializes class properties correctly', () => { + it('initializes and binds UI elements correctly', () => { const videoModal = new VideoModal('modal', 'videoFrame', 'close', '.video-card'); + // Check proper instantiation and method calls expect(document.getElementById).toHaveBeenCalledWith('modal'); expect(document.getElementById).toHaveBeenCalledWith('videoFrame'); expect(document.getElementsByClassName).toHaveBeenCalledWith('close'); expect(document.querySelectorAll).toHaveBeenCalledWith('.video-card'); - expect(videoModal.modal).toBeTruthy(); - expect(videoModal.videoFrame).toBeTruthy(); - expect(videoModal.closeButton).toBeTruthy(); - expect(videoModal.videoCards.length).toBe(1); - }); - it('calls fetch and updates like state for video cards', async () => { - fetch.mockResolvedValue({ - ok: true, - json: () => Promise.resolve({ - liked: true, - likes: 10 - }) - }); + // Assert that properties are set up correctly + expect(videoModal.modal).toBeDefined(); + expect(videoModal.videoFrame).toBeDefined(); + expect(videoModal.closeButton).toBeDefined(); + expect(videoModal.videoCards.length).toBe(5); + }); + it('updates like states correctly when initializing', async () => { const videoModal = new VideoModal('modal', 'videoFrame', 'close', '.video-card'); - await videoModal.updateAllLikeStates(); - // Assertions to check the fetch mechanism and results - expect(fetch).toHaveBeenCalledTimes(1); - expect(fetch).toHaveBeenCalledWith('/api/likes?videoId=123'); + // The updateAllLikeStates method should be called during initialization + await videoModal.init(); + + // Since there are 5 cards, ensure fetch was called 5 times + expect(fetch).toHaveBeenCalledTimes(5); + expect(fetch.mock.calls[0][0]).toBe('/api/likes?videoId=123'); + + const card = document.querySelectorAll().mock.results[0].value[0]; + expect(card.querySelector.mock.calls.length).toBe(2); // Called twice per card: once for button, once for count + expect(card.querySelector().classList.toggle).toHaveBeenCalledWith('liked', true); + expect(card.querySelector().textContent).toBe('10 Likes'); + }); + + it('handles modal opening and closing correctly', () => { + const videoModal = new VideoModal('modal', 'videoFrame', 'close', '.video-card'); + videoModal.openModal('https://youtube.com/watch?v=dQw4w9WgXcQ'); - const card = document.querySelectorAll.mock.results[0].value[0]; - const likeCountElement = card.querySelector.mock.results[1].value; - const likeButton = card.querySelector.mock.results[0].value; + // Verify that the modal display style changes to block + expect(videoModal.modal.style.display).toBe('block'); + expect(videoModal.videoFrame.src).toContain('https://youtube.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0'); - expect(likeCountElement.textContent).toBe('10 Likes'); - expect(likeButton.classList.toggle).toHaveBeenCalledWith('liked', true); - expect(likeButton.innerHTML).toContain('Liked'); + // Simulate closing the modal + videoModal.closeModal(); + expect(videoModal.modal.style.display).toBe('none'); + expect(videoModal.videoFrame.src).toBe(''); }); }); \ No newline at end of file diff --git a/tests/openModal.test.js b/tests/openModal.test.js index 9b96532f..f8a34d84 100644 --- a/tests/openModal.test.js +++ b/tests/openModal.test.js @@ -1,6 +1,6 @@ const VideoModal = require('../scripts/videopage'); -// Mocking fetch globally +// Mock fetch global.fetch = jest.fn(() => Promise.resolve({ ok: true, @@ -8,36 +8,40 @@ global.fetch = jest.fn(() => }) ); -describe('VideoModal - openModal', () => { - let mockModal, mockVideoFrame; - +describe('VideoModal', () => { + let mockModal, mockVideoFrame, mockCards; + beforeEach(() => { - // Reset mocks before each test fetch.mockClear(); - // Mock modal and videoFrame elements mockModal = { style: { display: 'none' } }; mockVideoFrame = { src: '' }; - - document.getElementById = jest.fn().mockImplementation((id) => { - if (id === 'modal') return mockModal; - if (id === 'videoFrame') return mockVideoFrame; - return null; - }); + mockCards = [{ + getAttribute: jest.fn().mockReturnValue('123'), + querySelector: jest.fn().mockReturnValue({ + textContent: '', + classList: { + toggle: jest.fn() + }, + innerHTML: '' + }) + }]; + + document.getElementById = jest.fn((id) => ({ + 'modal': mockModal, + 'videoFrame': mockVideoFrame + })[id]); document.getElementsByClassName = jest.fn().mockReturnValue([{ onclick: null }]); - document.querySelectorAll = jest.fn().mockReturnValue([{ - addEventListener: jest.fn(), - getAttribute: jest.fn().mockReturnValue('https://www.example.com/watch?v=example') - }]); + document.querySelectorAll = jest.fn().mockReturnValue(mockCards); }); - it('sets videoFrame src and displays modal', () => { + it('updates all like states when initialized', async () => { const videoModal = new VideoModal('modal', 'videoFrame', 'close', '.video-card'); - const testUrl = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'; - videoModal.openModal(testUrl); + await videoModal.updateAllLikeStates(); - expect(mockVideoFrame.src).toContain('https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0'); - expect(mockModal.style.display).toBe('block'); + expect(fetch).toHaveBeenCalledTimes(mockCards.length); + expect(mockCards[0].querySelector).toHaveBeenCalledWith('.like-btn'); + expect(mockCards[0].querySelector).toHaveBeenCalledWith('.like-count'); }); }); \ No newline at end of file diff --git a/tests/transformVideoUrl.test.js b/tests/transformVideoUrl.test.js index 1fe12547..67a47528 100644 --- a/tests/transformVideoUrl.test.js +++ b/tests/transformVideoUrl.test.js @@ -1,16 +1,40 @@ const VideoModal = require('../scripts/videopage'); +global.fetch = jest.fn(() => + Promise.resolve({ + ok: true, + json: () => Promise.resolve({ likes: 10, liked: true }) + }) +); + describe('VideoModal - transformVideoUrl', () => { + beforeEach(() => { + // Clear all mocks before each test + jest.clearAllMocks(); + }); + it('transforms YouTube watch URL to embed URL correctly', () => { - // Mocking the DOM elements to provide necessary mock values - document.getElementById = jest.fn(() => document.createElement('div')); - document.getElementsByClassName = jest.fn(() => [document.createElement('button')]); - document.querySelectorAll = jest.fn(() => [document.createElement('div')]); + // Mocking the necessary DOM elements + document.getElementById = jest.fn(id => { + if (id === 'dummyModalId') return document.createElement('div'); + if (id === 'dummyVideoFrameId') return document.createElement('iframe'); + return null; + }); + document.getElementsByClassName = jest.fn((className) => { + if (className === 'dummyCloseButtonClass') return [document.createElement('button')]; + return []; + }); + document.querySelectorAll = jest.fn((selector) => { + if (selector === 'dummyVideoCardClass') return [document.createElement('div')]; + return []; + }); const videoModal = new VideoModal('dummyModalId', 'dummyVideoFrameId', 'dummyCloseButtonClass', 'dummyVideoCardClass'); const inputUrl = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'; const expectedUrl = 'https://www.youtube.com/embed/dQw4w9WgXcQ'; expect(videoModal.transformVideoUrl(inputUrl)).toBe(expectedUrl); + + expect(fetch).not.toHaveBeenCalled(); }); }); \ No newline at end of file