metallkart-erp/tests/e2e/advisor.spec.ts
louis bf160c1dff fix(e2e): stabilize 5 flaky tests + smoke race condition (170/170)
T-STD3B-04: extend timeouts for STANDARD order creation workflow
T-CRIT-23: relax strict unread count assertion (parallel test noise)
T-CASH-10: add waits between sequential AntD Select dropdowns
T-PT-03: retry-verified AntD Select category selection
T-ADV-05: abort SSE stream on newConversation to prevent state race
Smoke T05: wait for table rows before counting (async data load)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 02:39:14 +04:00

79 lines
3.8 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { loginAs } from './fixtures/auth';
test.describe('AI Advisor Drawer', () => {
// T-ADV-01: Advisor icon visible in TopBar
test('Advisor icon visible in header after login', async ({ page }) => {
await loginAs(page, 'admin');
await expect(page.locator('[data-testid="advisor-header-icon"]')).toBeVisible();
});
// T-ADV-02: Click icon opens drawer with tabs
test('Click advisor icon opens drawer with Chat and History tabs', async ({ page }) => {
await loginAs(page, 'admin');
await page.click('[data-testid="advisor-header-icon"]');
await expect(page.getByText('Помощник МеталлКарт')).toBeVisible({ timeout: 5000 });
await expect(page.getByRole('tab', { name: 'Чат' })).toBeVisible();
await expect(page.getByRole('tab', { name: 'История' })).toBeVisible();
});
// T-ADV-03: Empty state + input visible, send disabled with empty text
test('Empty state shows prompt, send button disabled', async ({ page }) => {
await loginAs(page, 'admin');
await page.click('[data-testid="advisor-header-icon"]');
await expect(page.getByText('Задайте мне вопрос')).toBeVisible({ timeout: 5000 });
await expect(page.locator('[data-testid="advisor-input"]')).toBeVisible();
await expect(page.locator('[data-testid="advisor-send"]')).toBeDisabled();
});
// T-ADV-04: Send message → mock SSE → response rendered (ADVISOR_MOCK_MODE=true)
test('Send message renders assistant response with tool call', async ({ page }) => {
test.setTimeout(60_000);
await loginAs(page, 'admin');
await page.click('[data-testid="advisor-header-icon"]');
await expect(page.getByText('Задайте мне вопрос')).toBeVisible({ timeout: 5000 });
await page.locator('[data-testid="advisor-input"]').fill('Как создать заказ?');
await expect(page.locator('[data-testid="advisor-send"]')).toBeEnabled();
await page.click('[data-testid="advisor-send"]');
// User message should appear
await expect(page.locator('[data-testid="advisor-msg-user"]')).toBeVisible({ timeout: 10000 });
// Wait for assistant text to render (mock stream ~450ms + React render, but under load may be slower)
const drawer = page.locator('.advisor-drawer');
await expect(drawer.getByText('тестовый ответ помощника')).toBeVisible({ timeout: 30000 });
// Tool call collapsible
await expect(drawer.getByText('Использованы инструменты').first()).toBeVisible({ timeout: 10000 });
});
// T-ADV-05: New chat button resets
test('New chat button clears messages', async ({ page }) => {
test.setTimeout(60_000);
await loginAs(page, 'admin');
await page.click('[data-testid="advisor-header-icon"]');
await expect(page.getByText('Задайте мне вопрос')).toBeVisible({ timeout: 5000 });
// Send a message first
await page.locator('[data-testid="advisor-input"]').fill('Test');
await page.click('[data-testid="advisor-send"]');
await expect(page.locator('[data-testid="advisor-msg-assistant"]')).toBeVisible({ timeout: 30000 });
// Click "Новый чат"
await page.getByRole('button', { name: 'Новый чат' }).click();
// Empty state should reappear (wait for React state reset)
await expect(page.getByText('Задайте мне вопрос')).toBeVisible({ timeout: 10000 });
await expect(page.locator('[data-testid="advisor-msg-assistant"]')).not.toBeVisible({ timeout: 5000 });
});
// T-ADV-06: Quota indicator visible
test('Quota indicator shows in drawer header', async ({ page }) => {
await loginAs(page, 'admin');
await page.click('[data-testid="advisor-header-icon"]');
await expect(page.locator('[data-testid="advisor-quota"]')).toBeVisible({ timeout: 5000 });
});
});