feat: publish av-tools 0.2.0
This commit is contained in:
@@ -16,7 +16,9 @@ describe('HelpDialog', () => {
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('n5.1.4')).toBeInTheDocument();
|
||||
expect(screen.getByText('0.12.15')).toBeInTheDocument();
|
||||
expect(screen.getByText('0.12.10 · ST & MT')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('0.12.10-reviewed-stack5m.1 · ST & MT')
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(/copyright © 2026 Albrecht Degering/i)
|
||||
).toBeInTheDocument();
|
||||
@@ -29,6 +31,9 @@ describe('HelpDialog', () => {
|
||||
expect(
|
||||
screen.getByRole('link', { name: 'GPL text', hidden: true })
|
||||
).toHaveAttribute('href', expect.stringContaining('GPL-2.0-or-later'));
|
||||
expect(
|
||||
screen.getByRole('link', { name: 'Font licence', hidden: true })
|
||||
).toHaveAttribute('href', expect.stringContaining('DEJAVU_FONTS'));
|
||||
expect(
|
||||
screen.getByRole('link', {
|
||||
name: 'Complete inventory',
|
||||
|
||||
@@ -26,6 +26,41 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe('MediaPreview', () => {
|
||||
it('starts declared local video playback while inspection continues and preserves the element', () => {
|
||||
const probingAsset: ImportedMediaAsset = {
|
||||
id: 'asset-probing-video',
|
||||
file: new File(['video'], 'lecture.mp4', {
|
||||
type: 'application/octet-stream',
|
||||
}),
|
||||
objectUrl: 'blob:probing-video',
|
||||
phase: 'probing',
|
||||
};
|
||||
const { container, rerender } = render(
|
||||
<MediaPreview asset={probingAsset} />
|
||||
);
|
||||
|
||||
const progressiveVideo = requiredElement(container.querySelector('video'));
|
||||
expect(progressiveVideo).toHaveAttribute('src', probingAsset.objectUrl);
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Local source preview · Media inspection continues in the background.'
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
rerender(
|
||||
<MediaPreview
|
||||
asset={{
|
||||
...videoAsset(),
|
||||
id: probingAsset.id,
|
||||
file: probingAsset.file,
|
||||
objectUrl: probingAsset.objectUrl,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(container.querySelector('video')).toBe(progressiveVideo);
|
||||
});
|
||||
|
||||
it('offers bounded configurable proxy settings after playback fails', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onCreateProxy = vi.fn();
|
||||
|
||||
@@ -138,6 +138,28 @@ describe('QuickConvert', () => {
|
||||
).toBeDisabled();
|
||||
});
|
||||
|
||||
it('enables Opus after the reviewed core passed both regression modes', () => {
|
||||
const engineState: EngineState = {
|
||||
status: 'ready',
|
||||
mode: 'single-thread',
|
||||
capabilities: {
|
||||
...capabilities(['mp4', 'opus']),
|
||||
encoders: new Set(['libx264', 'aac', 'libopus']),
|
||||
},
|
||||
};
|
||||
|
||||
render(
|
||||
<QuickConvert
|
||||
asset={createAsset('asset-a', 'source-a.mp4')}
|
||||
engineState={engineState}
|
||||
busy={false}
|
||||
onExport={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByRole('option', { name: 'Opus' })).toBeEnabled();
|
||||
});
|
||||
|
||||
it('exposes a validated user preset and returns it unchanged on export', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onExport = vi.fn<(configuration: QuickExportConfiguration) => void>();
|
||||
|
||||
@@ -274,6 +274,7 @@ describe('StructuralOperations', () => {
|
||||
presetId: 'video-ready',
|
||||
missingAudioPolicy: 'insert-silence',
|
||||
subtitlePolicy: 'reject',
|
||||
crossfadeSeconds: 0,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -328,6 +329,55 @@ describe('StructuralOperations', () => {
|
||||
presetId: 'video-ready',
|
||||
missingAudioPolicy: 'insert-silence',
|
||||
subtitlePolicy: 'drop-all',
|
||||
crossfadeSeconds: 0,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('emits a bounded crossfade only after its filters are verified', async () => {
|
||||
const user = userEvent.setup();
|
||||
const onConcat = vi.fn();
|
||||
render(
|
||||
<StructuralOperations
|
||||
timeline={{
|
||||
...TIMELINE,
|
||||
clips: TIMELINE.clips.map((clip) => ({
|
||||
...clip,
|
||||
durationSeconds: 3,
|
||||
})),
|
||||
}}
|
||||
exportPresets={PRESETS}
|
||||
availability={capabilities('concat-normalized', 'concat-crossfade')}
|
||||
onConcat={onConcat}
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /Normalized re-encode/iu })
|
||||
);
|
||||
await user.selectOptions(
|
||||
screen.getByLabelText('Normalized concat preset'),
|
||||
'video-ready'
|
||||
);
|
||||
await user.click(screen.getByRole('radio', { name: /Insert silence/iu }));
|
||||
await user.click(
|
||||
screen.getByRole('radio', { name: /Reject subtitle input/iu })
|
||||
);
|
||||
await user.clear(screen.getByLabelText(/^Crossfade duration/iu));
|
||||
await user.type(screen.getByLabelText(/^Crossfade duration/iu), '0.5');
|
||||
await user.click(
|
||||
screen.getByRole('button', { name: 'Export normalized concat' })
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(onConcat).toHaveBeenCalledWith({
|
||||
operation: 'concat',
|
||||
mode: 'normalized',
|
||||
clipIds: ['clip-a', 'clip-b'],
|
||||
presetId: 'video-ready',
|
||||
missingAudioPolicy: 'insert-silence',
|
||||
subtitlePolicy: 'reject',
|
||||
crossfadeSeconds: 0.5,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user