Kontrola językiem naturalnym
Prompt: “Testuj przepływ płatności z wykrywaniem regresji wizualnej”
Wynik: Kompletna podróż użytkownika z porównaniem zrzutów ekranu
PRD: System inteligentnego testowania E2E
Wymagania: Utwórz kompleksowe testy end-to-end symulujące prawdziwe podróże użytkowników, dostosowujące się do zmian UI i zapewniające 99,5%+ niezawodności we wszystkich przeglądarkach i urządzeniach używając automatyzacji wspieranej przez AI.
Plan: Wykorzystaj Playwright MCP do bezpośredniej kontroli przeglądarki, w połączeniu z Cursor i Claude Code do tworzenia i utrzymania testów w języku naturalnym.
Todo:
Testowanie E2E ewoluuje od skryptowanych interakcji do inteligentnej symulacji użytkowników. AI rozumie intencje użytkowników, generuje realistyczne scenariusze testowe i utrzymuje testy w miarę zmian aplikacji.
Kontrola językiem naturalnym
Prompt: “Testuj przepływ płatności z wykrywaniem regresji wizualnej”
Wynik: Kompletna podróż użytkownika z porównaniem zrzutów ekranu
Inteligentne wykrywanie elementów
AI znajduje elementy używając wielu strategii: atrybuty danych, etykiety ARIA, semantyczny HTML
Inteligencja wizualna
Automatycznie wykrywa przesunięcia układu, zmiany kolorów i uszkodzone komponenty UI
Testowanie międzyplatformowe
Jeden prompt generuje testy dla desktop, tablet i mobilne viewport
Scenariusz: Testowanie kompletnego przepływu zakupu od przeglądania produktów do potwierdzenia zamówienia z wieloma personami użytkowników.
# PRD: Testowanie płatności e-commerce end-to-end# Wymagania: Testuj kompletny przepływ zakupu dla różnych typów użytkowników i urządzeń
"Używając Playwright MCP, utwórz kompleksowe testy płatności:
Persony użytkowników:1. Użytkownik gość (mobile, wolne połączenie)2. Zarejestrowany użytkownik (desktop, szybkie połączenie)3. Członek premium (tablet, średnie połączenie)
Przepływ testów dla każdej persony:1. Nawiguj do katalogu produktów2. Szukaj i filtruj produkty3. Dodaj wiele przedmiotów do koszyka4. Zastosuj kody rabatowe5. Przejdź do płatności6. Wypełnij informacje wysyłkowe7. Wybierz metodę płatności8. Sfinalizuj zakup9. Weryfikuj potwierdzenie zamówienia
Wymagane walidacje:- Regresja wizualna na każdym kroku- Metryki wydajności (< 3s ładowania stron)- Zgodność z dostępnością (WCAG 2.1 AA)- Kompatybilność międzyprzeglądarowa- Responsywność mobilna- Obsługa błędów (awarie płatności, brak towaru)- Śledzenie zdarzeń analitycznych"
// AI generuje kompleksowy zestaw testów E2Eimport { test, expect, devices } from '@playwright/test';import { UserPersona, ProductCatalog, CheckoutFlow } from './test-helpers';
// AI tworzy konfiguracje testów oparte na personachconst personas = [ { name: 'guest_mobile', device: devices['iPhone 12'], connection: 'slow-3g', user: null }, { name: 'registered_desktop', device: devices['Desktop Chrome'], connection: 'fast', user: UserPersona.build('returning_customer') }, { name: 'premium_tablet', device: devices['iPad Pro'], connection: 'medium', user: UserPersona.build('premium_member') }];
personas.forEach(persona => { test.describe(`Przepływ płatności - ${persona.name}`, () => { test.use({ ...persona.device });
test.beforeEach(async ({ page, context }) => { // AI konfiguruje warunki sieciowe if (persona.connection === 'slow-3g') { await context.setNetworkConditions({ download: 500 * 1024, upload: 500 * 1024, latency: 2000 }); }
// Logowanie jeśli zarejestrowany użytkownik if (persona.user) { await page.goto('/login'); await page.fill('[data-testid="email"]', persona.user.email); await page.fill('[data-testid="password"]', persona.user.password); await page.click('[data-testid="login-submit"]'); await page.waitForURL('/dashboard'); } });
test('kompletna podróż zakupu', async ({ page }) => { // Krok 1: Nawiguj do katalogu const startTime = Date.now(); await page.goto('/products'); await page.waitForLoadState('networkidle');
// AI dodaje asercje wydajności const catalogLoadTime = Date.now() - startTime; expect(catalogLoadTime).toBeLessThan(3000);
// Kontrola regresji wizualnej await expect(page).toHaveScreenshot(`catalog-${persona.name}.png`);
// Krok 2: Szukaj i filtruj await page.fill('[data-testid="search-input"]', 'laptop'); await page.click('[data-testid="search-submit"]'); await page.waitForSelector('[data-testid="product-list"]');
// Zastosuj filtry await page.click('[data-testid="price-filter-500-1000"]'); await page.waitForTimeout(1000); // Pozwól filtrowi się zastosować
// Krok 3: Dodaj produkty do koszyka const products = page.locator('[data-testid="product-card"]'); const productCount = await products.count();
// Dodaj pierwsze dwa produkty for (let i = 0; i < Math.min(2, productCount); i++) { await products.nth(i).locator('[data-testid="add-to-cart"]').click();
// Czekaj na animację koszyka await page.waitForSelector('[data-testid="cart-counter"]');
// Weryfikuj zwiększony licznik koszyka const cartCount = await page.textContent('[data-testid="cart-counter"]'); expect(parseInt(cartCount)).toBe(i + 1); }
// Krok 4: Zastosuj kod rabatowy await page.click('[data-testid="cart-icon"]'); await page.click('[data-testid="discount-toggle"]'); await page.fill('[data-testid="discount-input"]', 'SAVE10'); await page.click('[data-testid="apply-discount"]');
// Weryfikuj zastosowany rabat await expect(page.locator('[data-testid="discount-applied"]')) .toContainText('10% zniżki');
// Krok 5: Przejdź do płatności await page.click('[data-testid="checkout-button"]'); await page.waitForURL('/checkout');
// Kontrola wizualna strony płatności await expect(page).toHaveScreenshot(`checkout-${persona.name}.png`);
// Krok 6: Wypełnij wysyłkę (jeśli użytkownik gość) if (!persona.user) { await page.fill('[data-testid="shipping-email"]', 'guest@example.com'); await page.fill('[data-testid="shipping-name"]', 'Jan Kowalski'); await page.fill('[data-testid="shipping-address"]', 'ul. Główna 123'); await page.fill('[data-testid="shipping-city"]', 'Warszawa'); await page.fill('[data-testid="shipping-zip"]', '00-001'); }
// Krok 7: Wybierz płatność await page.click('[data-testid="payment-card"]'); await page.fill('[data-testid="card-number"]', '4242424242424242'); await page.fill('[data-testid="card-expiry"]', '12/25'); await page.fill('[data-testid="card-cvc"]', '123');
// Krok 8: Sfinalizuj zakup await page.click('[data-testid="place-order"]');
// Krok 9: Weryfikuj potwierdzenie zamówienia await page.waitForURL('/order-confirmation/*');
await expect(page.locator('[data-testid="order-success"]')) .toContainText('Zamówienie złożone pomyślnie');
// Weryfikuj szczegóły zamówienia await expect(page.locator('[data-testid="order-number"]')) .toBeVisible();
// Finalna kontrola wizualna await expect(page).toHaveScreenshot(`confirmation-${persona.name}.png`);
// Walidacja dostępności await expect(page).toPassAccessibilityAudit(); }); });});
Scenariusz: Używanie poleceń w języku naturalnym do bezpośredniej kontroli przeglądarek bez pisania kodu testowego.
# PRD: Bezpośrednia kontrola przeglądarki przez MCP# Plan: Użyj Playwright MCP do automatyzacji przeglądarki w języku naturalnym
# Najpierw zainstaluj i połącz z Playwright MCP"Zainstaluj serwer Playwright MCP:npx -y @playwright/mcp@latest"
# Połącz z serwerem MCP"Połącz się z serwerem Playwright MCP do bezpośredniej kontroli przeglądarki"
# Automatyzacja przeglądarki w języku naturalnym"Używając Playwright MCP:
1. Uruchom przeglądarkę i przejdź do https://example-shop.com2. Zrób zrzut ekranu strony głównej3. Kliknij na 'Produkty' w nawigacji4. Szukaj 'słuchawki bezprzewodowe'5. Kliknij na pierwszy wynik produktu6. Zrób zrzut ekranu strony produktu7. Kliknij przycisk 'Dodaj do koszyka'8. Przejdź do strony koszyka9. Weryfikuj, że produkt jest w koszyku10. Zrób finalna zrzut ekranu
Dla każdego kroku, waliduj, że strona załadowała się poprawnie i elementy są widoczne"
# Odpowiedź MCP (AI wykonuje każde polecenie):# ✓ Przeglądarka uruchomiona pomyślnie# ✓ Przeszedł do https://example-shop.com# ✓ Zrzut ekranu zapisany: homepage.png# ✓ Kliknięto nawigację 'Produkty'# ✓ Wyszukiwanie 'słuchawki bezprzewodowe' ukończone# ✓ Pierwszy produkt kliknięty# ✓ Zrzut ekranu zapisany: product-page.png# ✓ Dodano do koszyka pomyślnie# ✓ Strona koszyka załadowana# ✓ Produkt zweryfikowany w koszyku# ✓ Zrzut ekranu zapisany: cart-final.png
# PRD: Testowanie złożonych podróży użytkowników# Wymagania: Testuj wielokrokowe przepływy pracy z obsługą błędów
"Używając Playwright MCP, wykonaj ten złożony scenariusz testowy:
Scenariusz: Rejestracja nowego użytkownika i pierwszy zakup
1. Przejdź do strony rejestracji2. Wypełnij formularz rejestracji: - Email: testuser@example.com - Hasło: SecurePass123! - Potwierdź hasło: SecurePass123! - Zaakceptuj regulamin3. Prześlij rejestrację4. Obsłuż weryfikację emaila (mock)5. Zaloguj się nowymi danymi6. Przeglądaj katalog produktów7. Dodaj 3 różne przedmioty do koszyka8. Zastosuj kod rabatowy 'WELCOME10'9. Przejdź do płatności10. Wypełnij informacje wysyłkowe11. Wprowadź testowe dane płatności12. Sfinalizuj zakup13. Weryfikuj potwierdzenie zamówienia
Obsługa błędów:- Jeśli jakikolwiek krok się nie powiedzie, zrób zrzut ekranu- Ponów nieudane działania do 3 razy- Loguj szczegółowe informacje o błędach- Kontynuuj następny test jeśli krytyczna awaria
Walidacja:- Zrzut ekranu na każdym głównym kroku- Weryfikuj tytuły stron i kluczowe elementy- Sprawdzaj błędy JavaScript- Waliduj dostępność przy płatności- Mierzy metryki wydajności"
# AI wykonuje cały przepływ pracy z inteligentną obsługą błędów# i zapewnia szczegółowy raport wykonania
Scenariusz: Wykrywanie zmian wizualnych w aktualizacjach aplikacji z inteligentną analizą różnic.
// PRD: System testowania regresji wizualnej// Plan: Użyj Playwright MCP do zarządzania zrzutami ekranu
// Użyj Playwright MCP do zrzutów ekranu"Używając Playwright MCP:1. Rób pełnostronicowe zrzuty ekranu2. Porównuj z obrazami bazowymi3. Identyfikuj różnice wizualne4. Generuj raporty różnic"
// Testowanie regresji wizualnej ulepszone przez AItest.describe('Zestaw regresji wizualnej', () => { // AI generuje scenariusze testów wizualnych const viewports = [ { width: 375, height: 667, name: 'mobile' }, { width: 768, height: 1024, name: 'tablet' }, { width: 1920, height: 1080, name: 'desktop' } ];
test('spójność wizualna strony głównej', async ({ page }) => { for (const viewport of viewports) { await page.setViewportSize(viewport); await page.goto('/');
// Porównanie wizualne wspierane przez AI const screenshot = await page.screenshot({ fullPage: true, animations: 'disabled' });
// AI analizuje różnice wizualne const analysis = await ai.compareVisual({ current: screenshot, baseline: `homepage-${viewport.name}.png`, threshold: 0.1, ignoreRegions: [ { selector: '.dynamic-content' }, { selector: '[data-testid="timestamp"]' } ] });
if (analysis.hasDifferences) { console.log('Analiza AI:', analysis.summary); // AI sugeruje czy różnice są zamierzone expect(analysis.isIntentional).toBe(true); } } });});
Scenariusz: Tworzenie testów automatycznie dostosowujących się do zmian UI i modyfikacji selektorów.
// Strategie lokatorów samonaprawialnychclass SmartLocator { constructor(private page: Page) {}
async findElement(intent: string): Promise<Locator> { // Główna strategia: data-testid let element = this.page.locator(`[data-testid="${intent}"]`);
if (!(await element.count())) { // Fallback: semantyczny HTML element = this.page.getByRole('button', { name: new RegExp(intent, 'i') }); }
if (!(await element.count())) { // Fallback wspierany przez AI const selector = await this.ai.findElement({ intent, screenshot: await this.page.screenshot(), dom: await this.page.content() });
element = this.page.locator(selector); }
return element; }}
// Użycie w testachtest('samonaprawialny test logowania', async ({ page }) => { const smart = new SmartLocator(page);
// Te będą się dostosowywać do zmian UI await (await smart.findElement('email-input')).fill('user@example.com'); await (await smart.findElement('password-input')).fill('password123'); await (await smart.findElement('login-submit')).click();});
Scenariusz: Walidacja zachowania aplikacji w różnych przeglądarkach, urządzeniach i systemach operacyjnych.
// Testowanie międzyprzeglądarowe napędzane przez AIconst browsers = ['chromium', 'firefox', 'webkit'];
browsers.forEach(browserName => { test.describe(`Testy ${browserName}`, () => { test.use({ browserName });
test('kompatybilność międzyprzeglądarowa', async ({ page }) => { await page.goto('/');
// AI wykrywa problemy specyficzne dla przeglądarki const issues = await ai.detectCompatibilityIssues({ browser: browserName, page: await page.screenshot(), metrics: await page.metrics() });
expect(issues).toHaveLength(0);
// Dostosowania specyficzne dla przeglądarki if (browserName === 'webkit') { // AI zna dziwactwa Safari await page.waitForTimeout(100); } }); });});
// Cypress z komendami wspieranymi przez AICypress.Commands.add('aiClick', (selector) => { // AI znajduje najlepszy sposób kliknięcia elementu cy.window().then(async (win) => { const element = await ai.findClickableElement({ selector, viewport: win.innerWidth, dom: win.document.body.innerHTML });
cy.get(element.selector) .scrollIntoView() .should('be.visible') .click({ force: element.needsForce }); });});
describe('E2E międzyprzeglądarowe', () => { it('działa we wszystkich przeglądarkach', () => { cy.visit('/');
// Interakcje wspierane przez AI cy.aiClick('login'); cy.aiType('email', 'user@example.com'); cy.aiClick('submit');
// AI waliduje wynik cy.aiAssert('login successful'); });});
# PRD: Automatyczne testowanie podróży użytkowników# Wymagania: Testuj realistyczne ścieżki użytkowników przez aplikację
# Plan:"Używaj Playwright MCP do:1. Analizy obecnej struktury stron2. Identyfikacji elementów interaktywnych3. Generowania realistycznych ścieżek użytkowników4. Wykonywania i walidacji podróży"
# Todo:# - [ ] Połącz z Playwright MCP# - [ ] Mapuj nawigację aplikacji# - [ ] Generuj podróże oparte na personach# - [ ] Wykonuj testy podróży# - [ ] Zbieraj metryki wydajności
// AI tworzy realistyczne podróże użytkownikówclass UserJourneyGenerator { async generateJourney(persona: UserPersona): Promise<TestJourney> { const journey = await ai.createJourney({ persona: { type: persona.type, // 'power-user', 'first-time', 'mobile' goals: persona.goals, constraints: persona.constraints }, application: { type: 'e-commerce', features: await this.analyzeFeatures() } });
return { name: journey.name, steps: journey.steps.map(step => ({ action: step.action, validation: step.expectedOutcome, alternatives: step.fallbackActions })) }; }}
// Testuj wiele podróży użytkownikówtest.describe('Testy podróży użytkowników', () => { const personas = [ { type: 'first-time', goals: ['browse', 'purchase'] }, { type: 'returning', goals: ['reorder', 'track'] }, { type: 'mobile', goals: ['quick-buy'] } ];
personas.forEach(persona => { test(`podróż użytkownika ${persona.type}`, async ({ page }) => { const generator = new UserJourneyGenerator(); const journey = await generator.generateJourney(persona);
for (const step of journey.steps) { // Wykonaj krok await page.evaluate(step.action);
// Waliduj wynik const result = await step.validation(page); expect(result.success).toBe(true);
// Przechwyć metryki await captureStepMetrics(page, step.name); } }); });});
// Metryki wydajności podczas testów E2Etest('wydajność przepływu płatności', async ({ page }) => { const metrics = new PerformanceCollector();
// Monitoruj przez całą podróż page.on('load', () => metrics.capture('pageLoad')); page.on('domcontentloaded', () => metrics.capture('domReady'));
// Nawiguj i wchodzi w interakcje await page.goto('/products'); metrics.mark('products-loaded');
await page.click('[data-product-id="123"]'); metrics.mark('product-selected');
await page.click('button:has-text("Dodaj do koszyka")'); metrics.mark('added-to-cart');
// AI analizuje wydajność const analysis = await ai.analyzePerformance({ metrics: metrics.getAll(), budgets: { 'products-loaded': 2000, 'added-to-cart': 500 } });
expect(analysis.violations).toHaveLength(0);
// Generuj raport wydajności await generatePerformanceReport({ journey: 'checkout', metrics: analysis, suggestions: analysis.aiSuggestions });});
// Kompleksowe testowanie dostępnościtest.describe('Zgodność z dostępnością', () => { test('zgodność WCAG 2.1 AA', async ({ page }) => { await page.goto('/');
// Uruchom axe-core z ulepszeniem AI const violations = await page.evaluate(async () => { const results = await window.axe.run();
// AI kategoryzuje i priorytetyzuje naruszenia return ai.analyzeA11yViolations({ violations: results.violations, context: { pageType: 'landing', userFlow: 'initial-visit' } }); });
// AI sugeruje poprawki for (const violation of violations) { console.log(` Problem: ${violation.description} Wpływ: ${violation.impact} Poprawka AI: ${violation.suggestedFix} Kod: ${violation.codeSnippet} `); }
expect(violations.filter(v => v.impact === 'critical')).toHaveLength(0); });
test('nawigacja klawiaturowa', async ({ page }) => { await page.goto('/');
// AI testuje dostępność klawiatury const keyboardTest = await ai.testKeyboardNavigation({ startElement: 'body', expectedFlow: ['nav', 'main', 'footer'], interactions: ['tab', 'enter', 'escape'] });
expect(keyboardTest.accessible).toBe(true); });});
// Testy specyficzne dla mobiletest.describe('Doświadczenie mobilne', () => { test.use({ viewport: { width: 375, height: 812 }, // iPhone X hasTouch: true, isMobile: true });
test('przepływ płatności mobilnej', async ({ page }) => { await page.goto('/');
// Testuj interakcje dotykowe await page.tap('[data-testid="menu-burger"]'); await expect(page.locator('.mobile-menu')).toBeVisible();
// Przeciągnij do przeglądania produktów await page.locator('.product-carousel').swipe('left');
// Testuj funkcje specyficzne dla mobile await page.tap('text=Dodaj do koszyka');
// Weryfikuj optymalizacje mobilne const mobileOptimizations = await ai.checkMobileOptimizations({ viewport: await page.viewportSize(), performance: await page.metrics(), interactions: ['tap', 'swipe', 'pinch'] });
expect(mobileOptimizations.score).toBeGreaterThan(90); });});
Playwright MCP do kontroli przeglądarki
# Bezpośrednia manipulacja przeglądarki"Użyj Playwright MCP do przejścia do /products""Zrób zrzut ekranu obecnej strony""Kliknij na pierwszy produkt""Waliduj, że szczegóły produktu są widoczne"
Database MCP dla danych testowych
# Skonfiguruj dane testowe"Połącz z PostgreSQL MCP i:1. Utwórz testowe konta użytkowników2. Dodaj przykładowe produkty3. Wyczyść dane testowe po uruchomieniach"
GitHub MCP dla wyników testów
# Raportuj status testów"Użyj GitHub MCP do:1. Komentowania wyników testów na PR2. Aktualizacji statusu commita3. Linkowania do raportów testów"
Testuj podróże użytkowników
// Skup się na kompletnych przepływach użytkownikówtest('zakup end-to-end', async ({ page }) => { await completePurchaseJourney(page, { product: 'laptop', payment: 'credit-card', shipping: 'express' });});
Używaj wzorców Page Object
// Utrzymywalny wzorzec page objectclass LoginPage { constructor(private page: Page) {}
async login(email: string, password: string) { await this.page.fill('#email', email); await this.page.fill('#password', password); await this.page.click('button[type="submit"]'); }}
Obsługuj operacje asynchroniczne
// Inteligentne strategie oczekiwaniaawait page.waitForLoadState('networkidle');await page.waitForSelector('.content', { state: 'visible'});
Równoległe wykonywanie
// Uruchamiaj testy równolegletest.describe.parallel('Testy produktów', () => { test('produkt A', async ({ page }) => { /* ... */ }); test('produkt B', async ({ page }) => { /* ... */ });});
# PRD: Potok ciągłego testowania E2E# Plan: Integruj testy E2E z CI/CD używając GitHub Actions
"Używając GitHub MCP (jeśli dostępne) lub standardowych GitHub Actions:1. Skonfiguruj macierz testów dla przeglądarek2. Skonfiguruj Playwright MCP w CI3. Uruchamiaj testy na PR i push4. Generuj raporty testów"
# Przepływ pracy E2E GitHub Actionsname: Testy E2E
on: push: branches: [main] pull_request:
jobs: e2e-tests: runs-on: ubuntu-latest strategy: matrix: browser: [chromium, firefox, webkit]
steps: - uses: actions/checkout@v3
- name: Zainstaluj Playwright run: npx playwright install --with-deps ${{ matrix.browser }}
- name: Uruchom testy E2E run: | npm run test:e2e -- \ --browser=${{ matrix.browser }} \ --reporter=html \ --retries=2 env: AI_API_KEY: ${{ secrets.AI_API_KEY }}
- name: Prześlij raporty if: always() uses: actions/upload-artifact@v3 with: name: playwright-report-${{ matrix.browser }} path: playwright-report/
- name: Analiza testów AI if: failure() run: | npm run analyze:test-failures -- \ --report=playwright-report \ --suggest-fixes