mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
chore: tests
This commit is contained in:
261
autogpt_platform/frontend/src/tests/agent-notifications.spec.ts
Normal file
261
autogpt_platform/frontend/src/tests/agent-notifications.spec.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { test } from "./fixtures";
|
||||
import { LibraryPage } from "./pages/library.page";
|
||||
|
||||
test.describe("Agent Notifications", () => {
|
||||
let libraryPage: LibraryPage;
|
||||
|
||||
test.beforeEach(async ({ page, loginPage, testUser }) => {
|
||||
libraryPage = new LibraryPage(page);
|
||||
|
||||
// Start each test with login using worker auth
|
||||
await page.goto("/login");
|
||||
await loginPage.login(testUser.email, testUser.password);
|
||||
await test.expect(page).toHaveURL("/marketplace");
|
||||
});
|
||||
|
||||
test("notification badge appears when agent is running", async ({ page }) => {
|
||||
// Navigate to library
|
||||
await libraryPage.navigateToLibrary();
|
||||
await test.expect(page).toHaveURL(new RegExp("/library"));
|
||||
|
||||
// Click on first available agent
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
// Verify we're on agent page
|
||||
await test.expect(libraryPage.isLoaded()).resolves.toBeTruthy();
|
||||
|
||||
// Initially, no notification badge should be visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||
.resolves.toBeFalsy();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
|
||||
// Wait for run to start and notification badge to appear
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Check that notification badge appears
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||
.resolves.toBeTruthy();
|
||||
|
||||
// Check that notification count is at least 1
|
||||
const notificationCount =
|
||||
await libraryPage.agentNotifications.getNotificationCount();
|
||||
test.expect(parseInt(notificationCount)).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("notification dropdown shows running agent with correct status", async ({
|
||||
page: _page,
|
||||
}) => {
|
||||
// Navigate to library and run an agent
|
||||
await libraryPage.navigateToLibrary();
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
const agentName = await libraryPage.getAgentName();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Click on notification button to open dropdown
|
||||
await libraryPage.agentNotifications.clickNotificationButton();
|
||||
|
||||
// Verify dropdown is visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||
.resolves.toBeTruthy();
|
||||
|
||||
// Check that running agent appears in dropdown
|
||||
await test
|
||||
.expect(
|
||||
libraryPage.agentNotifications.hasNotificationWithStatus("running"),
|
||||
)
|
||||
.resolves.toBeTruthy();
|
||||
|
||||
// Check that the agent name appears in notifications
|
||||
const notification =
|
||||
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||
agentName,
|
||||
);
|
||||
test.expect(notification).not.toBeNull();
|
||||
test.expect(notification?.status).toBe("running");
|
||||
});
|
||||
|
||||
test("notification dropdown shows completed agent after run finishes", async ({
|
||||
page: _page,
|
||||
}, testInfo) => {
|
||||
// Increase timeout for this test since we need to wait for completion
|
||||
await test.setTimeout(testInfo.timeout * 3);
|
||||
|
||||
// Navigate to library and run an agent
|
||||
await libraryPage.navigateToLibrary();
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
const agentName = await libraryPage.getAgentName();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Wait for agent to complete (with longer timeout)
|
||||
await libraryPage.waitForRunToComplete(60000);
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Click on notification button to open dropdown
|
||||
await libraryPage.agentNotifications.clickNotificationButton();
|
||||
|
||||
// Verify dropdown is visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||
.resolves.toBeTruthy();
|
||||
|
||||
// Check that completed agent appears in dropdown
|
||||
const notification =
|
||||
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||
agentName,
|
||||
);
|
||||
test.expect(notification).not.toBeNull();
|
||||
test.expect(notification?.status).toMatch(/completed|failed|terminated/);
|
||||
});
|
||||
|
||||
test("notification dropdown shows correct time information", async ({
|
||||
page: _page,
|
||||
}) => {
|
||||
// Navigate to library and run an agent
|
||||
await libraryPage.navigateToLibrary();
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
const agentName = await libraryPage.getAgentName();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Click on notification button to open dropdown
|
||||
await libraryPage.agentNotifications.clickNotificationButton();
|
||||
|
||||
// Get notification for this agent
|
||||
const notification =
|
||||
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||
agentName,
|
||||
);
|
||||
test.expect(notification).not.toBeNull();
|
||||
|
||||
// Check that time information is present and contains expected text
|
||||
test.expect(notification?.time).toContain("Started");
|
||||
test.expect(notification?.time).toMatch(/Started.*ago.*seconds/);
|
||||
});
|
||||
|
||||
test("notification dropdown shows multiple agents when multiple are running", async ({
|
||||
page: _page,
|
||||
}) => {
|
||||
// Navigate to library
|
||||
await libraryPage.navigateToLibrary();
|
||||
|
||||
// Run first agent
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
const firstAgentName = await libraryPage.getAgentName();
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Go back to library and run another agent (if available)
|
||||
await libraryPage.navigateToLibrary();
|
||||
const agentCards = await libraryPage.agentCards.count();
|
||||
|
||||
if (agentCards > 1) {
|
||||
await libraryPage.agentCards.nth(1).click();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
const secondAgentName = await libraryPage.getAgentName();
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Click on notification button to open dropdown
|
||||
await libraryPage.agentNotifications.clickNotificationButton();
|
||||
|
||||
// Verify both agents appear in dropdown
|
||||
const firstNotification =
|
||||
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||
firstAgentName,
|
||||
);
|
||||
const secondNotification =
|
||||
await libraryPage.agentNotifications.getNotificationByAgentName(
|
||||
secondAgentName,
|
||||
);
|
||||
|
||||
test.expect(firstNotification).not.toBeNull();
|
||||
test.expect(secondNotification).not.toBeNull();
|
||||
|
||||
// Check that notification count reflects multiple running agents
|
||||
const notificationCount =
|
||||
await libraryPage.agentNotifications.getNotificationCount();
|
||||
test.expect(parseInt(notificationCount)).toBeGreaterThanOrEqual(2);
|
||||
} else {
|
||||
// Skip this part if only one agent is available
|
||||
console.log("Only one agent available, skipping multiple agent test");
|
||||
}
|
||||
});
|
||||
|
||||
test("notification dropdown closes when clicking outside", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Navigate to library and run an agent
|
||||
await libraryPage.navigateToLibrary();
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Click on notification button to open dropdown
|
||||
await libraryPage.agentNotifications.clickNotificationButton();
|
||||
|
||||
// Verify dropdown is visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||
.resolves.toBeTruthy();
|
||||
|
||||
// Click outside the dropdown
|
||||
await page.click("body");
|
||||
|
||||
// Verify dropdown is no longer visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationDropdownVisible())
|
||||
.resolves.toBeFalsy();
|
||||
});
|
||||
|
||||
test("notification badge count updates correctly", async ({
|
||||
page: _page,
|
||||
}) => {
|
||||
// Navigate to library and run an agent
|
||||
await libraryPage.navigateToLibrary();
|
||||
await libraryPage.clickFirstAgent();
|
||||
await libraryPage.waitForAgentPageLoad();
|
||||
|
||||
// Initially, no notification badge should be visible
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||
.resolves.toBeFalsy();
|
||||
|
||||
// Run the agent
|
||||
await libraryPage.runAgent();
|
||||
await libraryPage.agentNotifications.waitForNotificationUpdate();
|
||||
|
||||
// Check that notification count is 1
|
||||
const notificationCount =
|
||||
await libraryPage.agentNotifications.getNotificationCount();
|
||||
test.expect(notificationCount).toBe("1");
|
||||
|
||||
// Check that badge is visible and animating
|
||||
await test
|
||||
.expect(libraryPage.agentNotifications.isNotificationBadgeVisible())
|
||||
.resolves.toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
|
||||
export class AgentNotificationsPage {
|
||||
constructor(private page: Page) {}
|
||||
|
||||
get notificationButton(): Locator {
|
||||
return this.page.locator('button[title="Agent Activity"]');
|
||||
}
|
||||
|
||||
get notificationBadge(): Locator {
|
||||
return this.page
|
||||
.locator('button[title="Agent Activity"] .animate-spin')
|
||||
.first();
|
||||
}
|
||||
|
||||
get notificationDropdown(): Locator {
|
||||
return this.page.locator('[role="dialog"]:has-text("Agent Activity")');
|
||||
}
|
||||
|
||||
get notificationItems(): Locator {
|
||||
return this.notificationDropdown.locator('[role="button"]');
|
||||
}
|
||||
|
||||
async clickNotificationButton(): Promise<void> {
|
||||
await this.notificationButton.click();
|
||||
}
|
||||
|
||||
async isNotificationBadgeVisible(): Promise<boolean> {
|
||||
return await this.notificationBadge.isVisible();
|
||||
}
|
||||
|
||||
async isNotificationDropdownVisible(): Promise<boolean> {
|
||||
return await this.notificationDropdown.isVisible();
|
||||
}
|
||||
|
||||
async getNotificationCount(): Promise<string> {
|
||||
const badge = this.page.locator(
|
||||
'button[title="Agent Activity"] .bg-purple-600',
|
||||
);
|
||||
return (await badge.textContent()) || "0";
|
||||
}
|
||||
|
||||
async getNotificationItems(): Promise<
|
||||
{ name: string; status: string; time: string }[]
|
||||
> {
|
||||
const items = await this.notificationItems.all();
|
||||
const results = [];
|
||||
|
||||
for (const item of items) {
|
||||
const name = (await item.locator(".truncate").textContent()) || "";
|
||||
const time =
|
||||
(await item.locator(".\\!text-zinc-500").textContent()) || "";
|
||||
|
||||
// Determine status from icon classes and text content
|
||||
let status = "unknown";
|
||||
if (await item.locator(".animate-spin").isVisible()) {
|
||||
status = "running";
|
||||
} else if (await item.locator("svg").first().isVisible()) {
|
||||
// For non-animated icons, check the text content to determine status
|
||||
const timeText = time.toLowerCase();
|
||||
if (timeText.includes("completed")) {
|
||||
status = "completed";
|
||||
} else if (timeText.includes("failed")) {
|
||||
status = "failed";
|
||||
} else if (timeText.includes("stopped")) {
|
||||
status = "terminated";
|
||||
} else if (timeText.includes("incomplete")) {
|
||||
status = "incomplete";
|
||||
} else if (timeText.includes("queued")) {
|
||||
status = "queued";
|
||||
}
|
||||
}
|
||||
|
||||
results.push({ name, status, time });
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async waitForNotificationUpdate(_timeout = 10000): Promise<void> {
|
||||
await this.page.waitForTimeout(1000); // Wait for potential updates
|
||||
}
|
||||
|
||||
async hasNotificationWithStatus(status: string): Promise<boolean> {
|
||||
const items = await this.getNotificationItems();
|
||||
return items.some((item) => item.status === status);
|
||||
}
|
||||
|
||||
async getNotificationByAgentName(
|
||||
agentName: string,
|
||||
): Promise<{ name: string; status: string; time: string } | null> {
|
||||
const items = await this.getNotificationItems();
|
||||
return items.find((item) => item.name.includes(agentName)) || null;
|
||||
}
|
||||
}
|
||||
107
autogpt_platform/frontend/src/tests/pages/library.page.ts
Normal file
107
autogpt_platform/frontend/src/tests/pages/library.page.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
import { AgentNotificationsPage } from "./agent-notifications.page";
|
||||
|
||||
export class LibraryPage {
|
||||
public agentNotifications: AgentNotificationsPage;
|
||||
|
||||
constructor(private page: Page) {
|
||||
this.agentNotifications = new AgentNotificationsPage(page);
|
||||
}
|
||||
|
||||
get libraryTab(): Locator {
|
||||
return this.page.locator('a[href="/library"]');
|
||||
}
|
||||
|
||||
get agentCards(): Locator {
|
||||
return this.page.locator(".agpt-div").filter({ hasText: /^test-agent-/ });
|
||||
}
|
||||
|
||||
get runButton(): Locator {
|
||||
return this.page.locator('button:has-text("Run")');
|
||||
}
|
||||
|
||||
get newRunButton(): Locator {
|
||||
return this.page.locator('button:has-text("New run")');
|
||||
}
|
||||
|
||||
get runDialogRunButton(): Locator {
|
||||
return this.page.locator('button:has-text("Run"):last-child');
|
||||
}
|
||||
|
||||
get agentTitle(): Locator {
|
||||
return this.page.locator("h1").first();
|
||||
}
|
||||
|
||||
async navigateToLibrary(): Promise<void> {
|
||||
await this.libraryTab.click();
|
||||
await this.page.waitForURL(/.*\/library/);
|
||||
}
|
||||
|
||||
async clickFirstAgent(): Promise<void> {
|
||||
const firstAgent = this.agentCards.first();
|
||||
await firstAgent.click();
|
||||
}
|
||||
|
||||
async navigateToAgentByName(agentName: string): Promise<void> {
|
||||
const agentCard = this.agentCards.filter({ hasText: agentName }).first();
|
||||
await agentCard.click();
|
||||
}
|
||||
|
||||
async clickRunButton(): Promise<void> {
|
||||
await this.runButton.click();
|
||||
}
|
||||
|
||||
async clickNewRunButton(): Promise<void> {
|
||||
await this.newRunButton.click();
|
||||
}
|
||||
|
||||
async runAgent(inputs: Record<string, string> = {}): Promise<void> {
|
||||
await this.clickRunButton();
|
||||
|
||||
// Fill in any required inputs
|
||||
for (const [key, value] of Object.entries(inputs)) {
|
||||
const input = this.page.locator(
|
||||
`input[placeholder*="${key}"], textarea[placeholder*="${key}"]`,
|
||||
);
|
||||
if (await input.isVisible()) {
|
||||
await input.fill(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Click the run button in the dialog
|
||||
await this.runDialogRunButton.click();
|
||||
}
|
||||
|
||||
async waitForAgentPageLoad(): Promise<void> {
|
||||
await this.page.waitForURL(/.*\/library\/agents\/[^/]+/);
|
||||
await this.page.waitForLoadState("networkidle");
|
||||
}
|
||||
|
||||
async getAgentName(): Promise<string> {
|
||||
return (await this.agentTitle.textContent()) || "";
|
||||
}
|
||||
|
||||
async isLoaded(): Promise<boolean> {
|
||||
return await this.page.locator("h1").isVisible();
|
||||
}
|
||||
|
||||
async waitForRunToComplete(timeout = 30000): Promise<void> {
|
||||
// Wait for completion badge or status change
|
||||
await this.page.waitForSelector(
|
||||
".bg-green-500, .bg-red-500, .bg-purple-500",
|
||||
{ timeout },
|
||||
);
|
||||
}
|
||||
|
||||
async getRunStatus(): Promise<string> {
|
||||
// Check for different status indicators
|
||||
if (await this.page.locator(".animate-spin").isVisible()) {
|
||||
return "running";
|
||||
} else if (await this.page.locator(".bg-green-500").isVisible()) {
|
||||
return "completed";
|
||||
} else if (await this.page.locator(".bg-red-500").isVisible()) {
|
||||
return "failed";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user