diff --git a/autogpt_platform/frontend/src/tests/marketplace.spec.ts b/autogpt_platform/frontend/src/tests/marketplace.spec.ts new file mode 100644 index 0000000000..2c08e391dc --- /dev/null +++ b/autogpt_platform/frontend/src/tests/marketplace.spec.ts @@ -0,0 +1,129 @@ +import { expect, TestInfo } from "@playwright/test"; +import { test } from "./fixtures"; +import { BuildPage } from "./pages/build.page"; +import { MonitorPage } from "./pages/monitor.page"; +import { v4 as uuidv4 } from "uuid"; +import * as fs from "fs/promises"; +import path from "path"; +import { MarketplacePage } from "./pages/marketplace.page"; + +test.describe("Marketplace", () => { + let buildPage: BuildPage; + let monitorPage: MonitorPage; + let marketplacePage: MarketplacePage; + test.beforeEach(async ({ page, loginPage, testUser }, testInfo: TestInfo) => { + buildPage = new BuildPage(page); + monitorPage = new MonitorPage(page); + marketplacePage = new MarketplacePage(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("/"); + + // add a test agent + const basicBlock = await buildPage.getDictionaryBlockDetails(); + const testAttachName = uuidv4(); + await buildPage.createSingleBlockAgent( + `test-agent-${testAttachName}`, + `test-agent-description-${testAttachName}`, + basicBlock, + ); + await buildPage.runAgent(); + await monitorPage.navbar.clickMonitorLink(); + await monitorPage.waitForPageLoad(); + await test.expect(monitorPage.isLoaded()).resolves.toBeTruthy(); + testInfo.attach("agent-testAttachName", { body: testAttachName }); + }); + + test.afterAll(async ({}) => { + await marketplacePage.deleteAgent(`test-agent-${testAttachName}`); + }); + + test("user can view marketplace", async ({ page }) => { + await test.expect(marketplacePage.isLoaded()).resolves.toBeTruthy(); + }); + + test("user can view store page", async ({ page }, testInfo: TestInfo) => { + await marketplacePage.navbar.clickStoreLink(); + await test.expect(page).toHaveURL(new RegExp("/.*store")); + }); + + test("user can view a specific agent", async ({ page }) => { + await marketplacePage.navbar.clickStoreLink(); + await test.expect(page).toHaveURL(new RegExp("/.*store")); + await marketplacePage.selectAgent(`test-agent-${testAttachName}`); + await test.expect(page).toHaveURL(new RegExp("/.*store/agent")); + }); + + test("user can submit an agent to the marketplace", async ({ + page, + }, testInfo: TestInfo) => { + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.submitAgent(`test-agent-${testAttachName}`); + }); + + test("admin can approve an agent", async ({ page }, testInfo: TestInfo) => { + // Submit the agent to the marketplace + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.submitAgent(`test-agent-${testAttachName}`); + + // Approve the agent + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.approveAgent(`test-agent-${testAttachName}`); + + // Check that the agent is in the marketplace + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + // Search for the agent + const results = await marketplacePage.searchAgent(`test-agent-${testAttachName}`); + test.expect(results.length).toBe(1); + }); + + test("admin can reject an agent", async ({ page }, testInfo: TestInfo) => { + // Submit the agent to the marketplace + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.submitAgent(`test-agent-${testAttachName}`); + + // Reject the agent + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.rejectAgent(`test-agent-${testAttachName}`); + + // Check that the agent is not in the marketplace + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + const results = await marketplacePage.searchAgent(`test-agent-${testAttachName}`); + test.expect(results.length).toBe(0); + }); + + test("user can run a marketplace agent", async ({ + page, + }, testInfo: TestInfo) => { + // Get the agent testAttachName from the test info + if (testInfo.attachments.length === 0 || !testInfo.attachments[0].body) { + throw new Error("No agent testAttachName attached to the test"); + } + const testAttachName = testInfo.attachments[0].body.toString(); + + // Download the agent + await marketplacePage.navbar.clickMarketplaceLink(); + await test.expect(page).toHaveURL(new RegExp("/.*marketplace")); + await marketplacePage.selectAgent(`test-agent-${testAttachName}`); + await marketplacePage.downloadAgent(`test-agent-${testAttachName}`); + + // Open the agent in the monitor page + await monitorPage.navbar.clickMonitorLink(); + await test.expect(page).toHaveURL(new RegExp("/.*monitor")); + await monitorPage.waitForPageLoad(); + await test.expect(monitorPage.isLoaded()).resolves.toBeTruthy(); + await monitorPage.clickAgent(`test-agent-${testAttachName}`); + + // Run the agent + await buildPage.runAgent(); + }); +}); diff --git a/autogpt_platform/frontend/src/tests/pages/marketplace.page.ts b/autogpt_platform/frontend/src/tests/pages/marketplace.page.ts new file mode 100644 index 0000000000..327c83a0af --- /dev/null +++ b/autogpt_platform/frontend/src/tests/pages/marketplace.page.ts @@ -0,0 +1,73 @@ +import { ElementHandle, Locator, Page } from "@playwright/test"; +import { BasePage } from "./base.page"; +import path from "path"; + +export class MarketplacePage extends BasePage { + constructor(page: Page) { + super(page); + } + + async isLoaded(): Promise { + console.log(`checking if marketplace page is loaded`); + try { + // Wait for the marketplace page + await this.page.getByTestId("marketplace-page").waitFor({ + state: "visible", + timeout: 10_000, + }); + + return true; + } catch (error) { + return false; + } + } + + // async listAgents(): Promise { + // console.log(`listing agents in marketplace`); + // Wait for table rows to be available + // const rows = await this.page.locator("tbody tr[data-testid]").all(); + + // const agents: Agent[] = []; + + // for (const row of rows) { + // // Get the id from data-testid attribute + // const id = (await row.getAttribute("data-testid")) || ""; + + // // Get columns - there are 3 cells per row (name, run count, last run) + // const cells = await row.locator("td").all(); + + // // Extract name from first cell + // const name = (await row.getAttribute("data-name")) || ""; + + // // Extract run count from second cell + // const runCountText = (await cells[1].textContent()) || "0"; + // const runCount = parseInt(runCountText, 10); + + // // Extract last run from third cell's title attribute (contains full timestamp) + // // If no title, the cell will be empty indicating no last run + // const lastRunCell = cells[2]; + // const lastRun = (await lastRunCell.getAttribute("title")) || ""; + + // agents.push({ + // id, + // name, + // runCount, + // lastRun, + // }); + // } + + // agents.reduce((acc, agent) => { + // if (!agent.id.includes("flow-run")) { + // acc.push(agent); + // } + // return acc; + // }, [] as Agent[]); + + // return agents; + // } + + async clickAgent(id: string) { + console.log(`selecting agent ${id} in marketplace`); + await this.page.getByTestId(id).click(); + } +}