Files
dockergprompt/playwright-report/data/dd2e8ae9f36374fdbc4083f4ced15a0879b8266a.md
2026-09-01 09:22:30 -03:00

11 KiB
Executable File

Instructions

  • Following Playwright test failed.
  • Explain why, be concise, respect Playwright best practices.
  • Provide a snippet of code with the fix, if possible.

Test info

  • Name: application.spec.js >> Forms Validation and Error Messages >> Temperature field accepts only 0.0-1.0 range
  • Location: tests/e2e/application.spec.js:543:3

Error details

Error: expect(locator).toBeVisible() failed

Locator: locator('.text-danger')
Expected: visible
Error: strict mode violation: locator('.text-danger') resolved to 2 elements:
    1) <div class="text-danger small">The title field is required.</div> aka getByText('The title field is required.')
    2) <div class="text-danger small">The temperature field must not be greater than 1.</div> aka getByText('The temperature field must')

Call log:
  - Expect "toBeVisible" with timeout 10000ms
  - waiting for locator('.text-danger')
    - waiting for navigation to finish...
    - navigated to "http://localhost:16820/prompt-projects/create"

Test source

  460 |       untestableFeatures.push('AI provider detail view: no providers exist to click');
  461 |     }
  462 |   });
  463 | 
  464 |   test('Edit AI provider', async () => {
  465 |     await adminPage.goto(`${BASE_URL}/ai-providers`);
  466 |     const firstEdit = adminPage.locator('a[href*="ai-providers/"][class*="btn-warning"]').first();
  467 |     const count = await firstEdit.count();
  468 |     if (count > 0) {
  469 |       await firstEdit.click();
  470 |       await adminPage.waitForURL((url) => url.pathname.includes('/ai-providers/') && !url.pathname.includes('/create'), { timeout: 10000 });
  471 |       await adminPage.waitForLoadState('networkidle').catch(() => {});
  472 |       await expect(adminPage.locator('#name')).toBeVisible();
  473 |     } else {
  474 |       untestableFeatures.push('AI provider edit: no providers exist to edit');
  475 |     }
  476 |   });
  477 | 
  478 |   test('Delete AI provider', async () => {
  479 |     await adminPage.goto(`${BASE_URL}/ai-providers`);
  480 |     const firstDelete = adminPage.locator('form[action*="ai-providers"][method="POST"]').first();
  481 |     const count = await firstDelete.count();
  482 |     if (count > 0) {
  483 |       adminPage.on('dialog', (dialog) => dialog.accept());
  484 |       await firstDelete.evaluate((form) => form.submit());
  485 |       await expect(adminPage.locator('.alert-success, .alert-danger')).toBeVisible({ timeout: 10000 });
  486 |     } else {
  487 |       untestableFeatures.push('AI provider delete: no providers exist to delete');
  488 |     }
  489 |   });
  490 | 
  491 |   test('API key visibility toggle works', async () => {
  492 |     await adminPage.goto(`${BASE_URL}/ai-providers/create`);
  493 |     const apiKeyInput = adminPage.locator('#api_key');
  494 |     const toggleBtn = adminPage.locator('#toggleApiKey');
  495 |     if (await toggleBtn.count() > 0) {
  496 |       await expect(apiKeyInput).toHaveAttribute('type', 'password');
  497 |       await toggleBtn.click();
  498 |       await expect(apiKeyInput).toHaveAttribute('type', 'text');
  499 |       await toggleBtn.click();
  500 |       await expect(apiKeyInput).toHaveAttribute('type', 'password');
  501 |     } else {
  502 |       untestableFeatures.push('API key toggle: toggle button not found');
  503 |     }
  504 |   });
  505 | });
  506 | 
  507 | // ========== FORMS VALIDATION ==========
  508 | test.describe('Forms Validation and Error Messages', () => {
  509 |   let adminPage;
  510 | 
  511 |   test.beforeEach(async ({ context }) => {
  512 |     adminPage = await login(context, SUPERADMIN_EMAIL, SUPERADMIN_PASSWORD);
  513 |   });
  514 | 
  515 |   test.afterEach(async () => {
  516 |     await adminPage.close();
  517 |   });
  518 | 
  519 |   test('Prompt project form shows validation errors for missing fields', async () => {
  520 |     await adminPage.goto(`${BASE_URL}/prompt-projects/create`);
  521 |     await adminPage.evaluate(() => {
  522 |       const form = document.querySelector('form:has(#title)');
  523 |       if (form) {
  524 |         Array.from(form.querySelectorAll('[required]')).forEach(el => el.removeAttribute('required'));
  525 |         form.submit();
  526 |       }
  527 |     });
  528 |     await expect(adminPage.locator('.text-danger')).toHaveCount(2, { timeout: 10000 });
  529 |   });
  530 | 
  531 |   test('AI provider form shows validation errors for missing fields', async () => {
  532 |     await adminPage.goto(`${BASE_URL}/ai-providers/create`);
  533 |     await adminPage.evaluate(() => {
  534 |       const form = document.querySelector('form:has(#name)');
  535 |       if (form) {
  536 |         Array.from(form.querySelectorAll('[required]')).forEach(el => el.removeAttribute('required'));
  537 |         form.submit();
  538 |       }
  539 |     });
  540 |     await expect(adminPage.locator('.text-danger')).toHaveCount(4, { timeout: 10000 });
  541 |   });
  542 | 
  543 |   test('Temperature field accepts only 0.0-1.0 range', async () => {
  544 |     await adminPage.goto(`${BASE_URL}/prompt-projects/create`);
  545 |     await adminPage.fill('#temperature', '1.5');
  546 |     await adminPage.evaluate(() => {
  547 |       const form = document.querySelector('form:has(#title)');
  548 |       if (form) form.submit();
  549 |     });
  550 |     const providerSelect = adminPage.locator('#provider_id');
  551 |     const providerCount = await providerSelect.locator('option').count();
  552 |     if (providerCount > 1) {
  553 |       await providerSelect.selectOption({ index: 1 });
  554 |     }
  555 |     await adminPage.fill('#objective', 'Test');
  556 |     await adminPage.evaluate(() => {
  557 |       const form = document.querySelector('form:has(#title)');
  558 |       if (form) form.submit();
  559 |     });
> 560 |     await expect(adminPage.locator('.text-danger')).toBeVisible({ timeout: 10000 });
      |                                                     ^ Error: expect(locator).toBeVisible() failed
  561 |   });
  562 | 
  563 |   test('Max tokens must be a positive integer', async () => {
  564 |     await adminPage.goto(`${BASE_URL}/prompt-projects/create`);
  565 |     await adminPage.fill('#max_tokens', '-5');
  566 |     await adminPage.evaluate(() => {
  567 |       const form = document.querySelector('form:has(#title)');
  568 |       if (form) form.submit();
  569 |     });
  570 |     const providerSelect = adminPage.locator('#provider_id');
  571 |     const providerCount = await providerSelect.locator('option').count();
  572 |     if (providerCount > 1) {
  573 |       await providerSelect.selectOption({ index: 1 });
  574 |     }
  575 |     await adminPage.fill('#objective', 'Test');
  576 |     await adminPage.evaluate(() => {
  577 |       const form = document.querySelector('form:has(#title)');
  578 |       if (form) form.submit();
  579 |     });
  580 |     await expect(adminPage.locator('.text-danger')).toBeVisible({ timeout: 10000 });
  581 |   });
  582 | });
  583 | 
  584 | // ========== COOKIE CONSENT ==========
  585 | test.describe('Cookie Consent Banner', () => {
  586 |   test('Banner appears on public pages', async ({ page }) => {
  587 |     await page.goto(BASE_URL);
  588 |     await expect(page.locator('#cookieConsentBanner')).toBeAttached();
  589 |   });
  590 | 
  591 |   test('Accept all cookies closes banner', async ({ page }) => {
  592 |     await page.goto(BASE_URL);
  593 |     await page.waitForSelector('#cookieConsentBanner', { state: 'visible', timeout: 5000 }).catch(() => {});
  594 |     const acceptBtn = page.locator('.cookie-btn-accept');
  595 |     if (await acceptBtn.count() > 0) {
  596 |       await acceptBtn.click();
  597 |       await page.waitForTimeout(500);
  598 |       await expect(page.locator('#cookieConsentBanner')).not.toBeVisible();
  599 |     } else {
  600 |       untestableFeatures.push('Cookie consent accept button not visible (banner may not have appeared)');
  601 |     }
  602 |   });
  603 | 
  604 |   test('Cookie preferences modal can be opened', async ({ page }) => {
  605 |     await page.goto(BASE_URL);
  606 |     await page.waitForSelector('#cookieConsentBanner', { state: 'visible', timeout: 5000 }).catch(() => {});
  607 |     const customizeBtn = page.locator('.cookie-btn-customize');
  608 |     if (await customizeBtn.count() > 0) {
  609 |       await customizeBtn.click();
  610 |       await expect(page.locator('#cookieConsentPreferences')).toBeVisible();
  611 |       await page.locator('.btn-close').click();
  612 |     } else {
  613 |       untestableFeatures.push('Cookie customize button not visible');
  614 |     }
  615 |   });
  616 | 
  617 |   test('Cookie consent persists across page navigation', async ({ page }) => {
  618 |     await page.goto(BASE_URL);
  619 |     await page.waitForSelector('#cookieConsentBanner', { state: 'visible', timeout: 5000 }).catch(() => {});
  620 |     const acceptBtn = page.locator('.cookie-btn-accept');
  621 |     if (await acceptBtn.count() > 0) {
  622 |       await acceptBtn.click();
  623 |       await page.waitForTimeout(500);
  624 |       await page.goto(`${BASE_URL}/login`);
  625 |       const banner = page.locator('#cookieConsentBanner');
  626 |       await expect(banner).not.toBeVisible({ timeout: 3000 }).catch(() => {});
  627 |     } else {
  628 |       untestableFeatures.push('Cookie consent accept button not visible for persistence test');
  629 |     }
  630 |   });
  631 | });
  632 | 
  633 | // ========== RESPONSIVENESS ==========
  634 | test.describe('Responsiveness', () => {
  635 |   test('Desktop viewport 1920x1080: sidebar visible and layout stable', async ({ page }) => {
  636 |     await page.setViewportSize({ width: 1920, height: 1080 });
  637 |     await page.goto(`${BASE_URL}/login`);
  638 |     await expect(page.locator('.login-card')).toBeVisible();
  639 |   });
  640 | 
  641 |   test('Mobile viewport 375x667: login page adapts', async ({ page }) => {
  642 |     await page.setViewportSize({ width: 375, height: 667 });
  643 |     await page.goto(`${BASE_URL}/login`);
  644 |     await expect(page.locator('.login-card')).toBeVisible();
  645 |     await expect(page.locator('#email')).toBeVisible();
  646 |   });
  647 | 
  648 |   test('Mobile: hamburger menu toggles sidebar', async ({ context }) => {
  649 |     const page = await login(context, SUPERADMIN_EMAIL, SUPERADMIN_PASSWORD);
  650 |     await page.setViewportSize({ width: 375, height: 667 });
  651 |     await page.goto(`${BASE_URL}/dashboard`);
  652 |     const sidebar = page.locator('#sidebar');
  653 |     await expect(sidebar).toBeVisible();
  654 |     await page.click('#sidebarCollapse');
  655 |     await page.waitForTimeout(300);
  656 |     await page.close();
  657 |   });
  658 | 
  659 |   test('Mobile: dashboard cards stack vertically', async ({ page }) => {
  660 |     await page.setViewportSize({ width: 375, height: 667 });