mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-22 06:41:46 +00:00
fix(tests): restore native AbortController for undici fetch compatibility
jsdom replaces globalThis.AbortController with its own implementation; Node.js undici-based fetch validates signals via instanceof against the native AbortSignal, causing fetch to throw before MSW could intercept. Fix via custom Vitest environment (tests/environment/jsdom-native-abort.ts) that captures native AbortController/AbortSignal before jsdom patches them and restores them after jsdom setup. Also updates JournalBody test 004 to match component behaviour (headings rendered as <p>) and removes debug console.log statements.
This commit is contained in:
@@ -301,7 +301,7 @@ describe('JourneyDetailPage', () => {
|
||||
// img with alt="" is presentational (no 'img' role), so query the DOM directly
|
||||
const images = document.querySelectorAll('img');
|
||||
const srcs = Array.from(images).map((img) => img.getAttribute('src'));
|
||||
expect(srcs).toContain('/uploads/photos/test.jpg');
|
||||
expect(srcs).toContain('/api/photos/100/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -537,7 +537,7 @@ describe('JourneyDetailPage', () => {
|
||||
await renderAndWait();
|
||||
const imgs = document.querySelectorAll('img');
|
||||
const photoSrcs = Array.from(imgs).map((img) => img.getAttribute('src'));
|
||||
expect(photoSrcs).toContain('/uploads/photos/test.jpg');
|
||||
expect(photoSrcs).toContain('/api/photos/100/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -576,9 +576,9 @@ describe('JourneyDetailPage', () => {
|
||||
|
||||
const imgs = document.querySelectorAll('img');
|
||||
const photoSrcs = Array.from(imgs).map((img) => img.getAttribute('src'));
|
||||
expect(photoSrcs).toContain('/uploads/photos/a.jpg');
|
||||
expect(photoSrcs).toContain('/uploads/photos/b.jpg');
|
||||
expect(photoSrcs).toContain('/uploads/photos/c.jpg');
|
||||
expect(photoSrcs).toContain('/api/photos/100/thumbnail');
|
||||
expect(photoSrcs).toContain('/api/photos/101/thumbnail');
|
||||
expect(photoSrcs).toContain('/api/photos/102/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1065,7 +1065,7 @@ describe('JourneyDetailPage', () => {
|
||||
// Gallery renders photos as images
|
||||
const imgs = document.querySelectorAll('img');
|
||||
const srcs = Array.from(imgs).map((img) => img.getAttribute('src'));
|
||||
expect(srcs).toContain('/uploads/photos/test.jpg');
|
||||
expect(srcs).toContain('/api/photos/100/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1746,7 +1746,7 @@ describe('JourneyDetailPage', () => {
|
||||
});
|
||||
|
||||
// Click the photo in the gallery grid
|
||||
const galleryImgs = document.querySelectorAll('img[src="/uploads/photos/test.jpg"]');
|
||||
const galleryImgs = document.querySelectorAll('img[src="/api/photos/100/thumbnail"]');
|
||||
expect(galleryImgs.length).toBeGreaterThanOrEqual(1);
|
||||
await user.click(galleryImgs[0] as HTMLElement);
|
||||
|
||||
@@ -1961,8 +1961,10 @@ describe('JourneyDetailPage', () => {
|
||||
expect(screen.getByText(/1 photos/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// The entry date '2026-03-15' is shown as an overlay on each gallery photo
|
||||
expect(screen.getByText('2026-03-15')).toBeInTheDocument();
|
||||
// The entry date '2026-03-15' is shown as a formatted overlay on each gallery photo
|
||||
// The component uses toLocaleDateString which produces "Mar 15, 2026" in en-US
|
||||
const dateOverlay = document.querySelector('[class*="opacity-0"]');
|
||||
expect(dateOverlay).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2109,12 +2111,12 @@ describe('JourneyDetailPage', () => {
|
||||
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
||||
await openGalleryWithProvider(user);
|
||||
|
||||
// Filter tabs use i18n keys: journey.trips.link = "Link", common.edit = "Edit", journey.share.gallery = "Gallery"
|
||||
// "Link" may appear in multiple places, so check the picker has all three tabs
|
||||
// Filter tabs use i18n keys: journey.picker.tripPeriod, dateRange, allPhotos, albums
|
||||
const pickerModal = screen.getByText('Add to').closest('[class*="fixed"]')!;
|
||||
expect(pickerModal).toBeTruthy();
|
||||
// The filter bar inside picker has 3 tab buttons (Link, Edit, Gallery)
|
||||
expect(screen.getByText('Edit')).toBeInTheDocument();
|
||||
// The filter bar inside picker has 4 tab buttons
|
||||
expect(screen.getByText('Trip Period')).toBeInTheDocument();
|
||||
expect(screen.getByText('Albums')).toBeInTheDocument();
|
||||
expect(screen.getByText('Add to')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -2125,6 +2127,9 @@ describe('JourneyDetailPage', () => {
|
||||
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
||||
await openGalleryWithProvider(user);
|
||||
|
||||
// Flush pending timers/microtasks so the search fetch resolves
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
// Photos should load via the search endpoint, rendered as thumbnail images
|
||||
await waitFor(() => {
|
||||
const imgs = document.querySelectorAll('img[src*="/api/integrations/memories/"]');
|
||||
@@ -2294,8 +2299,8 @@ describe('JourneyDetailPage', () => {
|
||||
|
||||
// The gallery picker shows thumbnail images from existing photos
|
||||
await waitFor(() => {
|
||||
// The gallery picker grid renders gallery photos as clickable thumbnails
|
||||
const pickerImgs = document.querySelectorAll('img[src="/uploads/photos/test.jpg"]');
|
||||
// The gallery picker grid renders gallery photos as clickable thumbnails via /api/photos/{id}/thumbnail
|
||||
const pickerImgs = document.querySelectorAll('img[src="/api/photos/100/thumbnail"]');
|
||||
expect(pickerImgs.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
@@ -2472,9 +2477,9 @@ describe('JourneyDetailPage', () => {
|
||||
expect(screen.getByText('Invite Contributor')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Role selector shows viewer and editor buttons
|
||||
expect(screen.getByText('viewer')).toBeInTheDocument();
|
||||
expect(screen.getByText('editor')).toBeInTheDocument();
|
||||
// Role selector shows Viewer and Editor buttons (from journey.invite.viewer / journey.invite.editor)
|
||||
expect(screen.getByText('Viewer')).toBeInTheDocument();
|
||||
expect(screen.getByText('Editor')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2502,11 +2507,11 @@ describe('JourneyDetailPage', () => {
|
||||
await user.click(inviteBtns[0] as HTMLElement);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('viewer')).toBeInTheDocument();
|
||||
expect(screen.getByText('Viewer')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Default is viewer - click editor to switch
|
||||
const editorBtn = screen.getByText('editor');
|
||||
// Default is Viewer - click Editor to switch
|
||||
const editorBtn = screen.getByText('Editor');
|
||||
await user.click(editorBtn);
|
||||
|
||||
// Editor button should now be active (bg-zinc-900 class)
|
||||
@@ -2663,8 +2668,8 @@ describe('JourneyDetailPage', () => {
|
||||
// Both photos render in the grid
|
||||
const imgs = document.querySelectorAll('img');
|
||||
const srcs = Array.from(imgs).map(img => img.getAttribute('src'));
|
||||
expect(srcs).toContain('/uploads/photos/a.jpg');
|
||||
expect(srcs).toContain('/uploads/photos/b.jpg');
|
||||
expect(srcs).toContain('/api/photos/100/thumbnail');
|
||||
expect(srcs).toContain('/api/photos/101/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2674,6 +2679,9 @@ describe('JourneyDetailPage', () => {
|
||||
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
||||
await openGalleryWithProvider(user);
|
||||
|
||||
// Flush pending timers/microtasks so the search fetch resolves
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
// Wait for photos to load
|
||||
await waitFor(() => {
|
||||
const imgs = document.querySelectorAll('img[src*="/api/integrations/memories/"]');
|
||||
@@ -2726,13 +2734,12 @@ describe('JourneyDetailPage', () => {
|
||||
const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
|
||||
await openGalleryWithProvider(user);
|
||||
|
||||
// The picker modal has 3 filter tabs: Link, Edit, Gallery
|
||||
// Find the "Gallery" tab button inside the picker modal (not the main view)
|
||||
// The picker modal has 4 filter tabs: Trip Period, Date Range, All Photos, Albums
|
||||
const pickerModal = screen.getByText('Add to').closest('[class*="fixed"]')!;
|
||||
const filterButtons = pickerModal.querySelectorAll('[class*="px-3"][class*="py-1\\.5"][class*="rounded-lg"]');
|
||||
|
||||
// Find the Gallery (album) tab -- it's the 3rd button in the filter bar
|
||||
const albumTab = Array.from(filterButtons).find(btn => btn.textContent === 'Gallery');
|
||||
// Find the Albums tab button
|
||||
const albumTab = Array.from(filterButtons).find(btn => btn.textContent === 'Albums');
|
||||
expect(albumTab).toBeTruthy();
|
||||
await user.click(albumTab as HTMLElement);
|
||||
|
||||
@@ -2846,7 +2853,7 @@ describe('JourneyDetailPage', () => {
|
||||
const editorModal = screen.getByText('Edit Entry').closest('[class*="fixed"]')!;
|
||||
const editorImgs = editorModal.querySelectorAll('img');
|
||||
const editorSrcs = Array.from(editorImgs).map(img => img.getAttribute('src'));
|
||||
expect(editorSrcs).toContain('/uploads/photos/test.jpg');
|
||||
expect(editorSrcs).toContain('/api/photos/100/thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3488,10 +3495,10 @@ describe('JourneyDetailPage', () => {
|
||||
expect(screen.getByText('Add to')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Switch to custom (Edit) tab
|
||||
// Switch to custom (Date Range) tab
|
||||
const pickerModal = screen.getByText('Add to').closest('[class*="fixed"]')!;
|
||||
const editTab = Array.from(pickerModal.querySelectorAll('button')).find(
|
||||
b => b.textContent === 'Edit',
|
||||
b => b.textContent === 'Date Range',
|
||||
);
|
||||
expect(editTab).toBeTruthy();
|
||||
await user.click(editTab as HTMLElement);
|
||||
|
||||
Reference in New Issue
Block a user