fix: just use one test

This commit is contained in:
Marc Diaz
2026-04-23 17:37:08 -04:00
parent d1087af63c
commit cffca5f2ff
7 changed files with 29 additions and 79 deletions
+7 -5
View File
@@ -7222,13 +7222,15 @@
"license": "MIT"
},
"node_modules/baseline-browser-mapping": {
"version": "2.8.15",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.15.tgz",
"integrity": "sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q==",
"version": "2.10.21",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.21.tgz",
"integrity": "sha512-Q+rUQ7Uz8AHM7DEaNdwvfFCTq7a43lNTzuS94eiWqwyxfV/wJv+oUivef51T91mmRY4d4A1u9rcSvkeufCVXlA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"baseline-browser-mapping": "dist/cli.js"
"baseline-browser-mapping": "dist/cli.cjs"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/bcrypt-pbkdf": {
@@ -1,6 +1,5 @@
import { describe, expect, it } from "vitest";
import sampleVideoUrl from "../../../tests/fixtures/sample.webm?url";
import inflatedDurationVideoUrl from "../../../tests/fixtures/sample-inflated-duration.webm?url";
import { GifExporter } from "./gifExporter";
import type { ExportProgress } from "./types";
@@ -41,33 +40,4 @@ describe("GifExporter (real browser)", () => {
expect(finalizing.length).toBeGreaterThan(0);
expect(finalizing.at(-1)!.percentage).toBe(100);
});
it("exports successfully when container duration is inflated beyond actual content", async () => {
const exporter = new GifExporter({
videoUrl: inflatedDurationVideoUrl,
width: 320,
height: 180,
frameRate: 15,
loop: true,
sizePreset: "medium",
wallpaper: "#1a1a2e",
zoomRegions: [],
showShadow: false,
shadowIntensity: 0,
showBlur: false,
cropRegion: { x: 0, y: 0, width: 1, height: 1 },
onProgress: () => {
/**noop**/
},
});
const result = await exporter.export();
expect(result.success, result.error).toBe(true);
expect(result.blob).toBeInstanceOf(Blob);
const buf = await result.blob!.arrayBuffer();
const header = new TextDecoder().decode(new Uint8Array(buf, 0, 6));
expect(header).toMatch(/^GIF8[79]a/);
});
});
+14
View File
@@ -83,4 +83,18 @@ describe("shouldFailDecodeEndedEarly", () => {
}),
).toBe(true);
});
it("does not fail when decoder reached stream end but container tail is large (inflated metadata)", () => {
// Real case: ~20min video where container reports 1234s but actual stream
// ends at 1226s. Decoder correctly stops at 1226s (= streamDurationSec).
// The 8s tail is container metadata inflation, not a real decode failure.
expect(
shouldFailDecodeEndedEarly({
cancelled: false,
lastDecodedFrameSec: 1226,
requiredEndSec: 1234,
streamDurationSec: 1226,
}),
).toBe(false);
});
});
+6 -13
View File
@@ -129,11 +129,8 @@ export function shouldFailDecodeEndedEarly({
const decodedNearStreamEnd =
Math.abs(lastDecodedFrameSec - streamDurationSec) <= STREAM_DURATION_MATCH_TOLERANCE_SEC;
if (
decodedNearStreamEnd &&
metadataTailSec > 0 &&
metadataTailSec <= METADATA_TAIL_TOLERANCE_SEC
) {
const maxTailSec = Math.max(METADATA_TAIL_TOLERANCE_SEC, requiredEndSec * 0.01);
if (decodedNearStreamEnd && metadataTailSec > 0 && metadataTailSec <= maxTailSec) {
return false;
}
@@ -246,13 +243,14 @@ export class StreamingVideoDecoder {
const hintedDurationSec = Math.max(containerDurationSec, streamDurationSec, 0);
const scanEndSec =
hintedDurationSec > 0 ? hintedDurationSec + 0.5 : SCAN_UNBOUNDED_FALLBACK_SEC;
let maxPacketTimestampUs = 0;
let maxPacketEndUs = 0;
const scanReader = this.demuxer.read("video", 0, scanEndSec).getReader();
try {
while (true) {
const { done, value } = await scanReader.read();
if (done || !value) break;
if (value.timestamp > maxPacketTimestampUs) maxPacketTimestampUs = value.timestamp;
const endUs = value.timestamp + (value.duration ?? 0);
if (endUs > maxPacketEndUs) maxPacketEndUs = endUs;
}
} finally {
try {
@@ -261,12 +259,7 @@ export class StreamingVideoDecoder {
/* already closed */
}
}
// Use last frame's timestamp + one frame duration. The `duration` field on the last
// packet in a WebM container is frequently inflated by the demuxer to match the
// container's declared end, causing validateDuration to see no divergence and
// propagate a duration that the decoder can never actually reach.
const typicalFrameDurationUs = Math.ceil(1_000_000 / frameRate);
const scannedDuration = (maxPacketTimestampUs + typicalFrameDurationUs) / 1_000_000;
const scannedDuration = maxPacketEndUs / 1_000_000;
const validatedDuration = validateDuration(mediaInfo.duration, scannedDuration);
this.metadata = {
@@ -1,6 +1,5 @@
import { describe, expect, it } from "vitest";
import sampleVideoUrl from "../../../tests/fixtures/sample.webm?url";
import inflatedDurationVideoUrl from "../../../tests/fixtures/sample-inflated-duration.webm?url";
import type { ExportProgress } from "./types";
import { VideoExporter } from "./videoExporter";
@@ -41,33 +40,4 @@ describe("VideoExporter (real browser)", () => {
expect(finalizing.length).toBeGreaterThan(0);
expect(finalizing.at(-1)!.percentage).toBe(100);
});
it("exports successfully when container duration is inflated beyond actual content", async () => {
const exporter = new VideoExporter({
videoUrl: inflatedDurationVideoUrl,
width: 320,
height: 180,
frameRate: 15,
bitrate: 1_000_000,
wallpaper: "#1a1a2e",
zoomRegions: [],
showShadow: false,
shadowIntensity: 0,
showBlur: false,
cropRegion: { x: 0, y: 0, width: 1, height: 1 },
onProgress: () => {
/**noop**/
},
});
const result = await exporter.export();
expect(result.success, result.error).toBe(true);
expect(result.blob).toBeInstanceOf(Blob);
const buf = await result.blob!.arrayBuffer();
const bytes = new Uint8Array(buf);
const ftyp = new TextDecoder().decode(bytes.slice(4, 8));
expect(ftyp).toBe("ftyp");
});
});
Binary file not shown.
+2 -1
View File
@@ -4,8 +4,9 @@ import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
environment: "node",
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
exclude: ["src/**/*.browser.test.{ts,tsx}", "node_modules"],
},
resolve: {
alias: {