Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions tests/e2e/pr-174/bot-edit-preview-accordion-sections.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { test, expect } from '@playwright/test';

test('Bot-Edit System-Prompt preview modal shows all 6 accordion sections', async ({ page }) => {
await page.goto('/bots');

// Open the edit modal for the first bot listed
const editTrigger = page
.locator('[data-bs-toggle="modal"], a, button')
.filter({ hasText: /Edit/i })
.first();
await editTrigger.click();

// Trigger the System-Prompt preview action
const previewBtn = page
.locator('button, a')
.filter({ hasText: /Preview.*System-?Prompt|System-?Prompt.*Preview/i })
.first();
await previewBtn.click();

const previewAccordion = page.locator('#systemPromptPreviewAccordion');
await expect(previewAccordion).toBeVisible({ timeout: 8000 });

const items = previewAccordion.locator('.accordion-item');
await expect(items).toHaveCount(6);

const headersText = (await previewAccordion.locator('.accordion-button').allTextContents()).join(' | ');
expect(headersText).toContain('E2E Planner');
expect(headersText).toContain('E2E Author');
expect(headersText).toContain('E2E Runner System-Prompt');

// Close any open modal so the page state stays clean
await page.keyboard.press('Escape').catch(() => {});
});
26 changes: 26 additions & 0 deletions tests/e2e/pr-174/system-prompts-accordion-renders.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { test, expect } from '@playwright/test';

test('System-Prompts edit page renders accordion with all 6 sections', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');

const accordion = page.locator('#systemPromptsAccordion');
await expect(accordion).toBeVisible();

const items = accordion.locator('.accordion-item');
await expect(items).toHaveCount(6);

// Verify the expected prompt headers are present
const expectedHeaders = [
'Review System-Prompt',
'Issue-Agent System-Prompt',
'Writer-Agent System-Prompt',
'E2E Planner',
'E2E Author',
'E2E Runner System-Prompt',
];

const headerText = (await accordion.locator('.accordion-button').allTextContents()).join(' | ');
for (const expected of expectedHeaders) {
expect(headerText).toContain(expected);
}
});
22 changes: 22 additions & 0 deletions tests/e2e/pr-174/system-prompts-collapse-all-button.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test, expect } from '@playwright/test';

test('Collapse all button closes every prompt section', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');

await page.locator('#expandAllPromptsBtn').click();
await page.waitForTimeout(600);

await page.locator('#collapseAllPromptsBtn').click();
await page.waitForTimeout(600);

const collapses = page.locator('#systemPromptsAccordion .accordion-collapse');
const count = await collapses.count();
expect(count).toBeGreaterThan(0);

for (let i = 0; i < count; i++) {
await expect(collapses.nth(i)).not.toHaveClass(/\bshow\b/, { timeout: 5000 });
}

// Cleanup the localStorage so the default state resumes for other tests
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
});
45 changes: 45 additions & 0 deletions tests/e2e/pr-174/system-prompts-edit-and-save.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { test, expect } from '@playwright/test';

test('User can edit a prompt inside an accordion section and save successfully', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');

// Ensure the Review section is open
const reviewCollapse = page.locator('#collapseReviewPrompt');
if (!(await reviewCollapse.evaluate((el) => el.classList.contains('show')).catch(() => false))) {
await page.getByRole('button', { name: /Review System-Prompt/i }).click();
await expect(reviewCollapse).toHaveClass(/\bshow\b/, { timeout: 5000 });
}

const textarea = page.locator('#reviewSystemPrompt');
await expect(textarea).toBeVisible();

const original = (await textarea.inputValue()) ?? '';
const marker = `\n<!-- e2e-marker-${Date.now()} -->`;
await textarea.fill(original + marker);

// Submit the form containing this textarea
await textarea.evaluate((el: HTMLTextAreaElement) => el.form?.requestSubmit());

// Wait for navigation / save to settle
await page.waitForLoadState('networkidle').catch(() => {});

// Navigate back to the edit page
await page.goto('/system-settings/system-prompts/1/edit');

// Ensure the section is open to read the textarea value
const reviewCollapse2 = page.locator('#collapseReviewPrompt');
if (!(await reviewCollapse2.evaluate((el) => el.classList.contains('show')).catch(() => false))) {
await page.getByRole('button', { name: /Review System-Prompt/i }).click();
await expect(reviewCollapse2).toHaveClass(/\bshow\b/, { timeout: 5000 });
}

const reloadedValue = await page.locator('#reviewSystemPrompt').inputValue();
expect(reloadedValue).toContain(marker.trim());

// Cleanup: restore the original value to keep the test idempotent
await page.locator('#reviewSystemPrompt').fill(original);
await page
.locator('#reviewSystemPrompt')
.evaluate((el: HTMLTextAreaElement) => el.form?.requestSubmit());
await page.waitForLoadState('networkidle').catch(() => {});
});
22 changes: 22 additions & 0 deletions tests/e2e/pr-174/system-prompts-expand-all-button.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { test, expect } from '@playwright/test';

test('Expand all button opens every prompt section', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');

await page.locator('#expandAllPromptsBtn').click();

// Wait briefly for the bootstrap collapse animations
await page.waitForTimeout(600);

const collapses = page.locator('#systemPromptsAccordion .accordion-collapse');
const count = await collapses.count();
expect(count).toBe(6);

for (let i = 0; i < count; i++) {
await expect(collapses.nth(i)).toHaveClass(/\bshow\b/, { timeout: 5000 });
}

// Cleanup so subsequent tests start fresh
await page.locator('#collapseAllPromptsBtn').click().catch(() => {});
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
});
21 changes: 21 additions & 0 deletions tests/e2e/pr-174/system-prompts-expand-section.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test, expect } from '@playwright/test';

test('Clicking an accordion header expands a collapsed prompt section', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
await page.reload();

const button = page.getByRole('button', { name: /Issue-Agent System-Prompt/i });
await button.click();

const collapse = page.locator('#collapseIssueAgentPrompt');
// Wait for the collapse animation to finish
await expect(collapse).toHaveClass(/\bshow\b/, { timeout: 5000 });

const textarea = page.locator('#issueAgentSystemPrompt');
await expect(textarea).toBeVisible();

// Cleanup: collapse it back so subsequent tests start clean
await button.click();
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { test, expect } from '@playwright/test';

test('Review System-Prompt section is expanded by default on first visit', async ({ browser }) => {
// Use a fresh context with cleared storage so this is the first visit
const context = await browser.newContext();
const page = await context.newPage();

// Ensure localStorage is clean before navigation
await page.goto('/system-settings/system-prompts/1/edit');
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
await page.reload();

const reviewCollapse = page.locator('#collapseReviewPrompt');
await expect(reviewCollapse).toHaveClass(/\bshow\b/);

const reviewTextarea = page.locator('#reviewSystemPrompt');
await expect(reviewTextarea).toBeVisible();

// Other sections should not have the show class
const otherCollapseIds = [
'#collapseIssueAgentPrompt',
'#collapseWriterAgentPrompt',
'#collapseE2EPlannerPrompt',
'#collapseE2EAuthorPrompt',
'#collapseE2ERunnerPrompt',
];

for (const sel of otherCollapseIds) {
const el = page.locator(sel);
if (await el.count() > 0) {
await expect(el).not.toHaveClass(/\bshow\b/);
}
}

await context.close();
});
19 changes: 19 additions & 0 deletions tests/e2e/pr-174/system-prompts-multiple-open-allowed.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { test, expect } from '@playwright/test';

test('Multiple prompt sections can be open simultaneously', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
await page.reload();

await page.getByRole('button', { name: /Issue-Agent System-Prompt/i }).click();
await expect(page.locator('#collapseIssueAgentPrompt')).toHaveClass(/\bshow\b/, { timeout: 5000 });

await page.getByRole('button', { name: /Writer-Agent System-Prompt/i }).click();
await expect(page.locator('#collapseWriterAgentPrompt')).toHaveClass(/\bshow\b/, { timeout: 5000 });

// Issue-Agent should still be open
await expect(page.locator('#collapseIssueAgentPrompt')).toHaveClass(/\bshow\b/);

// Cleanup
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
});
29 changes: 29 additions & 0 deletions tests/e2e/pr-174/system-prompts-state-persisted.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { test, expect } from '@playwright/test';

test('Expanded/collapsed state persists across page reloads via localStorage', async ({ page }) => {
await page.goto('/system-settings/system-prompts/1/edit');
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
await page.reload();

// Open E2E Runner System-Prompt section
const button = page.getByRole('button', { name: /E2E Runner System-Prompt/i });
await button.click();

const collapse = page.locator('#collapseE2ERunnerPrompt');
await expect(collapse).toHaveClass(/\bshow\b/, { timeout: 5000 });

await page.reload();

// After reload the section should still be open
await expect(page.locator('#collapseE2ERunnerPrompt')).toHaveClass(/\bshow\b/, { timeout: 5000 });

const stored = await page.evaluate(() =>
localStorage.getItem('systemPromptsEdit.collapsedSections'),
);
expect(stored).not.toBeNull();
// Either records the open section explicitly, or marks others as closed
expect(stored).toContain('E2ERunnerPrompt');

// Cleanup so the test is idempotent
await page.evaluate(() => localStorage.removeItem('systemPromptsEdit.collapsedSections'));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { test, expect } from '@playwright/test';

test('System settings list still toggles sections after refactor to shared helper', async ({ page }) => {
await page.goto('/system-settings');

await page.locator('#collapseAllSections').click();

// Wait for collapse animations to settle
await page.waitForTimeout(600);

await page.reload();

// Wait for sections to be present
await page.waitForSelector('[id^=section-].collapse', { state: 'attached' });

const sections = page.locator('[id^=section-].collapse');
const count = await sections.count();
expect(count).toBeGreaterThan(0);

for (let i = 0; i < count; i++) {
await expect(sections.nth(i)).not.toHaveClass(/\bshow\b/);
}

// Cleanup: re-expand sections by clicking expand-all if it exists, otherwise clear key
const expandBtn = page.locator('#expandAllSections');
if (await expandBtn.count() > 0) {
await expandBtn.click();
await page.waitForTimeout(600);
}
});