Files
main_frontend/tests/e2e/specs/upload/file-extension.integration.spec.ts
2026-04-04 14:51:40 +03:00

350 lines
9.4 KiB
TypeScript

import { test, expect } from "#tests/e2e/fixtures/upload"
test.describe("File Type and Extension Validation (Integration)", () => {
test.describe("Input Accept Attribute", () => {
test("should restrict file input to video/* MIME types", async ({
uploadPage,
}) => {
await expect(uploadPage.fileInput).toHaveAttribute(
"accept",
"video/*",
)
})
})
test.describe("Valid Video Files", () => {
test("should accept and upload an MP4 file", async ({ uploadPage }) => {
const { page, testVideoPath } = uploadPage
await uploadPage.uploadFile(testVideoPath)
await expect(
page.locator("[data-testid='VerifyStep']"),
).toBeVisible({ timeout: 30_000 })
await expect(
page
.locator("[data-testid='VerifyStep']")
.getByText("Готово к обработке"),
).toBeVisible({ timeout: 10_000 })
})
test("should attempt upload for a WebM file", async ({ uploadPage }) => {
const { page, dropZone } = uploadPage
// Create a minimal buffer pretending to be WebM
const webmBuffer = Buffer.from([
0x1a, 0x45, 0xdf, 0xa3, // EBML header magic
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
])
await uploadPage.uploadBuffer("test.webm", "video/webm", webmBuffer)
// Upload should begin (progress or error — both prove the file was sent)
const uploadStarted = await Promise.race([
dropZone
.getByText("Загрузка файла...")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
])
expect(uploadStarted).toBe(true)
})
test("should attempt upload for an MOV file", async ({ uploadPage }) => {
const { page, dropZone } = uploadPage
// Minimal ftyp atom for MOV
const movBuffer = Buffer.from([
0x00, 0x00, 0x00, 0x14, // size: 20
0x66, 0x74, 0x79, 0x70, // ftyp
0x71, 0x74, 0x20, 0x20, // qt (QuickTime)
0x00, 0x00, 0x00, 0x00, // minor version
0x71, 0x74, 0x20, 0x20, // compatible brand
])
await uploadPage.uploadBuffer(
"test.mov",
"video/quicktime",
movBuffer,
)
const uploadStarted = await Promise.race([
dropZone
.getByText("Загрузка файла...")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
])
expect(uploadStarted).toBe(true)
})
})
test.describe("Non-Video Files (Bypass via setInputFiles)", () => {
test("should attempt to upload a non-video file (no client-side validation)", async ({
uploadPage,
}) => {
const { page, dropZone } = uploadPage
// setInputFiles bypasses the accept attribute — proves no JS validation
const txtBuffer = Buffer.from("Hello, this is a text file")
await uploadPage.uploadBuffer(
"document.txt",
"text/plain",
txtBuffer,
)
// Upload should begin regardless — component has no file type check
const uploadStarted = await Promise.race([
dropZone
.getByText("Загрузка файла...")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 10_000 })
.then(() => true)
.catch(() => false),
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 10_000 })
.then(() => true)
.catch(() => false),
])
expect(uploadStarted).toBe(true)
})
test("should attempt to upload a PDF file", async ({ uploadPage }) => {
const { page, dropZone } = uploadPage
const pdfBuffer = Buffer.from("%PDF-1.4 fake content")
await uploadPage.uploadBuffer(
"document.pdf",
"application/pdf",
pdfBuffer,
)
const uploadStarted = await Promise.race([
dropZone
.getByText("Загрузка файла...")
.waitFor({ timeout: 5_000 })
.then(() => true)
.catch(() => false),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 10_000 })
.then(() => true)
.catch(() => false),
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 10_000 })
.then(() => true)
.catch(() => false),
])
expect(uploadStarted).toBe(true)
})
})
test.describe("Edge Cases — File Names", () => {
test("should handle a file with Unicode characters in the name", async ({
uploadPage,
}) => {
const { page, dropZone, testVideoPath } = uploadPage
const fs = await import("node:fs")
const videoContent = fs.readFileSync(testVideoPath)
await uploadPage.uploadBuffer(
"видео_тест_2026.mp4",
"video/mp4",
videoContent,
)
// Should upload successfully
const result = await Promise.race([
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 30_000 })
.then(() => "verify" as const),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 30_000 })
.then(() => "error" as const),
])
// Both outcomes are valid — we verify no crash
expect(["verify", "error"]).toContain(result)
})
test("should handle a file with special characters in the name", async ({
uploadPage,
}) => {
const { page, dropZone, testVideoPath } = uploadPage
const fs = await import("node:fs")
const videoContent = fs.readFileSync(testVideoPath)
await uploadPage.uploadBuffer(
"test file (1) [final].mp4",
"video/mp4",
videoContent,
)
const result = await Promise.race([
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 30_000 })
.then(() => "verify" as const),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 30_000 })
.then(() => "error" as const),
])
expect(["verify", "error"]).toContain(result)
})
test("should handle a zero-byte video file", async ({ uploadPage }) => {
const { page, dropZone } = uploadPage
const emptyBuffer = Buffer.alloc(0)
await uploadPage.uploadBuffer("empty.mp4", "video/mp4", emptyBuffer)
// Should attempt upload, likely fail server-side
const result = await Promise.race([
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 15_000 })
.then(() => "error" as const),
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 15_000 })
.then(() => "verify" as const),
])
expect(["error", "verify"]).toContain(result)
})
test("should handle a file with no extension", async ({
uploadPage,
}) => {
const { page, dropZone, testVideoPath } = uploadPage
const fs = await import("node:fs")
const videoContent = fs.readFileSync(testVideoPath)
await uploadPage.uploadBuffer(
"videofile",
"video/mp4",
videoContent,
)
const result = await Promise.race([
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 30_000 })
.then(() => "verify" as const),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 30_000 })
.then(() => "error" as const),
])
expect(["verify", "error"]).toContain(result)
})
test("should handle a file with double extension", async ({
uploadPage,
}) => {
const { page, dropZone, testVideoPath } = uploadPage
const fs = await import("node:fs")
const videoContent = fs.readFileSync(testVideoPath)
await uploadPage.uploadBuffer(
"video.mp4.mp4",
"video/mp4",
videoContent,
)
const result = await Promise.race([
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 30_000 })
.then(() => "verify" as const),
dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 30_000 })
.then(() => "error" as const),
])
expect(["verify", "error"]).toContain(result)
})
})
test.describe("FormData Payload Verification", () => {
test("should send file in FormData and include correct folder path", async ({
uploadPage,
}) => {
const { page, projectId, testVideoPath } = uploadPage
let requestFired = false
let hasAuthHeader = false
let requestUrl = ""
page.on("request", (req) => {
if (req.url().includes("/api/files/upload")) {
requestFired = true
requestUrl = req.url()
hasAuthHeader = !!req.headers()["authorization"]
}
})
await uploadPage.uploadFile(testVideoPath)
// Wait for the request to fire
await expect(async () => {
expect(requestFired).toBe(true)
}).toPass({ timeout: 10_000 })
expect(requestUrl).toContain("/api/files/upload")
expect(hasAuthHeader).toBe(true)
// Wait for upload to complete (verify or error)
await Promise.race([
page
.locator("[data-testid='VerifyStep']")
.waitFor({ timeout: 30_000 }),
uploadPage.dropZone
.getByText("Не удалось загрузить файл")
.waitFor({ timeout: 30_000 }),
])
})
})
})