end fase 2
This commit is contained in:
@ -8,13 +8,15 @@ import { test, expect } from '@playwright/test';
|
||||
* - Создание идей
|
||||
* - Inline-редактирование
|
||||
* - Удаление
|
||||
*
|
||||
* Используем data-testid для стабильных селекторов
|
||||
*/
|
||||
|
||||
test.describe('Фаза 1: Базовый функционал', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
// Ждём загрузки таблицы
|
||||
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
|
||||
// Ждём загрузки таблицы идей
|
||||
await page.waitForSelector('[data-testid="ideas-table"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Страница загружается', async ({ page }) => {
|
||||
@ -23,29 +25,22 @@ test.describe('Фаза 1: Базовый функционал', () => {
|
||||
});
|
||||
|
||||
test('Таблица идей отображается', async ({ page }) => {
|
||||
const table = page.locator('table, [role="grid"]');
|
||||
const table = page.locator('[data-testid="ideas-table"]');
|
||||
await expect(table).toBeVisible();
|
||||
});
|
||||
|
||||
test('Таблица имеет заголовки колонок', async ({ page }) => {
|
||||
const headers = page.locator('th, [role="columnheader"]');
|
||||
const count = await headers.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
|
||||
// Проверяем что есть хотя бы несколько важных колонок
|
||||
const headerTexts = await headers.allTextContents();
|
||||
expect(headerTexts.length).toBeGreaterThan(0);
|
||||
test('Контейнер таблицы присутствует', async ({ page }) => {
|
||||
const container = page.locator('[data-testid="ideas-table-container"]');
|
||||
await expect(container).toBeVisible();
|
||||
});
|
||||
|
||||
test('Фильтры присутствуют на странице', async ({ page }) => {
|
||||
// Ищем элементы фильтров (inputs, selects, MUI компоненты)
|
||||
const filterElements = page.locator('input, [role="combobox"], .MuiSelect-select');
|
||||
const count = await filterElements.count();
|
||||
expect(count).toBeGreaterThanOrEqual(1);
|
||||
const filters = page.locator('[data-testid="ideas-filters"]');
|
||||
await expect(filters).toBeVisible();
|
||||
});
|
||||
|
||||
test('Поле поиска работает', async ({ page }) => {
|
||||
const searchInput = page.locator('input[placeholder*="Поиск"]');
|
||||
const searchInput = page.locator('[data-testid="search-input"] input');
|
||||
await expect(searchInput).toBeVisible();
|
||||
|
||||
await searchInput.fill('test');
|
||||
@ -55,13 +50,19 @@ test.describe('Фаза 1: Базовый функционал', () => {
|
||||
await searchInput.clear();
|
||||
});
|
||||
|
||||
test('Кнопка создания идеи существует', async ({ page }) => {
|
||||
const buttons = page.locator('button');
|
||||
const createButton = buttons.filter({
|
||||
hasText: /создать|добавить|новая|\+/i,
|
||||
});
|
||||
test('Фильтр статуса присутствует', async ({ page }) => {
|
||||
const statusFilter = page.locator('[data-testid="filter-status"]');
|
||||
await expect(statusFilter).toBeVisible();
|
||||
});
|
||||
|
||||
await expect(createButton.first()).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 }) => {
|
||||
@ -73,8 +74,8 @@ test.describe('Фаза 1: Базовый функционал', () => {
|
||||
|
||||
await createButton.click();
|
||||
|
||||
// Проверяем что модалка открылась (используем .first() т.к. MUI создаёт вложенные элементы)
|
||||
const modal = page.locator('[role="dialog"]').first();
|
||||
// Проверяем что модалка открылась
|
||||
const modal = page.locator('[data-testid="create-idea-modal"]');
|
||||
await expect(modal).toBeVisible();
|
||||
|
||||
// Закрываем модалку
|
||||
@ -82,74 +83,116 @@ test.describe('Фаза 1: Базовый функционал', () => {
|
||||
await expect(modal).toBeHidden();
|
||||
});
|
||||
|
||||
test('Таблица показывает данные или empty state', async ({ page }) => {
|
||||
const rows = page.locator('tbody tr, [role="row"]');
|
||||
const rowCount = await rows.count();
|
||||
test('Модалка создания содержит необходимые поля', async ({ page }) => {
|
||||
const createButton = page
|
||||
.locator('button')
|
||||
.filter({ hasText: /создать|добавить|новая/i })
|
||||
.first();
|
||||
|
||||
if (rowCount > 1) {
|
||||
// Есть данные
|
||||
expect(rowCount).toBeGreaterThan(1);
|
||||
} else {
|
||||
// Ищем empty state
|
||||
const emptyState = page.locator('text=/нет|пусто|Нет идей/i');
|
||||
const hasEmptyState = (await emptyState.count()) > 0;
|
||||
expect(hasEmptyState || rowCount >= 1).toBeTruthy();
|
||||
}
|
||||
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, [aria-label*="pagination"], nav[aria-label*="pagination"]'
|
||||
);
|
||||
const pagination = page.locator('.MuiTablePagination-root');
|
||||
await expect(pagination.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Inline-редактирование работает (double-click)', async ({ page }) => {
|
||||
// Находим ячейки таблицы (пропускаем первую - drag handle)
|
||||
const cells = page.locator('tbody td');
|
||||
const cellCount = await cells.count();
|
||||
// Проверяем есть ли данные
|
||||
const ideaRows = page.locator('[data-testid^="idea-row-"]');
|
||||
const rowCount = await ideaRows.count();
|
||||
|
||||
if (cellCount > 1) {
|
||||
// Пробуем double-click на ячейках (начиная со второй)
|
||||
for (let i = 1; i < Math.min(cellCount, 6); i++) {
|
||||
const cell = cells.nth(i);
|
||||
const text = await cell.textContent();
|
||||
if (rowCount > 0) {
|
||||
// Находим первую строку и кликаем дважды на ячейку
|
||||
const firstRow = ideaRows.first();
|
||||
const cells = firstRow.locator('td');
|
||||
const cellCount = await cells.count();
|
||||
|
||||
if (text && text.trim()) {
|
||||
await cell.dblclick();
|
||||
await page.waitForTimeout(500);
|
||||
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, input.MuiInput-input, tbody input, [role="combobox"]'
|
||||
);
|
||||
const inputCount = await input.count();
|
||||
// Проверяем появился ли input для редактирования
|
||||
const input = page.locator('.MuiInputBase-input, [role="combobox"]');
|
||||
const inputCount = await input.count();
|
||||
|
||||
if (inputCount > 0) {
|
||||
// Отменяем редактирование
|
||||
await page.keyboard.press('Escape');
|
||||
return; // Тест прошёл
|
||||
}
|
||||
if (inputCount > 0) {
|
||||
// Отменяем редактирование
|
||||
await page.keyboard.press('Escape');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если нет данных для inline-редактирования - это ОК
|
||||
// Тест прошёл без ошибок
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Кнопка удаления в таблице', async ({ page }) => {
|
||||
// Ищем иконки/кнопки удаления в строках
|
||||
const deleteButtons = page.locator(
|
||||
'tbody button[aria-label*="delete"], tbody button[aria-label*="удалить"], tbody [data-testid="DeleteIcon"], tbody svg'
|
||||
);
|
||||
test('Кнопка удаления присутствует в строке', async ({ page }) => {
|
||||
const ideaRows = page.locator('[data-testid^="idea-row-"]');
|
||||
const rowCount = await ideaRows.count();
|
||||
|
||||
const count = await deleteButtons.count();
|
||||
// Если есть данные, должны быть кнопки удаления
|
||||
const rows = await page.locator('tbody tr').count();
|
||||
if (rowCount > 0) {
|
||||
const deleteButtons = page.locator('[data-testid="delete-idea-button"]');
|
||||
const count = await deleteButtons.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
if (rows > 0) {
|
||||
expect(count).toBeGreaterThanOrEqual(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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user