Update admin theme/layout and refresh README details.

Align the project baseline with the latest admin interface styling and layout structure while documenting setup and usage updates in README.
This commit is contained in:
vlad
2026-07-14 17:12:28 +03:00
commit 86cc3fa541
278 changed files with 19416 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
import { expect, test } from "@playwright/test";
test("login page renders", async ({ page }) => {
await page.goto("/login");
await expect(page.getByRole("heading", { name: "Вход" })).toBeVisible();
});
+33
View File
@@ -0,0 +1,33 @@
import { expect, test } from "@playwright/test";
import { API_URL, fetchLatestToken, registerVerifyLogin, uniqueEmail } from "../helpers/api";
test.describe("§15.7 scenario 3: Password reset", () => {
test("forgot password → reset → login with new password", async ({ request }) => {
const email = uniqueEmail("e2e-reset");
const oldPassword = "Valid1234";
const newPassword = "ResetValid1";
await registerVerifyLogin(request, email, oldPassword);
const forgot = await request.post(`${API_URL}/api/v1/auth/forgot-password`, {
data: { email }
});
expect(forgot.ok()).toBeTruthy();
const token = await fetchLatestToken(request, email, "reset_password");
const reset = await request.post(`${API_URL}/api/v1/auth/reset-password`, {
data: { token, new_password: newPassword }
});
expect(reset.ok()).toBeTruthy();
const oldLogin = await request.post(`${API_URL}/api/v1/auth/login`, {
data: { email, password: oldPassword }
});
expect(oldLogin.status()).toBe(401);
const newLogin = await request.post(`${API_URL}/api/v1/auth/login`, {
data: { email, password: newPassword }
});
expect(newLogin.ok()).toBeTruthy();
});
});
@@ -0,0 +1,37 @@
import { expect, test } from "@playwright/test";
import { API_URL, registerVerifyLogin, uniqueEmail } from "../helpers/api";
function extractRefreshCookie(headers: Record<string, string>): string {
const setCookie = headers["set-cookie"] ?? headers["Set-Cookie"] ?? "";
const match = setCookie.match(/refresh_token=([^;]+)/);
if (!match) {
throw new Error("refresh_token cookie missing");
}
return match[1];
}
test.describe("§15.7 scenario 7: Refresh rotation", () => {
test("old refresh token rejected after rotation; reuse revokes family", async ({ request }) => {
const email = uniqueEmail("e2e-refresh");
await registerVerifyLogin(request, email);
const login = await request.post(`${API_URL}/api/v1/auth/login`, { data: { email, password: "Valid1234" } });
const oldRefresh = extractRefreshCookie(login.headers());
const rotated = await request.post(`${API_URL}/api/v1/auth/refresh`, {
headers: { Cookie: `refresh_token=${oldRefresh}` }
});
expect(rotated.ok()).toBeTruthy();
const newRefresh = extractRefreshCookie(rotated.headers());
const oldReuse = await request.post(`${API_URL}/api/v1/auth/refresh`, {
headers: { Cookie: `refresh_token=${oldRefresh}` }
});
expect(oldReuse.status()).toBe(401);
const familyReuse = await request.post(`${API_URL}/api/v1/auth/refresh`, {
headers: { Cookie: `refresh_token=${newRefresh}` }
});
expect(familyReuse.status()).toBe(401);
});
});
@@ -0,0 +1,40 @@
import { expect, test } from "@playwright/test";
import {
loginViaUi,
registerUser,
uniqueEmail,
verifyEmail
} from "../helpers/api";
test.describe("§15.7 scenario 2: Auth full journey", () => {
test("register → verify → login → profile edit → change password → logout", async ({
page,
request
}) => {
const email = uniqueEmail("e2e-flow");
const password = "Valid1234";
const newPassword = "NewValid1";
await registerUser(request, email, password);
await verifyEmail(request, email);
await loginViaUi(page, email, password);
await expect(page).toHaveURL(/\/profile$/);
await expect(page.getByText(email)).toBeVisible();
await page.getByLabel("Display name").fill("E2E User");
await page.getByRole("button", { name: "Save name" }).click();
await expect(page.getByText("Profile updated")).toBeVisible();
await page.getByPlaceholder("Current password").fill(password);
await page.getByPlaceholder("New password").fill(newPassword);
await page.getByRole("button", { name: "Change password" }).click();
await expect(page.getByText("Password changed")).toBeVisible();
await page.getByRole("button", { name: "Logout" }).click();
await expect(page).toHaveURL(/\/login$/);
await loginViaUi(page, email, newPassword);
await expect(page).toHaveURL(/\/profile$/);
});
});