Files
nexu-io--open-design/apps/web/tests/components/plugins-home-preview-surface.test.tsx
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

117 lines
3.8 KiB
TypeScript

// @vitest-environment jsdom
import { cleanup, render, screen } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { PreviewSurface } from '../../src/components/plugins-home/cards/PreviewSurface';
import type { MediaPreviewSpec } from '../../src/components/plugins-home/preview';
const visibilityQueue: boolean[] = [];
vi.mock('../../src/components/plugins-home/useInView', () => ({
useInView: () => ({
ref: { current: null },
inView: visibilityQueue.shift() ?? false,
}),
}));
vi.mock('../../src/components/plugins-home/cards/MediaSurface', () => ({
MediaSurface: ({ inView, visible }: { inView: boolean; visible?: boolean }) => (
<div data-testid="media-surface" data-in-view={String(inView)} data-visible={String(visible)} />
),
}));
vi.mock('../../src/components/plugins-home/cards/HtmlSurface', () => ({
HtmlSurface: ({ inView }: { inView: boolean }) => (
<div data-testid="html-surface" data-in-view={String(inView)} />
),
}));
vi.mock('../../src/components/plugins-home/cards/DesignSystemSurface', () => ({
DesignSystemSurface: ({ inView }: { inView: boolean }) => (
<div data-testid="design-surface" data-in-view={String(inView)} />
),
}));
vi.mock('../../src/components/plugins-home/cards/TextSurface', () => ({
TextSurface: () => <div data-testid="text-surface" />,
}));
const IMAGE_PREVIEW: MediaPreviewSpec = {
kind: 'media',
mediaType: 'image',
poster: 'https://example.invalid/poster.jpg',
videoUrl: null,
audioUrl: null,
imageOnly: true,
};
const PLAIN_VIDEO_PREVIEW: MediaPreviewSpec = {
...IMAGE_PREVIEW,
mediaType: 'video',
videoUrl: 'https://example.invalid/plain.mp4',
imageOnly: false,
};
const BAKED_CLIP_PREVIEW: MediaPreviewSpec = {
...PLAIN_VIDEO_PREVIEW,
videoUrl: 'https://example.invalid/baked.mp4',
loopHoldMs: 2500,
};
function renderWithVisibility(preview: MediaPreviewSpec) {
// PreviewSurface calls useInView in this order: near, media, keep, visible. Make the
// values intentionally disagree so the gate passed to MediaSurface proves
// which zone each media subtype uses.
visibilityQueue.splice(0, visibilityQueue.length, false, true, false, true);
render(
<PreviewSurface pluginId="sample" pluginTitle="Sample" preview={preview} />,
);
return screen.getByTestId('media-surface');
}
afterEach(() => {
cleanup();
visibilityQueue.splice(0, visibilityQueue.length);
});
describe('PreviewSurface media visibility gates', () => {
beforeEach(() => {
visibilityQueue.splice(0, visibilityQueue.length);
});
it('warms image media on the medium media margin', () => {
expect(renderWithVisibility(IMAGE_PREVIEW).dataset.inView).toBe('true');
});
it('warms plain video media on the medium media margin', () => {
expect(renderWithVisibility(PLAIN_VIDEO_PREVIEW).dataset.inView).toBe('true');
});
it('uses the wide keepalive margin only for baked hover-pan clips', () => {
expect(renderWithVisibility(BAKED_CLIP_PREVIEW).dataset.inView).toBe('false');
});
it('keeps html and design surfaces on the tight near margin', () => {
visibilityQueue.splice(0, visibilityQueue.length, false, true, true, true);
render(
<PreviewSurface
pluginId="sample"
pluginTitle="Sample"
preview={{ kind: 'html', src: '/preview', label: 'preview', source: 'preview' }}
/>,
);
expect(screen.getByTestId('html-surface').dataset.inView).toBe('false');
cleanup();
visibilityQueue.splice(0, visibilityQueue.length, false, true, true, true);
render(
<PreviewSurface
pluginId="sample"
pluginTitle="Sample"
preview={{ kind: 'design', brand: 'Sample', designSystemId: null, swatches: [] }}
/>,
);
expect(screen.getByTestId('design-surface').dataset.inView).toBe('false');
});
});