Проект разделен на два репозитория

This commit is contained in:
mi
2026-08-14 15:42:45 +03:00
parent e06a77ee1d
commit bbef7a30c9
521 changed files with 2597 additions and 2302 deletions
@@ -0,0 +1,117 @@
import { expect, test } from "@playwright/test";
test("PWA-манифест и Service Worker доступны", async ({ request }) => {
const manifestResponse = await request.get("/manifest.json");
expect(manifestResponse.ok()).toBe(true);
const manifest = await manifestResponse.json();
expect(manifest).toMatchObject({
name: "HAN Chat",
display: "standalone",
icons: expect.arrayContaining([
expect.objectContaining({ src: "/icon-192.png", sizes: "192x192" }),
expect.objectContaining({ src: "/icon-512.png", sizes: "512x512" }),
]),
});
const serviceWorkerResponse = await request.get("/service-worker.js");
expect(serviceWorkerResponse.ok()).toBe(true);
expect(await serviceWorkerResponse.text()).toContain("precacheAndRoute");
});
test.beforeEach(async ({ page }) => {
await page.route("**/api/v1/public/app-config", (route) => route.fulfill({
json: {
auth: { phone_enabled: true, password_enabled: false },
operator: { call_phone: "+74950000000" },
messages: { max_text_length: 4000 },
ux: { idle_timeout_minutes: 15 },
attachments: { max_size_mb: 5, allowed_extensions: ["png", "pdf"], allowed_mime_types: ["image/png", "application/pdf"] },
consents: {
personal_data: {
required: true,
version: "2026-07-01",
document_url: "https://example.test/personal",
privacy_policy_document_url: "https://example.test/privacy",
},
user_agreement: { required: true, version: "2026-07-01", document_url: "https://example.test/agreement" },
marketing: { required: false, version: "2026-07-01", document_url: "https://example.test/marketing" },
},
},
}));
await page.route("**/api/v1/public/content", (route) => route.fulfill({
json: {
locale: "ru",
texts: { welcome: "Добро пожаловать в HAN Chat" },
popular_questions: [{ id: "visa", mnemonic: "visa", text: "Как оформить визу?" }],
version: "1",
},
}));
});
test("гостевой экран загружает публичный контент", async ({ page }) => {
await page.goto("/");
await expect(page.getByRole("heading", { name: "Привет! Я HAN" })).toBeVisible();
await expect(page.getByText("Добро пожаловать в HAN Chat")).toBeVisible();
await expect(page.getByRole("button", { name: "Как оформить визу?" })).toBeVisible();
await expect(page.getByRole("button", { name: "Голосовое сообщение" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Прикрепить файл" })).toBeVisible();
await expect(page.getByText("Продление патента через 14 дней")).toHaveCount(0);
await expect(page.getByRole("button", { name: "Чат" })).toBeEnabled();
await expect(page.getByRole("button", { name: "Оператор" })).toBeEnabled();
await expect(page.getByText("+74950000000")).toHaveCount(0);
await expect(page.getByText(/Гость/)).toHaveCount(0);
});
test("Колокольчик открывает центр уведомлений", async ({ page }) => {
await page.goto("/");
await page.getByRole("link", { name: "Уведомления" }).click();
await expect(page).toHaveURL(/\/notifications$/);
await expect(page.getByRole("heading", { name: "Центр уведомлений" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Уведомления доступны после входа" })).toBeVisible();
await expect(page.getByRole("button", { name: "Авторизоваться" })).toBeVisible();
});
test("первое сообщение требует обязательные согласия", async ({ page }) => {
await page.goto("/");
await page.getByLabel("Сообщение").fill("Здравствуйте");
await page.getByRole("button", { name: "Отправить" }).click();
await expect(page.getByRole("heading", { name: "Перед началом работы" })).toBeVisible();
await expect(page.getByText("Согласие на обработку ПД")).toBeVisible();
await expect(page.getByText("Политика обработки ПД")).toBeVisible();
await expect(page.getByRole("button", { name: "Продолжить" })).toBeDisabled();
});
test("Enter отправляет введённое сообщение", async ({ page }) => {
await page.goto("/");
await page.getByLabel("Сообщение").fill("Отправка с клавиатуры");
await page.getByLabel("Сообщение").press("Enter");
await expect(page.getByRole("heading", { name: "Перед началом работы" })).toBeVisible();
});
test("счётчик показывает и ограничивает 4000 символов", async ({ page }) => {
await page.goto("/");
await page.getByLabel("Сообщение").fill("а".repeat(4001));
await expect(page.getByText("4001/4000")).toBeVisible();
await expect(page.getByRole("button", { name: "Отправить" })).toBeDisabled();
await expect(page.getByRole("heading", { name: "Перед началом работы" })).toHaveCount(0);
});
test("профиль гостя не делает защищённый запрос", async ({ page }) => {
let protectedCalls = 0;
await page.route("**/api/v1/me", (route) => { protectedCalls++; return route.abort(); });
await page.goto("/profile");
await expect(page.getByRole("heading", { name: "Профиль доступен после входа" })).toBeVisible();
await expect(page.getByText("Авторизуйтесь, чтобы видеть личные данные и документы компании.")).toBeVisible();
await expect(page.getByRole("button", { name: "Авторизоваться" })).toBeVisible();
expect(protectedCalls).toBe(0);
});
test("гостевой чат предлагает авторизоваться", async ({ page }) => {
await page.goto("/dialogs");
await expect(page.getByRole("heading", { name: "Чат доступен после входа" })).toBeVisible();
await expect(page.getByText("Авторизуйтесь, чтобы переписываться с оператором и получать ответы.")).toBeVisible();
await page.getByRole("button", { name: "Авторизоваться" }).click();
await expect(page).toHaveURL(/\/\?authorize=1$/);
await expect(page.getByRole("heading", { name: "Перед началом работы" })).toBeVisible();
});