Files
readest/apps/readest-app/src/__tests__/components/AtmosphereOverlay.test.tsx
T
Huang Xin 7b60b1bb0c fix(ios): reduce GPU memory pressure to prevent WebKit GPU process crash (#3842)
On iOS, navigating to a book group in the library caused the WebKit GPU
process to exceed its 300 MB jetsam limit (peaking at ~328 MB), resulting
in a blank screen flash and broken scroll state.

Three changes reduce peak GPU memory usage:

- Add overscan={200} to VirtuosoGrid/Virtuoso so only items within 200px
  of the viewport are rendered, limiting simultaneous image decoding
- Add loading="lazy" to both Image components in BookCover so the browser
  defers decoding offscreen cover images
- Conditionally mount the <video> and <audio> elements in AtmosphereOverlay
  only when atmosphere mode is active, eliminating idle H.264 decoder
  memory overhead

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:06:16 +02:00

42 lines
1.3 KiB
TypeScript

import { describe, it, expect, vi, afterEach } from 'vitest';
import { render, cleanup } from '@testing-library/react';
// Mock zustand stores before importing the component
vi.mock('@/store/atmosphereStore', () => ({
useAtmosphereStore: vi.fn(),
}));
vi.mock('@/store/themeStore', () => ({
useThemeStore: vi.fn(),
}));
import AtmosphereOverlay from '@/components/AtmosphereOverlay';
import { useAtmosphereStore } from '@/store/atmosphereStore';
import { useThemeStore } from '@/store/themeStore';
afterEach(cleanup);
const setupStores = (active: boolean) => {
vi.mocked(useAtmosphereStore).mockImplementation((selector: unknown) =>
(selector as (s: { active: boolean }) => unknown)({ active }),
);
vi.mocked(useThemeStore).mockImplementation((selector: unknown) =>
(selector as (s: { isDarkMode: boolean }) => unknown)({ isDarkMode: false }),
);
};
describe('AtmosphereOverlay', () => {
it('does not render <video> element when inactive', () => {
setupStores(false);
const { container } = render(<AtmosphereOverlay />);
const video = container.querySelector('video');
expect(video).toBeNull();
});
it('renders <video> element when active', () => {
setupStores(true);
const { container } = render(<AtmosphereOverlay />);
const video = container.querySelector('video');
expect(video).toBeTruthy();
});
});