This commit is contained in:
Daniil
2026-04-04 14:51:40 +03:00
parent 10a1d28f77
commit 0523ef3d72
191 changed files with 12065 additions and 2658 deletions
+130
View File
@@ -0,0 +1,130 @@
import { API_URL } from "./config"
const E2E_API_URL = API_URL
const DEFAULT_PASSWORD = "E2eTestPass123"
export interface TestUser {
id: string
username: string
email: string
firstName: string
lastName: string
password: string
accessToken: string
refreshToken: string
}
interface IRegisterTestUserOptions {
firstName?: string
lastName?: string
password?: string
}
export const registerTestUser = async (
options?: IRegisterTestUserOptions,
): Promise<TestUser> => {
const suffix =
Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
const username = `e2e_${suffix}`
const firstName = options?.firstName ?? "E2E"
const lastName = options?.lastName ?? "Test"
const password = options?.password ?? DEFAULT_PASSWORD
const email = `${username}@test.local`
const response = await fetch(`${E2E_API_URL}/auth/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username,
email,
password,
first_name: firstName,
last_name: lastName,
}),
})
if (!response.ok) {
throw new Error(
`Register failed: ${response.status} ${await response.text()}`,
)
}
const data = await response.json()
return {
id: data.user.id,
username: data.user.username,
email,
firstName,
lastName,
password,
accessToken: data.access,
refreshToken: data.refresh,
}
}
/* ------------------------------------------------------------------ */
/* Admin helpers (shared by upload / silence / etc. fixtures) */
/* ------------------------------------------------------------------ */
export interface AuthTokens {
accessToken: string
refreshToken: string
}
export async function loginAsAdmin(): Promise<AuthTokens> {
const res = await fetch(`${E2E_API_URL}/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: "admin", password: "admin" }),
})
if (!res.ok) {
throw new Error(`Admin login failed: ${res.status} ${await res.text()}`)
}
const data = await res.json()
return {
accessToken: data.access,
refreshToken: data.refresh,
}
}
export async function createProjectViaApi(
token: string,
name: string,
): Promise<string> {
const res = await fetch(`${E2E_API_URL}/api/projects/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ name, language: "auto" }),
})
if (!res.ok) {
throw new Error(
`Create project failed: ${res.status} ${await res.text()}`,
)
}
const data = await res.json()
return data.id
}
export async function deleteProjectViaApi(
token: string,
projectId: string,
): Promise<void> {
const res = await fetch(`${E2E_API_URL}/api/projects/${projectId}/`, {
method: "DELETE",
headers: { Authorization: `Bearer ${token}` },
})
if (!res.ok && res.status !== 404) {
throw new Error(`Delete project failed: ${res.status}`)
}
}
export { DEFAULT_PASSWORD as TEST_USER_PASSWORD, E2E_API_URL }
+20
View File
@@ -0,0 +1,20 @@
/**
* Central configuration for all E2E test ports and URLs.
* Change values here instead of hardcoding in fixtures / config.
*/
/** Real backend API */
export const API_PORT = 8000
export const API_URL = `http://localhost:${API_PORT}`
/** Lightweight mock API server (used by unit/component Playwright tests) */
export const MOCK_API_PORT = 4444
export const MOCK_API_URL = `http://localhost:${MOCK_API_PORT}`
/** Frontend dev server for unit/component tests (uses mock API) */
export const FRONTEND_MOCK_PORT = 3005
export const FRONTEND_MOCK_URL = `http://localhost:${FRONTEND_MOCK_PORT}`
/** Frontend dev server for integration tests (uses real backend) */
export const FRONTEND_INTEGRATION_PORT = 3000
export const FRONTEND_INTEGRATION_URL = `http://localhost:${FRONTEND_INTEGRATION_PORT}`
+71
View File
@@ -0,0 +1,71 @@
import { createServer } from "node:http"
import { MOCK_API_PORT } from "./config"
const PORT = MOCK_API_PORT
const DEFAULT_USER = {
id: "00000000-0000-0000-0000-000000000001",
username: "testuser",
email: "test@example.com",
first_name: "Test",
last_name: "User",
phone_number: null,
avatar: null,
email_verified: true,
phone_verified: false,
is_active: true,
is_staff: false,
is_superuser: false,
date_joined: "2025-01-01T00:00:00Z",
}
const json = (res: import("node:http").ServerResponse, status: number, body: unknown) => {
res.writeHead(status, { "Content-Type": "application/json" })
res.end(JSON.stringify(body))
}
const server = createServer((req, res) => {
const url = new URL(req.url ?? "/", `http://localhost:${PORT}`)
// CORS headers for browser requests
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type")
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
if (req.method === "OPTIONS") {
res.writeHead(204)
res.end()
return
}
// GET /api/ping/ — server health check
if (url.pathname === "/api/ping/" && req.method === "GET") {
return json(res, 200, { status: "ok" })
}
// GET /api/users/me/ — token verification
if (url.pathname === "/api/users/me/" && req.method === "GET") {
const auth = req.headers.authorization
if (auth?.startsWith("Bearer ")) {
return json(res, 200, DEFAULT_USER)
}
return json(res, 401, { detail: "Not authenticated" })
}
// POST /auth/login — login endpoint
if (url.pathname === "/auth/login" && req.method === "POST") {
return json(res, 200, {
user: DEFAULT_USER,
access: "fake-access-jwt",
refresh: "fake-refresh-jwt",
})
}
// Fallback: 404 for any unhandled route
json(res, 404, { detail: "Not found" })
})
server.listen(PORT, () => {
console.log(`Mock API server running on http://localhost:${PORT}`)
})