add auth
This commit is contained in:
208
tests/e2e/phase2.spec.ts
Normal file
208
tests/e2e/phase2.spec.ts
Normal file
@ -0,0 +1,208 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user