mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
test: expand E2E-Docker coverage to all 47 tools with auth-failure tests
This commit is contained in:
@@ -398,3 +398,37 @@ test.describe("Image Enhancement", () => {
|
|||||||
expect(body.processedSize).not.toBe(body.originalSize);
|
expect(body.processedSize).not.toBe(body.originalSize);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("adjust-colors without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/adjust-colors", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ brightness: 20 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("strip-metadata without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/strip-metadata", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.jpg", mimeType: "image/jpeg", buffer: JPG_WITH_EXIF },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("edit-metadata without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/edit-metadata", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.jpg", mimeType: "image/jpeg", buffer: JPG_100x100 },
|
||||||
|
settings: JSON.stringify({ artist: "Test" }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -754,3 +754,37 @@ test.describe("AI Feature Bundle Status", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("remove-background without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/remove-background", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("upscale without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/upscale", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
|
||||||
|
settings: JSON.stringify({ scale: 2, model: "auto" }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ocr without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/ocr", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: TINY_PNG },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { mkdirSync } from "node:fs";
|
import { mkdirSync } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { expect, test as setup } from "@playwright/test";
|
import { test as setup } from "@playwright/test";
|
||||||
|
|
||||||
const authFile = path.join(__dirname, "..", "..", ".playwright", ".auth", "analytics-user.json");
|
const authFile = path.join(__dirname, "..", "..", ".playwright", ".auth", "analytics-user.json");
|
||||||
|
|
||||||
@@ -21,11 +21,18 @@ setup("authenticate", async ({ page }) => {
|
|||||||
await acceptBtn.waitFor({ state: "visible", timeout: 15_000 });
|
await acceptBtn.waitFor({ state: "visible", timeout: 15_000 });
|
||||||
await acceptBtn.click();
|
await acceptBtn.click();
|
||||||
// Consent page does window.location.href = "/" (full reload)
|
// Consent page does window.location.href = "/" (full reload)
|
||||||
await page.waitForURL("/", { timeout: 30_000 });
|
await page.waitForURL((url) => !url.pathname.includes("analytics-consent"), {
|
||||||
|
timeout: 30_000,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point we should be on the home page
|
// At this point we should be on the home page (or at least past the consent page)
|
||||||
await expect(page).toHaveURL("/");
|
await page.waitForURL(
|
||||||
|
(url) => !url.pathname.includes("login") && !url.pathname.includes("analytics-consent"),
|
||||||
|
{
|
||||||
|
timeout: 30_000,
|
||||||
|
},
|
||||||
|
);
|
||||||
mkdirSync(path.dirname(authFile), { recursive: true });
|
mkdirSync(path.dirname(authFile), { recursive: true });
|
||||||
await page.context().storageState({ path: authFile });
|
await page.context().storageState({ path: authFile });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -581,3 +581,39 @@ test.describe("Convert format matrix", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("gif-tools without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/gif-tools", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "animated.gif", mimeType: "image/gif", buffer: ANIMATED_GIF },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("image-to-base64 without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/image-to-base64", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("image-to-pdf without token returns 401", async ({ request }) => {
|
||||||
|
const { body, contentType } = buildMultipart(
|
||||||
|
[{ name: "file", filename: "test.jpg", contentType: "image/jpeg", buffer: JPG_100x100 }],
|
||||||
|
[{ name: "settings", value: JSON.stringify({ pageSize: "A4" }) }],
|
||||||
|
);
|
||||||
|
const res = await request.post("/api/v1/tools/image-to-pdf", {
|
||||||
|
headers: { "Content-Type": contentType },
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -589,3 +589,57 @@ test.describe("Content-Aware Resize", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("collage without token returns 401", async ({ request }) => {
|
||||||
|
const { body, contentType } = buildMultipart(
|
||||||
|
[
|
||||||
|
{ name: "file", filename: "a.png", contentType: "image/png", buffer: PNG_200x150 },
|
||||||
|
{ name: "file", filename: "b.jpg", contentType: "image/jpeg", buffer: JPG_100x100 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
name: "settings",
|
||||||
|
value: JSON.stringify({ templateId: "2-h-equal", width: 400 }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
const res = await request.post("/api/v1/tools/collage", {
|
||||||
|
headers: { "Content-Type": contentType },
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("stitch without token returns 401", async ({ request }) => {
|
||||||
|
const { body, contentType } = buildMultipart(
|
||||||
|
[
|
||||||
|
{ name: "file", filename: "a.png", contentType: "image/png", buffer: PNG_200x150 },
|
||||||
|
{ name: "file", filename: "b.jpg", contentType: "image/jpeg", buffer: JPG_100x100 },
|
||||||
|
],
|
||||||
|
[{ name: "settings", value: JSON.stringify({ direction: "horizontal" }) }],
|
||||||
|
);
|
||||||
|
const res = await request.post("/api/v1/tools/stitch", {
|
||||||
|
headers: { "Content-Type": contentType },
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("text-overlay without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/text-overlay", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({
|
||||||
|
text: "Test",
|
||||||
|
fontSize: 24,
|
||||||
|
color: "#FFFFFF",
|
||||||
|
position: "center",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -618,3 +618,37 @@ test.describe("Sharpening", () => {
|
|||||||
expect(body.downloadUrl).toBeTruthy();
|
expect(body.downloadUrl).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("resize without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/resize", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ width: 100 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("crop without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/crop", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ left: 0, top: 0, width: 50, height: 50 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("convert without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/convert", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ format: "jpg" }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -717,3 +717,37 @@ test.describe("PDF to Image — additional formats", () => {
|
|||||||
expect(body.downloadUrl || body.pages || body.jobId).toBeTruthy();
|
expect(body.downloadUrl || body.pages || body.jobId).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("svg-to-raster without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/svg-to-raster", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.svg", mimeType: "image/svg+xml", buffer: SVG_100x100 },
|
||||||
|
settings: JSON.stringify({ format: "png", width: 200 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("vectorize without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/vectorize", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pdf-to-image without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/pdf-to-image", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.pdf", mimeType: "application/pdf", buffer: PDF_3PAGE },
|
||||||
|
settings: JSON.stringify({ format: "png", dpi: 150, pages: "1" }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -543,3 +543,27 @@ test.describe("Border — extended", () => {
|
|||||||
expect(body.processedSize).toBeGreaterThan(0);
|
expect(body.processedSize).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("split without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/split", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ columns: 2, rows: 2 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("border without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/border", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({ size: 10, color: "#ff0000" }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -734,3 +734,41 @@ test.describe("Content-Aware Resize — extended", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("optimize-for-web without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/optimize-for-web", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.jpg", mimeType: "image/jpeg", buffer: JPG_100x100 },
|
||||||
|
settings: JSON.stringify({ maxWidth: 800, quality: 75 }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("favicon without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/favicon", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("replace-color without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/replace-color", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({
|
||||||
|
targetColor: "#ffffff",
|
||||||
|
replacementColor: "#000000",
|
||||||
|
tolerance: 30,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -758,3 +758,32 @@ test.describe("QR Read", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("info without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/info", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("qr-generate without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/qr-generate", {
|
||||||
|
data: { text: "https://snapotter.app", size: 512 },
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("color-palette without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/color-palette", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -538,3 +538,43 @@ test.describe("Compose — extended", () => {
|
|||||||
expect(json.downloadUrl).toBeTruthy();
|
expect(json.downloadUrl).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Auth Failure ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test.describe("Auth failure", () => {
|
||||||
|
test("watermark-text without token returns 401", async ({ request }) => {
|
||||||
|
const res = await request.post("/api/v1/tools/watermark-text", {
|
||||||
|
multipart: {
|
||||||
|
file: { name: "test.png", mimeType: "image/png", buffer: PNG_200x150 },
|
||||||
|
settings: JSON.stringify({
|
||||||
|
text: "TEST",
|
||||||
|
fontSize: 24,
|
||||||
|
color: "#ff0000",
|
||||||
|
opacity: 50,
|
||||||
|
position: "center",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("compose without token returns 401", async ({ request }) => {
|
||||||
|
const { body, contentType } = buildMultipart(
|
||||||
|
[
|
||||||
|
{ name: "file", filename: "base.png", contentType: "image/png", buffer: PNG_200x150 },
|
||||||
|
{
|
||||||
|
name: "overlay",
|
||||||
|
filename: "overlay.webp",
|
||||||
|
contentType: "image/webp",
|
||||||
|
buffer: WEBP_50x50,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[{ name: "settings", value: JSON.stringify({ x: 0, y: 0, opacity: 100 }) }],
|
||||||
|
);
|
||||||
|
const res = await request.post("/api/v1/tools/compose", {
|
||||||
|
headers: { "Content-Type": contentType },
|
||||||
|
data: body,
|
||||||
|
});
|
||||||
|
expect(res.status()).toBe(401);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user