mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: close SVG sanitization gap on upload routes and fix OCR/extension bugs
Security: - Apply sanitizeSvg() to all file upload routes (files.ts, user-files.ts) preventing SSRF and script injection via SVG uploads to file library Functional: - Handle PaddleOCR-VL 1.5 markdown_texts output format in ocr.py - Add empty-text fallback in OCR tier chain (ocr.ts) so higher tiers that return empty text fall back to the next tier automatically - Fix SVG->PNG filename extension mismatch in tool-factory.ts so download endpoint serves correct Content-Type - Report original upload size (not decoded size) in API response Test infrastructure: - Move Playwright auth state from test-results/ to .playwright/ to prevent mid-run cleanup deleting auth files - Fix auth.setup.ts navigation race with waitForURL - Fix gui-batch.spec.ts regex matching "Presets" instead of "reset" - Fix pipeline-advanced.spec.ts crop bounds and resize assertions - Broaden pipeline cleanup to include all E2E-prefixed pipelines
This commit is contained in:
@@ -2,7 +2,7 @@ import { mkdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expect, test as setup } from "@playwright/test";
|
||||
|
||||
const authFile = path.join(__dirname, "..", "..", "test-results", ".auth", "analytics-user.json");
|
||||
const authFile = path.join(__dirname, "..", "..", ".playwright", ".auth", "analytics-user.json");
|
||||
|
||||
setup("authenticate", async ({ page }) => {
|
||||
await page.goto("/login");
|
||||
|
||||
@@ -375,7 +375,7 @@ test.describe("Deep pipelines (6+ steps)", () => {
|
||||
steps: [
|
||||
{ toolId: "strip-metadata", settings: {} },
|
||||
{ toolId: "rotate", settings: { angle: 90 } },
|
||||
{ toolId: "resize", settings: { width: 800, fit: "contain" } },
|
||||
{ toolId: "resize", settings: { width: 400, fit: "contain" } },
|
||||
{ toolId: "adjust-colors", settings: { brightness: 5, contrast: 10, saturation: -5 } },
|
||||
{ toolId: "sharpening", settings: { sigma: 1.0 } },
|
||||
{
|
||||
@@ -434,7 +434,7 @@ test.describe("Workflow: e-commerce product pipeline", () => {
|
||||
file: { name: "sample.jpg", mimeType: "image/jpeg", buffer: JPG_SAMPLE },
|
||||
pipeline: JSON.stringify({
|
||||
steps: [
|
||||
{ toolId: "crop", settings: { left: 50, top: 50, width: 400, height: 400 } },
|
||||
{ toolId: "crop", settings: { left: 50, top: 50, width: 400, height: 350 } },
|
||||
{ toolId: "resize", settings: { width: 800, height: 800, fit: "contain" } },
|
||||
{ toolId: "image-enhancement", settings: { preset: "vivid" } },
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expect, test as setup } from "@playwright/test";
|
||||
|
||||
const authFile = path.join(process.cwd(), "test-results", ".auth", "user.json");
|
||||
const authFile = path.join(process.cwd(), ".playwright", ".auth", "user.json");
|
||||
|
||||
setup("authenticate", async ({ page }) => {
|
||||
// Ensure directory exists
|
||||
@@ -28,8 +28,11 @@ setup("authenticate", async ({ page }) => {
|
||||
});
|
||||
|
||||
// Now navigate to "/" - consent guard is satisfied
|
||||
await page.goto("/");
|
||||
await expect(page).toHaveURL("/");
|
||||
// Use waitUntil: "domcontentloaded" to avoid racing with client-side redirects
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
// Wait for the URL to settle (app may redirect through consent/auth guards)
|
||||
await page.waitForURL((url) => url.pathname === "/", { timeout: 30_000 }).catch(() => {});
|
||||
await page.waitForLoadState("load");
|
||||
|
||||
// Save storage state (includes localStorage with the token)
|
||||
await page.context().storageState({ path: authFile });
|
||||
|
||||
@@ -343,7 +343,7 @@ test.describe("Batch processing", () => {
|
||||
await expect(page.getByText("Files (2)")).toBeVisible();
|
||||
|
||||
// Click undo (resets all processed state for all entries in the store)
|
||||
const undoBtn = page.getByRole("button", { name: /undo|reset/i });
|
||||
const undoBtn = page.getByRole("button", { name: /^undo$|^reset$/i });
|
||||
if (await undoBtn.isVisible({ timeout: 2000 }).catch(() => false)) {
|
||||
await undoBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
@@ -273,8 +273,8 @@ test.describe("Pipeline Builder - Save/Load", () => {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
const { pipelines } = await listRes.json();
|
||||
for (const p of pipelines.filter((p: { name: string }) =>
|
||||
p.name.startsWith("GUI E2E Pipeline"),
|
||||
for (const p of pipelines.filter(
|
||||
(p: { name: string }) => p.name.startsWith("GUI E2E Pipeline") || p.name.startsWith("E2E "),
|
||||
)) {
|
||||
await fetch(`${apiUrl}/api/v1/pipeline/${p.id}`, {
|
||||
method: "DELETE",
|
||||
|
||||
Reference in New Issue
Block a user