199 lines
7.4 KiB
TypeScript
199 lines
7.4 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||
|
||
/**
|
||
* E2E тесты для Фазы 1 Team Planner
|
||
* - Базовая загрузка страницы
|
||
* - Таблица идей
|
||
* - Фильтры
|
||
* - Создание идей
|
||
* - Inline-редактирование
|
||
* - Удаление
|
||
*
|
||
* Используем data-testid для стабильных селекторов
|
||
*/
|
||
|
||
test.describe('Фаза 1: Базовый функционал', () => {
|
||
test.beforeEach(async ({ page }) => {
|
||
await page.goto('/');
|
||
// Ждём загрузки таблицы идей
|
||
await page.waitForSelector('[data-testid="ideas-table"]', { timeout: 10000 });
|
||
});
|
||
|
||
test('Страница загружается', async ({ page }) => {
|
||
await expect(page.locator('body')).toBeVisible();
|
||
await expect(page).toHaveTitle(/.*/);
|
||
});
|
||
|
||
test('Таблица идей отображается', async ({ page }) => {
|
||
const table = page.locator('[data-testid="ideas-table"]');
|
||
await expect(table).toBeVisible();
|
||
});
|
||
|
||
test('Контейнер таблицы присутствует', async ({ page }) => {
|
||
const container = page.locator('[data-testid="ideas-table-container"]');
|
||
await expect(container).toBeVisible();
|
||
});
|
||
|
||
test('Фильтры присутствуют на странице', async ({ page }) => {
|
||
const filters = page.locator('[data-testid="ideas-filters"]');
|
||
await expect(filters).toBeVisible();
|
||
});
|
||
|
||
test('Поле поиска работает', async ({ page }) => {
|
||
const searchInput = page.locator('[data-testid="search-input"] input');
|
||
await expect(searchInput).toBeVisible();
|
||
|
||
await searchInput.fill('test');
|
||
await expect(searchInput).toHaveValue('test');
|
||
|
||
// Очищаем
|
||
await searchInput.clear();
|
||
});
|
||
|
||
test('Фильтр статуса присутствует', async ({ page }) => {
|
||
const statusFilter = page.locator('[data-testid="filter-status"]');
|
||
await expect(statusFilter).toBeVisible();
|
||
});
|
||
|
||
test('Фильтр приоритета присутствует', async ({ page }) => {
|
||
const priorityFilter = page.locator('[data-testid="filter-priority"]');
|
||
await expect(priorityFilter).toBeVisible();
|
||
});
|
||
|
||
test('Фильтр модуля присутствует', async ({ page }) => {
|
||
const moduleFilter = page.locator('[data-testid="filter-module"]');
|
||
await expect(moduleFilter).toBeVisible();
|
||
});
|
||
|
||
test('Модалка создания открывается', async ({ page }) => {
|
||
// Находим и кликаем кнопку создания
|
||
const createButton = page
|
||
.locator('button')
|
||
.filter({ hasText: /создать|добавить|новая/i })
|
||
.first();
|
||
|
||
await createButton.click();
|
||
|
||
// Проверяем что модалка открылась
|
||
const modal = page.locator('[data-testid="create-idea-modal"]');
|
||
await expect(modal).toBeVisible();
|
||
|
||
// Закрываем модалку
|
||
await page.keyboard.press('Escape');
|
||
await expect(modal).toBeHidden();
|
||
});
|
||
|
||
test('Модалка создания содержит необходимые поля', async ({ page }) => {
|
||
const createButton = page
|
||
.locator('button')
|
||
.filter({ hasText: /создать|добавить|новая/i })
|
||
.first();
|
||
|
||
await createButton.click();
|
||
|
||
const modal = page.locator('[data-testid="create-idea-modal"]');
|
||
await expect(modal).toBeVisible();
|
||
|
||
// Проверяем наличие формы и поля ввода
|
||
const form = page.locator('[data-testid="create-idea-form"]');
|
||
await expect(form).toBeVisible();
|
||
|
||
const titleInput = page.locator('[data-testid="idea-title-input"]');
|
||
await expect(titleInput).toBeVisible();
|
||
|
||
const cancelButton = page.locator('[data-testid="cancel-create-idea"]');
|
||
await expect(cancelButton).toBeVisible();
|
||
|
||
const submitButton = page.locator('[data-testid="submit-create-idea"]');
|
||
await expect(submitButton).toBeVisible();
|
||
|
||
await page.keyboard.press('Escape');
|
||
});
|
||
|
||
test('Таблица показывает данные или empty state', async ({ page }) => {
|
||
// Проверяем либо есть строки с данными, либо пустое состояние
|
||
const emptyState = page.locator('[data-testid="ideas-empty-state"]');
|
||
const ideaRows = page.locator('[data-testid^="idea-row-"]');
|
||
|
||
const hasEmptyState = await emptyState.isVisible().catch(() => false);
|
||
const rowCount = await ideaRows.count();
|
||
|
||
expect(hasEmptyState || rowCount > 0).toBeTruthy();
|
||
});
|
||
|
||
test('Пагинация присутствует', async ({ page }) => {
|
||
const pagination = page.locator('.MuiTablePagination-root');
|
||
await expect(pagination.first()).toBeVisible();
|
||
});
|
||
|
||
test('Inline-редактирование работает (double-click)', async ({ page }) => {
|
||
// Проверяем есть ли данные
|
||
const ideaRows = page.locator('[data-testid^="idea-row-"]');
|
||
const rowCount = await ideaRows.count();
|
||
|
||
if (rowCount > 0) {
|
||
// Находим первую строку и кликаем дважды на ячейку
|
||
const firstRow = ideaRows.first();
|
||
const cells = firstRow.locator('td');
|
||
const cellCount = await cells.count();
|
||
|
||
if (cellCount > 2) {
|
||
// Пробуем double-click на ячейках (пропускаем drag handle и color)
|
||
const cell = cells.nth(2);
|
||
await cell.dblclick();
|
||
await page.waitForTimeout(500);
|
||
|
||
// Проверяем появился ли input для редактирования
|
||
const input = page.locator('.MuiInputBase-input, [role="combobox"]');
|
||
const inputCount = await input.count();
|
||
|
||
if (inputCount > 0) {
|
||
// Отменяем редактирование
|
||
await page.keyboard.press('Escape');
|
||
}
|
||
}
|
||
}
|
||
|
||
// Тест прошёл без ошибок
|
||
expect(true).toBeTruthy();
|
||
});
|
||
|
||
test('Кнопка удаления присутствует в строке', async ({ page }) => {
|
||
const ideaRows = page.locator('[data-testid^="idea-row-"]');
|
||
const rowCount = await ideaRows.count();
|
||
|
||
if (rowCount > 0) {
|
||
const deleteButtons = page.locator('[data-testid="delete-idea-button"]');
|
||
const count = await deleteButtons.count();
|
||
expect(count).toBeGreaterThan(0);
|
||
}
|
||
});
|
||
|
||
test('Кнопка сброса фильтров появляется при активных фильтрах', async ({ page }) => {
|
||
// Изначально кнопка сброса скрыта
|
||
const clearButton = page.locator('[data-testid="clear-filters-button"]');
|
||
await expect(clearButton).toBeHidden();
|
||
|
||
// Выбираем статус в фильтре
|
||
const statusFilter = page.locator('[data-testid="filter-status"]');
|
||
await statusFilter.locator('[role="combobox"]').click();
|
||
|
||
const listbox = page.locator('[role="listbox"]');
|
||
await expect(listbox).toBeVisible();
|
||
|
||
// Выбираем любой статус кроме "Все"
|
||
const options = listbox.locator('[role="option"]');
|
||
const optionCount = await options.count();
|
||
if (optionCount > 1) {
|
||
await options.nth(1).click();
|
||
|
||
// Теперь кнопка сброса должна быть видна
|
||
await expect(clearButton).toBeVisible();
|
||
|
||
// Сбрасываем фильтры
|
||
await clearButton.click();
|
||
await expect(clearButton).toBeHidden();
|
||
}
|
||
});
|
||
});
|