Files
wehub-resource-sync c48612c494
CI / E2E Tests (push) Has been cancelled
CI / Lint, Typecheck & Unit Tests (push) Has been cancelled
Docs Build / Build docs site (push) Has been cancelled
Publish @openmaic packages / Build, validate & publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:23 +08:00

106 lines
3.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import type { PPTImageElement } from '@openmaic/dsl';
import type { MediaTask } from '@/lib/store/media-generation';
import { resolveImageSrc } from '@/components/slide-renderer/components/element/ImageElement/useResolvedImageSrc';
const STAGE = 'stage-a';
const PLACEHOLDER: PPTImageElement = {
id: 'el-placeholder',
type: 'image',
src: 'gen_img_alpha_001',
left: 0,
top: 0,
width: 100,
height: 100,
rotate: 0,
fixedRatio: false,
};
const CONCRETE: PPTImageElement = {
...PLACEHOLDER,
id: 'el-concrete',
src: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=',
};
function task(over: Partial<MediaTask>): MediaTask {
return {
elementId: PLACEHOLDER.src,
type: 'image',
status: 'done',
prompt: '',
params: {} as MediaTask['params'],
retryCount: 0,
stageId: STAGE,
...over,
};
}
describe('resolveImageSrc (pure)', () => {
it('returns the objectUrl when the placeholder task is done', () => {
const r = resolveImageSrc(
PLACEHOLDER,
STAGE,
task({ status: 'done', objectUrl: 'blob:fake-1' }),
);
expect(r.resolvedSrc).toBe('blob:fake-1');
expect(r.isPlaceholder).toBe(true);
expect(r.task?.status).toBe('done');
});
it('falls back to the raw placeholder src when no task is supplied', () => {
const r = resolveImageSrc(PLACEHOLDER, STAGE, undefined);
expect(r.resolvedSrc).toBe(PLACEHOLDER.src);
expect(r.isPlaceholder).toBe(true);
expect(r.task).toBeUndefined();
});
it.each(['pending', 'generating', 'failed'] as const)(
'falls back when task status is %s',
(status) => {
const r = resolveImageSrc(PLACEHOLDER, STAGE, task({ status, objectUrl: undefined }));
expect(r.resolvedSrc).toBe(PLACEHOLDER.src);
expect(r.task?.status).toBe(status);
},
);
it('falls back when a done task has no objectUrl set', () => {
const r = resolveImageSrc(PLACEHOLDER, STAGE, task({ status: 'done', objectUrl: undefined }));
expect(r.resolvedSrc).toBe(PLACEHOLDER.src);
});
it('cross-stage isolation: drops a done task that belongs to a different stage', () => {
const r = resolveImageSrc(
PLACEHOLDER,
STAGE,
task({ status: 'done', objectUrl: 'blob:other-stage', stageId: 'stage-other' }),
);
expect(r.resolvedSrc).toBe(PLACEHOLDER.src);
expect(r.task).toBeUndefined();
});
it('does not consider anything a placeholder when there is no stageId', () => {
// Even if a "done" task is supplied, no stageId → skip placeholder logic entirely.
const r = resolveImageSrc(
PLACEHOLDER,
undefined,
task({ status: 'done', objectUrl: 'blob:leak' }),
);
expect(r.resolvedSrc).toBe(PLACEHOLDER.src);
expect(r.isPlaceholder).toBe(false);
expect(r.task).toBeUndefined();
});
it('passes through non-placeholder src unchanged (additive contract)', () => {
// Even with a done task supplied — the regex gate rejects non-placeholder src.
const r = resolveImageSrc(
CONCRETE,
STAGE,
task({ status: 'done', objectUrl: 'blob:should-not-touch' }),
);
expect(r.resolvedSrc).toBe(CONCRETE.src);
expect(r.isPlaceholder).toBe(false);
expect(r.task).toBeUndefined();
});
});