feat: use export testing
This commit is contained in:
@@ -31,6 +31,19 @@ jobs:
|
||||
- run: npm ci
|
||||
- run: npx tsc --noEmit
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
- run: npx playwright install --with-deps chromium
|
||||
- run: npm run test:browser
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
+4
-1
@@ -29,4 +29,7 @@ release/**
|
||||
|
||||
# Playwright
|
||||
test-results
|
||||
playwright-report/
|
||||
playwright-report/
|
||||
|
||||
# Vitest browser mode screenshots
|
||||
__screenshots__/
|
||||
Generated
+1721
-196
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
"test": "vitest --run",
|
||||
"test:watch": "vitest",
|
||||
"build-vite": "tsc && vite build",
|
||||
"test:browser": "vitest --config vitest.browser.config.ts --run",
|
||||
"test:e2e": "playwright test",
|
||||
"prepare": "husky"
|
||||
},
|
||||
@@ -82,6 +83,8 @@
|
||||
"@types/react-dom": "^18.2.21",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"@vitest/browser": "^4.0.16",
|
||||
"@vitest/browser-playwright": "^4.0.16",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"electron": "^39.2.7",
|
||||
"electron-builder": "^26.7.0",
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import sampleVideoUrl from "../../../tests/fixtures/sample.webm?url";
|
||||
import { GifExporter } from "./gifExporter";
|
||||
import type { ExportProgress } from "./types";
|
||||
|
||||
describe("GifExporter (real browser)", () => {
|
||||
it("exports a valid GIF blob from a real video", async () => {
|
||||
const progressEvents: ExportProgress[] = [];
|
||||
|
||||
const exporter = new GifExporter({
|
||||
videoUrl: sampleVideoUrl,
|
||||
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: (p) => progressEvents.push(p),
|
||||
});
|
||||
|
||||
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/);
|
||||
|
||||
expect(result.blob!.size).toBeGreaterThan(1024);
|
||||
|
||||
expect(progressEvents.length).toBeGreaterThan(0);
|
||||
|
||||
const finalizing = progressEvents.filter((p) => p.phase === "finalizing");
|
||||
expect(finalizing.length).toBeGreaterThan(0);
|
||||
expect(finalizing.at(-1)!.percentage).toBe(100);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import sampleVideoUrl from "../../../tests/fixtures/sample.webm?url";
|
||||
import type { ExportProgress } from "./types";
|
||||
import { VideoExporter } from "./videoExporter";
|
||||
|
||||
describe("VideoExporter (real browser)", () => {
|
||||
it("exports a valid MP4 blob from a real video", async () => {
|
||||
const progressEvents: ExportProgress[] = [];
|
||||
|
||||
const exporter = new VideoExporter({
|
||||
videoUrl: sampleVideoUrl,
|
||||
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: (p) => progressEvents.push(p),
|
||||
});
|
||||
|
||||
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");
|
||||
|
||||
expect(result.blob!.size).toBeGreaterThan(1024);
|
||||
|
||||
expect(progressEvents.length).toBeGreaterThan(0);
|
||||
|
||||
const finalizing = progressEvents.filter((p) => p.phase === "finalizing");
|
||||
expect(finalizing.length).toBeGreaterThan(0);
|
||||
expect(finalizing.at(-1)!.percentage).toBe(100);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import path from "node:path";
|
||||
import { playwright } from "@vitest/browser-playwright";
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/**/*.browser.test.{ts,tsx}"],
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: playwright({
|
||||
launch: {
|
||||
// Software WebGL so Pixi.js works in headless CI without a GPU.
|
||||
args: ["--enable-unsafe-swiftshader", "--use-gl=swiftshader"],
|
||||
},
|
||||
}),
|
||||
headless: true,
|
||||
instances: [{ browser: "chromium" }],
|
||||
},
|
||||
// GIF export encodes frames and renders — give it plenty of time.
|
||||
testTimeout: 120_000,
|
||||
hookTimeout: 30_000,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
// Let Vite treat .webm and .wasm files as static assets importable via `?url`.
|
||||
assetsInclude: ["**/*.webm"],
|
||||
});
|
||||
Reference in New Issue
Block a user