144 lines
4.6 KiB
TypeScript
144 lines
4.6 KiB
TypeScript
/// <reference types="node" />
|
|
|
|
import { join } from 'node:path';
|
|
import { expect, test, type Page } from '@playwright/test';
|
|
import {
|
|
GENERATED_FIXTURES,
|
|
observeRuntime,
|
|
PRIMARY_FIXTURE,
|
|
type RuntimeObservation,
|
|
} from './browser-helpers';
|
|
|
|
function mediaInput(page: Page) {
|
|
return page.locator('input[type="file"][accept*="audio"]').first();
|
|
}
|
|
|
|
async function initializeSingleThread(page: Page): Promise<void> {
|
|
await page.getByText('Engine & browser').click();
|
|
await page.getByLabel('Engine mode').selectOption('force-single-thread');
|
|
await page.getByRole('button', { name: 'Initialize engine' }).click();
|
|
await expect(
|
|
page
|
|
.locator('.engine-pill')
|
|
.filter({ hasText: 'Single-threaded compatibility mode' })
|
|
).toBeVisible({ timeout: 120_000 });
|
|
}
|
|
|
|
function assertLocalOnly(runtime: RuntimeObservation): void {
|
|
const networkUrls = runtime.requests.filter((url) => /^https?:/u.test(url));
|
|
expect(
|
|
networkUrls.every((url) => new URL(url).origin === 'http://127.0.0.1:4173')
|
|
).toBe(true);
|
|
const materialFailures = runtime.failedRequests.filter(
|
|
(failure) =>
|
|
!(failure.startsWith('blob:') && failure.endsWith('net::ERR_ABORTED'))
|
|
);
|
|
expect(materialFailures).toEqual([]);
|
|
expect(runtime.pageErrors).toEqual([]);
|
|
expect(runtime.consoleErrors).toEqual([]);
|
|
}
|
|
|
|
test.describe
|
|
.serial('generated edge-case fixtures in pinned ffmpeg.wasm', () => {
|
|
test('probes attached cover art without treating it as the playback video stream', async ({
|
|
page,
|
|
}) => {
|
|
test.setTimeout(180_000);
|
|
const runtime = observeRuntime(page);
|
|
await page.goto('/');
|
|
await initializeSingleThread(page);
|
|
|
|
await mediaInput(page).setInputFiles(
|
|
join(GENERATED_FIXTURES, 'attached-cover.mp3')
|
|
);
|
|
await expect(page.locator('.source-summary .phase--ready')).toHaveText(
|
|
'Ready',
|
|
{ timeout: 60_000 }
|
|
);
|
|
await expect(page.locator('.source-summary')).toContainText(
|
|
'attached-cover.mp3'
|
|
);
|
|
await expect(page.locator('.source-summary')).toContainText('0:01.08');
|
|
await expect(page.locator('.quick-preview audio')).toHaveAttribute(
|
|
'src',
|
|
/^blob:/u
|
|
);
|
|
await expect(page.locator('.quick-preview video')).toHaveCount(0);
|
|
await expect(
|
|
page.getByRole('checkbox', { name: /#0 · mp3/u })
|
|
).toBeChecked();
|
|
await expect(
|
|
page.getByRole('checkbox', { name: /#1 · png/u })
|
|
).toBeChecked();
|
|
|
|
await page.getByRole('tab', { name: 'Edit' }).click();
|
|
const inspectorStreams = page.locator('.inspector-streams');
|
|
await expect(
|
|
inspectorStreams.locator('li').filter({ hasText: '#0 · mp3' })
|
|
).toContainText('audio');
|
|
await expect(
|
|
inspectorStreams.locator('li').filter({ hasText: '#1 · png' })
|
|
).toContainText('video');
|
|
|
|
const advanced = page.locator('.advanced-operations');
|
|
await advanced.getByRole('tab', { name: 'Metadata policies' }).click();
|
|
await expect(advanced.getByLabel('Cover art')).toHaveValue('keep');
|
|
await advanced
|
|
.getByText('Other stream dispositions', { exact: true })
|
|
.nth(1)
|
|
.click();
|
|
await expect(
|
|
advanced.getByRole('checkbox', {
|
|
name: 'Attached pic stream #1',
|
|
})
|
|
).toBeChecked();
|
|
|
|
assertLocalOnly(runtime);
|
|
});
|
|
|
|
test('bounds a truncated-file probe failure, cleans up, and probes a valid file next', async ({
|
|
page,
|
|
}) => {
|
|
test.setTimeout(180_000);
|
|
const runtime = observeRuntime(page);
|
|
await page.goto('/');
|
|
await initializeSingleThread(page);
|
|
|
|
const probeStartedAt = Date.now();
|
|
await mediaInput(page).setInputFiles(
|
|
join(GENERATED_FIXTURES, 'truncated.mp4')
|
|
);
|
|
const malformedCard = page
|
|
.locator('.media-card')
|
|
.filter({ hasText: 'truncated.mp4' });
|
|
await expect(malformedCard.locator('.phase--error')).toContainText(
|
|
'ffprobe did not find any media streams.',
|
|
{ timeout: 30_000 }
|
|
);
|
|
expect(Date.now() - probeStartedAt).toBeLessThan(30_000);
|
|
await expect(
|
|
page
|
|
.locator('.engine-pill')
|
|
.filter({ hasText: 'Single-threaded compatibility mode' })
|
|
).toBeVisible();
|
|
|
|
await mediaInput(page).setInputFiles(PRIMARY_FIXTURE);
|
|
const validCard = page
|
|
.locator('.media-card')
|
|
.filter({ hasText: 'pattern-av.mp4' });
|
|
await expect(validCard.locator('.phase--ready')).toContainText('1 audio', {
|
|
timeout: 60_000,
|
|
});
|
|
await validCard.click();
|
|
await expect(
|
|
page.getByRole('checkbox', { name: /#0 · h264/u })
|
|
).toBeChecked();
|
|
await expect(
|
|
page.getByRole('checkbox', { name: /#1 · aac/u })
|
|
).toBeChecked();
|
|
await expect(page.getByRole('alert')).toHaveCount(0);
|
|
|
|
assertLocalOnly(runtime);
|
|
});
|
|
});
|