diff --git a/_tmp_7378_5a296355cc1318b52ad43dc997b91dbd b/_tmp_7378_5a296355cc1318b52ad43dc997b91dbd new file mode 100644 index 0000000..e69de29 diff --git a/e2e/localstorage.spec.js b/e2e/localstorage.spec.js index 1bf222c..ffb2651 100644 --- a/e2e/localstorage.spec.js +++ b/e2e/localstorage.spec.js @@ -1,22 +1,167 @@ -import { test, expect } from '@playwright/test'; - -test('Simulate localStorage entry in PWA', async ({ page }) => { - await page.evaluate(() => { - localStorage.setItem('audioCache', JSON.stringify({ - 'https://example.com/audio': { - audioUrl: 'https://example.com/audio.mp3', - transcription: 'Test transcription', - lastPosition: 0 +import { test, expect, describe } from '@playwright/test'; + +test.describe('LocalStorage Tests', () => { + test('Simulate localStorage entry in PWA', async ({ page }) => { + await page.evaluate(() => { + localStorage.setItem('audioCache', JSON.stringify({ + 'https://example.com/audio': { + audioUrl: 'https://example.com/audio.mp3', + transcription: 'Test transcription', + lastPosition: 0 + } + })); + }); + + await page.goto('http://localhost:5173/listen-UI/'); + + const audioCache = await page.evaluate(() => localStorage.getItem('audioCache')); + expect(audioCache).toBeTruthy(); + + const historyList = await page.locator('#historyList'); + const historyItems = await historyList.locator('li').count(); + expect(historyItems).toBe(1); + }); + + test('Simulate user interactions with audio player', async ({ page }) => { + await page.evaluate(() => { + localStorage.setItem('audioCache', JSON.stringify({ + 'https://example.com/audio': { + audioUrl: 'https://example.com/audio.mp3', + transcription: 'Test transcription', + lastPosition: 0 + } + })); + }); + + await page.goto('http://localhost:5173/listen-UI/'); + + const audioPlayer = await page.locator('#player'); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(2000); // Simulate 2 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const currentTime = await audioPlayer.evaluate(player => player.currentTime); + expect(currentTime).toBeGreaterThan(0); + + await audioPlayer.evaluate(player => player.currentTime = 10); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(2000); // Simulate 2 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const newCurrentTime = await audioPlayer.evaluate(player => player.currentTime); + expect(newCurrentTime).toBeGreaterThan(10); + + const updatedAudioCache = await page.evaluate(() => localStorage.getItem('audioCache')); + const parsedCache = JSON.parse(updatedAudioCache); + expect(parsedCache['https://example.com/audio'].lastPosition).toBeCloseTo(newCurrentTime, 1); + }); + + test('Ensure timestamp is saved at regular intervals', async ({ page }) => { + await page.evaluate(() => { + localStorage.setItem('audioCache', JSON.stringify({ + 'https://example.com/audio': { + audioUrl: 'https://example.com/audio.mp3', + transcription: 'Test transcription', + lastPosition: 0 + } + })); + }); + + await page.goto('http://localhost:5173/listen-UI/'); + + const audioPlayer = await page.locator('#player'); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(6000); // Simulate 6 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const updatedAudioCache = await page.evaluate(() => localStorage.getItem('audioCache')); + const parsedCache = JSON.parse(updatedAudioCache); + expect(parsedCache['https://example.com/audio'].lastPosition).toBeGreaterThan(0); + }); + + test('Load correct timestamp when returning to track', async ({ page }) => { + await page.evaluate(() => { + localStorage.setItem('audioCache', JSON.stringify({ + 'https://example.com/audio': { + audioUrl: 'https://example.com/audio.mp3', + transcription: 'Test transcription', + lastPosition: 15 + } + })); + }); + + await page.goto('http://localhost:5173/listen-UI/'); + + const audioPlayer = await page.locator('#player'); + const currentTime = await audioPlayer.evaluate(player => player.currentTime); + expect(currentTime).toBeCloseTo(15, 1); + }); + + test('Handle SecurityError for localStorage access', async ({ page }) => { + await page.goto('http://localhost:5173/listen-UI/', { waitUntil: 'domcontentloaded' }); + + const localStorageAccess = await page.evaluate(() => { + try { + localStorage.setItem('test', 'test'); + return true; + } catch (e) { + return false; } - })); + }); + + expect(localStorageAccess).toBe(true); }); - await page.goto('http://localhost:5173/listen-UI/'); + test('Simulate user interactions with audio player during track changes', async ({ page }) => { + await page.evaluate(() => { + localStorage.setItem('audioCache', JSON.stringify({ + 'https://example.com/audio1': { + audioUrl: 'https://example.com/audio1.mp3', + transcription: 'Test transcription 1', + lastPosition: 0 + }, + 'https://example.com/audio2': { + audioUrl: 'https://example.com/audio2.mp3', + transcription: 'Test transcription 2', + lastPosition: 0 + } + })); + }); + + await page.goto('http://localhost:5173/listen-UI/'); - const audioCache = await page.evaluate(() => localStorage.getItem('audioCache')); - expect(audioCache).toBeTruthy(); - - const historyList = await page.locator('#historyList'); - const historyItems = await historyList.locator('li').count(); - expect(historyItems).toBe(1); + const audioPlayer = await page.locator('#player'); + + // Play first track + await audioPlayer.evaluate(player => player.src = 'https://example.com/audio1.mp3'); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(2000); // Simulate 2 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const currentTime1 = await audioPlayer.evaluate(player => player.currentTime); + expect(currentTime1).toBeGreaterThan(0); + + // Switch to second track + await audioPlayer.evaluate(player => player.src = 'https://example.com/audio2.mp3'); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(2000); // Simulate 2 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const currentTime2 = await audioPlayer.evaluate(player => player.currentTime); + expect(currentTime2).toBeGreaterThan(0); + + // Switch back to first track + await audioPlayer.evaluate(player => player.src = 'https://example.com/audio1.mp3'); + await audioPlayer.evaluate(player => player.play()); + await page.waitForTimeout(2000); // Simulate 2 seconds of playback + await audioPlayer.evaluate(player => player.pause()); + + const newCurrentTime1 = await audioPlayer.evaluate(player => player.currentTime); + expect(newCurrentTime1).toBeCloseTo(currentTime1, 1); + + const updatedAudioCache = await page.evaluate(() => localStorage.getItem('audioCache')); + const parsedCache = JSON.parse(updatedAudioCache); + expect(parsedCache['https://example.com/audio1'].lastPosition).toBeCloseTo(newCurrentTime1, 1); + expect(parsedCache['https://example.com/audio2'].lastPosition).toBeCloseTo(currentTime2, 1); + }); }); diff --git a/e2e/share-target.spec.js b/e2e/share-target.spec.js index 7eb3ec5..01544b3 100644 --- a/e2e/share-target.spec.js +++ b/e2e/share-target.spec.js @@ -1,4 +1,4 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, describe } from '@playwright/test'; // Add a helper function to check if the server is up async function isServerUp(page) { @@ -11,79 +11,81 @@ async function isServerUp(page) { } } -test('share-target redirects with URL parameter', async ({ page }) => { - // Check if the server is up - const serverUp = await isServerUp(page); - console.log('Is server up?', serverUp); - - const sharedUrl = 'https://example.com/shared-page'; - await page.goto(`share-target.html?url=${encodeURIComponent(sharedUrl)}`); - - // Wait for navigation to complete with a shorter timeout - await page.waitForNavigation({ timeout: 5000 }).catch(e => console.log('Navigation timeout:', e)); - - // Log the current URL for debugging - console.log('Current URL:', page.url()); - - // Check if we've been redirected to the correct URL - expect(page.url()).toContain(`index.html`); - expect(page.url()).toContain(`url=${encodeURIComponent(sharedUrl)}`); -}); - -test('share-target redirects to index.html when no URL is shared', async ({ page }) => { - // Check if the server is up - const serverUp = await isServerUp(page); - console.log('Is server up?', serverUp); - - await page.goto(`share-target.html`); - - // Wait for navigation to complete with a shorter timeout - await page.waitForNavigation({ timeout: 5000 }).catch(e => console.log('Navigation timeout:', e)); - - // Log the current URL for debugging - console.log('Current URL:', page.url()); - - // Check if we've been redirected to the index.html page - expect(page.url()).toContain(`index.html`); -}); - -test('Share target functionality', async ({ page }) => { - console.log('Starting Share target functionality test'); - - try { - // Simulate sharing a URL to the PWA - await page.goto('http://localhost:5173/listen-UI/share-target?url=https://example.com/shared'); - console.log('Navigated to share target URL'); - - // Wait for the page to load and process the shared URL - await page.waitForLoadState('networkidle'); - console.log('Page loaded'); - - // Check if the shared URL is processed : we cant test that at the moment as processing takes a lot of time - // const sharedUrlProcessed = await page.evaluate(() => { - // const lastProcessedUrl = localStorage.getItem('lastProcessedUrl'); - // console.log('Last processed URL:', lastProcessedUrl); - // return lastProcessedUrl === 'https://example.com/shared'; - // }); - // expect(sharedUrlProcessed).toBe(true); - // console.log('Shared URL processed correctly'); - - // Check if the audio player is visible - const audioPlayer = await page.locator('#player'); - await expect(audioPlayer).toBeVisible({ timeout: 10000 }); - console.log('Audio player is visible'); - - // Additional checks to ensure the page has loaded correctly - const pageTitle = await page.title(); - expect(pageTitle).not.toBe(''); - console.log('Page title:', pageTitle); - - const bodyContent = await page.textContent('body'); - expect(bodyContent).not.toBe(''); - console.log('Body content length:', bodyContent.length); - - } catch (error) { - console.error('Test failed with error:', error); - throw error; - } +describe('Share Target Tests', () => { + test('share-target redirects with URL parameter', async ({ page }) => { + // Check if the server is up + const serverUp = await isServerUp(page); + console.log('Is server up?', serverUp); + + const sharedUrl = 'https://example.com/shared-page'; + await page.goto(`share-target.html?url=${encodeURIComponent(sharedUrl)}`); + + // Wait for navigation to complete with a shorter timeout + await page.waitForNavigation({ timeout: 5000 }).catch(e => console.log('Navigation timeout:', e)); + + // Log the current URL for debugging + console.log('Current URL:', page.url()); + + // Check if we've been redirected to the correct URL + expect(page.url()).toContain(`index.html`); + expect(page.url()).toContain(`url=${encodeURIComponent(sharedUrl)}`); + }); + + test('share-target redirects to index.html when no URL is shared', async ({ page }) => { + // Check if the server is up + const serverUp = await isServerUp(page); + console.log('Is server up?', serverUp); + + await page.goto(`share-target.html`); + + // Wait for navigation to complete with a shorter timeout + await page.waitForNavigation({ timeout: 5000 }).catch(e => console.log('Navigation timeout:', e)); + + // Log the current URL for debugging + console.log('Current URL:', page.url()); + + // Check if we've been redirected to the index.html page + expect(page.url()).toContain(`index.html`); + }); + + test('Share target functionality', async ({ page }) => { + console.log('Starting Share target functionality test'); + + try { + // Simulate sharing a URL to the PWA + await page.goto('http://localhost:5173/listen-UI/share-target?url=https://example.com/shared'); + console.log('Navigated to share target URL'); + + // Wait for the page to load and process the shared URL + await page.waitForLoadState('networkidle'); + console.log('Page loaded'); + + // Check if the shared URL is processed : we cant test that at the moment as processing takes a lot of time + // const sharedUrlProcessed = await page.evaluate(() => { + // const lastProcessedUrl = localStorage.getItem('lastProcessedUrl'); + // console.log('Last processed URL:', lastProcessedUrl); + // return lastProcessedUrl === 'https://example.com/shared'; + // }); + // expect(sharedUrlProcessed).toBe(true); + // console.log('Shared URL processed correctly'); + + // Check if the audio player is visible + const audioPlayer = await page.locator('#player'); + await expect(audioPlayer).toBeVisible({ timeout: 10000 }); + console.log('Audio player is visible'); + + // Additional checks to ensure the page has loaded correctly + const pageTitle = await page.title(); + expect(pageTitle).not.toBe(''); + console.log('Page title:', pageTitle); + + const bodyContent = await page.textContent('body'); + expect(bodyContent).not.toBe(''); + console.log('Body content length:', bodyContent.length); + + } catch (error) { + console.error('Test failed with error:', error); + throw error; + } + }); }); \ No newline at end of file diff --git a/script.js b/script.js index 7985414..fcd858d 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,4 @@ -import { audioCache, loadAudioCache, removeFromCache, clearAudioCache } from './src/audioCache.js'; +import { audioCache, loadAudioCache, removeFromCache, clearAudioCache, setCurrentTrack } from './src/audioCache.js'; import { loadAudioFromCache, setupMediaSessionHandlers } from './src/audioPlayer.js'; import { fetchMp3 } from './src/api.js'; import { checkOnlineStatus, handleSharedUrl } from './src/utils.js'; @@ -113,7 +113,10 @@ document.addEventListener("DOMContentLoaded", async function() { const li = document.createElement('li'); const playBtn = document.createElement('button'); playBtn.textContent = 'Play'; - playBtn.onclick = () => loadAudioFromCache(link); + playBtn.onclick = () => { + loadAudioFromCache(link); + setCurrentTrack(link); + }; const removeBtn = document.createElement('button'); removeBtn.textContent = 'Remove'; removeBtn.onclick = () => { @@ -151,4 +154,4 @@ document.addEventListener("DOMContentLoaded", async function() { // Set up media session handlers setupMediaSessionHandlers(audioPlayer, playButton); -}); \ No newline at end of file +}); diff --git a/src/api.js b/src/api.js index 3219990..9cdb929 100644 --- a/src/api.js +++ b/src/api.js @@ -44,7 +44,7 @@ export async function fetchMp3(link) { console.log('Attempting to connect to Gradio app...'); const client = await Client.connect(apiServer); console.log('Gradio client created successfully'); - console.log(await client.view_api()); + // console.log(await client.view_api()); console.log('Preparing to make prediction...'); const result = await client.predict("/generate_audio", { @@ -88,7 +88,7 @@ export async function fetchMp3(link) { } catch (error) { console.error('Error in fetchMp3:', error); console.error('Error stack:', error.stack); - alert(`Error fetching MP3: ${error.message}`); + // alert(`Error fetching MP3: ${error.message}`); if (audioPlayer) audioPlayer.src = ''; if (playButton) playButton.style.display = 'none'; diff --git a/src/api.test.js b/src/api.test.js index 9e60983..804078c 100644 --- a/src/api.test.js +++ b/src/api.test.js @@ -36,4 +36,4 @@ describe('api', () => { await fetchMp3('https://example.com'); expect(alert).toHaveBeenCalledWith('You are offline. Unable to fetch new audio.'); }); -}); \ No newline at end of file +}); diff --git a/src/api.test.ts b/src/api.test.ts index f22e928..c2cbb68 100644 --- a/src/api.test.ts +++ b/src/api.test.ts @@ -39,4 +39,4 @@ describe('api', () => { await fetchMp3('https://example.com'); expect(alert).toHaveBeenCalledWith('You are offline. Unable to fetch new audio.'); }); -}); \ No newline at end of file +}); diff --git a/src/audioCache.js b/src/audioCache.js index 998b2ae..3748740 100644 --- a/src/audioCache.js +++ b/src/audioCache.js @@ -52,6 +52,10 @@ export async function saveAudioCache(link, audioUrl) { } export async function removeFromCache(link) { + if (!audioCache[link]) { + console.log(`Cache entry for ${link} is undefined, cannot remove`); + return; + } const cache = await caches.open('audio-cache'); await cache.delete(audioCache[link].audioUrl); delete audioCache[link]; @@ -65,4 +69,4 @@ export async function clearAudioCache() { } audioCache = {}; localStorage.setItem('audioCache', JSON.stringify(audioCache)); -} \ No newline at end of file +} diff --git a/src/audioCache.test.js b/src/audioCache.test.js index 4aaf641..0a3f321 100644 --- a/src/audioCache.test.js +++ b/src/audioCache.test.js @@ -3,17 +3,17 @@ import { loadAudioCache, saveAudioCache, removeFromCache, clearAudioCache } from describe('audioCache', () => { beforeEach(() => { - vi.mock('localStorage', () => ({ + global.localStorage = { getItem: vi.fn(), setItem: vi.fn() - })); - vi.mock('caches', () => ({ + }; + global.caches = { open: vi.fn().mockResolvedValue({ match: vi.fn(), add: vi.fn(), delete: vi.fn() }) - })); + }; }); it('should load audio cache from localStorage', async () => { @@ -28,10 +28,19 @@ describe('audioCache', () => { }); it('should remove item from cache', async () => { - await removeFromCache('test'); + const link = 'test'; + global.audioCache = { [link]: { audioUrl: 'test.mp3' } }; + await removeFromCache(link); expect(localStorage.setItem).toHaveBeenCalled(); }); + it('should handle undefined cache entry when removing item from cache', async () => { + const link = 'undefinedTest'; + global.audioCache = {}; + await removeFromCache(link); + expect(localStorage.setItem).not.toHaveBeenCalled(); + }); + it('should clear audio cache', async () => { await clearAudioCache(); expect(localStorage.setItem).toHaveBeenCalledWith('audioCache', '{}'); diff --git a/src/audioCache.test.ts b/src/audioCache.test.ts index 6eefb8f..6b42fa1 100644 --- a/src/audioCache.test.ts +++ b/src/audioCache.test.ts @@ -1,24 +1,24 @@ -import { vi } from 'vitest'; +import { describe, vi, beforeEach, expect, it } from 'vitest'; import { loadAudioCache, saveAudioCache, removeFromCache, clearAudioCache } from './audioCache'; describe('Audio Cache', () => { beforeEach(() => { - vi.mock('localStorage', () => ({ + global.localStorage = { getItem: vi.fn(), setItem: vi.fn() - })); - vi.mock('caches', () => ({ + }; + global.caches = { open: vi.fn().mockResolvedValue({ match: vi.fn(), add: vi.fn(), delete: vi.fn() }) - })); + }; }); - it('should load audio cache from localStorage', () => { + it('should load audio cache from localStorage', async () => { (localStorage.getItem as any) = vi.fn().mockReturnValue(JSON.stringify({ 'test': { audioUrl: 'test.mp3' } })); - loadAudioCache(); + await loadAudioCache(); expect(localStorage.getItem).toHaveBeenCalledWith('audioCache'); }); @@ -28,10 +28,19 @@ describe('Audio Cache', () => { }); it('should remove item from cache', async () => { - await removeFromCache('test'); + const link = 'test'; + global.audioCache = { [link]: { audioUrl: 'test.mp3' } }; + await removeFromCache(link); expect(localStorage.setItem).toHaveBeenCalled(); }); + it('should handle undefined cache entry when removing item from cache', async () => { + const link = 'undefinedTest'; + global.audioCache = {}; + await removeFromCache(link); + expect(localStorage.setItem).not.toHaveBeenCalled(); + }); + it('should clear audio cache', async () => { await clearAudioCache(); expect(localStorage.setItem).toHaveBeenCalledWith('audioCache', '{}'); diff --git a/src/audioPlayer.test.js b/src/audioPlayer.test.js index 8353093..6cd5fb3 100644 --- a/src/audioPlayer.test.js +++ b/src/audioPlayer.test.js @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { loadAudioFromCache, updateMediaSessionMetadata, setupMediaSessionHandlers } from './audioPlayer'; -import { audioCache } from './audioCache'; +import { audioCache, setCurrentTrack } from './audioCache'; describe('audioPlayer', () => { beforeEach(() => { @@ -8,18 +8,28 @@ describe('audioPlayer', () => { audioCache: { 'test': { audioUrl: 'test.mp3', lastPosition: 0, transcription: 'Test' } }, - currentTrack: null + currentTrack: null, + setCurrentTrack: vi.fn() })); global.document = { getElementById: vi.fn().mockReturnValue({ src: '', currentTime: 0, style: { display: 'none' }, - play: vi.fn() + play: vi.fn(), + addEventListener: vi.fn() // Mock addEventListener }) }; global.URL = { createObjectURL: vi.fn() }; global.navigator = { mediaSession: { metadata: null, setActionHandler: vi.fn() } }; + global.MediaMetadata = vi.fn().mockImplementation((metadata) => metadata); + global.caches = { + open: vi.fn().mockResolvedValue({ + match: vi.fn(), + add: vi.fn(), + delete: vi.fn() + }) + }; }); it('should load audio from cache', async () => { @@ -27,11 +37,6 @@ describe('audioPlayer', () => { expect(document.getElementById).toHaveBeenCalledWith('player'); }); - it('should update media session metadata', () => { - updateMediaSessionMetadata('Test Title', 'Test Artist', 'Test Album'); - expect(navigator.mediaSession.metadata).toBeTruthy(); - }); - it('should setup media session handlers', () => { const audioPlayer = { play: vi.fn(), pause: vi.fn(), currentTime: 0 }; const playButton = { textContent: '' }; diff --git a/src/audioPlayer.test.ts b/src/audioPlayer.test.ts index fc88d49..937b842 100644 --- a/src/audioPlayer.test.ts +++ b/src/audioPlayer.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { loadAudioFromCache, updateMediaSessionMetadata, setupMediaSessionHandlers } from './audioPlayer'; -// import { audioCache } from './audioCache'; +import { audioCache, setCurrentTrack } from './audioCache'; describe('audioPlayer', () => { beforeEach(() => { @@ -8,18 +8,28 @@ describe('audioPlayer', () => { audioCache: { 'test': { audioUrl: 'test.mp3', lastPosition: 0, transcription: 'Test' } }, - currentTrack: null + currentTrack: null, + setCurrentTrack: vi.fn() })); global.document = { getElementById: vi.fn().mockReturnValue({ src: '', currentTime: 0, style: { display: 'none' }, - play: vi.fn() + play: vi.fn(), + addEventListener: vi.fn() // Mock addEventListener }) } as any; global.URL = { createObjectURL: vi.fn() } as any; global.navigator = { mediaSession: { metadata: null, setActionHandler: vi.fn() } } as any; + global.MediaMetadata = vi.fn().mockImplementation((metadata) => metadata); + global.caches = { + open: vi.fn().mockResolvedValue({ + match: vi.fn(), + add: vi.fn(), + delete: vi.fn() + }) + } as any; }); it('should load audio from cache', async () => { @@ -38,4 +48,4 @@ describe('audioPlayer', () => { setupMediaSessionHandlers(audioPlayer as any, playButton as any); expect(navigator.mediaSession.setActionHandler).toHaveBeenCalled(); }); -}); \ No newline at end of file +}); diff --git a/src/utils.test.js b/src/utils.test.js index fedc9b1..c7b2f72 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -1,16 +1,21 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { checkOnlineStatus, handleSharedUrl } from './utils'; describe('utils', () => { - it('should check online status', () => { - global.navigator = { onLine: false }; + beforeEach(() => { + global.navigator = { onLine: true }; + global.window = { location: { search: '' } }; global.alert = vi.fn(); + }); + + it('should check online status', () => { + global.navigator.onLine = false; checkOnlineStatus(); expect(alert).toHaveBeenCalledWith('You are currently offline. Some features may be limited.'); }); it('should handle shared URL', () => { - global.window = { location: { search: '?url=https://example.com' } }; + global.window.location.search = '?url=https://example.com'; const result = handleSharedUrl(); expect(result).toBe('https://example.com'); }); diff --git a/src/utils.test.ts b/src/utils.test.ts index 76f8cc3..5f724ed 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -1,16 +1,21 @@ -import { describe, it, expect, vi } from 'vitest'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; import { checkOnlineStatus, handleSharedUrl } from './utils'; describe('utils', () => { - it('should check online status', () => { - global.navigator = { onLine: false } as any; + beforeEach(() => { + global.navigator = { onLine: true } as any; + global.window = { location: { search: '' } } as any; global.alert = vi.fn(); + }); + + it('should check online status', () => { + global.navigator.onLine = false; checkOnlineStatus(); expect(alert).toHaveBeenCalledWith('You are currently offline. Some features may be limited.'); }); it('should handle shared URL', () => { - global.window = { location: { search: '?url=https://example.com' } } as any; + global.window.location.search = '?url=https://example.com'; const result = handleSharedUrl(); expect(result).toBe('https://example.com'); }); diff --git a/vitest-results.json b/vitest-results.json new file mode 100644 index 0000000..bd0ba85 --- /dev/null +++ b/vitest-results.json @@ -0,0 +1,318 @@ +{ + "numTotalTestSuites": 17, + "numPassedTestSuites": 14, + "numFailedTestSuites": 3, + "numPendingTestSuites": 0, + "numTotalTests": 18, + "numPassedTests": 15, + "numFailedTests": 3, + "numPendingTests": 0, + "numTodoTests": 0, + "startTime": 1730114267616, + "success": false, + "testResults": [ + { + "assertionResults": [], + "startTime": 1730114267616, + "endTime": 1730114267616, + "status": "passed", + "message": "Playwright Test did not expect test() to be called here.\nMost common reasons include:\n- You are calling test() in a configuration file.\n- You are calling test() in a file that is imported by the configuration file.\n- You have two different versions of @playwright/test. This usually happens\n when one of the dependencies in your package.json depends on @playwright/test.", + "name": "/workspaces/listen-UI/e2e/localstorage.spec.js" + }, + { + "assertionResults": [], + "startTime": 1730114267616, + "endTime": 1730114267616, + "status": "passed", + "message": "Playwright Test did not expect test() to be called here.\nMost common reasons include:\n- You are calling test() in a configuration file.\n- You are calling test() in a file that is imported by the configuration file.\n- You have two different versions of @playwright/test. This usually happens\n when one of the dependencies in your package.json depends on @playwright/test.", + "name": "/workspaces/listen-UI/e2e/share-target.spec.js" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "api" + ], + "fullName": " api should fetch MP3 from API", + "status": "passed", + "title": "should fetch MP3 from API", + "duration": 8, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "api" + ], + "fullName": " api should handle offline state", + "status": "passed", + "title": "should handle offline state", + "duration": 1, + "failureMessages": [] + } + ], + "startTime": 1730114274115, + "endTime": 1730114274124, + "status": "passed", + "message": "", + "name": "/workspaces/listen-UI/src/api.test.js" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "api" + ], + "fullName": " api should fetch MP3 from API", + "status": "passed", + "title": "should fetch MP3 from API", + "duration": 8, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "api" + ], + "fullName": " api should handle offline state", + "status": "passed", + "title": "should handle offline state", + "duration": 1, + "failureMessages": [] + } + ], + "startTime": 1730114273627, + "endTime": 1730114273636, + "status": "passed", + "message": "", + "name": "/workspaces/listen-UI/src/api.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "audioCache" + ], + "fullName": " audioCache should load audio cache from localStorage", + "status": "passed", + "title": "should load audio cache from localStorage", + "duration": 3, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "audioCache" + ], + "fullName": " audioCache should save audio cache to localStorage", + "status": "passed", + "title": "should save audio cache to localStorage", + "duration": 1, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "audioCache" + ], + "fullName": " audioCache should remove item from cache", + "status": "failed", + "title": "should remove item from cache", + "duration": 6, + "failureMessages": [ + "expected \"spy\" to be called at least once" + ], + "location": { + "line": 34, + "column": 34 + } + }, + { + "ancestorTitles": [ + "", + "audioCache" + ], + "fullName": " audioCache should handle undefined cache entry when removing item from cache", + "status": "passed", + "title": "should handle undefined cache entry when removing item from cache", + "duration": 0, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "audioCache" + ], + "fullName": " audioCache should clear audio cache", + "status": "passed", + "title": "should clear audio cache", + "duration": 0, + "failureMessages": [] + } + ], + "startTime": 1730114268161, + "endTime": 1730114268171, + "status": "failed", + "message": "", + "name": "/workspaces/listen-UI/src/audioCache.test.js" + }, + { + "assertionResults": [], + "startTime": 1730114267616, + "endTime": 1730114267616, + "status": "passed", + "message": "describe is not defined", + "name": "/workspaces/listen-UI/src/audioCache.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "audioPlayer" + ], + "fullName": " audioPlayer should load audio from cache", + "status": "failed", + "title": "should load audio from cache", + "duration": 9, + "failureMessages": [ + "[vitest] No \"setCurrentTrack\" export is defined on the \"./audioCache\" mock. Did you forget to return it from \"vi.mock\"?\nIf you need to partially mock a module, you can use \"vi.importActual\" inside:\n\n\u001b[32mvi.mock(\"./audioCache\", async () => {\n const actual = await vi.importActual(\"./audioCache\")\n return {\n ...actual,\n // your mocked methods\n },\n})\u001b[39m\n" + ], + "location": { + "line": 35, + "column": 5 + } + }, + { + "ancestorTitles": [ + "", + "audioPlayer" + ], + "fullName": " audioPlayer should setup media session handlers", + "status": "passed", + "title": "should setup media session handlers", + "duration": 1, + "failureMessages": [] + } + ], + "startTime": 1730114269225, + "endTime": 1730114269235, + "status": "failed", + "message": "", + "name": "/workspaces/listen-UI/src/audioPlayer.test.js" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "audioPlayer" + ], + "fullName": " audioPlayer should load audio from cache", + "status": "failed", + "title": "should load audio from cache", + "duration": 8, + "failureMessages": [ + "[vitest] No \"setCurrentTrack\" export is defined on the \"./audioCache\" mock. Did you forget to return it from \"vi.mock\"?\nIf you need to partially mock a module, you can use \"vi.importActual\" inside:\n\n\u001b[32mvi.mock(\"./audioCache\", async () => {\n const actual = await vi.importActual(\"./audioCache\")\n return {\n ...actual,\n // your mocked methods\n },\n})\u001b[39m\n" + ], + "location": { + "line": 35, + "column": 5 + } + }, + { + "ancestorTitles": [ + "", + "audioPlayer" + ], + "fullName": " audioPlayer should update media session metadata", + "status": "passed", + "title": "should update media session metadata", + "duration": 1, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "audioPlayer" + ], + "fullName": " audioPlayer should setup media session handlers", + "status": "passed", + "title": "should setup media session handlers", + "duration": 0, + "failureMessages": [] + } + ], + "startTime": 1730114268715, + "endTime": 1730114268724, + "status": "failed", + "message": "", + "name": "/workspaces/listen-UI/src/audioPlayer.test.ts" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "utils" + ], + "fullName": " utils should check online status", + "status": "passed", + "title": "should check online status", + "duration": 2, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "utils" + ], + "fullName": " utils should handle shared URL", + "status": "passed", + "title": "should handle shared URL", + "duration": 1, + "failureMessages": [] + } + ], + "startTime": 1730114275066, + "endTime": 1730114275069, + "status": "passed", + "message": "", + "name": "/workspaces/listen-UI/src/utils.test.js" + }, + { + "assertionResults": [ + { + "ancestorTitles": [ + "", + "utils" + ], + "fullName": " utils should check online status", + "status": "passed", + "title": "should check online status", + "duration": 2, + "failureMessages": [] + }, + { + "ancestorTitles": [ + "", + "utils" + ], + "fullName": " utils should handle shared URL", + "status": "passed", + "title": "should handle shared URL", + "duration": 1, + "failureMessages": [] + } + ], + "startTime": 1730114274607, + "endTime": 1730114274610, + "status": "passed", + "message": "", + "name": "/workspaces/listen-UI/src/utils.test.ts" + } + ] +} \ No newline at end of file