Files
team-planner/tests/e2e/phase2.spec.ts
2026-01-14 01:10:01 +03:00

209 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { test, expect } from '@playwright/test';
/**
* E2E тесты для Фазы 2 Team Planner
* - Drag & Drop
* - Цветовая маркировка
* - Комментарии
* - Управление командой
*/
test.describe('Фаза 2: Drag & Drop', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
});
test('Drag handle присутствует в таблице', async ({ page }) => {
// Ждём загрузки строк таблицы
await page.waitForSelector('tbody tr', { timeout: 10000 });
// Drag handle — это div с aria-roledescription="sortable" (dnd-kit)
const handles = page.locator('[aria-roledescription="sortable"]');
// Ждём появления хотя бы одного handle
await expect(handles.first()).toBeVisible({ timeout: 5000 });
const count = await handles.count();
expect(count).toBeGreaterThan(0);
});
test('Строки имеют drag handle для сортировки', async ({ page }) => {
// Ждём загрузки строк таблицы
await page.waitForSelector('tbody tr', { timeout: 10000 });
// dnd-kit добавляет aria-roledescription="sortable" на drag handle
const handles = page.locator('[aria-roledescription="sortable"]');
await expect(handles.first()).toBeVisible({ timeout: 5000 });
const count = await handles.count();
const totalRows = await page.locator('tbody tr').count();
// Все строки должны иметь drag handle
expect(count).toBe(totalRows);
});
test('Визуальное перетаскивание работает', async ({ page }) => {
const rows = page.locator('tbody tr');
const rowCount = await rows.count();
if (rowCount >= 2) {
const firstRow = rows.first();
const handle = firstRow.locator('td:first-child svg, td:first-child').first();
// Начинаем перетаскивание
const box = await handle.boundingBox();
if (box) {
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await page.mouse.down();
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2 + 50);
await page.waitForTimeout(300);
// Проверяем появление визуальной индикации
const overlay = page.locator(
'[data-dnd-kit-drag-overlay], ' + '.drag-overlay, ' + '[style*="position: fixed"]'
);
await page.mouse.up();
// Drag action выполнен успешно
expect(true).toBeTruthy();
}
}
});
});
test.describe('Фаза 2: Цветовая маркировка', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
});
test('Колонка цвета присутствует', async ({ page }) => {
const headers = page.locator('th, [role="columnheader"]');
const headerTexts = await headers.allTextContents();
const hasColorColumn = headerTexts.some(
(text) => text.toLowerCase().includes('цвет') || text.toLowerCase().includes('color')
);
// Фича может быть ещё не реализована - отмечаем как skip
test.skip(!hasColorColumn, 'Колонка цвета ещё не реализована');
expect(hasColorColumn).toBeTruthy();
});
test('Color picker или индикаторы доступны', async ({ page }) => {
const colorElements = page.locator(
'input[type="color"], ' +
'.color-picker, ' +
'[aria-label*="цвет" i], ' +
'[aria-label*="color" i], ' +
'tbody [style*="background"]'
);
const count = await colorElements.count();
// Фича может быть ещё не реализована
test.skip(count === 0, 'Color picker ещё не реализован');
expect(count).toBeGreaterThan(0);
});
test('Строки могут иметь цветной фон', async ({ page }) => {
const rows = page.locator('tbody tr');
const rowCount = await rows.count();
let coloredRows = 0;
for (let i = 0; i < rowCount; i++) {
const row = rows.nth(i);
const bg = await row.evaluate((el) => getComputedStyle(el).backgroundColor);
// Проверяем что фон не прозрачный и не белый
if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'rgb(255, 255, 255)') {
coloredRows++;
}
}
// Фича может быть ещё не реализована
test.skip(coloredRows === 0, 'Цветные строки ещё не реализованы');
expect(coloredRows).toBeGreaterThan(0);
});
});
test.describe('Фаза 2: Комментарии', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
});
test('Кнопка комментариев присутствует', async ({ page }) => {
const commentButtons = page.locator(
'[aria-label*="комментар" i], ' +
'[aria-label*="comment" i], ' +
'button svg[data-testid*="Comment"], ' +
'[data-testid="CommentIcon"], ' +
'[data-testid="ChatBubbleIcon"]'
);
const count = await commentButtons.count();
// Фича может быть ещё не реализована
test.skip(count === 0, 'Комментарии ещё не реализованы');
expect(count).toBeGreaterThan(0);
});
test('Секция комментариев существует', async ({ page }) => {
const commentsSection = page.locator(
'.comments-section, ' +
'[class*="comment"], ' +
'[data-testid*="comment"], ' +
'textarea[placeholder*="комментар" i]'
);
const count = await commentsSection.count();
// Фича может быть ещё не реализована
test.skip(count === 0, 'Секция комментариев ещё не реализована');
expect(count).toBeGreaterThan(0);
});
});
test.describe('Фаза 2: Управление командой', () => {
test('Страница /team существует', async ({ page }) => {
await page.goto('/team');
await page.waitForLoadState('networkidle');
const bodyText = await page.locator('body').textContent();
const is404 =
bodyText?.toLowerCase().includes('404') || bodyText?.toLowerCase().includes('not found');
// Фича может быть ещё не реализована
test.skip(is404, 'Страница /team ещё не реализована');
expect(is404).toBeFalsy();
});
test('Ссылка на команду в навигации', async ({ page }) => {
await page.goto('/');
await page.waitForSelector('body');
const teamLinks = page.locator('a[href*="team"], nav a, [role="navigation"] a');
const allLinks = await teamLinks.allTextContents();
const hasTeamLink = allLinks.some(
(text) => text.toLowerCase().includes('команд') || text.toLowerCase().includes('team')
);
// Фича может быть ещё не реализована
test.skip(!hasTeamLink, 'Навигация на команду ещё не реализована');
expect(hasTeamLink).toBeTruthy();
});
test('Таблица участников команды', async ({ page }) => {
await page.goto('/team');
await page.waitForLoadState('networkidle');
const table = page.locator('table, [role="grid"]');
const count = await table.count();
// Фича может быть ещё не реализована
test.skip(count === 0, 'Таблица команды ещё не реализована');
expect(count).toBeGreaterThan(0);
});
});